Merge pull request #15753 from hrydgard/thin3d-simplify-stencil

Improve and simplify stencil buffer support in thin3d
This commit is contained in:
Henrik Rydgård 2022-07-30 11:13:48 +02:00 committed by GitHub
commit d6e699aa56
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 178 additions and 118 deletions

View File

@ -13,6 +13,8 @@
#include "Common/Data/Encoding/Utf8.h"
#include "Common/Log.h"
#include <map>
#include <cfloat>
#include <D3Dcommon.h>
#include <d3d11.h>
@ -39,6 +41,24 @@ class D3D11SamplerState;
class D3D11RasterState;
class D3D11Framebuffer;
// This must stay POD for the memcmp to work reliably.
struct D3D11DepthStencilKey {
DepthStencilStateDesc desc;
u8 writeMask;
u8 compareMask;
bool operator < (const D3D11DepthStencilKey &other) const {
return memcmp(this, &other, sizeof(D3D11DepthStencilKey)) < 0;
}
};
class D3D11DepthStencilState : public DepthStencilState {
public:
~D3D11DepthStencilState() {}
DepthStencilStateDesc desc;
};
class D3D11DrawContext : public DrawContext {
public:
D3D11DrawContext(ID3D11Device *device, ID3D11DeviceContext *deviceContext, ID3D11Device1 *device1, ID3D11DeviceContext1 *deviceContext1, D3D_FEATURE_LEVEL featureLevel, HWND hWnd, std::vector<std::string> deviceList);
@ -102,9 +122,11 @@ public:
blendFactorDirty_ = true;
}
}
void SetStencilRef(uint8_t ref) override {
stencilRef_ = ref;
stencilRefDirty_ = true;
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override {
stencilRef_ = refValue;
stencilWriteMask_ = writeMask;
stencilCompareMask_ = compareMask;
stencilDirty_ = true;
}
void EndFrame() override;
@ -174,6 +196,8 @@ public:
private:
void ApplyCurrentState();
ID3D11DepthStencilState *GetCachedDepthStencilState(D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask);
HWND hWnd_;
ID3D11Device *device_;
ID3D11DeviceContext *context_;
@ -200,8 +224,11 @@ private:
DeviceCaps caps_{};
AutoRef<D3D11BlendState> curBlend_;
AutoRef<D3D11DepthStencilState> curDepth_;
AutoRef<D3D11DepthStencilState> curDepthStencil_;
AutoRef<D3D11RasterState> curRaster_;
std::map<D3D11DepthStencilKey, ID3D11DepthStencilState *> depthStencilCache_;
ID3D11InputLayout *curInputLayout_ = nullptr;
ID3D11VertexShader *curVS_ = nullptr;
ID3D11PixelShader *curPS_ = nullptr;
@ -219,7 +246,9 @@ private:
float blendFactor_[4]{};
bool blendFactorDirty_ = false;
uint8_t stencilRef_ = 0;
bool stencilRefDirty_ = true;
uint8_t stencilWriteMask_ = 0xFF;
uint8_t stencilCompareMask_ = 0xFF;
bool stencilDirty_ = true;
// Temporaries
ID3D11Texture2D *packTexture_ = nullptr;
@ -415,14 +444,6 @@ void D3D11DrawContext::SetScissorRect(int left, int top, int width, int height)
context_->RSSetScissorRects(1, &rc);
}
class D3D11DepthStencilState : public DepthStencilState {
public:
~D3D11DepthStencilState() {
dss->Release();
}
ID3D11DepthStencilState *dss;
};
static const D3D11_COMPARISON_FUNC compareToD3D11[] = {
D3D11_COMPARISON_NEVER,
D3D11_COMPARISON_LESS,
@ -487,28 +508,13 @@ static D3D11_PRIMITIVE_TOPOLOGY primToD3D11[] = {
D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP_ADJ,
};
inline void CopyStencilSide(D3D11_DEPTH_STENCILOP_DESC &side, const StencilSide &input) {
inline void CopyStencilSide(D3D11_DEPTH_STENCILOP_DESC &side, const StencilSetup &input) {
side.StencilFunc = compareToD3D11[(int)input.compareOp];
side.StencilDepthFailOp = stencilOpToD3D11[(int)input.depthFailOp];
side.StencilFailOp = stencilOpToD3D11[(int)input.failOp];
side.StencilPassOp = stencilOpToD3D11[(int)input.passOp];
}
DepthStencilState *D3D11DrawContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
D3D11DepthStencilState *ds = new D3D11DepthStencilState();
D3D11_DEPTH_STENCIL_DESC d3ddesc{};
d3ddesc.DepthEnable = desc.depthTestEnabled;
d3ddesc.DepthWriteMask = desc.depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
d3ddesc.DepthFunc = compareToD3D11[(int)desc.depthCompare];
d3ddesc.StencilEnable = desc.stencilEnabled;
CopyStencilSide(d3ddesc.FrontFace, desc.front);
CopyStencilSide(d3ddesc.BackFace, desc.back);
if (SUCCEEDED(device_->CreateDepthStencilState(&d3ddesc, &ds->dss)))
return ds;
delete ds;
return nullptr;
}
static const D3D11_BLEND_OP blendOpToD3D11[] = {
D3D11_BLEND_OP_ADD,
D3D11_BLEND_OP_SUBTRACT,
@ -547,6 +553,46 @@ public:
float blendFactor[4];
};
ID3D11DepthStencilState *D3D11DrawContext::GetCachedDepthStencilState(D3D11DepthStencilState *state, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
D3D11DepthStencilKey key;
key.desc = state->desc;
key.writeMask = stencilWriteMask;
key.compareMask = stencilCompareMask;
auto findResult = depthStencilCache_.find(key);
if (findResult != depthStencilCache_.end()) {
return findResult->second;
}
// OK, create and insert.
D3D11_DEPTH_STENCIL_DESC d3ddesc{};
d3ddesc.DepthEnable = state->desc.depthTestEnabled;
d3ddesc.DepthWriteMask = state->desc.depthWriteEnabled ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO;
d3ddesc.DepthFunc = compareToD3D11[(int)state->desc.depthCompare];
d3ddesc.StencilEnable = state->desc.stencilEnabled;
d3ddesc.StencilReadMask = stencilCompareMask;
d3ddesc.StencilWriteMask = stencilWriteMask;
if (d3ddesc.StencilEnable) {
CopyStencilSide(d3ddesc.FrontFace, state->desc.stencil);
CopyStencilSide(d3ddesc.BackFace, state->desc.stencil);
}
ID3D11DepthStencilState *dss = nullptr;
if (SUCCEEDED(device_->CreateDepthStencilState(&d3ddesc, &dss))) {
depthStencilCache_[key] = dss;
return dss;
} else {
return nullptr;
}
}
DepthStencilState *D3D11DrawContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) {
D3D11DepthStencilState *dss = new D3D11DepthStencilState();
dss->desc = desc;
return dynamic_cast<DepthStencilState *>(dss);
}
BlendState *D3D11DrawContext::CreateBlendState(const BlendStateDesc &desc) {
D3D11BlendState *bs = new D3D11BlendState();
D3D11_BLEND_DESC d3ddesc{};
@ -677,8 +723,7 @@ InputLayout *D3D11DrawContext::CreateInputLayout(const InputLayoutDesc &desc) {
class D3D11ShaderModule : public ShaderModule {
public:
D3D11ShaderModule(const std::string &tag) : tag_(tag) {
}
D3D11ShaderModule(const std::string &tag) : tag_(tag) { }
~D3D11ShaderModule() {
if (vs)
vs->Release();
@ -716,8 +761,11 @@ public:
AutoRef<D3D11InputLayout> input;
ID3D11InputLayout *il = nullptr;
AutoRef<D3D11BlendState> blend;
AutoRef<D3D11DepthStencilState> depth;
AutoRef<D3D11RasterState> raster;
// Combined with dynamic state to key into cached D3D11DepthStencilState, to emulate dynamic parameters.
AutoRef<D3D11DepthStencilState> depthStencil;
ID3D11VertexShader *vs = nullptr;
ID3D11PixelShader *ps = nullptr;
ID3D11GeometryShader *gs = nullptr;
@ -969,7 +1017,7 @@ ShaderModule *D3D11DrawContext::CreateShaderModule(ShaderStage stage, ShaderLang
Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
D3D11Pipeline *dPipeline = new D3D11Pipeline();
dPipeline->blend = (D3D11BlendState *)desc.blend;
dPipeline->depth = (D3D11DepthStencilState *)desc.depthStencil;
dPipeline->depthStencil = (D3D11DepthStencilState *)desc.depthStencil;
dPipeline->input = (D3D11InputLayout *)desc.inputLayout;
dPipeline->raster = (D3D11RasterState *)desc.raster;
dPipeline->topology = primToD3D11[(int)desc.prim];
@ -977,8 +1025,9 @@ Pipeline *D3D11DrawContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
dPipeline->dynamicUniformsSize = desc.uniformDesc->uniformBufferSize;
D3D11_BUFFER_DESC bufdesc{};
bufdesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bufdesc.ByteWidth = (UINT)dPipeline->dynamicUniformsSize;
bufdesc.StructureByteStride = (UINT)dPipeline->dynamicUniformsSize;
// We just round up to 16 here. If we get some garbage, that's fine.
bufdesc.ByteWidth = ((UINT)dPipeline->dynamicUniformsSize + 15) & ~15;
bufdesc.StructureByteStride = bufdesc.ByteWidth;
bufdesc.Usage = D3D11_USAGE_DYNAMIC;
bufdesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
HRESULT hr = device_->CreateBuffer(&bufdesc, nullptr, &dPipeline->dynamicUniforms);
@ -1042,7 +1091,7 @@ void D3D11DrawContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
void D3D11DrawContext::InvalidateCachedState() {
// This is a signal to forget all our state caching.
curBlend_ = nullptr;
curDepth_ = nullptr;
curDepthStencil_ = nullptr;
curRaster_ = nullptr;
curPS_ = nullptr;
curVS_ = nullptr;
@ -1065,10 +1114,11 @@ void D3D11DrawContext::ApplyCurrentState() {
curBlend_ = curPipeline_->blend;
blendFactorDirty_ = false;
}
if (curDepth_ != curPipeline_->depth || stencilRefDirty_) {
context_->OMSetDepthStencilState(curPipeline_->depth->dss, stencilRef_);
curDepth_ = curPipeline_->depth;
stencilRefDirty_ = false;
if (curDepthStencil_ != curPipeline_->depthStencil || stencilDirty_) {
ID3D11DepthStencilState *dss = GetCachedDepthStencilState(curPipeline_->depthStencil, stencilWriteMask_, stencilCompareMask_);
context_->OMSetDepthStencilState(dss, stencilRef_);
curDepthStencil_ = curPipeline_->depthStencil;
stencilDirty_ = false;
}
if (curRaster_ != curPipeline_->raster) {
context_->RSSetState(curPipeline_->raster->rs);
@ -1375,8 +1425,8 @@ void D3D11DrawContext::BeginFrame() {
if (curBlend_ != nullptr) {
context_->OMSetBlendState(curBlend_->bs, blendFactor_, 0xFFFFFFFF);
}
if (curDepth_ != nullptr) {
context_->OMSetDepthStencilState(curDepth_->dss, stencilRef_);
if (curDepthStencil_ != nullptr) {
context_->OMSetDepthStencilState(GetCachedDepthStencilState(curDepthStencil_, stencilWriteMask_, stencilCompareMask_), stencilRef_);
}
if (curRaster_ != nullptr) {
context_->RSSetState(curRaster_->rs);

View File

@ -163,9 +163,7 @@ public:
D3DSTENCILOP stencilPass;
D3DCMPFUNC stencilCompareOp;
uint8_t stencilCompareMask;
uint8_t stencilWriteMask;
void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef) {
void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
using namespace DX9;
dxstate.depthTest.set(depthTestEnabled);
if (depthTestEnabled) {
@ -289,7 +287,7 @@ public:
AutoRef<D3D9RasterState> raster;
UniformBufferDesc dynamicUniforms;
void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef);
void Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask);
};
class D3D9Texture : public Texture {
@ -556,10 +554,9 @@ public:
void SetScissorRect(int left, int top, int width, int height) override;
void SetViewports(int count, Viewport *viewports) override;
void SetBlendFactor(float color[4]) override;
void SetStencilRef(uint8_t ref) override {
stencilRef_ = ref;
}
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override;
void ApplyDynamicState();
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
@ -618,6 +615,10 @@ private:
int curIBufferOffset_ = 0;
AutoRef<Framebuffer> curRenderTarget_;
u8 stencilRefValue_ = 0;
u8 stencilCompareMask_ = 0xFF;
u8 stencilWriteMask_ = 0xFF;
// Framebuffer state
LPDIRECT3DSURFACE9 deviceRTsurf = 0;
LPDIRECT3DSURFACE9 deviceDSsurf = 0;
@ -730,12 +731,10 @@ DepthStencilState *D3D9Context::CreateDepthStencilState(const DepthStencilStateD
ds->depthWriteEnabled = desc.depthWriteEnabled;
ds->depthCompare = compareToD3D9[(int)desc.depthCompare];
ds->stencilEnabled = desc.stencilEnabled;
ds->stencilCompareOp = compareToD3D9[(int)desc.front.compareOp];
ds->stencilPass = stencilOpToD3D9[(int)desc.front.passOp];
ds->stencilFail = stencilOpToD3D9[(int)desc.front.failOp];
ds->stencilZFail = stencilOpToD3D9[(int)desc.front.depthFailOp];
ds->stencilWriteMask = desc.front.writeMask;
ds->stencilCompareMask = desc.front.compareMask;
ds->stencilCompareOp = compareToD3D9[(int)desc.stencil.compareOp];
ds->stencilPass = stencilOpToD3D9[(int)desc.stencil.passOp];
ds->stencilFail = stencilOpToD3D9[(int)desc.stencil.failOp];
ds->stencilZFail = stencilOpToD3D9[(int)desc.stencil.depthFailOp];
return ds;
}
@ -956,32 +955,44 @@ void D3D9Context::UpdateBuffer(Buffer *buffer, const uint8_t *data, size_t offse
}
}
void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef) {
void D3D9Pipeline::Apply(LPDIRECT3DDEVICE9 device, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
vshader->Apply(device);
pshader->Apply(device);
blend->Apply(device);
depthStencil->Apply(device, stencilRef);
depthStencil->Apply(device, stencilRef, stencilWriteMask, stencilCompareMask);
raster->Apply(device);
}
void D3D9Context::ApplyDynamicState() {
// Apply dynamic state.
if (curPipeline_->depthStencil->stencilEnabled) {
device_->SetRenderState(D3DRS_STENCILREF, (DWORD)stencilRefValue_);
device_->SetRenderState(D3DRS_STENCILWRITEMASK, (DWORD)stencilWriteMask_);
device_->SetRenderState(D3DRS_STENCILMASK, (DWORD)stencilCompareMask_);
}
}
void D3D9Context::Draw(int vertexCount, int offset) {
device_->SetStreamSource(0, curVBuffers_[0]->vbuffer_, curVBufferOffsets_[0], curPipeline_->inputLayout->GetStride(0));
curPipeline_->Apply(device_, stencilRef_);
curPipeline_->inputLayout->Apply(device_);
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
ApplyDynamicState();
device_->DrawPrimitive(curPipeline_->prim, offset, vertexCount / 3);
}
void D3D9Context::DrawIndexed(int vertexCount, int offset) {
curPipeline_->Apply(device_, stencilRef_);
curPipeline_->inputLayout->Apply(device_);
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
ApplyDynamicState();
device_->SetStreamSource(0, curVBuffers_[0]->vbuffer_, curVBufferOffsets_[0], curPipeline_->inputLayout->GetStride(0));
device_->SetIndices(curIBuffer_->ibuffer_);
device_->DrawIndexedPrimitive(curPipeline_->prim, 0, 0, vertexCount, offset, vertexCount / curPipeline_->primDivisor);
}
void D3D9Context::DrawUP(const void *vdata, int vertexCount) {
curPipeline_->Apply(device_, stencilRef_);
curPipeline_->inputLayout->Apply(device_);
curPipeline_->Apply(device_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
ApplyDynamicState();
device_->DrawPrimitiveUP(curPipeline_->prim, vertexCount / 3, vdata, curPipeline_->inputLayout->GetStride(0));
}
@ -1025,6 +1036,12 @@ void D3D9Context::SetBlendFactor(float color[4]) {
dxstate.blendColor.set(color);
}
void D3D9Context::SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) {
stencilRefValue_ = refValue;
stencilWriteMask_ = writeMask;
stencilCompareMask_ = compareMask;
}
bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) {
LPD3D_SHADER_MACRO defines = nullptr;
LPD3DINCLUDE includes = nullptr;

View File

@ -175,10 +175,8 @@ public:
GLuint stencilZFail;
GLuint stencilPass;
GLuint stencilCompareOp;
uint8_t stencilCompareMask;
uint8_t stencilWriteMask;
void Apply(GLRenderManager *render, uint8_t stencilRef) {
void Apply(GLRenderManager *render, uint8_t stencilRef, uint8_t stencilWriteMask, uint8_t stencilCompareMask) {
render->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp);
render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask);
render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass);
@ -388,13 +386,21 @@ public:
renderManager_.SetBlendFactor(color);
}
void SetStencilRef(uint8_t ref) override {
stencilRef_ = ref;
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override {
stencilRef_ = refValue;
stencilWriteMask_ = writeMask;
stencilCompareMask_ = compareMask;
// Do we need to update on the fly here?
renderManager_.SetStencilFunc(
curPipeline_->depthStencil->stencilEnabled,
curPipeline_->depthStencil->stencilCompareOp,
ref,
curPipeline_->depthStencil->stencilCompareMask);
refValue,
compareMask);
renderManager_.SetStencilOp(
writeMask,
curPipeline_->depthStencil->stencilFail,
curPipeline_->depthStencil->stencilZFail,
curPipeline_->depthStencil->stencilPass);
}
void BindTextures(int start, int count, Texture **textures) override;
@ -491,6 +497,8 @@ private:
AutoRef<Framebuffer> curRenderTarget_;
uint8_t stencilRef_ = 0;
uint8_t stencilWriteMask_ = 0;
uint8_t stencilCompareMask_ = 0;
// Frames in flight is not such a strict concept as with Vulkan until we start using glBufferStorage and fences.
// But might as well have the structure ready, and can't hurt to rotate buffers.
@ -936,12 +944,10 @@ DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStat
ds->depthWriteEnabled = desc.depthWriteEnabled;
ds->depthComp = compToGL[(int)desc.depthCompare];
ds->stencilEnabled = desc.stencilEnabled;
ds->stencilCompareOp = compToGL[(int)desc.front.compareOp];
ds->stencilPass = stencilOpToGL[(int)desc.front.passOp];
ds->stencilFail = stencilOpToGL[(int)desc.front.failOp];
ds->stencilZFail = stencilOpToGL[(int)desc.front.depthFailOp];
ds->stencilWriteMask = desc.front.writeMask;
ds->stencilCompareMask = desc.front.compareMask;
ds->stencilCompareOp = compToGL[(int)desc.stencil.compareOp];
ds->stencilPass = stencilOpToGL[(int)desc.stencil.passOp];
ds->stencilFail = stencilOpToGL[(int)desc.stencil.failOp];
ds->stencilZFail = stencilOpToGL[(int)desc.stencil.depthFailOp];
return ds;
}
@ -1185,7 +1191,7 @@ void OpenGLContext::BindPipeline(Pipeline *pipeline) {
return;
}
curPipeline_->blend->Apply(&renderManager_);
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_);
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
curPipeline_->raster->Apply(&renderManager_);
renderManager_.BindProgram(curPipeline_->program_);
}

View File

@ -283,8 +283,6 @@ public:
int dynamicUniformSize = 0;
bool usesStencil = false;
uint8_t stencilWriteMask = 0xFF;
uint8_t stencilTestMask = 0xFF;
private:
VulkanContext *vulkan_;
@ -407,7 +405,7 @@ public:
void SetScissorRect(int left, int top, int width, int height) override;
void SetViewports(int count, Viewport *viewports) override;
void SetBlendFactor(float color[4]) override;
void SetStencilRef(uint8_t stencilRef) override;
void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override;
void BindSamplerStates(int start, int count, SamplerState **state) override;
void BindTextures(int start, int count, Texture **textures) override;
@ -554,6 +552,8 @@ private:
DeviceCaps caps_{};
uint8_t stencilRef_ = 0;
uint8_t stencilWriteMask_ = 0xFF;
uint8_t stencilCompareMask_ = 0xFF;
};
static int GetBpp(VkFormat format) {
@ -1131,8 +1131,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
}
if (depth->info.stencilTestEnable) {
pipeline->usesStencil = true;
pipeline->stencilTestMask = depth->info.front.compareMask;
pipeline->stencilWriteMask = depth->info.front.writeMask;
}
return pipeline;
}
@ -1160,10 +1158,12 @@ void VKContext::SetBlendFactor(float color[4]) {
renderManager_.SetBlendFactor(col);
}
void VKContext::SetStencilRef(uint8_t stencilRef) {
void VKContext::SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) {
if (curPipeline_->usesStencil)
renderManager_.SetStencilParams(curPipeline_->stencilWriteMask, curPipeline_->stencilTestMask, stencilRef);
stencilRef_ = stencilRef;
renderManager_.SetStencilParams(writeMask, compareMask, refValue);
stencilRef_ = refValue;
stencilWriteMask_ = writeMask;
stencilCompareMask_ = compareMask;
}
InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
@ -1207,9 +1207,7 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) {
}
}
static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {
dest.compareMask = src.compareMask;
dest.writeMask = src.writeMask;
static inline void CopySide(VkStencilOpState &dest, const StencilSetup &src) {
dest.compareOp = compToVK[(int)src.compareOp];
dest.failOp = stencilOpToVK[(int)src.failOp];
dest.passOp = stencilOpToVK[(int)src.passOp];
@ -1224,8 +1222,8 @@ DepthStencilState *VKContext::CreateDepthStencilState(const DepthStencilStateDes
ds->info.stencilTestEnable = desc.stencilEnabled;
ds->info.depthBoundsTestEnable = false;
if (ds->info.stencilTestEnable) {
CopySide(ds->info.front, desc.front);
CopySide(ds->info.back, desc.back);
CopySide(ds->info.front, desc.stencil);
CopySide(ds->info.back, desc.stencil);
}
return ds;
}
@ -1313,7 +1311,7 @@ void VKContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
void VKContext::ApplyDynamicState() {
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
if (curPipeline_->usesStencil) {
renderManager_.SetStencilParams(curPipeline_->stencilWriteMask, curPipeline_->stencilTestMask, stencilRef_);
renderManager_.SetStencilParams(stencilWriteMask_, stencilCompareMask_, stencilRef_);
}
}

View File

@ -453,13 +453,11 @@ public:
class RasterState : public RefCountedObject {};
struct StencilSide {
struct StencilSetup {
StencilOp failOp;
StencilOp passOp;
StencilOp depthFailOp;
Comparison compareOp;
uint8_t compareMask;
uint8_t writeMask;
};
struct DepthStencilStateDesc {
@ -467,8 +465,7 @@ struct DepthStencilStateDesc {
bool depthWriteEnabled;
Comparison depthCompare;
bool stencilEnabled;
StencilSide front;
StencilSide back;
StencilSetup stencil;
};
struct BlendStateDesc {
@ -652,7 +649,7 @@ public:
virtual void SetScissorRect(int left, int top, int width, int height) = 0;
virtual void SetViewports(int count, Viewport *viewports) = 0;
virtual void SetBlendFactor(float color[4]) = 0;
virtual void SetStencilRef(uint8_t ref) = 0;
virtual void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) = 0;
virtual void BindSamplerStates(int start, int count, SamplerState **state) = 0;
virtual void BindTextures(int start, int count, Texture **textures) = 0;

View File

@ -329,13 +329,10 @@ void GPUDriverTestScreen::DiscardTest() {
dsDesc.depthWriteEnabled = true;
dsDesc.depthCompare = Comparison::ALWAYS;
dsDesc.stencilEnabled = true;
dsDesc.front.compareMask = 0xFF;
dsDesc.front.compareOp = Comparison::ALWAYS;
dsDesc.front.passOp = StencilOp::REPLACE;
dsDesc.front.failOp = StencilOp::REPLACE; // These two shouldn't matter, because the test that fails is discard, not stencil.
dsDesc.front.depthFailOp = StencilOp::REPLACE;
dsDesc.front.writeMask = 0xFF;
dsDesc.back = dsDesc.front;
dsDesc.stencil.compareOp = Comparison::ALWAYS;
dsDesc.stencil.passOp = StencilOp::REPLACE;
dsDesc.stencil.failOp = StencilOp::REPLACE; // These two shouldn't matter, because the test that fails is discard, not stencil.
dsDesc.stencil.depthFailOp = StencilOp::REPLACE;
DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc);
// Write only depth.
@ -353,33 +350,27 @@ void GPUDriverTestScreen::DiscardTest() {
dsDesc.depthTestEnabled = true;
dsDesc.stencilEnabled = true;
dsDesc.depthCompare = Comparison::ALWAYS;
dsDesc.front.compareOp = Comparison::EQUAL;
dsDesc.front.failOp = StencilOp::KEEP;
dsDesc.front.depthFailOp = StencilOp::KEEP;
dsDesc.front.writeMask = 0x0;
dsDesc.back = dsDesc.front;
dsDesc.stencil.compareOp = Comparison::EQUAL;
dsDesc.stencil.failOp = StencilOp::KEEP;
dsDesc.stencil.depthFailOp = StencilOp::KEEP;
DepthStencilState *stencilEqualDepthAlways = draw->CreateDepthStencilState(dsDesc);
dsDesc.depthTestEnabled = false;
dsDesc.front.compareOp = Comparison::EQUAL;
dsDesc.back = dsDesc.front;
dsDesc.stencil.compareOp = Comparison::EQUAL;
DepthStencilState *stencilEqual = draw->CreateDepthStencilState(dsDesc);
dsDesc.depthTestEnabled = true;
dsDesc.depthCompare = Comparison::ALWAYS;
dsDesc.front.compareOp = Comparison::NOT_EQUAL;
dsDesc.back = dsDesc.front;
dsDesc.stencil.compareOp = Comparison::NOT_EQUAL;
DepthStencilState *stenciNotEqualDepthAlways = draw->CreateDepthStencilState(dsDesc);
dsDesc.depthTestEnabled = false;
dsDesc.front.compareOp = Comparison::NOT_EQUAL;
dsDesc.back = dsDesc.front;
dsDesc.stencil.compareOp = Comparison::NOT_EQUAL;
DepthStencilState *stencilNotEqual = draw->CreateDepthStencilState(dsDesc);
dsDesc.stencilEnabled = true;
dsDesc.depthTestEnabled = true;
dsDesc.front.compareOp = Comparison::ALWAYS;
dsDesc.back = dsDesc.front;
dsDesc.stencil.compareOp = Comparison::ALWAYS;
dsDesc.depthCompare = Comparison::LESS_EQUAL;
DepthStencilState *stencilAlwaysDepthTestLessEqual = draw->CreateDepthStencilState(dsDesc);
dsDesc.depthCompare = Comparison::GREATER;
@ -506,27 +497,28 @@ void GPUDriverTestScreen::DiscardTest() {
dc.BeginPipeline(writePipelines[j], samplerNearest_);
// Draw the rectangle with stencil value 0, depth 0.1f and the text with stencil 0xFF, depth 0.9. Then set 0xFF as the stencil value and draw the rectangles at depth 0.5.
draw->SetStencilRef(0x0);
draw->SetStencilParams(0, 0xFF, 0xFF);
dc.SetCurZ(0.1f);
dc.FillRect(UI::Drawable(bgColorBAD), bounds);
// test bounds
dc.Flush();
draw->SetStencilRef(0xff);
draw->SetStencilParams(0xff, 0xFF, 0xFF);
dc.SetCurZ(0.9f);
dc.DrawTextRect("TEST OK", bounds, textColorBAD, ALIGN_HCENTER | ALIGN_VCENTER | FLAG_DYNAMIC_ASCII);
dc.Flush();
// Draw rectangle that should result in the text
dc.BeginPipeline(testPipeline1[i], samplerNearest_);
draw->SetStencilRef(0xff);
draw->SetStencilParams(0xff, 0, 0xFF);
dc.SetCurZ(0.5f);
dc.FillRect(UI::Drawable(textColorOK), bounds);
dc.Flush();
// Draw rectangle that should result in the bg
dc.BeginPipeline(testPipeline2[i], samplerNearest_);
draw->SetStencilRef(0xff);
draw->SetStencilParams(0xff, 0, 0xFF);
dc.SetCurZ(0.5f);
dc.FillRect(UI::Drawable(bgColorOK), bounds);
dc.Flush();