thin3d: Make the stencil ref value dynamic state (all APIs support this directly).

This commit is contained in:
Henrik Rydgård 2018-12-18 09:35:53 +01:00
parent df98721e73
commit c2319cd6d1
7 changed files with 88 additions and 32 deletions

View File

@ -4,27 +4,39 @@
static const std::vector<Draw::ShaderSource> fsDiscard = {
{Draw::ShaderLanguage::GLSL_ES_200,
R"(varying vec4 oColor0;
R"(
#ifdef GL_ES
precision lowp float;
#endif
#if __VERSION__ >= 130
#define varying in
#define gl_FragColor fragColor0
out vec4 fragColor0;
#endif
varying vec4 oColor0;
varying vec2 oTexCoord0;
uniform sampler2D Sampler0;
void main() {
vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
gl_FragColor = color;
vec4 color = texture2D(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
gl_FragColor = color;
})"
},
{Draw::ShaderLanguage::GLSL_VULKAN,
R"(layout(location = 0) in vec4 oColor0;
R"(#version 140
#extension GL_ARB_separate_shader_objects : enable
#extension GL_ARB_shading_language_420pack : enable
layout(location = 0) in vec4 oColor0;
layout(location = 1) in vec2 oTexCoord0;
layout(location = 0) out vec4 fragColor0;
layout(set = 0, binding = 1) uniform sampler2D Sampler0;
void main() {
vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
fragColor0 = color;
})"
vec4 color = texture(Sampler0, oTexCoord0) * oColor0;
if (color.a <= 0.0)
discard;
fragColor0 = color;
})"
},
};
@ -81,7 +93,6 @@ void GPUDriverTestScreen::render() {
dsDesc.front.passOp = StencilOp::REPLACE;
dsDesc.front.failOp = StencilOp::ZERO;
dsDesc.front.depthFailOp = StencilOp::ZERO;
dsDesc.front.reference = 0xFF;
dsDesc.front.writeMask = 0xFF;
dsDesc.back = dsDesc.front;
DepthStencilState *depthStencilWrite = draw->CreateDepthStencilState(dsDesc);
@ -129,9 +140,11 @@ void GPUDriverTestScreen::render() {
}
UIContext &dc = *screenManager()->getUIContext();
Draw::DrawContext *draw = dc.GetDrawContext();
const Bounds &bounds = dc.GetBounds();
const char *testNames[] = {"Normal", "Z test", "Stencil test"};
Pipeline *testPipelines[] = { drawTestStencil_, drawTestDepth_, drawTestStencil_ };
const int numTests = ARRAY_SIZE(testNames);
@ -152,6 +165,7 @@ void GPUDriverTestScreen::render() {
dc.Begin();
dc.SetFontScale(1.0f, 1.0f);
Bounds bounds = {x - testW / 2, y + 40, testW, 70};
draw->SetStencilRef(0x0);
dc.DrawText(testNames[i], bounds.x, y, style.fgColor, FLAG_DYNAMIC_ASCII);
dc.FillRect(UI::Drawable(bgColorOK), bounds);

View File

@ -679,6 +679,8 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
screenManager->switchScreen(new LogoScreen());
}
screenManager->push(new GPUDriverTestScreen());
if (g_Config.bRemoteShareOnStartup && g_Config.bRemoteDebuggerOnStartup)
StartWebServer(WebServerFlags::ALL);
else if (g_Config.bRemoteShareOnStartup)

View File

@ -416,7 +416,6 @@ struct StencilSide {
Comparison compareOp;
uint8_t compareMask;
uint8_t writeMask;
uint8_t reference;
};
struct DepthStencilStateDesc {
@ -588,6 +587,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 BindSamplerStates(int start, int count, SamplerState **state) = 0;
virtual void BindTextures(int start, int count, Texture **textures) = 0;

View File

@ -95,6 +95,10 @@ public:
blendFactorDirty_ = true;
}
}
void SetStencilRef(uint8_t ref) override {
stencilRef_ = ref;
stencilRefDirty_ = true;
}
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
@ -204,8 +208,8 @@ private:
// Dynamic state
float blendFactor_[4]{};
bool blendFactorDirty_ = false;
uint8_t stencilRef_;
bool stencilRefDirty_;
uint8_t stencilRef_ = 0;
bool stencilRefDirty_ = true;
// Temporaries
ID3D11Texture2D *packTexture_ = nullptr;
@ -975,7 +979,6 @@ void D3D11DrawContext::BindPipeline(Pipeline *pipeline) {
curPipeline_ = dPipeline;
}
// Gonna need dirtyflags soon..
void D3D11DrawContext::ApplyCurrentState() {
if (curBlend_ != curPipeline_->blend || blendFactorDirty_) {
context_->OMSetBlendState(curPipeline_->blend->bs, blendFactor_, 0xFFFFFFFF);

View File

@ -154,7 +154,6 @@ public:
D3DSTENCILOP stencilZFail;
D3DSTENCILOP stencilPass;
D3DCMPFUNC stencilCompareOp;
uint8_t stencilReference;
uint8_t stencilCompareMask;
uint8_t stencilWriteMask;
void Apply(LPDIRECT3DDEVICE9 device) {
@ -170,7 +169,6 @@ public:
device->SetRenderState(D3DRS_STENCILPASS, stencilPass);
device->SetRenderState(D3DRS_STENCILFUNC, stencilCompareOp);
device->SetRenderState(D3DRS_STENCILMASK, stencilCompareMask);
device->SetRenderState(D3DRS_STENCILREF, stencilReference);
device->SetRenderState(D3DRS_STENCILWRITEMASK, stencilWriteMask);
}
}
@ -523,6 +521,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 ref) override;
void Draw(int vertexCount, int offset) override;
void DrawIndexed(int vertexCount, int offset) override;
@ -684,7 +683,6 @@ DepthStencilState *D3D9Context::CreateDepthStencilState(const DepthStencilStateD
ds->stencilFail = stencilOpToD3D9[(int)desc.front.failOp];
ds->stencilZFail = stencilOpToD3D9[(int)desc.front.depthFailOp];
ds->stencilWriteMask = desc.front.writeMask;
ds->stencilReference = desc.front.reference;
ds->stencilCompareMask = desc.front.compareMask;
return ds;
}
@ -966,6 +964,10 @@ void D3D9Context::SetBlendFactor(float color[4]) {
device_->SetRenderState(D3DRS_BLENDFACTOR, r | (g << 8) | (b << 16) | (a << 24));
}
void D3D9Context::SetStencilRef(uint8_t ref) {
device_->SetRenderState(D3DRS_STENCILREF, (DWORD)ref);
}
bool D3D9ShaderModule::Compile(LPDIRECT3DDEVICE9 device, const uint8_t *data, size_t size) {
LPD3DXMACRO defines = nullptr;
LPD3DXINCLUDE includes = nullptr;

View File

@ -192,13 +192,12 @@ public:
GLuint stencilZFail;
GLuint stencilPass;
GLuint stencilCompareOp;
uint8_t stencilReference;
uint8_t stencilCompareMask;
uint8_t stencilWriteMask;
void Apply(GLRenderManager *render) {
void Apply(GLRenderManager *render, uint8_t stencilRef) {
render->SetDepth(depthTestEnabled, depthWriteEnabled, depthComp);
render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilReference, stencilCompareMask);
render->SetStencilFunc(stencilEnabled, stencilCompareOp, stencilRef, stencilCompareMask);
render->SetStencilOp(stencilWriteMask, stencilFail, stencilZFail, stencilPass);
}
};
@ -404,6 +403,15 @@ public:
renderManager_.SetBlendFactor(color);
}
void SetStencilRef(uint8_t ref) override {
stencilRef_ = ref;
renderManager_.SetStencilFunc(
curPipeline_->depthStencil->stencilEnabled,
curPipeline_->depthStencil->stencilCompareOp,
ref,
curPipeline_->depthStencil->stencilCompareMask);
}
void BindTextures(int start, int count, Texture **textures) override;
void BindPipeline(Pipeline *pipeline) override;
void BindVertexBuffers(int start, int count, Buffer **buffers, int *offsets) override {
@ -485,6 +493,8 @@ private:
OpenGLBuffer *curIBuffer_ = nullptr;
int curIBufferOffset_ = 0;
uint8_t stencilRef_ = 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.
struct FrameData {
@ -750,7 +760,6 @@ DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStat
ds->stencilFail = stencilOpToGL[(int)desc.front.failOp];
ds->stencilZFail = stencilOpToGL[(int)desc.front.depthFailOp];
ds->stencilWriteMask = desc.front.writeMask;
ds->stencilReference = desc.front.reference;
ds->stencilCompareMask = desc.front.compareMask;
return ds;
}
@ -959,7 +968,7 @@ bool OpenGLPipeline::LinkShaders() {
void OpenGLContext::BindPipeline(Pipeline *pipeline) {
curPipeline_ = (OpenGLPipeline *)pipeline;
curPipeline_->blend->Apply(&renderManager_);
curPipeline_->depthStencil->Apply(&renderManager_);
curPipeline_->depthStencil->Apply(&renderManager_, stencilRef_);
curPipeline_->raster->Apply(&renderManager_);
renderManager_.BindProgram(curPipeline_->program_);
}

View File

@ -275,6 +275,10 @@ public:
int stride[4]{};
int dynamicUniformSize = 0;
bool usesStencil = false;
uint8_t stencilWriteMask = 0xFF;
uint8_t stencilTestMask = 0xFF;
private:
VulkanContext *vulkan_;
uint8_t *ubo_;
@ -388,6 +392,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 BindSamplerStates(int start, int count, SamplerState **state) override;
void BindTextures(int start, int count, Texture **textures) override;
@ -414,6 +419,8 @@ public:
void DrawIndexed(int vertexCount, int offset) override;
void DrawUP(const void *vdata, int vertexCount) override;
void ApplyDynamicState();
void Clear(int mask, uint32_t colorval, float depthVal, int stencilVal) override;
void BeginFrame() override;
@ -541,6 +548,8 @@ private:
VulkanPushBuffer *push_ = nullptr;
DeviceCaps caps_{};
uint8_t stencilRef_ = 0;
};
static int GetBpp(VkFormat format) {
@ -979,9 +988,10 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
inputAssembly.topology = primToVK[(int)desc.prim];
inputAssembly.primitiveRestartEnable = false;
VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR };
// We treat the three stencil states as a unit in other places, so let's do that here too.
VkDynamicState dynamics[] = { VK_DYNAMIC_STATE_VIEWPORT, VK_DYNAMIC_STATE_SCISSOR, VK_DYNAMIC_STATE_STENCIL_COMPARE_MASK, VK_DYNAMIC_STATE_STENCIL_REFERENCE, VK_DYNAMIC_STATE_STENCIL_WRITE_MASK };
VkPipelineDynamicStateCreateInfo dynamicInfo = { VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO };
dynamicInfo.dynamicStateCount = ARRAY_SIZE(dynamics);
dynamicInfo.dynamicStateCount = depth->info.stencilTestEnable ? ARRAY_SIZE(dynamics) : 2;
dynamicInfo.pDynamicStates = dynamics;
VkPipelineMultisampleStateCreateInfo ms = { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO };
@ -1027,7 +1037,11 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) {
if (desc.uniformDesc) {
pipeline->dynamicUniformSize = (int)desc.uniformDesc->uniformBufferSize;
}
if (depth->info.stencilTestEnable) {
pipeline->usesStencil = true;
pipeline->stencilTestMask = depth->info.front.compareMask;
pipeline->stencilWriteMask = depth->info.front.writeMask;
}
return pipeline;
}
@ -1053,6 +1067,12 @@ void VKContext::SetBlendFactor(float color[4]) {
renderManager_.SetBlendFactor(color);
}
void VKContext::SetStencilRef(uint8_t stencilRef) {
if (curPipeline_->usesStencil)
renderManager_.SetStencilParams(curPipeline_->stencilWriteMask, curPipeline_->stencilTestMask, stencilRef);
stencilRef_ = stencilRef;
}
InputLayout *VKContext::CreateInputLayout(const InputLayoutDesc &desc) {
VKInputLayout *vl = new VKInputLayout();
vl->visc = { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO };
@ -1096,7 +1116,6 @@ Texture *VKContext::CreateTexture(const TextureDesc &desc) {
static inline void CopySide(VkStencilOpState &dest, const StencilSide &src) {
dest.compareMask = src.compareMask;
dest.reference = src.reference;
dest.writeMask = src.writeMask;
dest.compareOp = compToVK[(int)src.compareOp];
dest.failOp = stencilOpToVK[(int)src.failOp];
@ -1109,7 +1128,7 @@ DepthStencilState *VKContext::CreateDepthStencilState(const DepthStencilStateDes
ds->info.depthCompareOp = compToVK[(int)desc.depthCompare];
ds->info.depthTestEnable = desc.depthTestEnabled;
ds->info.depthWriteEnable = desc.depthWriteEnabled;
ds->info.stencilTestEnable = false;
ds->info.stencilTestEnable = desc.stencilEnabled;
ds->info.depthBoundsTestEnable = false;
if (ds->info.stencilTestEnable) {
CopySide(ds->info.front, desc.front);
@ -1197,6 +1216,13 @@ void VKContext::UpdateDynamicUniformBuffer(const void *ub, size_t size) {
curPipeline_->SetDynamicUniformData(ub, size);
}
void VKContext::ApplyDynamicState() {
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
if (curPipeline_->usesStencil) {
renderManager_.SetStencilParams(curPipeline_->stencilWriteMask, curPipeline_->stencilTestMask, stencilRef_);
}
}
void VKContext::Draw(int vertexCount, int offset) {
VKBuffer *vbuf = curVBuffers_[0];
@ -1208,7 +1234,7 @@ void VKContext::Draw(int vertexCount, int offset) {
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
renderManager_.BindPipeline(curPipeline_->vkpipeline);
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
ApplyDynamicState();
renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount);
}
@ -1224,7 +1250,7 @@ void VKContext::DrawIndexed(int vertexCount, int offset) {
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
renderManager_.BindPipeline(curPipeline_->vkpipeline);
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
ApplyDynamicState();
renderManager_.DrawIndexed(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vulkanIbuf, (int)ibBindOffset, vertexCount, 1, VK_INDEX_TYPE_UINT32);
}
@ -1236,7 +1262,7 @@ void VKContext::DrawUP(const void *vdata, int vertexCount) {
VkDescriptorSet descSet = GetOrCreateDescriptorSet(vulkanUBObuf);
renderManager_.BindPipeline(curPipeline_->vkpipeline);
// TODO: blend constants, stencil, viewports should be here, after bindpipeline..
ApplyDynamicState();
renderManager_.Draw(pipelineLayout_, descSet, 1, &ubo_offset, vulkanVbuf, (int)vbBindOffset, vertexCount);
}