DXR now supports portal culling.

This commit is contained in:
Justin Marshall
2026-05-08 00:45:48 -07:00
parent 205e9b8b1d
commit c1e344ca94
12 changed files with 1212 additions and 275 deletions
+158 -3
View File
@@ -1275,7 +1275,7 @@ static inline void glRaytracingBuildInstanceDesc(
(meshMaterialFlags | instanceMaterialFlags) & GL_RAYTRACING_INSTANCE_MATERIAL_MASK;
const uint32_t materialBits = combinedMaterialFlags << GL_RAYTRACING_INSTANCE_MATERIAL_SHIFT;
outDesc->InstanceID = userInstanceId | materialBits;
outDesc->InstanceMask = (UINT8)(inst.descCpu.mask ? inst.descCpu.mask : 0xFF);
outDesc->InstanceMask = (UINT8)(inst.descCpu.mask & 0xFFu);
outDesc->InstanceContributionToHitGroupIndex = 0;
outDesc->Flags = D3D12_RAYTRACING_INSTANCE_FLAG_NONE;
outDesc->AccelerationStructure = blasGpuVA;
@@ -2066,6 +2066,12 @@ void glRaytracingDeleteMesh(glRaytracingMeshHandle_t meshHandle)
glRaytracingMarkAllWorldsNeedRebuild();
}
static inline uint32_t glRaytracingNormalizeVisibleInstanceMask(uint32_t mask)
{
mask &= 0xFFu;
return mask ? mask : 0xFFu;
}
glRaytracingInstanceHandle_t glRaytracingCreateInstanceInScene(glRaytracingSceneHandle_t worldHandle, const glRaytracingInstanceDesc_t* desc)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
@@ -2084,6 +2090,7 @@ glRaytracingInstanceHandle_t glRaytracingCreateInstanceInScene(glRaytracingScene
inst.handle = world->nextInstanceHandle++;
inst.alive = 1;
inst.descCpu = *desc;
inst.descCpu.mask = glRaytracingNormalizeVisibleInstanceMask(inst.descCpu.mask);
inst.dirty = 1;
world->instances.push_back(inst);
@@ -2113,8 +2120,18 @@ int glRaytracingUpdateInstanceInScene(glRaytracingSceneHandle_t worldHandle, glR
return 0;
const uint32_t oldMeshHandle = inst->descCpu.meshHandle;
const uint32_t oldMask = ((uint32_t)inst->descCpu.mask) & 0xFFu;
const int wasHidden = (oldMask == 0u);
inst->descCpu = *desc;
glRaytracingInstanceDesc_t newDesc = *desc;
// If this instance is hidden, keep it hidden even if the caller's
// transform-update helper sends mask = 0xFF again.
newDesc.mask = wasHidden
? 0u
: glRaytracingNormalizeVisibleInstanceMask(newDesc.mask);
inst->descCpu = newDesc;
inst->dirty = 1;
if (oldMeshHandle != desc->meshHandle)
@@ -4494,7 +4511,7 @@ void RayGen()
// then reuse them for every stochastic GI sample.
float cavity = ComputeCavity(pixel, worldPos, N);
float ao = ComputeAmbientOcclusion(worldPos, N, pixel);
float skyVis = ComputeSkyVisibility(worldPos, N, pixel);
float skyVis = 0; // ComputeSkyVisibility(worldPos, N, pixel); // jmarshall - fix me later
float ambientSkyVis = TraceStraightUpToSky(worldPos, N);
float microShadow = lerp(0.75, 1.0, cavity);
@@ -6734,3 +6751,141 @@ uint32_t glRaytracingLightingGetLightCount(void)
return (uint32_t)g_glRaytracingLighting.cpuLights.size();
}
int glRaytracingSetInstanceVisibilityUnlocked(
glRaytracingRenderWorld_t* world,
glRaytracingInstanceHandle_t instanceHandle,
int visible)
{
if (!world || !world->alive)
return 0;
glRaytracingInstanceRecord_t* inst =
glRaytracingFindInstance(world, instanceHandle);
if (!inst || !inst->alive)
return 0;
const uint32_t newMask = visible ? 0xFFu : 0u;
if ((((uint32_t)inst->descCpu.mask) & 0xFFu) == newMask)
return 1;
inst->descCpu.mask = newMask;
inst->dirty = 1;
glRaytracingMarkWorldNeedsUpdate(world);
return 1;
}
static void glRaytracingSetAllInstancesVisibleUnlocked(
glRaytracingRenderWorld_t* world,
int visible)
{
if (!world || !world->alive)
return;
const uint32_t newMask = visible ? 0xFFu : 0u;
int changed = 0;
for (size_t i = 0; i < world->instances.size(); ++i)
{
glRaytracingInstanceRecord_t& inst = world->instances[i];
if (!inst.alive)
continue;
const int wasVisible = inst.descCpu.mask != 0;
if (wasVisible == (visible != 0))
continue;
inst.descCpu.mask = newMask;
inst.dirty = 1;
changed = 1;
}
if (changed)
glRaytracingMarkWorldNeedsUpdate(world);
}
int glRaytracingSetInstanceVisibilityInScene(
glRaytracingSceneHandle_t sceneHandle,
glRaytracingInstanceHandle_t instanceHandle,
int visible)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
if (!g_glRaytracingScene.initialized)
return 0;
glRaytracingRenderWorld_t* world = glRaytracingFindWorld(sceneHandle);
return glRaytracingSetInstanceVisibilityUnlocked(
world,
instanceHandle,
visible ? 1 : 0);
}
int glRaytracingGetInstanceVisibilityInScene(
glRaytracingSceneHandle_t sceneHandle,
glRaytracingInstanceHandle_t instanceHandle)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
if (!g_glRaytracingScene.initialized)
return 0;
glRaytracingRenderWorld_t* world = glRaytracingFindWorld(sceneHandle);
if (!world)
return 0;
glRaytracingInstanceRecord_t* inst =
glRaytracingFindInstance(world, instanceHandle);
if (!inst || !inst->alive)
return 0;
return inst->descCpu.mask != 0 ? 1 : 0;
}
void glRaytracingHideAllInstancesInScene(glRaytracingSceneHandle_t sceneHandle)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
if (!g_glRaytracingScene.initialized)
return;
glRaytracingRenderWorld_t* world = glRaytracingFindWorld(sceneHandle);
glRaytracingSetAllInstancesVisibleUnlocked(world, 0);
}
void glRaytracingShowAllInstancesInScene(glRaytracingSceneHandle_t sceneHandle)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
if (!g_glRaytracingScene.initialized)
return;
glRaytracingRenderWorld_t* world = glRaytracingFindWorld(sceneHandle);
glRaytracingSetAllInstancesVisibleUnlocked(world, 1);
}
void glRaytracingHideAllInstances(void)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
if (!g_glRaytracingScene.initialized)
return;
for (int i = 0; i < GL_RAYTRACING_MAX_RENDER_WORLDS; ++i)
glRaytracingSetAllInstancesVisibleUnlocked(&g_glRaytracingScene.worlds[i], 0);
}
void glRaytracingShowAllInstances(void)
{
std::lock_guard<std::mutex> lock(g_glRaytracingMutex);
if (!g_glRaytracingScene.initialized)
return;
for (int i = 0; i < GL_RAYTRACING_MAX_RENDER_WORLDS; ++i)
glRaytracingSetAllInstancesVisibleUnlocked(&g_glRaytracingScene.worlds[i], 1);
}
+153 -4
View File
@@ -242,6 +242,32 @@ void glRaytracingLightingSetSpecularInput(ID3D12Resource* texture, DXGI_FORMAT f
void glRaytracingSetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle, uint32_t materialFlags);
void glRaytracingSetMeshGlass(glRaytracingMeshHandle_t meshHandle, int isGlass);
uint32_t glRaytracingGetMeshMaterialFlags(glRaytracingMeshHandle_t meshHandle);
// Fast TLAS instance visibility controls are implemented in gl_raytracing.cpp.
// They flip the D3D12_RAYTRACING_INSTANCE_DESC InstanceMask via the existing
// TLAS update path, so hiding/showing a model does not rebuild or recreate BLAS.
int glRaytracingSetInstanceVisibilityInScene(glRaytracingSceneHandle_t sceneHandle, glRaytracingInstanceHandle_t instanceHandle, int visible);
int glRaytracingGetInstanceVisibilityInScene(glRaytracingSceneHandle_t sceneHandle, glRaytracingInstanceHandle_t instanceHandle);
void glRaytracingHideAllInstancesInScene(glRaytracingSceneHandle_t sceneHandle);
void glRaytracingShowAllInstancesInScene(glRaytracingSceneHandle_t sceneHandle);
void glRaytracingHideAllInstances(void);
void glRaytracingShowAllInstances(void);
// Shim/public helpers for the app's top-level acceleration-structure handles.
int glSetTopLevelAccelStructureVisible(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle, int visible);
void glHideTopLevelAccelStructure(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle);
void glShowTopLevelAccelStructure(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle);
int glIsTopLevelAccelStructureVisible(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle);
void glHideAllTopLevelAccelStructures(glRaytracingSceneHandle_t scene);
void glShowAllTopLevelAccelStructures(glRaytracingSceneHandle_t scene);
// Backward-compatible aliases matching the existing Aceel typo in this file.
int glSetTopLevelAceelStructureVisible(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle, int visible);
void glHideTopLevelAceelStructure(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle);
void glShowTopLevelAceelStructure(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle);
int glIsTopLevelAceelStructureVisible(glRaytracingSceneHandle_t scene, uint32_t topLevelHandle);
void glHideAllTopLevelAceelStructures(glRaytracingSceneHandle_t scene);
void glShowAllTopLevelAceelStructures(glRaytracingSceneHandle_t scene);
void QD3D12_SetPathTracingQuality(uint32_t samplesPerPixel, uint32_t maxBounces);
void QD3D12_SetPathTracingFallbackSamples(uint32_t samplesPerPixel);
void QD3D12_SetCameraInfo(
@@ -11976,6 +12002,18 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "QD3D12_ResolveGBufferNow", (PROC)QD3D12_ResolveGBufferNow },
{ "QD3D12_SetPathTracingQuality", (PROC)QD3D12_SetPathTracingQuality },
{ "QD3D12_SetPathTracingFallbackSamples", (PROC)QD3D12_SetPathTracingFallbackSamples },
{ "glSetTopLevelAccelStructureVisible", (PROC)glSetTopLevelAccelStructureVisible },
{ "glHideTopLevelAccelStructure", (PROC)glHideTopLevelAccelStructure },
{ "glShowTopLevelAccelStructure", (PROC)glShowTopLevelAccelStructure },
{ "glIsTopLevelAccelStructureVisible", (PROC)glIsTopLevelAccelStructureVisible },
{ "glHideAllTopLevelAccelStructures", (PROC)glHideAllTopLevelAccelStructures },
{ "glShowAllTopLevelAccelStructures", (PROC)glShowAllTopLevelAccelStructures },
{ "glSetTopLevelAceelStructureVisible", (PROC)glSetTopLevelAceelStructureVisible },
{ "glHideTopLevelAceelStructure", (PROC)glHideTopLevelAceelStructure },
{ "glShowTopLevelAceelStructure", (PROC)glShowTopLevelAceelStructure },
{ "glIsTopLevelAceelStructureVisible", (PROC)glIsTopLevelAceelStructureVisible },
{ "glHideAllTopLevelAceelStructures", (PROC)glHideAllTopLevelAceelStructures },
{ "glShowAllTopLevelAceelStructures", (PROC)glShowAllTopLevelAceelStructures },
{ "glRaytracingLightingSetVolumetricScattering", (PROC)glRaytracingLightingSetVolumetricScattering },
{ "glGenProgramsARB", (PROC)glGenProgramsARB },
{ "glDeleteProgramsARB", (PROC)glDeleteProgramsARB },
@@ -14257,6 +14295,108 @@ void glUpdateBottomAccelStructure(bool opaque, uint32_t& meshHandle)
}
}
int glSetTopLevelAccelStructureVisible(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle,
int visible)
{
if (scene == 0 || topLevelHandle == 0)
return 0;
return glRaytracingSetInstanceVisibilityInScene(
scene,
(glRaytracingInstanceHandle_t)topLevelHandle,
visible ? 1 : 0);
}
void glHideTopLevelAccelStructure(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle)
{
(void)glSetTopLevelAccelStructureVisible(scene, topLevelHandle, 0);
}
void glShowTopLevelAccelStructure(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle)
{
(void)glSetTopLevelAccelStructureVisible(scene, topLevelHandle, 1);
}
int glIsTopLevelAccelStructureVisible(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle)
{
if (scene == 0 || topLevelHandle == 0)
return 0;
return glRaytracingGetInstanceVisibilityInScene(
scene,
(glRaytracingInstanceHandle_t)topLevelHandle) ? 1 : 0;
}
void glHideAllTopLevelAccelStructures(glRaytracingSceneHandle_t scene)
{
if (scene == 0)
{
glRaytracingHideAllInstances();
return;
}
glRaytracingHideAllInstancesInScene(scene);
}
void glShowAllTopLevelAccelStructures(glRaytracingSceneHandle_t scene)
{
if (scene == 0)
{
glRaytracingShowAllInstances();
return;
}
glRaytracingShowAllInstancesInScene(scene);
}
int glSetTopLevelAceelStructureVisible(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle,
int visible)
{
return glSetTopLevelAccelStructureVisible(scene, topLevelHandle, visible);
}
void glHideTopLevelAceelStructure(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle)
{
glHideTopLevelAccelStructure(scene, topLevelHandle);
}
void glShowTopLevelAceelStructure(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle)
{
glShowTopLevelAccelStructure(scene, topLevelHandle);
}
int glIsTopLevelAceelStructureVisible(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle)
{
return glIsTopLevelAccelStructureVisible(scene, topLevelHandle);
}
void glHideAllTopLevelAceelStructures(glRaytracingSceneHandle_t scene)
{
glHideAllTopLevelAccelStructures(scene);
}
void glShowAllTopLevelAceelStructures(glRaytracingSceneHandle_t scene)
{
glShowAllTopLevelAccelStructures(scene);
}
void glUpdateTopLevelAceelStructure(
glRaytracingSceneHandle_t scene,
uint32_t mesh,
@@ -14271,7 +14411,10 @@ void glUpdateTopLevelAceelStructure(
const uint32_t materialFlags = QD3D12_GetRaytracingMeshMaterialFlags(mesh);
instDesc.instanceID = QD3D12_EncodeRaytracingInstanceId(0u, materialFlags);
instDesc.mask = 0xFF;
// Default for newly-created instances. Existing hidden instances preserve
// their current mask below instead of being forced visible by this update path.
instDesc.mask = 0xFFu;
if (transform == NULL)
{
@@ -14288,18 +14431,24 @@ void glUpdateTopLevelAceelStructure(
if (topLevelHandle == 0)
{
instDesc.mask = 0xFFu;
topLevelHandle = glRaytracingCreateInstanceInScene(scene, &instDesc);
return;
}
// Preserve the current hide/show state across transform/material updates.
const int wasVisible = glRaytracingGetInstanceVisibilityInScene(
scene,
(glRaytracingInstanceHandle_t)topLevelHandle);
instDesc.mask = wasVisible ? 0xFFu : 0u;
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.
// Stale handle path: create a fresh visible instance.
instDesc.mask = 0xFFu;
topLevelHandle = glRaytracingCreateInstanceInScene(scene, &instDesc);
}
}
+23
View File
@@ -2300,3 +2300,26 @@ void APIENTRY glTextureGlowMap(GLuint texture, GLboolean isGlowMap); // alias
void APIENTRY glBindGlowMapTexture(GLuint texture); // 0 disables explicit glow map
void APIENTRY glGlowMapTexture(GLuint texture); // alias
void APIENTRY glGlowMapStrengthf(GLfloat strength); // default 1.0; >1 allows overbright emission
int APIENTRY glSetTopLevelAccelStructureVisible(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle,
int visible);
void APIENTRY glHideTopLevelAccelStructure(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle);
void APIENTRY glShowTopLevelAccelStructure(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle);
int APIENTRY glIsTopLevelAccelStructureVisible(
glRaytracingSceneHandle_t scene,
uint32_t topLevelHandle);
void APIENTRY glHideAllTopLevelAccelStructures(
glRaytracingSceneHandle_t scene);
void APIENTRY glShowAllTopLevelAccelStructures(
glRaytracingSceneHandle_t scene);
+2
View File
@@ -674,6 +674,8 @@ public:
protected:
idMapFile * additionalMapFile;
virtual void SpawnAppendedMapEntities() {}
#else
bool DeathwalkMapLoaded() const { return false; }
#endif
// HUMANHEAD END
+14
View File
@@ -1871,6 +1871,20 @@ idImage* idMaterial::GetDiffuseImage(void) const {
return GetEditorImage();
}
/*
===================
idMaterial::IsLitMaterial
===================
*/
bool idMaterial::IsLitMaterial(void) const {
for (int i = 0; i < numStages; i++) {
if (stages[i].lighting == SL_DIFFUSE && stages[i].texture.image) {
return true;
}
}
return false;
}
/*
===================
idMaterial::IsSky
+15 -3
View File
@@ -504,13 +504,25 @@ public:
// returns true if the material will generate interactions with fog/blend lights
// All non-translucent surfaces receive fog unless they are explicitly noFog
bool ReceivesFog(void) const { return (IsDrawn() && !noFog && coverage != MC_TRANSLUCENT); }
// jmarshall
// jmarshall
// Returns the diffuse/albedo image used by this material stage.
idImage* GetDiffuseImage(void) const;
// Returns the bump/normal map image used by this material stage.
idImage* GetBumpImage(void) const;
// Returns the specular map image used by this material stage.
idImage* GetSpecImage(void) const;
// Returns the glow/emissive map image used by this material stage.
idImage* GetGlowImage(void) const;
bool IsSky(void) const;
// jmarshall end
// Returns true if this material participates in dynamic lighting.
bool IsLitMaterial(void) const;
// Returns true if this material is rendered as a sky surface.
bool IsSky(void) const;
// jmarshall end
// returns true if the material will generate interactions with normal lights
// Many special effect surfaces don't have any bump/diffuse/specular
// stages, and don't interact with lights at all
+15
View File
@@ -569,6 +569,13 @@ void idRenderModelStatic::UpdateDXR(uint32_t& dxrBottomAcel, int onlySurface)
modelSurface_t* surf = &surfaces[i];
if (onlySurface == -1)
{
if (!surf->shader->IsLitMaterial()) {
continue;
}
}
numDXRVerts += surf->geometry->numVerts;
numDXRIndexes += surf->geometry->numIndexes;
}
@@ -584,6 +591,14 @@ void idRenderModelStatic::UpdateDXR(uint32_t& dxrBottomAcel, int onlySurface)
continue;
modelSurface_t* surf = &surfaces[i];
if (onlySurface == -1)
{
if (!surf->shader->IsLitMaterial()) {
continue;
}
}
for (int d = 0; d < surf->geometry->numIndexes; ++d)
{
indices[indexId++] = vertexId + surf->geometry->indexes[d];
+14
View File
@@ -1634,6 +1634,20 @@ void idRenderWorldLocal::PushVolumeIntoTree_r( idRenderEntityLocal *def, idRende
}
}
/*
==============
GetDXRModelForSurf
==============
*/
dxrWorldModel_t* idRenderWorldLocal::GetDXRModelForSurf(srfTriangles_t* tri) {
for (int i = 0; i < worldDXRmodels.Num(); i++) {
if (worldDXRmodels[i].tri == tri)
return &worldDXRmodels[i];
}
return NULL;
}
/*
==============
PushVolumeIntoTree
+2 -1
View File
@@ -182,10 +182,11 @@ idRenderModel *idRenderWorldLocal::ParseModel( idLexer *src ) {
// add the completed surface to the model
model->AddSurface( surf );
if (!surf.shader->IsSky())
if (!surf.shader->IsSky() && surf.shader->IsLitMaterial() && surf.shader->SurfaceCastsShadow())
{
idRenderModelStatic* modelStatic = (idRenderModelStatic*)model;
dxrWorldModel_t dxrModel;
dxrModel.tri = tri;
modelStatic->UpdateDXR(dxrModel.dxrBottomAcel, model->NumSurfaces() - 1);
glUpdateTopLevelAceelStructure(dxrWorldId, dxrModel.dxrBottomAcel, NULL, dxrModel.topAccelStruct);
worldDXRmodels.Append(dxrModel);
+3
View File
@@ -75,6 +75,7 @@ typedef struct {
} areaNode_t;
struct dxrWorldModel_t {
srfTriangles_t* tri;
uint32_t dxrBottomAcel = 0;
uint32_t topAccelStruct = 0;
};
@@ -250,6 +251,8 @@ public:
void PushVolumeIntoTree( idRenderEntityLocal *def, idRenderLightLocal *light, int numPoints, const idVec3 (*points) );
dxrWorldModel_t* GetDXRModelForSurf(srfTriangles_t* tri);
//-------------------------------
// tr_light.c
void CreateLightDefInteractions( idRenderLightLocal *ldef );
File diff suppressed because it is too large Load Diff
+9
View File
@@ -1341,6 +1341,15 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
continue;
}
if (tr.viewDef->renderWorld)
{
dxrWorldModel_t* dxrWorldModel = tr.viewDef->renderWorld->GetDXRModelForSurf((srfTriangles_t*)tri);
if (dxrWorldModel)
{
glShowTopLevelAccelStructure(tr.viewDef->renderWorld->dxrWorldId, dxrWorldModel->topAccelStruct);
}
}
// debugging tool to make sure we are have the correct pre-calculated bounds
if ( r_checkBounds.GetBool() ) {
int j, k;