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

View File

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

View File

@ -175,10 +175,8 @@ public:
GLuint stencilZFail; GLuint stencilZFail;
GLuint stencilPass; GLuint stencilPass;
GLuint stencilCompareOp; 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->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp);
render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask); render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask);
render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass); render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass);
@ -388,13 +386,21 @@ public:
renderManager_.SetBlendFactor(color); renderManager_.SetBlendFactor(color);
} }
void SetStencilRef(uint8_t ref) override { void SetStencilParams(uint8_t refValue, uint8_t writeMask, uint8_t compareMask) override {
stencilRef_ = ref; stencilRef_ = refValue;
stencilWriteMask_ = writeMask;
stencilCompareMask_ = compareMask;
// Do we need to update on the fly here?
renderManager_.SetStencilFunc( renderManager_.SetStencilFunc(
curPipeline_->depthStencil->stencilEnabled, curPipeline_->depthStencil->stencilEnabled,
curPipeline_->depthStencil->stencilCompareOp, curPipeline_->depthStencil->stencilCompareOp,
ref, refValue,
curPipeline_->depthStencil->stencilCompareMask); compareMask);
renderManager_.SetStencilOp(
writeMask,
curPipeline_->depthStencil->stencilFail,
curPipeline_->depthStencil->stencilZFail,
curPipeline_->depthStencil->stencilPass);
} }
void BindTextures(int start, int count, Texture **textures) override; void BindTextures(int start, int count, Texture **textures) override;
@ -491,6 +497,8 @@ private:
AutoRef<Framebuffer> curRenderTarget_; AutoRef<Framebuffer> curRenderTarget_;
uint8_t stencilRef_ = 0; 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. // 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. // 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->depthWriteEnabled = desc.depthWriteEnabled;
ds->depthComp = compToGL[(int)desc.depthCompare]; ds->depthComp = compToGL[(int)desc.depthCompare];
ds->stencilEnabled = desc.stencilEnabled; ds->stencilEnabled = desc.stencilEnabled;
ds->stencilCompareOp = compToGL[(int)desc.front.compareOp]; ds->stencilCompareOp = compToGL[(int)desc.stencil.compareOp];
ds->stencilPass = stencilOpToGL[(int)desc.front.passOp]; ds->stencilPass = stencilOpToGL[(int)desc.stencil.passOp];
ds->stencilFail = stencilOpToGL[(int)desc.front.failOp]; ds->stencilFail = stencilOpToGL[(int)desc.stencil.failOp];
ds->stencilZFail = stencilOpToGL[(int)desc.front.depthFailOp]; ds->stencilZFail = stencilOpToGL[(int)desc.stencil.depthFailOp];
ds->stencilWriteMask = desc.front.writeMask;
ds->stencilCompareMask = desc.front.compareMask;
return ds; return ds;
} }
@ -1185,7 +1191,7 @@ void OpenGLContext::BindPipeline(Pipeline *pipeline) {
return; return;
} }
curPipeline_->blend->Apply(&renderManager_); curPipeline_->blend->Apply(&renderManager_);
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_); curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_, stencilWriteMask_, stencilCompareMask_);
curPipeline_->raster->Apply(&renderManager_); curPipeline_->raster->Apply(&renderManager_);
renderManager_.BindProgram(curPipeline_->program_); renderManager_.BindProgram(curPipeline_->program_);
} }

View File

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

View File

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