Implemented screenspace particles.

This commit is contained in:
Justin Marshall
2026-05-24 13:04:31 -07:00
parent ac9c10cc92
commit 56bb2f004f
10 changed files with 712 additions and 20 deletions
+17 -7
View File
@@ -9,7 +9,7 @@
1199 constants
135 enums
619 classes/structs/unions
620 classes/structs/unions
38 templates
7 max inheritance level for 'idAI_Vagary'
@@ -4129,6 +4129,15 @@ static classVariableInfo_t glScreenSpaceDecal_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t glScreenSpaceParticleVertex_t_typeInfo[] = {
{ "float[4]", "clip", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->clip), sizeof( ((glScreenSpaceParticleVertex_t *)0)->clip ) },
{ "float[2]", "st", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->st), sizeof( ((glScreenSpaceParticleVertex_t *)0)->st ) },
{ "float[4]", "color", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->color), sizeof( ((glScreenSpaceParticleVertex_t *)0)->color ) },
{ "float[3]", "world", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->world), sizeof( ((glScreenSpaceParticleVertex_t *)0)->world ) },
{ "float", "pad0", (intptr_t)(&((glScreenSpaceParticleVertex_t *)0)->pad0), sizeof( ((glScreenSpaceParticleVertex_t *)0)->pad0 ) },
{ NULL, 0 }
};
static classVariableInfo_t QD3D12NeuralPOMImageRGBA8_typeInfo[] = {
{ "uint32_t", "width", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->width), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->width ) },
{ "uint32_t", "height", (intptr_t)(&((QD3D12NeuralPOMImageRGBA8 *)0)->height), sizeof( ((QD3D12NeuralPOMImageRGBA8 *)0)->height ) },
@@ -5248,11 +5257,11 @@ static classVariableInfo_t frameLookup_t_typeInfo[] = {
{ NULL, 0 }
};
static classVariableInfo_t class_287_class_287_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_287::class_287 *)0)->soundShader), sizeof( ((class_287::class_287 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_287::class_287 *)0)->function), sizeof( ((class_287::class_287 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_287::class_287 *)0)->skin), sizeof( ((class_287::class_287 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_287::class_287 *)0)->index), sizeof( ((class_287::class_287 *)0)->index ) },
static classVariableInfo_t class_288_class_288_typeInfo[] = {
// { "const idSoundShader *", "soundShader", (intptr_t)(&((class_288::class_288 *)0)->soundShader), sizeof( ((class_288::class_288 *)0)->soundShader ) },
// { "const function_t *", "function", (intptr_t)(&((class_288::class_288 *)0)->function), sizeof( ((class_288::class_288 *)0)->function ) },
// { "const idDeclSkin *", "skin", (intptr_t)(&((class_288::class_288 *)0)->skin), sizeof( ((class_288::class_288 *)0)->skin ) },
// { "int", "index", (intptr_t)(&((class_288::class_288 *)0)->index), sizeof( ((class_288::class_288 *)0)->index ) },
{ NULL, 0 }
};
@@ -9174,6 +9183,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "glRaytracingLight_t", "", sizeof(glRaytracingLight_t), glRaytracingLight_t_typeInfo },
{ "glRaytracingLightingPassDesc_t", "", sizeof(glRaytracingLightingPassDesc_t), glRaytracingLightingPassDesc_t_typeInfo },
{ "glScreenSpaceDecal_t", "", sizeof(glScreenSpaceDecal_t), glScreenSpaceDecal_t_typeInfo },
{ "glScreenSpaceParticleVertex_t", "", sizeof(glScreenSpaceParticleVertex_t), glScreenSpaceParticleVertex_t_typeInfo },
{ "QD3D12NeuralPOMImageRGBA8", "", sizeof(QD3D12NeuralPOMImageRGBA8), QD3D12NeuralPOMImageRGBA8_typeInfo },
{ "QD3D12NeuralPOMTrainDesc", "", sizeof(QD3D12NeuralPOMTrainDesc), QD3D12NeuralPOMTrainDesc_typeInfo },
{ "QD3D12NeuralPOMTrainStats", "", sizeof(QD3D12NeuralPOMTrainStats), QD3D12NeuralPOMTrainStats_typeInfo },
@@ -9284,7 +9294,7 @@ static classTypeInfo_t classTypeInfo[] = {
{ "jointAnimInfo_t", "", sizeof(jointAnimInfo_t), jointAnimInfo_t_typeInfo },
{ "jointMod_t", "", sizeof(jointMod_t), jointMod_t_typeInfo },
{ "frameLookup_t", "", sizeof(frameLookup_t), frameLookup_t_typeInfo },
// { "class_287::class_287", "", sizeof(class_287::class_287), class_287_class_287_typeInfo },
// { "class_288::class_288", "", sizeof(class_288::class_288), class_288_class_288_typeInfo },
{ "frameCommand_t", "", sizeof(frameCommand_t), frameCommand_t_typeInfo },
{ "animFlags_t", "", sizeof(animFlags_t), animFlags_t_typeInfo },
{ "idModelExport", "", sizeof(idModelExport), idModelExport_typeInfo },
+542 -6
View File
@@ -467,11 +467,12 @@ static const UINT QD3D12_UploadBufferSize = 128 * 1024 * 1024;
// MSAA has been removed from the G-buffer path. Temporal AA now owns edge cleanup
// after lighting, so all scene/deferred render targets remain single-sample.
static const UINT QD3D12_RequestedGBufferSampleCount = 1;
static constexpr UINT QD3D12_PostSrvCount = 14;
static constexpr UINT QD3D12_PostSrvCount = 16;
static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount;
static constexpr UINT QD3D12_PostConstantDwords = 24;
static constexpr UINT QD3D12_ToneMapTileDim = 64;
static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64;
static constexpr UINT QD3D12_MaxScreenSpaceParticleLights = GL_RAYTRACING_MAX_LIGHTS;
enum QD3D12RTVSlotGroup
{
@@ -544,6 +545,14 @@ struct QD3D12CameraState
bool valid = false;
};
struct QD3D12ScreenSpaceParticleBatch
{
std::vector<glScreenSpaceParticleVertex_t> vertices;
uint32_t textureId = 0;
uint32_t blendMode = 0;
float softDepth = 16.0f;
};
enum PipelineMode
{
PIPE_OPAQUE_TEX = 0,
@@ -1504,17 +1513,29 @@ struct GLState
bool enableRayAIDenoise = false;
bool enableDLSSRayReconstruction = false;
bool enableFSRRayRegeneration = false;
bool blockLightingUpscaleInputThisFrame = false;
uint32_t frameGenerationMultiplier = 0;
uint32_t pathTracingSamplesPerPixel = 1;
uint32_t pathTracingFallbackSamplesPerPixel = 2;
uint32_t pathTracingMaxBounces = 3;
glScreenSpaceDecal_t screenSpaceDecals[QD3D12_MaxScreenSpaceDecals] = {};
uint32_t screenSpaceDecalCount = 0;
std::vector<QD3D12ScreenSpaceParticleBatch> screenSpaceParticleBatches;
glRaytracingLight_t screenSpaceParticleLights[QD3D12_MaxScreenSpaceParticleLights] = {};
uint32_t screenSpaceParticleLightCount = 0;
ComPtr<ID3D12Resource> screenSpaceDecalBuffer;
void* screenSpaceDecalBufferMapped = nullptr;
UINT screenSpaceDecalSrvIndex = UINT_MAX;
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceDecalSrvCpu{};
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceDecalSrvGpu{};
ComPtr<ID3D12Resource> screenSpaceParticleLightBuffer;
void* screenSpaceParticleLightBufferMapped = nullptr;
UINT screenSpaceParticleLightSrvIndex = UINT_MAX;
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceParticleLightSrvCpu{};
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceParticleLightSrvGpu{};
UINT screenSpaceParticleTlasSrvIndex = UINT_MAX;
D3D12_CPU_DESCRIPTOR_HANDLE screenSpaceParticleTlasSrvCpu{};
D3D12_GPU_DESCRIPTOR_HANDLE screenSpaceParticleTlasSrvGpu{};
float jitterX = 0.0f;
float jitterY = 0.0f;
@@ -1696,6 +1717,8 @@ struct GLState
ComPtr<ID3D12PipelineState> postGBufferPointResolveMsaaPSO;
ComPtr<ID3D12PipelineState> postScreenDecalPSO;
ComPtr<ID3D12PipelineState> postScreenDecalStainPSO;
ComPtr<ID3D12PipelineState> postScreenParticlePSO;
ComPtr<ID3D12PipelineState> postScreenParticleAdditivePSO;
ComPtr<ID3DBlob> vsMainBlob;
ComPtr<ID3DBlob> hsMainBlob;
@@ -1718,6 +1741,8 @@ struct GLState
ComPtr<ID3DBlob> postPsDepthResolveMsaaBlob;
ComPtr<ID3DBlob> postPsGBufferPointResolveMsaaBlob;
ComPtr<ID3DBlob> postPsScreenDecalBlob;
ComPtr<ID3DBlob> postVsScreenParticleBlob;
ComPtr<ID3DBlob> postPsScreenParticleBlob;
TextureResource whiteTexture;
@@ -4448,12 +4473,40 @@ struct ScreenSpaceDecal
StructuredBuffer<ScreenSpaceDecal> gScreenDecals : register(t13);
struct ScreenParticleLight
{
float3 position;
float radius;
float3 color;
float intensity;
float3 normal;
uint type;
float3 axisU;
float halfWidth;
float3 axisV;
float halfHeight;
uint samples;
uint twoSided;
float persistant;
float volumetricScattering;
float3 pointRadius;
float pointRadiusPad;
uint iesTextureId;
float iesStrength;
float2 iesPad;
};
StructuredBuffer<ScreenParticleLight> gScreenParticleLights : register(t14);
#if defined(QD3D12_SCREEN_PARTICLE_RAYQUERY)
RaytracingAccelerationStructure gScreenParticleSceneBVH : register(t15);
#endif
cbuffer PostCB : register(b0)
{
// gPostParams0: x = sharpen strength, y = history weight, z = TAA reset flag.
// gPostParams1: x = tone-map exposure, y = white-point scale, z = display brightness.
// gPostParams2: x = fog enabled, y = fog mode, z = fog density, w = fog start.
// gPostParams3: x = fog end, y = fog camera valid.
// gPostParams3: x = fog end, y = fog camera valid, z = particle soft depth, w = particle light count.
float4 gPostParams0;
float4 gPostParams1;
float4 gPostParams2;
@@ -4475,15 +4528,37 @@ cbuffer PostCB : register(b0)
#define gPostFogStart gPostParams2.w
#define gPostFogEnd gPostParams3.x
#define gPostFogCameraValid gPostParams3.y
#define gScreenParticleSoftDepth gPostParams3.z
#define gScreenParticleLightCount gPostParams3.w
#define gScreenDecalCount gPostFogCameraWorldPos.w
#define QD3D12_TONEMAP_TILE_DIM 64u
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u;
static const uint GL_RAYTRACING_LIGHT_TYPE_RECT = 1u;
static const uint GL_RAYTRACING_LIGHT_TYPE_SPOT = 2u;
struct VSOut
{
float4 pos : SV_Position;
float2 uv : TEXCOORD0;
};
struct ParticleVSIn
{
float4 clipPos : POSITION0;
float2 uv : TEXCOORD0;
float4 color : COLOR0;
float3 world : TEXCOORD1;
};
struct ParticleVSOut
{
float4 pos : SV_Position;
float2 uv : TEXCOORD0;
float4 color : COLOR0;
float3 world : TEXCOORD1;
};
VSOut VSMain(uint vid : SV_VertexID)
{
VSOut o;
@@ -4497,6 +4572,16 @@ VSOut VSMain(uint vid : SV_VertexID)
return o;
}
ParticleVSOut VSParticle(ParticleVSIn i)
{
ParticleVSOut o;
o.pos = i.clipPos;
o.uv = i.uv;
o.color = i.color;
o.world = i.world;
return o;
}
float QD3D12_PostFogFactor(float fogCoord)
{
if (gPostFogEnabled < 0.5)
@@ -4590,6 +4675,175 @@ float4 PSScreenDecals(VSOut i) : SV_Target0
return float4(decalColor, decalAlpha);
}
float3 ScreenParticleSafeNormalizeOr(float3 v, float3 fallbackDir)
{
float lenSq = dot(v, v);
return (lenSq > 1e-8) ? (v * rsqrt(lenSq)) : fallbackDir;
}
float3 ScreenParticlePointRadius(ScreenParticleLight Lgt)
{
float scalarRadius = max(abs(Lgt.radius), 1e-4);
float3 r = abs(Lgt.pointRadius);
if (max(max(r.x, r.y), r.z) <= 1e-4)
r = float3(scalarRadius, scalarRadius, scalarRadius);
return max(r, float3(1e-4, 1e-4, 1e-4));
}
float ScreenParticlePointAttenuation(float3 worldPos, ScreenParticleLight Lgt)
{
float3 radii = ScreenParticlePointRadius(Lgt);
float3 offset = worldPos - Lgt.position;
float3 axisU = ScreenParticleSafeNormalizeOr(Lgt.axisU, float3(1.0, 0.0, 0.0));
float3 axisV = ScreenParticleSafeNormalizeOr(Lgt.axisV, float3(0.0, 1.0, 0.0));
float3 axisW = ScreenParticleSafeNormalizeOr(Lgt.normal, float3(0.0, 0.0, 1.0));
float3 perAxis;
perAxis.x = 1.0 - saturate(abs(dot(offset, axisU)) / radii.x);
perAxis.y = 1.0 - saturate(abs(dot(offset, axisV)) / radii.y);
perAxis.z = 1.0 - saturate(abs(dot(offset, axisW)) / radii.z);
return perAxis.x * perAxis.y * perAxis.z;
}
float ScreenParticleBasicFalloff(float lightDist, float maxLightDist)
{
return saturate(1.0 - lightDist / max(maxLightDist, 1e-4));
}
float ScreenParticleSpotAttenuation(float3 worldPos, ScreenParticleLight Lgt)
{
float3 lightToSurface = worldPos - Lgt.position;
float nearClip = max(Lgt.pointRadius.x, 0.0);
float farClip = max(Lgt.radius, nearClip + 1e-4);
float3 spotDir = ScreenParticleSafeNormalizeOr(Lgt.normal, float3(0.0, 0.0, 1.0));
float depth = dot(lightToSurface, spotDir);
if (depth <= nearClip || depth >= farClip)
return 0.0;
float3 axisU = ScreenParticleSafeNormalizeOr(Lgt.axisU, float3(1.0, 0.0, 0.0));
float3 axisV = ScreenParticleSafeNormalizeOr(Lgt.axisV, float3(0.0, 1.0, 0.0));
float invDepth = 1.0 / max(depth, 1e-4);
float halfU = max(abs(Lgt.halfWidth), 1e-4);
float halfV = max(abs(Lgt.halfHeight), 1e-4);
float signedU = (dot(lightToSurface, axisU) * invDepth) / halfU;
float signedV = (dot(lightToSurface, axisV) * invDepth) / halfV;
if (abs(signedU) >= 1.0 || abs(signedV) >= 1.0)
return 0.0;
float3 lightVector = normalize(lightToSurface);
float maxSlope = max(halfU, halfV);
float outerAngle = rsqrt(1.0 + maxSlope * maxSlope);
float innerSlope = maxSlope * 0.65;
float innerAngle = rsqrt(1.0 + innerSlope * innerSlope);
float spotCookie = smoothstep(outerAngle, innerAngle, saturate(dot(lightVector, spotDir)));
return spotCookie * ScreenParticleBasicFalloff(depth - nearClip, farClip - nearClip);
}
float ScreenParticleTraceShadow(float3 worldPos, float3 viewDir, float3 L, float dist, ScreenParticleLight Lgt)
{
if (Lgt.samples == 0u)
return 1.0;
#if defined(QD3D12_SCREEN_PARTICLE_RAYQUERY)
RayDesc ray;
ray.Origin = worldPos + L * 5.0 + viewDir * 1.0;
ray.Direction = L;
ray.TMin = 0.001;
ray.TMax = max(dist - 8.0, 0.001);
RayQuery<RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES> q;
q.TraceRayInline(
gScreenParticleSceneBVH,
RAY_FLAG_ACCEPT_FIRST_HIT_AND_END_SEARCH | RAY_FLAG_FORCE_OPAQUE | RAY_FLAG_SKIP_PROCEDURAL_PRIMITIVES,
0xFF,
ray);
while (q.Proceed()) {}
return (q.CommittedStatus() == COMMITTED_TRIANGLE_HIT) ? 0.0 : 1.0;
#else
return 1.0;
#endif
}
float3 ScreenParticleDirectLighting(float3 worldPos)
{
uint lightCount = min((uint)gScreenParticleLightCount, 256u);
if (lightCount == 0u || gPostFogCameraValid <= 0.5)
return 1.0;
float3 viewDir = ScreenParticleSafeNormalizeOr(gPostFogCameraWorldPos.xyz - worldPos, float3(0.0, 0.0, 1.0));
float3 lighting = float3(0.16, 0.16, 0.16);
[loop]
for (uint lightIndex = 0u; lightIndex < lightCount; ++lightIndex)
{
ScreenParticleLight Lgt = gScreenParticleLights[lightIndex];
if (Lgt.type != GL_RAYTRACING_LIGHT_TYPE_POINT && Lgt.type != GL_RAYTRACING_LIGHT_TYPE_SPOT)
continue;
float3 toLight = Lgt.position - worldPos;
float dist = length(toLight);
if (dist <= 0.01)
continue;
float atten = (Lgt.type == GL_RAYTRACING_LIGHT_TYPE_POINT)
? ScreenParticlePointAttenuation(worldPos, Lgt)
: ScreenParticleSpotAttenuation(worldPos, Lgt);
if (atten <= 0.0)
continue;
float3 L = toLight / dist;
float shadow = ScreenParticleTraceShadow(worldPos, viewDir, L, dist, Lgt);
if (shadow <= 0.0)
continue;
float forwardScatter = saturate(dot(viewDir, -L) * 0.5 + 0.5);
float phase = lerp(0.65, 1.0, forwardScatter);
lighting += Lgt.color * (Lgt.intensity * atten * shadow * phase * 0.25);
}
return clamp(lighting, 0.08, 8.0);
}
float4 PSScreenParticles(ParticleVSOut i) : SV_Target0
{
float4 texel = gTex0.Sample(gSamp0, i.uv) * i.color;
float alpha = saturate(texel.a);
if (alpha <= 0.0001)
discard;
if (gPostFogCameraValid > 0.5)
{
uint2 pixel = uint2(i.pos.xy);
float sceneDepth = gFogDepth.Load(int3(pixel, 0));
float particleDepth = saturate(i.pos.z);
if (sceneDepth < 0.99999)
{
float4 positionSample = gScreenDecalPosition.Load(int3(pixel, 0));
uint geometryBits = (uint)round(max(positionSample.w, 0.0));
if ((geometryBits & 1u) == 0u)
{
float sceneDistance = length(positionSample.xyz - gPostFogCameraWorldPos.xyz);
float particleDistance = length(i.world - gPostFogCameraWorldPos.xyz);
float softDepth = max(gScreenParticleSoftDepth, 0.001);
alpha *= saturate((sceneDistance - particleDistance) / softDepth);
if (alpha <= 0.0001)
discard;
}
else if (particleDepth > sceneDepth + 0.00005)
{
discard;
}
}
}
texel.rgb *= ScreenParticleDirectLighting(i.world);
return float4(texel.rgb, alpha);
}
float4 PSCopy(VSOut i) : SV_Target0
{
return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv);
@@ -4681,7 +4935,8 @@ float4 PSToneMapFinalMax(VSOut i) : SV_Target0
return float4(min(maxBrightness, 65504.0), 0.0, 0.0, 1.0);
}
)HLSL"
R"HLSL(
float3 QD3D12_PostSharpenHDR(float2 uv, float3 center)
{
float amount = saturate(gPostSharpness);
@@ -4825,7 +5080,8 @@ float3 QD3D12_EmissiveBloom(float2 uv)
return min(bloom * 0.62, 5.0);
}
)HLSL"
R"HLSL(
float4 PSAdd(VSOut i) : SV_Target0
{
float4 center = gTex0.Sample(gSamp0, i.uv);
@@ -7260,6 +7516,7 @@ static bool QD3D12_CanUseDLSSRayReconstructionForLighting(const QD3D12Window& w)
static bool QD3D12_UseLightingTextureAsUpscaleInput(const QD3D12Window& w)
{
return QD3D12_CanUseDLSSRayReconstructionForLighting(w) &&
!g_gl.blockLightingUpscaleInputThisFrame &&
g_gl.raytracedLightingReadyThisFrame &&
g_lightingTexture[g_lightingReadIndex] &&
g_lightingTexture[g_lightingReadIndex]->texture;
@@ -7795,7 +8052,10 @@ static void QD3D12_SetPostConstants(
float toneMapBrightness = 1.0f,
bool applySceneFog = false,
float screenDecalCount = 0.0f,
float screenDecalIndex = 0.0f)
float screenDecalIndex = 0.0f,
bool forceCameraPosition = false,
float screenParticleSoftDepth = 16.0f,
float screenParticleLightCount = 0.0f)
{
if (!cl)
return;
@@ -7824,6 +8084,15 @@ static void QD3D12_SetPostConstants(
constants[21] = g_gl.sceneFogCameraWorldPos[1];
constants[22] = g_gl.sceneFogCameraWorldPos[2];
}
else if ( forceCameraPosition && g_gl.cameraState.valid )
{
constants[13] = 1.0f;
constants[20] = g_gl.cameraState.cameraPos[0];
constants[21] = g_gl.cameraState.cameraPos[1];
constants[22] = g_gl.cameraState.cameraPos[2];
}
constants[14] = screenParticleSoftDepth;
constants[15] = screenParticleLightCount;
constants[23] = screenDecalCount;
cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0);
}
@@ -7912,6 +8181,96 @@ static bool QD3D12_EnsureScreenSpaceDecalBuffer()
return true;
}
static bool QD3D12_EnsureScreenSpaceParticleLightBuffer()
{
if (!g_gl.device || !g_gl.srvHeap)
return false;
const UINT64 bufferSize = sizeof(glRaytracingLight_t) * QD3D12_MaxScreenSpaceParticleLights;
if (!g_gl.screenSpaceParticleLightBuffer)
{
D3D12_HEAP_PROPERTIES hp{};
hp.Type = D3D12_HEAP_TYPE_UPLOAD;
hp.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN;
hp.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN;
hp.CreationNodeMask = 1;
hp.VisibleNodeMask = 1;
D3D12_RESOURCE_DESC rd{};
rd.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER;
rd.Width = bufferSize;
rd.Height = 1;
rd.DepthOrArraySize = 1;
rd.MipLevels = 1;
rd.Format = DXGI_FORMAT_UNKNOWN;
rd.SampleDesc.Count = 1;
rd.SampleDesc.Quality = 0;
rd.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR;
rd.Flags = D3D12_RESOURCE_FLAG_NONE;
QD3D12_CHECK(g_gl.device->CreateCommittedResource(
&hp,
D3D12_HEAP_FLAG_NONE,
&rd,
D3D12_RESOURCE_STATE_GENERIC_READ,
nullptr,
IID_PPV_ARGS(&g_gl.screenSpaceParticleLightBuffer)));
QD3D12_CHECK(g_gl.screenSpaceParticleLightBuffer->Map(0, nullptr, &g_gl.screenSpaceParticleLightBufferMapped));
}
if (g_gl.screenSpaceParticleLightSrvIndex == UINT_MAX)
{
g_gl.screenSpaceParticleLightSrvIndex = g_gl.nextSrvIndex++;
g_gl.screenSpaceParticleLightSrvCpu = QD3D12_SrvCpu(g_gl.screenSpaceParticleLightSrvIndex);
g_gl.screenSpaceParticleLightSrvGpu = QD3D12_SrvGpu(g_gl.screenSpaceParticleLightSrvIndex);
D3D12_SHADER_RESOURCE_VIEW_DESC sd{};
sd.ViewDimension = D3D12_SRV_DIMENSION_BUFFER;
sd.Format = DXGI_FORMAT_UNKNOWN;
sd.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
sd.Buffer.FirstElement = 0;
sd.Buffer.NumElements = QD3D12_MaxScreenSpaceParticleLights;
sd.Buffer.StructureByteStride = sizeof(glRaytracingLight_t);
sd.Buffer.Flags = D3D12_BUFFER_SRV_FLAG_NONE;
g_gl.device->CreateShaderResourceView(g_gl.screenSpaceParticleLightBuffer.Get(), &sd, g_gl.screenSpaceParticleLightSrvCpu);
}
if (g_gl.screenSpaceParticleLightBufferMapped)
{
memset(g_gl.screenSpaceParticleLightBufferMapped, 0, bufferSize);
if (g_gl.screenSpaceParticleLightCount > 0)
{
memcpy(
g_gl.screenSpaceParticleLightBufferMapped,
g_gl.screenSpaceParticleLights,
sizeof(glRaytracingLight_t) * g_gl.screenSpaceParticleLightCount);
}
}
return true;
}
static bool QD3D12_UpdateScreenSpaceParticleTlasSrv(ID3D12Resource* tlas)
{
if (!g_gl.device || !g_gl.srvHeap || !tlas)
return false;
if (g_gl.screenSpaceParticleTlasSrvIndex == UINT_MAX)
{
g_gl.screenSpaceParticleTlasSrvIndex = g_gl.nextSrvIndex++;
g_gl.screenSpaceParticleTlasSrvCpu = QD3D12_SrvCpu(g_gl.screenSpaceParticleTlasSrvIndex);
g_gl.screenSpaceParticleTlasSrvGpu = QD3D12_SrvGpu(g_gl.screenSpaceParticleTlasSrvIndex);
}
D3D12_SHADER_RESOURCE_VIEW_DESC sd{};
sd.ViewDimension = D3D12_SRV_DIMENSION_RAYTRACING_ACCELERATION_STRUCTURE;
sd.Shader4ComponentMapping = D3D12_DEFAULT_SHADER_4_COMPONENT_MAPPING;
sd.RaytracingAccelerationStructure.Location = tlas->GetGPUVirtualAddress();
g_gl.device->CreateShaderResourceView(nullptr, &sd, g_gl.screenSpaceParticleTlasSrvCpu);
return true;
}
static void QD3D12_PostFullscreenPass(ID3D12GraphicsCommandList* cl,
ID3D12PipelineState* pso,
D3D12_GPU_DESCRIPTOR_HANDLE inputSrv,
@@ -8180,6 +8539,135 @@ void APIENTRY glDrawScreenSpaceDecalsQD3D12(void)
}
}
static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas)
{
const glScreenSpaceParticleVertex_t* verts = batch.vertices.empty() ? nullptr : batch.vertices.data();
const uint32_t vertexCount = (uint32_t)batch.vertices.size();
const uint32_t textureId = batch.textureId;
const uint32_t blendMode = batch.blendMode;
const float softDepth = batch.softDepth;
if (!verts || vertexCount == 0)
return;
QD3D12Window* window = g_currentWindow;
if (!window || !g_gl.device || !g_gl.cmdList || !g_gl.postScreenParticlePSO)
return;
if (!window->sceneColorBuffers[window->frameIndex] || !window->positionBuffers[window->frameIndex] || !window->depthBuffer)
return;
if (!QD3D12_EnsureScreenSpaceParticleLightBuffer() || !QD3D12_UpdateScreenSpaceParticleTlasSrv(tlas))
return;
QD3D12_EnsureFrameOpen();
QD3D12_FlushQueuedBatches();
QD3D12_ResolveGBufferForCurrentFrame(*window);
QD3D12_UpdateCameraInfoFromCurrentMatrices();
const UINT frame = window->frameIndex;
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
QD3D12_TransitionResource(cl, window->sceneColorBuffers[frame].Get(), window->sceneColorState[frame], D3D12_RESOURCE_STATE_RENDER_TARGET);
QD3D12_TransitionResource(cl, window->depthBuffer.Get(), window->depthState, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
QD3D12_TransitionResource(cl, window->positionBuffers[frame].Get(), window->positionBufferState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
const UINT vbBytes = vertexCount * sizeof(glScreenSpaceParticleVertex_t);
UploadAlloc upload = QD3D12_AllocUpload(vbBytes, 256);
memcpy(upload.cpu, verts, vbBytes);
D3D12_VERTEX_BUFFER_VIEW vbv{};
vbv.BufferLocation = upload.gpu;
vbv.SizeInBytes = vbBytes;
vbv.StrideInBytes = sizeof(glScreenSpaceParticleVertex_t);
D3D12_VIEWPORT viewport{};
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
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)window->renderWidth;
scissor.bottom = (LONG)window->renderHeight;
D3D12_GPU_DESCRIPTOR_HANDLE particleTextureSrv = g_gl.whiteTexture.srvGpu;
TextureResource* particleTexture = textureId ? QD3D12_FindTextureResource(textureId) : nullptr;
if (particleTexture)
{
EnsureTextureResource(*particleTexture);
if (particleTexture->texture && !particleTexture->gpuValid)
{
UploadTexture(*particleTexture);
}
if (particleTexture->texture && particleTexture->srvIndex != UINT_MAX)
{
particleTextureSrv = particleTexture->srvGpu;
}
}
ID3D12PipelineState* particlePSO = (blendMode == 1 && g_gl.postScreenParticleAdditivePSO.Get() != nullptr)
? g_gl.postScreenParticleAdditivePSO.Get()
: g_gl.postScreenParticlePSO.Get();
ID3D12DescriptorHeap* heaps[] = { g_gl.srvHeap.Get() };
cl->SetDescriptorHeaps(_countof(heaps), heaps);
cl->SetGraphicsRootSignature(g_gl.postRootSig.Get());
QD3D12_SetPostConstants(cl, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, false, 0.0f, 0.0f, true, softDepth, (float)g_gl.screenSpaceParticleLightCount);
cl->SetPipelineState(particlePSO);
D3D12_CPU_DESCRIPTOR_HANDLE sceneColorRtv = CurrentResolvedSceneColorRTV();
cl->OMSetRenderTargets(1, &sceneColorRtv, FALSE, nullptr);
cl->RSSetViewports(1, &viewport);
cl->RSSetScissorRects(1, &scissor);
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cl->IASetVertexBuffers(0, 1, &vbv);
cl->SetGraphicsRootDescriptorTable(0, particleTextureSrv);
cl->SetGraphicsRootDescriptorTable(10, window->depthSrvGpu);
cl->SetGraphicsRootDescriptorTable(12, window->positionSrvGpu[frame]);
cl->SetGraphicsRootDescriptorTable(14, g_gl.screenSpaceParticleLightSrvGpu);
cl->SetGraphicsRootDescriptorTable(15, g_gl.screenSpaceParticleTlasSrvGpu);
cl->DrawInstanced(vertexCount, 1, 0, 0);
}
void APIENTRY glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth)
{
if (!verts || vertexCount == 0)
return;
QD3D12ScreenSpaceParticleBatch batch;
batch.vertices.assign(verts, verts + vertexCount);
batch.textureId = textureId;
batch.blendMode = blendMode;
batch.softDepth = softDepth;
g_gl.screenSpaceParticleBatches.push_back(std::move(batch));
}
void APIENTRY glSetScreenSpaceParticleLightsQD3D12(const glRaytracingLight_t* lights, uint32_t lightCount)
{
g_gl.screenSpaceParticleLightCount = 0;
memset(g_gl.screenSpaceParticleLights, 0, sizeof(g_gl.screenSpaceParticleLights));
if (!lights || lightCount == 0)
return;
const uint32_t count = std::min<uint32_t>(lightCount, QD3D12_MaxScreenSpaceParticleLights);
memcpy(g_gl.screenSpaceParticleLights, lights, sizeof(glRaytracingLight_t) * count);
g_gl.screenSpaceParticleLightCount = count;
}
static void QD3D12_DrawQueuedScreenSpaceParticles(ID3D12Resource* tlas)
{
if (g_gl.screenSpaceParticleBatches.empty())
return;
for (const QD3D12ScreenSpaceParticleBatch& batch : g_gl.screenSpaceParticleBatches)
{
QD3D12_DrawScreenSpaceParticleBatch(batch, tlas);
}
g_gl.screenSpaceParticleBatches.clear();
}
static ID3D12Resource* QD3D12_PrepareStreamlineOutputForWrite(QD3D12Window& w)
{
ID3D12GraphicsCommandList* cl = g_gl.cmdList.Get();
@@ -9427,7 +9915,7 @@ static void QD3D12_DestroyUploadRingForWindow(QD3D12Window& w)
w.upload.offset = 0;
}
static ComPtr<ID3DBlob> CompileShaderSourceVariant(const char* source, const char* entry, const char* target)
static ComPtr<ID3DBlob> CompileShaderSourceVariant(const char* source, const char* entry, const char* target, LPCWSTR defineName = nullptr)
{
ComPtr<IDxcUtils> utils;
ComPtr<IDxcCompiler3> compiler;
@@ -9486,6 +9974,11 @@ static ComPtr<ID3DBlob> CompileShaderSourceVariant(const char* source, const cha
args.push_back(wTarget.c_str());
args.push_back(L"-HV");
args.push_back(L"2021");
if (defineName && defineName[0])
{
args.push_back(L"-D");
args.push_back(defineName);
}
#if defined(_DEBUG)
args.push_back(L"-Zi");
@@ -9677,6 +10170,8 @@ static void QD3D12_CompileShaders()
g_gl.postPsDepthResolveMsaaBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSDepthResolveMS", "ps_6_0");
g_gl.postPsGBufferPointResolveMsaaBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSGBufferPointResolveMS", "ps_6_0");
g_gl.postPsScreenDecalBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenDecals", "ps_6_0");
g_gl.postVsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "VSParticle", "vs_6_0");
g_gl.postPsScreenParticleBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSScreenParticles", "ps_6_5", L"QD3D12_SCREEN_PARTICLE_RAYQUERY=1");
}
static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayout[] =
@@ -9701,6 +10196,14 @@ static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayoutARB[] =
{ "BINORMAL", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(GLVertex, bx), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
static const D3D12_INPUT_ELEMENT_DESC kScreenSpaceParticleInputLayout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, clip), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, st), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, color), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 1, DXGI_FORMAT_R32G32B32_FLOAT, 0, (UINT)offsetof(glScreenSpaceParticleVertex_t, world), D3D12_INPUT_CLASSIFICATION_PER_VERTEX_DATA, 0 },
};
static UINT8 BuildColorWriteMask()
{
UINT8 mask = 0;
@@ -9900,6 +10403,24 @@ static void QD3D12_CreatePSOs()
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postScreenDecalStainPSO)));
D3D12_GRAPHICS_PIPELINE_STATE_DESC particleDesc = d;
particleDesc.VS = { g_gl.postVsScreenParticleBlob->GetBufferPointer(), g_gl.postVsScreenParticleBlob->GetBufferSize() };
particleDesc.PS = { g_gl.postPsScreenParticleBlob->GetBufferPointer(), g_gl.postPsScreenParticleBlob->GetBufferSize() };
particleDesc.InputLayout.pInputElementDescs = kScreenSpaceParticleInputLayout;
particleDesc.InputLayout.NumElements = _countof(kScreenSpaceParticleInputLayout);
particleDesc.BlendState.RenderTarget[0].BlendEnable = TRUE;
particleDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
particleDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
particleDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
particleDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&particleDesc, IID_PPV_ARGS(&g_gl.postScreenParticlePSO)));
particleDesc.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
particleDesc.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_ONE;
particleDesc.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
particleDesc.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_ONE;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&particleDesc, IID_PPV_ARGS(&g_gl.postScreenParticleAdditivePSO)));
D3D12_GRAPHICS_PIPELINE_STATE_DESC depthDesc{};
depthDesc.pRootSignature = g_gl.postRootSig.Get();
depthDesc.VS = { g_gl.postVsBlob->GetBufferPointer(), g_gl.postVsBlob->GetBufferSize() };
@@ -10476,6 +10997,9 @@ void QD3D12_BeginFrame()
g_gl.gbufferResolvedThisFrame = false;
g_gl.raytracedLightingReadyThisFrame = false;
g_gl.sceneFogValidThisFrame = false;
g_gl.blockLightingUpscaleInputThisFrame = false;
g_gl.screenSpaceParticleBatches.clear();
g_gl.screenSpaceParticleLightCount = 0;
QD3D12_UpdateViewportState();
FrameResources& fr = w.frames[w.frameIndex];
@@ -16714,6 +17238,8 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "QD3D12_ResolveGBufferNow", (PROC)QD3D12_ResolveGBufferNow },
{ "glSetScreenSpaceDecalsQD3D12",(PROC)glSetScreenSpaceDecalsQD3D12 },
{ "glDrawScreenSpaceDecalsQD3D12",(PROC)glDrawScreenSpaceDecalsQD3D12 },
{ "glSetScreenSpaceParticleLightsQD3D12",(PROC)glSetScreenSpaceParticleLightsQD3D12 },
{ "glDrawScreenSpaceParticlesQD3D12",(PROC)glDrawScreenSpaceParticlesQD3D12 },
{ "QD3D12_SetUpscalerBackend", (PROC)QD3D12_SetUpscalerBackend },
{ "QD3D12_SetUpscalerQuality", (PROC)QD3D12_SetUpscalerQuality },
{ "QD3D12_SetUpscalerSharpness", (PROC)QD3D12_SetUpscalerSharpness },
@@ -17502,6 +18028,14 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
QD3D12_RunRayAIDenoiseIfEnabled(cl, *window, writeLightingTex->texture.Get());
if (!g_gl.screenSpaceParticleBatches.empty())
{
// The particle pass is a blended graphics pass, so it needs a render-target
// scene color surface. Keep particle frames on the composited scene-color
// path instead of feeding the raw lighting texture straight to RR/upscale.
g_gl.blockLightingUpscaleInputThisFrame = true;
}
// If the denoiser changes the written texture state, restore it to a
// shader-readable state before this slot becomes the next read target.
// restore the texture to a shader-readable state for the post/upscale pass.
@@ -17570,6 +18104,8 @@ void glLightScene(glRaytracingSceneHandle_t sceneHandle)
// guide instead of overwriting it here.
}
QD3D12_DrawQueuedScreenSpaceParticles(tlas);
QD3D12_ResolveSceneToOutputAndEnterNativePhase(*window);
}
+11
View File
@@ -1748,6 +1748,15 @@ typedef struct glScreenSpaceDecal_s
float pad1[2];
} glScreenSpaceDecal_t;
typedef struct glScreenSpaceParticleVertex_s
{
float clip[4];
float st[2];
float color[4];
float world[3];
float pad0;
} glScreenSpaceParticleVertex_t;
int glRaytracingInit(void);
void glRaytracingShutdown(void);
void glRaytracingClear(void);
@@ -1843,6 +1852,8 @@ uint32_t glRaytracingLightingGetLightCount(void);
void glLightScene(glRaytracingSceneHandle_t sceneHandle);
void glSetScreenSpaceDecalsQD3D12(const glScreenSpaceDecal_t* decals, uint32_t decalCount);
void glDrawScreenSpaceDecalsQD3D12(void);
void glSetScreenSpaceParticleLightsQD3D12(const glRaytracingLight_t* lights, uint32_t lightCount);
void glDrawScreenSpaceParticlesQD3D12(const glScreenSpaceParticleVertex_t* verts, uint32_t vertexCount, uint32_t textureId, uint32_t blendMode, float softDepth);
ID3D12Device* QD3D12_GetDevice(void);
ID3D12CommandQueue* QD3D12_GetQueue(void);
@@ -138,6 +138,7 @@ idCVar r_frontBuffer( "r_frontBuffer", "0", CVAR_RENDERER | CVAR_BOOL, "draw to
idCVar r_skipSubviews( "r_skipSubviews", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = don't render any gui elements on surfaces" );
idCVar r_skipGuiShaders( "r_skipGuiShaders", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all gui elements on surfaces, 2 = skip drawing but still handle events, 3 = draw but skip events", 0, 3, idCmdSystem::ArgCompletion_Integer<0,3> );
idCVar r_skipParticles( "r_skipParticles", "0", CVAR_RENDERER | CVAR_INTEGER, "1 = skip all particle systems", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> );
idCVar r_screenSpaceParticles( "r_screenSpaceParticles", "1", CVAR_RENDERER | CVAR_INTEGER, "1 = render particles in a D3D12 screen-space pass", 0, 1, idCmdSystem::ArgCompletion_Integer<0,1> );
idCVar r_subviewOnly( "r_subviewOnly", "0", CVAR_RENDERER | CVAR_BOOL, "1 = don't render main view, allowing subviews to be debugged" );
idCVar r_shadows( "r_shadows", "1", CVAR_RENDERER | CVAR_BOOL | CVAR_ARCHIVE, "enable shadows" );
idCVar r_testARBProgram( "r_testARBProgram", "0", CVAR_RENDERER | CVAR_BOOL, "experiment with vertex/fragment programs" );
+125
View File
@@ -367,6 +367,10 @@ void RB_T_FillDepthBuffer(const drawSurf_t* surf) {
tri = surf->geo;
shader = surf->material;
if ( r_screenSpaceParticles.GetBool() && ( surf->dsFlags & DSF_SCREEN_SPACE_PARTICLE ) ) {
return;
}
// update the clip plane if needed
if (backEnd.viewDef->numClipPlanes && surf->space != backEnd.currentSpace) {
GL_SelectTexture(1);
@@ -802,6 +806,10 @@ void RB_STD_T_RenderShaderPasses( const drawSurf_t *surf ) {
tri = surf->geo;
shader = surf->material;
if ( r_screenSpaceParticles.GetBool() && ( surf->dsFlags & DSF_SCREEN_SPACE_PARTICLE ) ) {
return;
}
if ( !shader->HasAmbient() ) {
return;
}
@@ -1504,6 +1512,121 @@ void RB_STD_FogAllLights( void ) {
//=========================================================================================
static const shaderStage_t *RB_FirstDrawableParticleStage( const drawSurf_t *surf, idImage *&image, uint32_t &blendMode ) {
image = NULL;
blendMode = 0;
if ( !surf || !surf->material || !surf->shaderRegisters ) {
return NULL;
}
for ( int stage = 0; stage < surf->material->GetNumStages(); stage++ ) {
const shaderStage_t *pStage = surf->material->GetStage( stage );
if ( pStage->lighting != SL_AMBIENT ) {
continue;
}
if ( surf->shaderRegisters[pStage->conditionRegister] == 0.0f ) {
continue;
}
image = pStage->texture.image;
const int srcBlend = pStage->drawStateBits & GLS_SRCBLEND_BITS;
const int dstBlend = pStage->drawStateBits & GLS_DSTBLEND_BITS;
if ( srcBlend == GLS_SRCBLEND_ONE && dstBlend == GLS_DSTBLEND_ONE ) {
blendMode = 1;
}
return pStage;
}
return NULL;
}
static void RB_FillScreenSpaceParticleVertex( glScreenSpaceParticleVertex_t &dst, const idDrawVert &src, const viewEntity_t *space, const float *projectionMatrix, const float stageColor[4] ) {
idVec3 world;
idPlane eye, clip;
R_LocalPointToGlobal( space->modelMatrix, src.xyz, world );
R_TransformModelToClip( src.xyz, space->modelViewMatrix, projectionMatrix, eye, clip );
dst.clip[0] = clip[0];
dst.clip[1] = clip[1];
dst.clip[2] = 0.5f * ( clip[2] + clip[3] );
dst.clip[3] = clip[3];
dst.st[0] = src.st[0];
dst.st[1] = src.st[1];
dst.color[0] = ( src.color[0] * ( 1.0f / 255.0f ) ) * stageColor[0];
dst.color[1] = ( src.color[1] * ( 1.0f / 255.0f ) ) * stageColor[1];
dst.color[2] = ( src.color[2] * ( 1.0f / 255.0f ) ) * stageColor[2];
dst.color[3] = ( src.color[3] * ( 1.0f / 255.0f ) ) * stageColor[3];
dst.world[0] = world[0];
dst.world[1] = world[1];
dst.world[2] = world[2];
dst.pad0 = 0.0f;
}
static void RB_SubmitScreenSpaceParticleSurf( const drawSurf_t *surf ) {
if ( !surf || !surf->geo || !surf->space || !surf->material || !surf->geo->verts || !surf->geo->indexes ) {
return;
}
if ( !surf->geo->numIndexes || !surf->geo->numVerts ) {
return;
}
idImage *image = NULL;
uint32_t blendMode = 0;
const shaderStage_t *stage = RB_FirstDrawableParticleStage( surf, image, blendMode );
if ( !stage ) {
return;
}
float stageColor[4];
for ( int i = 0; i < 4; i++ ) {
stageColor[i] = surf->shaderRegisters[stage->color.registers[i]];
}
if ( image ) {
image->Bind();
} else {
globalImages->whiteImage->Bind();
image = globalImages->whiteImage;
}
float projectionMatrix[16];
memcpy( projectionMatrix, backEnd.viewDef->projectionMatrix, sizeof( projectionMatrix ) );
if ( surf->space->weaponDepthHack ) {
projectionMatrix[14] *= 0.25f;
}
if ( surf->space->modelDepthHack != 0.0f ) {
projectionMatrix[14] -= surf->space->modelDepthHack;
}
idList<glScreenSpaceParticleVertex_t> particleVerts;
particleVerts.SetNum( surf->geo->numIndexes, false );
for ( int i = 0; i < surf->geo->numIndexes; i++ ) {
const int vertIndex = surf->geo->indexes[i];
if ( vertIndex < 0 || vertIndex >= surf->geo->numVerts ) {
continue;
}
RB_FillScreenSpaceParticleVertex( particleVerts[i], surf->geo->verts[vertIndex], surf->space, projectionMatrix, stageColor );
}
glDrawScreenSpaceParticlesQD3D12( particleVerts.Ptr(), particleVerts.Num(), image->texnum, blendMode, 16.0f );
}
static void RB_STD_DrawScreenSpaceParticles( drawSurf_t **drawSurfs, int numDrawSurfs ) {
if ( !r_screenSpaceParticles.GetBool() || !backEnd.viewDef->viewEntitys ) {
return;
}
RB_LogComment( "---------- RB_STD_DrawScreenSpaceParticles ----------\n" );
for ( int i = 0; i < numDrawSurfs; i++ ) {
if ( drawSurfs[i]->dsFlags & DSF_SCREEN_SPACE_PARTICLE ) {
RB_SubmitScreenSpaceParticleSurf( drawSurfs[i] );
}
}
}
/*
=============
RB_STD_DrawView
@@ -1531,6 +1654,8 @@ void RB_STD_DrawView( void ) {
// subviews
RB_STD_FillDepthBuffer( drawSurfs, numDrawSurfs );
RB_STD_DrawScreenSpaceParticles( drawSurfs, numDrawSurfs );
// main light renderer
RB_DXDrawInteractions();
+4
View File
@@ -160,6 +160,8 @@ void RB_DXDrawInteractions(void)
QD3D12_SetToneMapBrightness(r_brightness.GetFloat());
QD3D12_SetFrameGenerationMultiplier(r_frameGen.GetInteger());
idList<glRaytracingLight_t> screenParticleLights;
for (vLight = backEnd.viewDef->viewLights; vLight; vLight = vLight->next)
{
backEnd.vLight = vLight;
@@ -240,12 +242,14 @@ void RB_DXDrawInteractions(void)
}
}
glRaytracingLightingAddLight(&light);
screenParticleLights.Append(light);
}
}
if (backEnd.viewDef->renderWorld)
{
backEnd.viewDef->renderWorld->SubmitWorldDecalsToScreenSpace();
glSetScreenSpaceParticleLightsQD3D12(screenParticleLights.Ptr(), screenParticleLights.Num());
glLightScene(backEnd.viewDef->renderWorld->dxrWorldId);
glRaytracingLightingClearLights(false);
}
+1 -1
View File
@@ -1211,7 +1211,7 @@ static void R_ParticleDeform( drawSurf_t *surf, bool useArea ) {
tri->ambientCache = vertexCache.AllocFrameTemp( tri->verts, tri->numVerts * sizeof( idDrawVert ) );
if ( tri->ambientCache ) {
// add the drawsurf
R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect );
R_AddDrawSurf( tri, surf->space, renderEntity, stage->material, surf->scissorRect, DSF_SCREEN_SPACE_PARTICLE );
}
}
}
+6 -3
View File
@@ -1110,7 +1110,7 @@ R_AddDrawSurf
=================
*/
void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
const idMaterial *shader, const idScreenRect &scissor ) {
const idMaterial *shader, const idScreenRect &scissor, int dsFlags ) {
drawSurf_t *drawSurf;
const float *shaderParms;
static float refRegs[MAX_EXPRESSION_REGISTERS]; // don't put on stack, or VC++ will do a page touch
@@ -1122,7 +1122,7 @@ void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const
drawSurf->material = shader;
drawSurf->scissorRect = scissor;
drawSurf->sort = shader->GetSort() + tr.sortOffset;
drawSurf->dsFlags = 0;
drawSurf->dsFlags = dsFlags;
// bumping this offset each time causes surfaces with equal sort orders to still
// deterministically draw in the order they are added
@@ -1351,8 +1351,11 @@ static void R_AddAmbientDrawsurfs( viewEntity_t *vEntity ) {
R_CreateIndexCache( tri );
}
const int particleFlags = ( def->dynamicModel &&
idStr::Icmp( model->Name(), "_ParametricParticle_Snapshot_" ) == 0 ) ? DSF_SCREEN_SPACE_PARTICLE : 0;
// add the surface for drawing
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect );
R_AddDrawSurf( tri, vEntity, &vEntity->entityDef->parms, shader, vEntity->scissorRect, particleFlags );
// ambientViewCount is used to allow light interactions to be rejected
// if the ambient surface isn't visible at all
+4 -2
View File
@@ -103,7 +103,8 @@ SURFACES
// unique srfTriangles_t
// drawSurf_t are always allocated and freed every frame, they are never cached
static const int DSF_VIEW_INSIDE_SHADOW = 1;
static const int DSF_VIEW_INSIDE_SHADOW = 1;
static const int DSF_SCREEN_SPACE_PARTICLE = 2;
typedef struct drawSurf_s {
const srfTriangles_t *geo;
@@ -910,6 +911,7 @@ extern idCVar r_skipFogLights; // skip all fog lights
extern idCVar r_skipSubviews; // 1 = don't render any mirrors / cameras / etc
extern idCVar r_skipGuiShaders; // 1 = don't render any gui elements on surfaces
extern idCVar r_skipParticles; // 1 = don't render any particles
extern idCVar r_screenSpaceParticles; // 1 = render particles in the D3D12 screen-space pass
extern idCVar r_skipUpdates; // 1 = don't accept any entity or light updates, making everything static
extern idCVar r_skipDeforms; // leave all deform materials in their original state
extern idCVar r_skipDynamicTextures; // don't dynamically create textures
@@ -1199,7 +1201,7 @@ viewEntity_t *R_SetEntityDefViewEntity( idRenderEntityLocal *def );
viewLight_t *R_SetLightDefViewLight( idRenderLightLocal *def );
void R_AddDrawSurf( const srfTriangles_t *tri, const viewEntity_t *space, const renderEntity_t *renderEntity,
const idMaterial *shader, const idScreenRect &scissor );
const idMaterial *shader, const idScreenRect &scissor, int dsFlags = 0 );
void R_LinkLightSurf( const drawSurf_t **link, const srfTriangles_t *tri, const viewEntity_t *space,
const idRenderLightLocal *light, const idMaterial *shader, const idScreenRect &scissor, bool viewInsideShadow );
+1 -1
View File
@@ -521,7 +521,7 @@ int idSampleDecoderLocal::DecodeOGG( idSoundSample *sample, int sampleOffset44k,
return 0;
}
if ( sample->nonCacheData == NULL ) {
assert( false ); // this should never happen
// assert( false ); // this should never happen
failed = true;
return 0;
}