Skip to content

Commit 391414f

Browse files
authored
Handle stencil test. (#16)
1 parent e79a788 commit 391414f

9 files changed

Lines changed: 455 additions & 302 deletions

File tree

MarathonRecomp/gpu/cache/pipeline_state_cache.h

Lines changed: 0 additions & 217 deletions
Large diffs are not rendered by default.

MarathonRecomp/gpu/rhi/plume_d3d12.cpp

Lines changed: 86 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,10 @@ namespace plume {
136136
return DXGI_FORMAT_R32_TYPELESS;
137137
case RenderFormat::D32_FLOAT:
138138
return DXGI_FORMAT_D32_FLOAT;
139+
case RenderFormat::D32_FLOAT_S8_UINT:
140+
// In order to be able to create both depth-stencil and shader resource views,
141+
// we must use R32G8X24_TYPELESS as the base type and specialize later.
142+
return DXGI_FORMAT_R32G8X24_TYPELESS;
139143
case RenderFormat::R32_FLOAT:
140144
return DXGI_FORMAT_R32_FLOAT;
141145
case RenderFormat::R32_UINT:
@@ -224,6 +228,29 @@ namespace plume {
224228
}
225229
}
226230

231+
static DXGI_FORMAT toDXGITextureView(RenderFormat format) {
232+
const DXGI_FORMAT dxgiFormat = toDXGI(format);
233+
if (dxgiFormat == DXGI_FORMAT_D32_FLOAT) {
234+
// D3D12 and Vulkan disagree on whether D32 is usable as a texture view format.
235+
// We just make D3D12 use R32 instead.
236+
return DXGI_FORMAT_R32_FLOAT;
237+
}
238+
if (dxgiFormat == DXGI_FORMAT_R32G8X24_TYPELESS) {
239+
// Specialize into depth view of depth-stencil texture.
240+
return DXGI_FORMAT_R32_FLOAT_X8X24_TYPELESS;
241+
}
242+
return dxgiFormat;
243+
}
244+
245+
static DXGI_FORMAT toDXGIDepthStencilView(RenderFormat format) {
246+
const DXGI_FORMAT dxgiFormat = toDXGI(format);
247+
if (dxgiFormat == DXGI_FORMAT_R32G8X24_TYPELESS) {
248+
// Specialize into full depth-stencil view.
249+
return DXGI_FORMAT_D32_FLOAT_S8X24_UINT;
250+
}
251+
return dxgiFormat;
252+
}
253+
227254
static D3D12_BLEND toD3D12(RenderBlend blend) {
228255
switch (blend) {
229256
case RenderBlend::ZERO:
@@ -472,6 +499,30 @@ namespace plume {
472499
}
473500
}
474501

502+
static D3D12_STENCIL_OP toD3D12(RenderStencilOp function) {
503+
switch (function) {
504+
case RenderStencilOp::KEEP:
505+
return D3D12_STENCIL_OP_KEEP;
506+
case RenderStencilOp::ZERO:
507+
return D3D12_STENCIL_OP_ZERO;
508+
case RenderStencilOp::REPLACE:
509+
return D3D12_STENCIL_OP_REPLACE;
510+
case RenderStencilOp::INCREMENT_AND_CLAMP:
511+
return D3D12_STENCIL_OP_INCR_SAT;
512+
case RenderStencilOp::DECREMENT_AND_CLAMP:
513+
return D3D12_STENCIL_OP_DECR_SAT;
514+
case RenderStencilOp::INVERT:
515+
return D3D12_STENCIL_OP_INVERT;
516+
case RenderStencilOp::INCREMENT_AND_WRAP:
517+
return D3D12_STENCIL_OP_INCR;
518+
case RenderStencilOp::DECREMENT_AND_WRAP:
519+
return D3D12_STENCIL_OP_DECR;
520+
default:
521+
assert(false && "Unknown stencil operation.");
522+
return D3D12_STENCIL_OP_KEEP;
523+
}
524+
}
525+
475526
static D3D12_PRIMITIVE_TOPOLOGY toD3D12(RenderPrimitiveTopology topology) {
476527
switch (topology) {
477528
case RenderPrimitiveTopology::POINT_LIST:
@@ -1664,12 +1715,14 @@ namespace plume {
16641715

16651716
void D3D12CommandList::drawInstanced(uint32_t vertexCountPerInstance, uint32_t instanceCount, uint32_t startVertexLocation, uint32_t startInstanceLocation) {
16661717
checkTopology();
1718+
checkStencilRef();
16671719
checkFramebufferSamplePositions();
16681720
d3d->DrawInstanced(vertexCountPerInstance, instanceCount, startVertexLocation, startInstanceLocation);
16691721
}
16701722

16711723
void D3D12CommandList::drawIndexedInstanced(uint32_t indexCountPerInstance, uint32_t instanceCount, uint32_t startIndexLocation, int32_t baseVertexLocation, uint32_t startInstanceLocation) {
16721724
checkTopology();
1725+
checkStencilRef();
16731726
checkFramebufferSamplePositions();
16741727
d3d->DrawIndexedInstanced(indexCountPerInstance, instanceCount, startIndexLocation, baseVertexLocation, startInstanceLocation);
16751728
}
@@ -1900,7 +1953,7 @@ namespace plume {
19001953
d3d->ClearRenderTargetView(targetFramebuffer->colorHandles[attachmentIndex], colorValue.rgba, clearRectsCount, (clearRectsCount > 0) ? rectVector.data() : nullptr);
19011954
}
19021955

1903-
void D3D12CommandList::clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) {
1956+
void D3D12CommandList::clearDepthStencil(bool clearDepth, bool clearStencil, float depthValue, uint32_t stencilValue, const RenderRect *clearRects, uint32_t clearRectsCount) {
19041957
assert(targetFramebuffer != nullptr);
19051958
assert(targetFramebuffer->depthHandle.ptr != 0);
19061959
assert((clearRectsCount == 0) || (clearRects != nullptr));
@@ -1916,8 +1969,13 @@ namespace plume {
19161969
}
19171970

19181971
D3D12_CLEAR_FLAGS clearFlags = {};
1919-
clearFlags |= clearDepth ? D3D12_CLEAR_FLAG_DEPTH : D3D12_CLEAR_FLAGS(0);
1920-
d3d->ClearDepthStencilView(targetFramebuffer->depthHandle, clearFlags, depthValue, 0, clearRectsCount, (clearRectsCount > 0) ? rectVector.data() : nullptr);
1972+
if (clearDepth) {
1973+
clearFlags |= D3D12_CLEAR_FLAG_DEPTH;
1974+
}
1975+
if (clearStencil) {
1976+
clearFlags |= D3D12_CLEAR_FLAG_STENCIL;
1977+
}
1978+
d3d->ClearDepthStencilView(targetFramebuffer->depthHandle, clearFlags, depthValue, stencilValue, clearRectsCount, (clearRectsCount > 0) ? rectVector.data() : nullptr);
19211979
}
19221980

19231981
void D3D12CommandList::copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) {
@@ -2085,6 +2143,17 @@ namespace plume {
20852143
activeTopology = graphicsPipeline->topology;
20862144
}
20872145
}
2146+
2147+
void D3D12CommandList::checkStencilRef() {
2148+
assert(activeGraphicsPipeline != nullptr);
2149+
assert(activeGraphicsPipeline->type == D3D12Pipeline::Type::Graphics);
2150+
2151+
const D3D12GraphicsPipeline *graphicsPipeline = static_cast<const D3D12GraphicsPipeline *>(activeGraphicsPipeline);
2152+
if (activeStencilRef != graphicsPipeline->stencilRef) {
2153+
d3d->OMSetStencilRef(graphicsPipeline->stencilRef);
2154+
activeStencilRef = graphicsPipeline->stencilRef;
2155+
}
2156+
}
20882157

20892158
void D3D12CommandList::checkFramebufferSamplePositions() {
20902159
if (!targetFramebufferSamplePositionsSet && (targetFramebuffer != nullptr)) {
@@ -2430,16 +2499,11 @@ namespace plume {
24302499
assert(texture != nullptr);
24312500

24322501
this->texture = texture;
2433-
this->format = toDXGI(desc.format);
2502+
this->format = toDXGITextureView(desc.format);
24342503
this->dimension = desc.dimension;
24352504
this->mipLevels = desc.mipLevels;
24362505
this->mipSlice = desc.mipSlice;
24372506
this->shader4ComponentMapping = toD3D12(desc.componentMapping);
2438-
2439-
// D3D12 and Vulkan disagree on whether D32 is usable as a texture view format. We just make D3D12 use R32 instead.
2440-
if (format == DXGI_FORMAT_D32_FLOAT) {
2441-
format = DXGI_FORMAT_R32_FLOAT;
2442-
}
24432507
}
24442508

24452509
D3D12TextureView::~D3D12TextureView() { }
@@ -2566,7 +2630,7 @@ namespace plume {
25662630
targetHeapDepth = true;
25672631

25682632
D3D12_DEPTH_STENCIL_VIEW_DESC dsvDesc = {};
2569-
dsvDesc.Format = toDXGI(desc.format);
2633+
dsvDesc.Format = toDXGIDepthStencilView(desc.format);
25702634

25712635
const bool isMSAA = (desc.multisampling.sampleCount > RenderSampleCount::COUNT_1);
25722636
switch (desc.dimension) {
@@ -2820,6 +2884,17 @@ namespace plume {
28202884
psoDesc.DepthStencilState.DepthEnable = desc.depthEnabled;
28212885
psoDesc.DepthStencilState.DepthWriteMask = desc.depthWriteEnabled ? D3D12_DEPTH_WRITE_MASK_ALL : D3D12_DEPTH_WRITE_MASK_ZERO;
28222886
psoDesc.DepthStencilState.DepthFunc = toD3D12(desc.depthFunction);
2887+
psoDesc.DepthStencilState.StencilEnable = desc.stencilEnabled;
2888+
psoDesc.DepthStencilState.StencilReadMask = desc.stencilReadMask;
2889+
psoDesc.DepthStencilState.StencilWriteMask = desc.stencilWriteMask;
2890+
psoDesc.DepthStencilState.FrontFace.StencilFailOp = toD3D12(desc.stencilFrontFace.failOp);
2891+
psoDesc.DepthStencilState.FrontFace.StencilDepthFailOp = toD3D12(desc.stencilFrontFace.depthFailOp);
2892+
psoDesc.DepthStencilState.FrontFace.StencilPassOp = toD3D12(desc.stencilFrontFace.passOp);
2893+
psoDesc.DepthStencilState.FrontFace.StencilFunc = toD3D12(desc.stencilFrontFace.compareFunction);
2894+
psoDesc.DepthStencilState.BackFace.StencilFailOp = toD3D12(desc.stencilBackFace.failOp);
2895+
psoDesc.DepthStencilState.BackFace.StencilDepthFailOp = toD3D12(desc.stencilBackFace.depthFailOp);
2896+
psoDesc.DepthStencilState.BackFace.StencilPassOp = toD3D12(desc.stencilBackFace.passOp);
2897+
psoDesc.DepthStencilState.BackFace.StencilFunc = toD3D12(desc.stencilBackFace.compareFunction);
28232898
psoDesc.NumRenderTargets = desc.renderTargetCount;
28242899
psoDesc.BlendState.AlphaToCoverageEnable = desc.alphaToCoverageEnabled;
28252900

@@ -2840,7 +2915,7 @@ namespace plume {
28402915
targetDesc.RenderTargetWriteMask = renderDesc.renderTargetWriteMask;
28412916
}
28422917

2843-
psoDesc.DSVFormat = toDXGI(desc.depthTargetFormat);
2918+
psoDesc.DSVFormat = toDXGIDepthStencilView(desc.depthTargetFormat);
28442919

28452920
std::vector<D3D12_INPUT_ELEMENT_DESC> inputElements;
28462921
for (uint32_t i = 0; i < desc.inputElementsCount; i++) {

MarathonRecomp/gpu/rhi/plume_d3d12.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ namespace plume {
170170
const D3D12GraphicsPipeline *activeGraphicsPipeline = nullptr;
171171
bool descriptorHeapsSet = false;
172172
D3D12_PRIMITIVE_TOPOLOGY activeTopology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
173+
uint32_t activeStencilRef = 0;
173174
bool activeSamplePositions = false;
174175

175176
D3D12CommandList(D3D12Device *device, RenderCommandListType type);
@@ -199,7 +200,7 @@ namespace plume {
199200
void setFramebuffer(const RenderFramebuffer *framebuffer) override;
200201
void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) override;
201202
void clearColor(uint32_t attachmentIndex, RenderColor colorValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
202-
void clearDepth(bool clearDepth, float depthValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
203+
void clearDepthStencil(bool clearDepth, bool clearStencil, float depthValue, uint32_t stencilValue, const RenderRect *clearRects, uint32_t clearRectsCount) override;
203204
void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) override;
204205
void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX, uint32_t dstY, uint32_t dstZ, const RenderBox *srcBox) override;
205206
void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) override;
@@ -214,6 +215,7 @@ namespace plume {
214215
void checkDescriptorHeaps();
215216
void notifyDescriptorHeapWasChangedExternally();
216217
void checkTopology();
218+
void checkStencilRef();
217219
void checkFramebufferSamplePositions();
218220
void setSamplePositions(const RenderTexture *texture);
219221
void resetSamplePositions();
@@ -384,6 +386,7 @@ namespace plume {
384386
ID3D12PipelineState *d3d = nullptr;
385387
std::vector<RenderInputSlot> inputSlots;
386388
D3D12_PRIMITIVE_TOPOLOGY topology = D3D_PRIMITIVE_TOPOLOGY_UNDEFINED;
389+
uint32_t stencilRef = 0;
387390

388391
D3D12GraphicsPipeline(D3D12Device *device, const RenderGraphicsPipelineDesc &desc);
389392
~D3D12GraphicsPipeline() override;

MarathonRecomp/gpu/rhi/plume_render_interface.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ namespace plume {
138138
virtual void setFramebuffer(const RenderFramebuffer *framebuffer) = 0;
139139
virtual void setDepthBias(float depthBias, float depthBiasClamp, float slopeScaledDepthBias) = 0;
140140
virtual void clearColor(uint32_t attachmentIndex = 0, RenderColor colorValue = RenderColor(), const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0;
141-
virtual void clearDepth(bool clearDepth = true, float depthValue = 1.0f, const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0;
141+
virtual void clearDepthStencil(bool clearDepth = true, bool clearStencil = true, float depthValue = 1.0f, uint32_t stencilValue = 0, const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) = 0;
142142
virtual void copyBufferRegion(RenderBufferReference dstBuffer, RenderBufferReference srcBuffer, uint64_t size) = 0;
143143
virtual void copyTextureRegion(const RenderTextureCopyLocation &dstLocation, const RenderTextureCopyLocation &srcLocation, uint32_t dstX = 0, uint32_t dstY = 0, uint32_t dstZ = 0, const RenderBox *srcBox = nullptr) = 0;
144144
virtual void copyBuffer(const RenderBuffer *dstBuffer, const RenderBuffer *srcBuffer) = 0;
@@ -191,6 +191,10 @@ namespace plume {
191191
inline void setScissors(const RenderRect &scissorRect) {
192192
setScissors(&scissorRect, 1);
193193
}
194+
195+
inline void clearDepth(bool clearDepth = true, float depthValue = 1.0f, const RenderRect *clearRects = nullptr, uint32_t clearRectsCount = 0) {
196+
clearDepthStencil(clearDepth, false, depthValue, 0, clearRects, clearRectsCount);
197+
}
194198
};
195199

196200
struct RenderCommandQueue {

MarathonRecomp/gpu/rhi/plume_render_interface_types.h

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,7 @@ namespace plume {
116116
R16G16_SINT,
117117
R32_TYPELESS,
118118
D32_FLOAT,
119+
D32_FLOAT_S8_UINT,
119120
R32_FLOAT,
120121
R32_UINT,
121122
R32_SINT,
@@ -226,6 +227,18 @@ namespace plume {
226227
ALWAYS
227228
};
228229

230+
enum class RenderStencilOp {
231+
UNKNOWN,
232+
KEEP,
233+
ZERO,
234+
REPLACE,
235+
INCREMENT_AND_CLAMP,
236+
DECREMENT_AND_CLAMP,
237+
INVERT,
238+
INCREMENT_AND_WRAP,
239+
DECREMENT_AND_WRAP
240+
};
241+
229242
enum class RenderInputSlotClassification {
230243
UNKNOWN,
231244
PER_VERTEX_DATA,
@@ -523,6 +536,7 @@ namespace plume {
523536
case RenderFormat::R32G32_FLOAT:
524537
case RenderFormat::R32G32_UINT:
525538
case RenderFormat::R32G32_SINT:
539+
case RenderFormat::D32_FLOAT_S8_UINT: // Has 24 unused bits
526540
return 8;
527541
case RenderFormat::R8G8B8A8_TYPELESS:
528542
case RenderFormat::R8G8B8A8_UNORM:
@@ -621,6 +635,7 @@ namespace plume {
621635
case RenderFormat::R16G16_SINT:
622636
case RenderFormat::R32_TYPELESS:
623637
case RenderFormat::D32_FLOAT:
638+
case RenderFormat::D32_FLOAT_S8_UINT:
624639
case RenderFormat::R32_FLOAT:
625640
case RenderFormat::R32_UINT:
626641
case RenderFormat::R32_SINT:
@@ -670,6 +685,21 @@ namespace plume {
670685
}
671686
};
672687

688+
constexpr bool RenderFormatIsDepth(RenderFormat format) {
689+
switch (format) {
690+
case RenderFormat::D16_UNORM:
691+
case RenderFormat::D32_FLOAT:
692+
case RenderFormat::D32_FLOAT_S8_UINT:
693+
return true;
694+
default:
695+
return false;
696+
}
697+
}
698+
699+
constexpr bool RenderFormatIsStencil(RenderFormat format) {
700+
return format == RenderFormat::D32_FLOAT_S8_UINT;
701+
}
702+
673703
// Concrete structs.
674704

675705
struct RenderColor {
@@ -1158,6 +1188,13 @@ namespace plume {
11581188
}
11591189
};
11601190

1191+
struct RenderStencilFaceDesc {
1192+
RenderStencilOp passOp = RenderStencilOp::KEEP;
1193+
RenderStencilOp failOp = RenderStencilOp::KEEP;
1194+
RenderStencilOp depthFailOp = RenderStencilOp::KEEP;
1195+
RenderComparisonFunction compareFunction = RenderComparisonFunction::ALWAYS;
1196+
};
1197+
11611198
struct RenderSpecConstant {
11621199
uint32_t index = 0;
11631200
uint32_t value = 0;
@@ -1198,6 +1235,12 @@ namespace plume {
11981235
bool dynamicDepthBiasEnabled = false;
11991236
bool depthEnabled = false;
12001237
bool depthWriteEnabled = false;
1238+
bool stencilEnabled = false;
1239+
uint32_t stencilReadMask = 0xFFFFFFFF;
1240+
uint32_t stencilWriteMask = 0xFFFFFFFF;
1241+
uint32_t stencilReference = 0;
1242+
RenderStencilFaceDesc stencilFrontFace;
1243+
RenderStencilFaceDesc stencilBackFace;
12011244
RenderMultisampling multisampling;
12021245
bool alphaToCoverageEnabled = false;
12031246
RenderPrimitiveTopology primitiveTopology = RenderPrimitiveTopology::TRIANGLE_LIST;

0 commit comments

Comments
 (0)