Raytracing backend now supports multiple worlds.

This commit is contained in:
Justin Marshall
2026-04-22 23:23:49 -07:00
parent a678dda40e
commit ef5b5f107d
18 changed files with 961 additions and 485 deletions
File diff suppressed because it is too large Load Diff
+93 -50
View File
@@ -10441,10 +10441,18 @@ static void QD3D12_ResolveSceneToOutputAndEnterNativePhase(QD3D12Window& w)
QD3D12_BindTargetsForCurrentPhase(w);
}
void glLightScene(void)
void glLightScene(glRaytracingSceneHandle_t sceneHandle)
{
const int width = (int)g_currentWindow->renderWidth;
const int height = (int)g_currentWindow->renderHeight;
if (sceneHandle == 0)
return;
auto* window = g_currentWindow;
if (!window)
return;
const int width = (int)window->renderWidth;
const int height = (int)window->renderHeight;
const auto frameIndex = window->frameIndex;
if (width <= 0 || height <= 0)
return;
@@ -10458,48 +10466,54 @@ void glLightScene(void)
if (!lightingTex || !lightingTex->texture)
return;
glRaytracingBuildScene();
// Scene/TLAS ownership is now per render world. Querying the scene TLAS here
// also builds dirty shared BLAS resources and this scene's TLAS before we
// touch the window G-buffer state.
ID3D12Resource* tlas = glRaytracingGetTopLevelASForScene(sceneHandle);
if (!tlas)
return;
glRaytracingBuildSceneForHandle(sceneHandle);
QD3D12_FlushQueuedBatches();
QD3D12_ResolveGBufferForCurrentFrame(*g_currentWindow);
QD3D12_ResolveGBufferForCurrentFrame(*window);
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
ID3D12Resource* sceneColor = g_currentWindow->sceneColorBuffers[g_currentWindow->frameIndex].Get();
ID3D12Resource* sceneNormal = g_currentWindow->normalBuffers[g_currentWindow->frameIndex].Get();
ID3D12Resource* scenePosition = g_currentWindow->positionBuffers[g_currentWindow->frameIndex].Get();
ID3D12Resource* sceneDepth = g_currentWindow->depthBuffer.Get();
ID3D12Resource* tlas = glRaytracingGetTopLevelAS();
ID3D12Resource* sceneColor = window->sceneColorBuffers[frameIndex].Get();
ID3D12Resource* sceneNormal = window->normalBuffers[frameIndex].Get();
ID3D12Resource* scenePosition = window->positionBuffers[frameIndex].Get();
ID3D12Resource* sceneDepth = window->depthBuffer.Get();
if (!sceneColor || !sceneNormal || !scenePosition || !sceneDepth || !tlas)
if (!sceneColor || !sceneNormal || !scenePosition || !sceneDepth)
return;
QD3D12_TransitionResource(
cl,
sceneColor,
g_currentWindow->sceneColorState[g_currentWindow->frameIndex],
window->sceneColorState[frameIndex],
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(
cl,
sceneNormal,
g_currentWindow->normalBufferState[g_currentWindow->frameIndex],
window->normalBufferState[frameIndex],
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(
cl,
scenePosition,
g_currentWindow->positionBufferState[g_currentWindow->frameIndex],
window->positionBufferState[frameIndex],
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(
cl,
sceneDepth,
g_currentWindow->depthState,
window->depthState,
D3D12_RESOURCE_STATE_NON_PIXEL_SHADER_RESOURCE);
// The external DXR module records and executes its own command list. Because
// of that, the scene input transitions must be submitted on the main command
// list before we call into glRaytracingLightingExecute.
// list before we call into glRaytracingLightingExecuteForScene.
if (g_lightingTextureState != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
{
QD3D12_TransitionResource(
@@ -10507,9 +10521,11 @@ void glLightScene(void)
lightingTex->texture.Get(),
g_lightingTextureState,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_lightingTextureState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
}
QD3D12_ExecuteMainCommandListAndWait(*g_currentWindow);
QD3D12_ExecuteMainCommandListAndWait(*window);
cl = g_gl.cmdList.Get();
glRaytracingLightingPassDesc_t pass = {};
@@ -10528,44 +10544,43 @@ void glLightScene(void)
pass.outputTexture = lightingTex->texture.Get();
pass.outputFormat = lightingTex->dxgiFormat;
pass.topLevelAS = tlas;
pass.width = (uint32_t)width;
pass.height = (uint32_t)height;
if (!glRaytracingLightingExecute(&pass))
if (!glRaytracingLightingExecuteForScene(&pass, sceneHandle))
{
if (QD3D12_GBufferMsaaEnabled())
{
QD3D12_TransitionResource(cl, g_currentWindow->sceneColorMsaaBuffers[g_currentWindow->frameIndex].Get(), g_currentWindow->sceneColorMsaaState[g_currentWindow->frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, g_currentWindow->normalMsaaBuffers[g_currentWindow->frameIndex].Get(), g_currentWindow->normalMsaaState[g_currentWindow->frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, g_currentWindow->positionMsaaBuffers[g_currentWindow->frameIndex].Get(), g_currentWindow->positionMsaaState[g_currentWindow->frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, g_currentWindow->velocityMsaaBuffers[g_currentWindow->frameIndex].Get(), g_currentWindow->velocityMsaaState[g_currentWindow->frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, g_currentWindow->depthMsaaBuffer.Get(), g_currentWindow->depthMsaaState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
QD3D12_TransitionResource(cl, window->sceneColorMsaaBuffers[frameIndex].Get(), window->sceneColorMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->normalMsaaBuffers[frameIndex].Get(), window->normalMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->positionMsaaBuffers[frameIndex].Get(), window->positionMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->velocityMsaaBuffers[frameIndex].Get(), window->velocityMsaaState[frameIndex], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->depthMsaaBuffer.Get(), window->depthMsaaState, D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
else
{
QD3D12_TransitionResource(
cl,
sceneColor,
g_currentWindow->sceneColorState[g_currentWindow->frameIndex],
window->sceneColorState[frameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(
cl,
sceneNormal,
g_currentWindow->normalBufferState[g_currentWindow->frameIndex],
window->normalBufferState[frameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(
cl,
scenePosition,
g_currentWindow->positionBufferState[g_currentWindow->frameIndex],
window->positionBufferState[frameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(
cl,
sceneDepth,
g_currentWindow->depthState,
window->depthState,
D3D12_RESOURCE_STATE_DEPTH_WRITE);
}
@@ -10573,46 +10588,55 @@ void glLightScene(void)
return;
}
g_lightingTextureState = D3D12_RESOURCE_STATE_UNORDERED_ACCESS;
// The scene-handle DXR path leaves outputTexture in PIXEL_SHADER_RESOURCE.
g_lightingTextureState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
QD3D12_RunRayAIDenoiseIfEnabled(cl, *g_currentWindow, lightingTex->texture.Get());
QD3D12_RunRayAIDenoiseIfEnabled(cl, *window, lightingTex->texture.Get());
QD3D12_TransitionResource(
cl,
lightingTex->texture.Get(),
g_lightingTextureState,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
// If the denoiser changes the texture state and updates g_lightingTextureState,
// restore the texture to a shader-readable state for the post/upscale pass.
if (g_lightingTextureState != D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)
{
QD3D12_TransitionResource(
cl,
lightingTex->texture.Get(),
g_lightingTextureState,
D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
g_lightingTextureState = D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE;
}
g_gl.raytracedLightingReadyThisFrame = true;
if (!QD3D12_UseLightingTextureAsUpscaleInput(*g_currentWindow))
if (!QD3D12_UseLightingTextureAsUpscaleInput(*window))
{
QD3D12_TransitionResource(
cl,
sceneColor,
g_currentWindow->sceneColorState[g_currentWindow->frameIndex],
window->sceneColorState[frameIndex],
D3D12_RESOURCE_STATE_RENDER_TARGET);
D3D12_VIEWPORT viewport{};
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = (float)g_currentWindow->renderWidth;
viewport.Height = (float)g_currentWindow->renderHeight;
viewport.Width = (float)window->renderWidth;
viewport.Height = (float)window->renderHeight;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
D3D12_RECT scissor{};
scissor.left = 0;
scissor.top = 0;
scissor.right = (LONG)g_currentWindow->renderWidth;
scissor.bottom = (LONG)g_currentWindow->renderHeight;
scissor.right = (LONG)window->renderWidth;
scissor.bottom = (LONG)window->renderHeight;
// Non-RR path: replace the low-resolution scene color with the lit result,
// then upscale that scene color into the backbuffer.
// then upscale that scene color into the backbuffer. Use the texture returned
// for this window instead of a separate global texture pointer.
QD3D12_PostFullscreenPass(
cl,
g_gl.postCopyPSO.Get(),
g_lightingTexture->srvGpu,
lightingTex->srvGpu,
CurrentResolvedSceneColorRTV(),
viewport,
scissor);
@@ -10624,9 +10648,10 @@ void glLightScene(void)
// guide instead of overwriting it here.
}
QD3D12_ResolveSceneToOutputAndEnterNativePhase(*g_currentWindow);
QD3D12_ResolveSceneToOutputAndEnterNativePhase(*window);
}
ID3D12Resource* QD3D12_GetCurrentBackBuffer()
{
if (!g_currentWindow->swapChain)
@@ -12090,9 +12115,17 @@ void glUpdateBottomAccelStructure(bool opaque, uint32_t& meshHandle)
meshHandle = glRaytracingCreateMesh(&meshDesc);
}
void glUpdateTopLevelAceelStructure(uint32_t mesh, float* transform, uint32_t& topLevelHandle) {
void glUpdateTopLevelAceelStructure(
glRaytracingSceneHandle_t scene,
uint32_t mesh,
float* transform,
uint32_t& topLevelHandle)
{
if (scene == 0 || mesh == 0)
return;
glRaytracingInstanceDesc_t instDesc = {};
instDesc.meshHandle = mesh;
instDesc.meshHandle = (glRaytracingMeshHandle_t)mesh;
instDesc.instanceID = 0;
instDesc.mask = 0xFF;
@@ -12104,15 +12137,25 @@ void glUpdateTopLevelAceelStructure(uint32_t mesh, float* transform, uint32_t& t
}
else
{
// Same contract as the old helper: transform is a 12-float
// D3D12_RAYTRACING_INSTANCE_DESC-compatible 3x4 transform.
memcpy(instDesc.transform, transform, sizeof(float) * 12);
}
if (topLevelHandle == 0)
{
topLevelHandle = glRaytracingCreateInstance(&instDesc);
}
else {
glRaytracingUpdateInstance(topLevelHandle, &instDesc);
topLevelHandle = glRaytracingCreateInstanceInScene(scene, &instDesc);
return;
}
if (!glRaytracingUpdateInstanceInScene(
scene,
(glRaytracingInstanceHandle_t)topLevelHandle,
&instDesc))
{
// The saved handle can become stale if the scene was cleared/deleted, or if
// the caller accidentally reuses a handle from another render world. Create
// a new per-scene instance and return that handle to the caller.
topLevelHandle = glRaytracingCreateInstanceInScene(scene, &instDesc);
}
}
+46 -13
View File
@@ -275,6 +275,15 @@ typedef char GLchar;
#define GL_TRUE 1
#endif
#ifndef GL_RAYTRACING_MAX_RENDER_WORLDS
#define GL_RAYTRACING_MAX_RENDER_WORLDS 24
#endif
#ifndef GL_RAYTRACING_SCENE_HANDLE_T_DEFINED
typedef uint32_t glRaytracingSceneHandle_t;
#define GL_RAYTRACING_SCENE_HANDLE_T_DEFINED
#endif
#ifndef GL_ARRAY_BUFFER
#define GL_ARRAY_BUFFER 0x8892
#endif
@@ -1540,8 +1549,6 @@ enum GeometryFlag_t
void APIENTRY glGeometryFlagf(GLfloat flag);
void glUpdateBottomAccelStructure(bool opaque, uint32_t& meshHandle);
void glUpdateTopLevelAceelStructure(uint32_t mesh, float* transform, uint32_t& topLevelHandle);
#endif
struct GLVertex
@@ -1669,8 +1676,6 @@ typedef struct glRaytracingLightingPassDesc_s
ID3D12Resource* outputTexture;
DXGI_FORMAT outputFormat;
ID3D12Resource* topLevelAS;
uint32_t width;
uint32_t height;
} glRaytracingLightingPassDesc_t;
@@ -1679,21 +1684,41 @@ int glRaytracingInit(void);
void glRaytracingShutdown(void);
void glRaytracingClear(void);
// Render-world / TLAS APIs.
// A render world owns its own instance list and TLAS. Meshes and BLAS resources
// remain shared globally. Valid scene handles are returned by glRaytracingCreateScene()
// and are in the range 1..GL_RAYTRACING_MAX_RENDER_WORLDS.
glRaytracingSceneHandle_t glRaytracingCreateScene(void);
void glRaytracingClearScene(glRaytracingSceneHandle_t sceneHandle);
void glRaytracingDeleteScene(glRaytracingSceneHandle_t sceneHandle);
uint32_t glRaytracingGetSceneCount(void);
glRaytracingMeshHandle_t glRaytracingCreateMesh(const glRaytracingMeshDesc_t* desc);
int glRaytracingUpdateMesh(glRaytracingMeshHandle_t meshHandle, const glRaytracingMeshDesc_t* desc);
void glRaytracingDeleteMesh(glRaytracingMeshHandle_t meshHandle);
glRaytracingInstanceHandle_t glRaytracingCreateInstance(const glRaytracingInstanceDesc_t* desc);
int glRaytracingUpdateInstance(glRaytracingInstanceHandle_t instanceHandle, const glRaytracingInstanceDesc_t* desc);
void glRaytracingDeleteInstance(glRaytracingInstanceHandle_t instanceHandle);
// Scene-specific instance APIs for multiple render worlds.
glRaytracingInstanceHandle_t glRaytracingCreateInstanceInScene(
glRaytracingSceneHandle_t sceneHandle,
const glRaytracingInstanceDesc_t* desc);
int glRaytracingUpdateInstanceInScene(
glRaytracingSceneHandle_t sceneHandle,
glRaytracingInstanceHandle_t instanceHandle,
const glRaytracingInstanceDesc_t* desc);
void glRaytracingDeleteInstanceInScene(
glRaytracingSceneHandle_t sceneHandle,
glRaytracingInstanceHandle_t instanceHandle);
int glRaytracingBuildMesh(glRaytracingMeshHandle_t meshHandle);
int glRaytracingBuildAllMeshes(void);
int glRaytracingBuildScene(void);
int glRaytracingBuildSceneIfDirty(void);
int glRaytracingBuildSceneForHandle(glRaytracingSceneHandle_t sceneHandle);
ID3D12Resource* glRaytracingGetTopLevelASForScene(glRaytracingSceneHandle_t sceneHandle);
uint32_t glRaytracingGetMeshCount(void);
uint32_t glRaytracingGetInstanceCount(void);
uint32_t glRaytracingGetInstanceCountForScene(glRaytracingSceneHandle_t sceneHandle);
bool glRaytracingLightingInit(void);
void glRaytracingLightingShutdown(void);
@@ -1711,7 +1736,9 @@ void glRaytracingLightingEnableSpecular(int enable);
void glRaytracingLightingEnableHalfLambert(int enable);
void glRaytracingLightingSetShadowBias(float bias);
bool glRaytracingLightingExecute(const glRaytracingLightingPassDesc_t* pass);
bool glRaytracingLightingExecuteForScene(
const glRaytracingLightingPassDesc_t* pass,
glRaytracingSceneHandle_t sceneHandle);
glRaytracingLight_t glRaytracingLightingMakePointLight(
float px, float py, float pz,
@@ -1732,7 +1759,7 @@ glRaytracingLight_t glRaytracingLightingMakeRectLight(
uint32_t glRaytracingLightingGetLightCount(void);
void glLightScene(void);
void glLightScene(glRaytracingSceneHandle_t sceneHandle);
ID3D12Device* QD3D12_GetDevice(void);
ID3D12CommandQueue* QD3D12_GetQueue(void);
@@ -2133,4 +2160,10 @@ void APIENTRY glTextureNormalMap(GLuint texture, GLboolean isNormalMap); // alia
void APIENTRY glBindNormalMapTexture(GLuint texture); // 0 disables explicit normal map
void APIENTRY glNormalMapTexture(GLuint texture); // alias
void APIENTRY glNormalMapStrengthf(GLfloat strength); // default 1.0
void APIENTRY glNormalMapYSignf(GLfloat sign); // default +1, pass -1 to flip green/Y
void APIENTRY glNormalMapYSignf(GLfloat sign); // default +1, pass -1 to flip green/Y
void glUpdateTopLevelAceelStructure(
glRaytracingSceneHandle_t scene,
uint32_t mesh,
float* transform,
uint32_t& topLevelHandle);