Added citybuilder and cloud pass.

This commit is contained in:
Justin Marshall
2026-05-28 01:09:16 -07:00
parent 5d2cb8640d
commit a7e7e8edbc
30 changed files with 58019 additions and 36996 deletions
+266 -11
View File
@@ -542,7 +542,7 @@ static const UINT QD3D12_UploadBufferSize = 128 * 1024 * 1024;
static const UINT QD3D12_RequestedGBufferSampleCount = 1;
static constexpr UINT QD3D12_PostSrvCount = 16;
static constexpr UINT QD3D12_PostRootConstants = QD3D12_PostSrvCount;
static constexpr UINT QD3D12_PostConstantDwords = 28;
static constexpr UINT QD3D12_PostConstantDwords = 48;
static constexpr UINT QD3D12_ToneMapTileDim = 64;
static constexpr UINT QD3D12_MaxScreenSpaceDecals = 64;
static constexpr UINT QD3D12_MaxScreenSpaceParticleLights = GL_RAYTRACING_MAX_LIGHTS;
@@ -1798,6 +1798,7 @@ struct GLState
ComPtr<ID3D12PipelineState> postScreenParticlePSO;
ComPtr<ID3D12PipelineState> postScreenParticleAdditivePSO;
ComPtr<ID3D12PipelineState> postScreenParticleEmissivePSO;
ComPtr<ID3D12PipelineState> postSkyCloudsPSO;
ComPtr<ID3DBlob> vsMainBlob;
ComPtr<ID3DBlob> hsMainBlob;
@@ -1822,6 +1823,7 @@ struct GLState
ComPtr<ID3DBlob> postPsScreenDecalBlob;
ComPtr<ID3DBlob> postVsScreenParticleBlob;
ComPtr<ID3DBlob> postPsScreenParticleBlob;
ComPtr<ID3DBlob> postPsSkyCloudsBlob;
TextureResource whiteTexture;
@@ -4778,6 +4780,11 @@ cbuffer PostCB : register(b0)
float4 gPostFogColor;
float4 gPostFogCameraWorldPos;
float4 gPostParticleParams;
float4 gSkyCloudColorOpacity;
float4 gSkyCloudForwardZMax;
float4 gSkyCloudRightTanX;
float4 gSkyCloudUpTanY;
float4 gSkyCloudParams;
};
#define gPostSharpness gPostParams0.x
@@ -4799,6 +4806,20 @@ cbuffer PostCB : register(b0)
#define gScreenParticleEmissiveScale gPostParticleParams.x
#define gScreenParticleOutputMode gPostParticleParams.y
#define gScreenParticleDepthScale gPostParticleParams.zw
#define gSkyCloudColor gSkyCloudColorOpacity.rgb
#define gSkyCloudOpacity gSkyCloudColorOpacity.a
#define gSkyCloudViewOrigin gPostFogCameraWorldPos.xyz
#define gSkyCloudZMin gPostFogCameraWorldPos.w
#define gSkyCloudForward gSkyCloudForwardZMax.xyz
#define gSkyCloudZMax gSkyCloudForwardZMax.w
#define gSkyCloudRight gSkyCloudRightTanX.xyz
#define gSkyCloudTanX gSkyCloudRightTanX.w
#define gSkyCloudUp gSkyCloudUpTanY.xyz
#define gSkyCloudTanY gSkyCloudUpTanY.w
#define gSkyCloudScale gSkyCloudParams.x
#define gSkyCloudCoverage gSkyCloudParams.y
#define gSkyCloudDensity gSkyCloudParams.z
#define gSkyCloudSeed gSkyCloudParams.w
#define QD3D12_TONEMAP_TILE_DIM 64u
static const uint GL_RAYTRACING_LIGHT_TYPE_POINT = 0u;
@@ -5134,12 +5155,124 @@ float4 PSCopy(VSOut i) : SV_Target0
{
return QD3D12_ApplyPostFog(gTex0.Sample(gSamp0, i.uv), i.uv);
}
float QD3D12_SkyCloudFade(float t)
{
t = saturate(t);
return t * t * (3.0 - 2.0 * t);
}
float QD3D12_SkyCloudHash(int3 p)
{
uint h = (uint)p.x * 374761393u + (uint)p.y * 668265263u + (uint)p.z * 2147483647u;
h = (h ^ (h >> 13)) * 1274126177u;
h ^= h >> 16;
return (float)(h & 0xffffu) * (1.0 / 65535.0);
}
float QD3D12_SkyCloudNoise(float3 p)
{
int3 ip = int3(floor(p));
float3 f = float3(
QD3D12_SkyCloudFade(p.x - (float)ip.x),
QD3D12_SkyCloudFade(p.y - (float)ip.y),
QD3D12_SkyCloudFade(p.z - (float)ip.z));
float x00 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 0, 0)), QD3D12_SkyCloudHash(ip + int3(1, 0, 0)), f.x);
float x10 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 1, 0)), QD3D12_SkyCloudHash(ip + int3(1, 1, 0)), f.x);
float x01 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 0, 1)), QD3D12_SkyCloudHash(ip + int3(1, 0, 1)), f.x);
float x11 = lerp(QD3D12_SkyCloudHash(ip + int3(0, 1, 1)), QD3D12_SkyCloudHash(ip + int3(1, 1, 1)), f.x);
return lerp(lerp(x00, x10, f.y), lerp(x01, x11, f.y), f.z);
}
float QD3D12_SkyCloudFBm(float3 p)
{
float sum = 0.0;
float amp = 0.56;
float norm = 0.0;
[unroll]
for (int octave = 0; octave < 5; ++octave)
{
sum += QD3D12_SkyCloudNoise(p) * amp;
norm += amp;
p *= 2.06;
amp *= 0.52;
}
return sum / max(norm, 1.0e-4);
}
float QD3D12_SkyCloudBillow(float3 p)
{
return 1.0 - abs(QD3D12_SkyCloudFBm(p) * 2.0 - 1.0);
}
)HLSL"
R"HLSL(
float4 PSSkyClouds(VSOut i) : SV_Target0
{
float2 ndc = float2(i.uv.x * 2.0 - 1.0, 1.0 - i.uv.y * 2.0);
float3 ray = normalize(gSkyCloudForward + gSkyCloudRight * (ndc.x * gSkyCloudTanX) + gSkyCloudUp * (ndc.y * gSkyCloudTanY));
float horizonMask = smoothstep(-0.015, 0.18, ray.z);
if (horizonMask <= 0.0001)
discard;
float zMin = gSkyCloudZMin;
float zMax = max(gSkyCloudZMax, zMin + 64.0);
float slabDepth = zMax - zMin;
float cloudZ = zMin + slabDepth * 0.55;
float rayZ = max(ray.z, 0.10);
float baseT = (cloudZ - gSkyCloudViewOrigin.z) / rayZ;
if (baseT <= 0.0)
discard;
float2 baseWorld = (gSkyCloudViewOrigin + ray * baseT).xy;
float alpha = 0.0;
float shade = 0.0;
float scale = max(gSkyCloudScale, 0.00001);
float seed = gSkyCloudSeed;
float3 seedVec = float3(11.7 + seed * 0.00011, 3.4 - seed * 0.00007, 9.1);
[unroll]
for (int layer = 0; layer < 7; ++layer)
{
float l = ((float)layer + 0.5) * (1.0 / 7.0);
float heightFade = smoothstep(0.02, 0.34, l) * (1.0 - smoothstep(0.70, 1.0, l));
float2 layerDrift = float2(0.62, -0.28) * (seed * 0.00003 + l * 310.0);
float2 parallax = ray.xy * ((l - 0.5) * slabDepth * 0.16);
float2 cloudXY = (baseWorld + parallax + layerDrift) * scale;
float3 p = float3(cloudXY, seed * 0.00009 + l * 2.7);
float broad = QD3D12_SkyCloudFBm(p * 0.48 + seedVec);
float warpA = QD3D12_SkyCloudFBm(p * 0.82 + broad * 0.85 + seedVec.yzx);
float billowA = smoothstep(0.18, 0.96, QD3D12_SkyCloudBillow(p * 1.35 + warpA * 1.20));
float billowB = smoothstep(0.42, 0.96, QD3D12_SkyCloudBillow(p * 2.05 + seedVec.zxy));
float anvil = smoothstep(0.20, 0.76, broad);
float shape = anvil * (billowA * 0.88 + billowB * 0.12);
shape = smoothstep(saturate(gSkyCloudCoverage) * 0.66, 0.94, shape);
float density = shape * heightFade * max(gSkyCloudDensity, 0.0);
alpha += (1.0 - alpha) * density * 0.36;
shade += density * (0.66 + l * 0.22 + broad * 0.12);
}
alpha = saturate(alpha * saturate(gSkyCloudOpacity) * horizonMask);
if (alpha <= 0.001)
discard;
float skyLum = dot(saturate(gSkyCloudColor), float3(0.299, 0.587, 0.114));
float3 brightCloud = lerp(saturate(gSkyCloudColor * 1.28), float3(1.0, 0.985, 0.94), 0.76);
brightCloud *= 0.92 + saturate(shade) * 0.16 + saturate(skyLum) * 0.16;
return float4(saturate(brightCloud), alpha);
}
)HLSL"
R"HLSL(
float4 PSSharpen(VSOut i) : SV_Target0
{
float4 center = gTex0.Sample(gSamp0, i.uv);
float amount = saturate(gPostSharpness);
float amount = saturate(gPostSharpness) * 2.35;
if (amount <= 0.0001)
return center;
@@ -5151,11 +5284,23 @@ float4 PSSharpen(VSOut i) : SV_Target0
float3 s = gTex0.Sample(gSamp0, saturate(i.uv + float2(0.0, texel.y))).rgb;
float3 e = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, 0.0))).rgb;
float3 w = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, 0.0))).rgb;
float3 blur = (n + s + e + w) * 0.25;
float3 ne = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, -texel.y))).rgb;
float3 nw = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, -texel.y))).rgb;
float3 se = gTex0.Sample(gSamp0, saturate(i.uv + float2( texel.x, texel.y))).rgb;
float3 sw = gTex0.Sample(gSamp0, saturate(i.uv + float2(-texel.x, texel.y))).rgb;
float3 blur = (n + s + e + w) * 0.18 + (ne + nw + se + sw) * 0.07;
float3 albedoC = gScreenDecalNormal.Sample(gSamp0, i.uv).rgb;
float3 albedoN = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2(0.0, -texel.y))).rgb;
float3 albedoS = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2(0.0, texel.y))).rgb;
float3 albedoE = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2( texel.x, 0.0))).rgb;
float3 albedoW = gScreenDecalNormal.Sample(gSamp0, saturate(i.uv + float2(-texel.x, 0.0))).rgb;
float3 albedoBlur = (albedoN + albedoS + albedoE + albedoW) * 0.25;
float3 albedoDetail = clamp(albedoC - albedoBlur, -0.18, 0.18);
// Sharpen strictly after temporal reconstruction. Keep it conservative so
// the TAA resolve is not undone by ringing on high-contrast UI/geometry edges.
float3 sharp = center.rgb + (center.rgb - blur) * amount;
float3 sharp = center.rgb + (center.rgb - blur) * amount + albedoDetail * (amount * 0.38);
return QD3D12_ApplyPostFog(float4(saturate(sharp), center.a), i.uv);
}
@@ -5226,7 +5371,7 @@ float4 PSToneMapFinalMax(VSOut i) : SV_Target0
R"HLSL(
float3 QD3D12_PostSharpenHDR(float2 uv, float3 center)
{
float amount = saturate(gPostSharpness);
float amount = saturate(gPostSharpness) * 2.35;
if (amount <= 0.0001)
return center;
@@ -5238,11 +5383,23 @@ float3 QD3D12_PostSharpenHDR(float2 uv, float3 center)
float3 s = max(gTex0.Sample(gSamp0, saturate(uv + float2(0.0, texel.y))).rgb, 0.0);
float3 e = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, 0.0))).rgb, 0.0);
float3 w = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, 0.0))).rgb, 0.0);
float3 blur = (n + s + e + w) * 0.25;
float3 ne = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, -texel.y))).rgb, 0.0);
float3 nw = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, -texel.y))).rgb, 0.0);
float3 se = max(gTex0.Sample(gSamp0, saturate(uv + float2( texel.x, texel.y))).rgb, 0.0);
float3 sw = max(gTex0.Sample(gSamp0, saturate(uv + float2(-texel.x, texel.y))).rgb, 0.0);
float3 blur = (n + s + e + w) * 0.18 + (ne + nw + se + sw) * 0.07;
float3 albedoC = max(gScreenDecalNormal.Sample(gSamp0, uv).rgb, 0.0);
float3 albedoN = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2(0.0, -texel.y))).rgb, 0.0);
float3 albedoS = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2(0.0, texel.y))).rgb, 0.0);
float3 albedoE = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2( texel.x, 0.0))).rgb, 0.0);
float3 albedoW = max(gScreenDecalNormal.Sample(gSamp0, saturate(uv + float2(-texel.x, 0.0))).rgb, 0.0);
float3 albedoBlur = (albedoN + albedoS + albedoE + albedoW) * 0.25;
float3 albedoDetail = clamp(albedoC - albedoBlur, -0.18, 0.18);
// Sharpen before tone mapping so highlights keep their shoulder instead of
// ringing after they have already been compressed to display range.
return min(max(center + (center - blur) * amount, 0.0), 65504.0);
return min(max(center + (center - blur) * amount + albedoDetail * (amount * 0.38), 0.0), 65504.0);
}
float3 QD3D12_ExtendedReinhard(float3 hdr, float whitePoint)
@@ -8531,7 +8688,8 @@ static void QD3D12_SetPostConstants(
float screenParticleEmissiveScale = 0.0f,
float screenParticleOutputMode = 0.0f,
float screenParticleDepthScaleX = 1.0f,
float screenParticleDepthScaleY = 1.0f)
float screenParticleDepthScaleY = 1.0f,
const glSkyClouds_t* skyClouds = nullptr)
{
if (!cl)
return;
@@ -8574,12 +8732,48 @@ static void QD3D12_SetPostConstants(
constants[25] = screenParticleOutputMode;
constants[26] = screenParticleDepthScaleX;
constants[27] = screenParticleDepthScaleY;
if (skyClouds)
{
constants[20] = skyClouds->viewOrigin[0];
constants[21] = skyClouds->viewOrigin[1];
constants[22] = skyClouds->viewOrigin[2];
constants[23] = skyClouds->zMin;
constants[28] = skyClouds->skyColor[0];
constants[29] = skyClouds->skyColor[1];
constants[30] = skyClouds->skyColor[2];
constants[31] = skyClouds->opacity;
constants[32] = skyClouds->viewForward[0];
constants[33] = skyClouds->viewForward[1];
constants[34] = skyClouds->viewForward[2];
constants[35] = skyClouds->zMax;
constants[36] = skyClouds->viewRight[0];
constants[37] = skyClouds->viewRight[1];
constants[38] = skyClouds->viewRight[2];
constants[39] = skyClouds->tanHalfFovX;
constants[40] = skyClouds->viewUp[0];
constants[41] = skyClouds->viewUp[1];
constants[42] = skyClouds->viewUp[2];
constants[43] = skyClouds->tanHalfFovY;
constants[44] = skyClouds->noiseScale;
constants[45] = skyClouds->coverage;
constants[46] = skyClouds->density;
constants[47] = skyClouds->seedOffset;
}
cl->SetGraphicsRoot32BitConstants(QD3D12_PostRootConstants, QD3D12_PostConstantDwords, constants, 0);
}
static void QD3D12_BindPostFogResources(ID3D12GraphicsCommandList* cl, QD3D12Window& w, bool applySceneFog)
{
if (!cl || !applySceneFog || !g_gl.sceneFogValidThisFrame)
if (!cl)
return;
if (w.sceneColorBuffers[w.frameIndex] && w.sceneColorSrvIndex[w.frameIndex] != UINT_MAX)
{
QD3D12_TransitionResource(cl, w.sceneColorBuffers[w.frameIndex].Get(), w.sceneColorState[w.frameIndex], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
cl->SetGraphicsRootDescriptorTable(11, w.sceneColorSrvGpu[w.frameIndex]);
}
if (!applySceneFog || !g_gl.sceneFogValidThisFrame)
return;
if (!w.positionBuffers[w.frameIndex] || !w.depthBuffer)
return;
@@ -8895,6 +9089,11 @@ static bool QD3D12_ToneMapFullscreenPass(
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cl->SetGraphicsRootDescriptorTable(0, hdrInputSrv);
cl->SetGraphicsRootDescriptorTable(7, w.toneMapSceneMaxSrvGpu[frame]);
if (w.sceneColorBuffers[frame] && w.sceneColorSrvIndex[frame] != UINT_MAX)
{
QD3D12_TransitionResource(cl, w.sceneColorBuffers[frame].Get(), w.sceneColorState[frame], D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE);
cl->SetGraphicsRootDescriptorTable(11, w.sceneColorSrvGpu[frame]);
}
QD3D12_BindPostFogResources(cl, w, applySceneFog);
cl->DrawInstanced(3, 1, 0, 0);
return true;
@@ -9019,6 +9218,52 @@ void APIENTRY glDrawScreenSpaceDecalsQD3D12(void)
}
}
void APIENTRY glDrawSkyCloudsQD3D12(const glSkyClouds_t* clouds)
{
if (!clouds || clouds->opacity <= 0.0f || clouds->density <= 0.0f)
return;
QD3D12Window* window = g_currentWindow;
if (!window || !g_gl.device || !g_gl.cmdList || !g_gl.postSkyCloudsPSO)
return;
if (!window->sceneColorBuffers[window->frameIndex])
return;
QD3D12_EnsureFrameOpen();
QD3D12_FlushQueuedBatches();
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);
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;
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, false, 16.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, clouds);
cl->SetPipelineState(g_gl.postSkyCloudsPSO.Get());
cl->SetGraphicsRootDescriptorTable(0, g_gl.whiteTexture.srvGpu);
D3D12_CPU_DESCRIPTOR_HANDLE sceneColorRtv = QD3D12_RtvAt(*window, QD3D12_RTV_SCENE_RENDER, frame);
cl->OMSetRenderTargets(1, &sceneColorRtv, FALSE, nullptr);
cl->RSSetViewports(1, &viewport);
cl->RSSetScissorRects(1, &scissor);
cl->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
cl->DrawInstanced(3, 1, 0, 0);
}
static void QD3D12_DrawScreenSpaceParticleBatch(const QD3D12ScreenSpaceParticleBatch& batch, ID3D12Resource* tlas, bool emissiveOnly, bool nativeOutput)
{
const glScreenSpaceParticleVertex_t* verts = batch.vertices.empty() ? nullptr : batch.vertices.data();
@@ -9538,7 +9783,6 @@ static void QD3D12_RunUpscalerOrBlit(QD3D12Window& w)
sl::Resource depth = { sl::ResourceType::eTex2d, w.depthBuffer.Get(), nullptr, nullptr, uint32_t(w.depthState) };
sl::Resource mvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.velocityBufferState[w.frameIndex]) };
sl::Resource diffuseAlbedo = { sl::ResourceType::eTex2d, w.sceneColorBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.sceneColorState[w.frameIndex]) };
sl::Resource specularMvec = { sl::ResourceType::eTex2d, w.velocityBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.velocityBufferState[w.frameIndex]) };
sl::Resource specularAlbedo = { sl::ResourceType::eTex2d, w.specularBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.specularBufferState[w.frameIndex]) };
sl::Resource normalRoughness = { sl::ResourceType::eTex2d, w.normalBuffers[w.frameIndex].Get(), nullptr, nullptr, uint32_t(w.normalBufferState[w.frameIndex]) };
@@ -9549,7 +9793,6 @@ static void QD3D12_RunUpscalerOrBlit(QD3D12Window& w)
sl::ResourceTag{ &depth, sl::kBufferTypeDepth, sl::ResourceLifecycle::eValidUntilPresent, &renderExtent },
sl::ResourceTag{ &mvec, sl::kBufferTypeMotionVectors, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &diffuseAlbedo, sl::kBufferTypeAlbedo, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &specularMvec, sl::kBufferTypeSpecularMotionVectors, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &specularAlbedo, sl::kBufferTypeSpecularAlbedo, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent },
sl::ResourceTag{ &normalRoughness, sl::kBufferTypeNormalRoughness, sl::ResourceLifecycle::eOnlyValidNow, &renderExtent }
};
@@ -10784,6 +11027,7 @@ static void QD3D12_CompileShaders()
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");
g_gl.postPsSkyCloudsBlob = CompileShaderSourceVariant(kQD3D12PostHLSL, "PSSkyClouds", "ps_6_0");
}
static const D3D12_INPUT_ELEMENT_DESC kGLVertexInputLayout[] =
@@ -11015,6 +11259,16 @@ 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)));
d.PS = { g_gl.postPsSkyCloudsBlob->GetBufferPointer(), g_gl.postPsSkyCloudsBlob->GetBufferSize() };
d.BlendState.RenderTarget[0].BlendEnable = TRUE;
d.BlendState.RenderTarget[0].SrcBlend = D3D12_BLEND_SRC_ALPHA;
d.BlendState.RenderTarget[0].DestBlend = D3D12_BLEND_INV_SRC_ALPHA;
d.BlendState.RenderTarget[0].BlendOp = D3D12_BLEND_OP_ADD;
d.BlendState.RenderTarget[0].SrcBlendAlpha = D3D12_BLEND_ONE;
d.BlendState.RenderTarget[0].DestBlendAlpha = D3D12_BLEND_INV_SRC_ALPHA;
d.BlendState.RenderTarget[0].BlendOpAlpha = D3D12_BLEND_OP_ADD;
QD3D12_CHECK(g_gl.device->CreateGraphicsPipelineState(&d, IID_PPV_ARGS(&g_gl.postSkyCloudsPSO)));
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() };
@@ -17881,6 +18135,7 @@ PROC WINAPI qd3d12_wglGetProcAddress(LPCSTR name) {
{ "glDrawScreenSpaceDecalsQD3D12",(PROC)glDrawScreenSpaceDecalsQD3D12 },
{ "glSetScreenSpaceParticleLightsQD3D12",(PROC)glSetScreenSpaceParticleLightsQD3D12 },
{ "glDrawScreenSpaceParticlesQD3D12",(PROC)glDrawScreenSpaceParticlesQD3D12 },
{ "glDrawSkyCloudsQD3D12", (PROC)glDrawSkyCloudsQD3D12 },
{ "QD3D12_SetUpscalerBackend", (PROC)QD3D12_SetUpscalerBackend },
{ "QD3D12_SetUpscalerQuality", (PROC)QD3D12_SetUpscalerQuality },
{ "QD3D12_SetUpscalerSharpness", (PROC)QD3D12_SetUpscalerSharpness },