From 10e4d4db14adf205cb38b217353b629bd1159bf0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Mon, 26 Dec 2016 23:11:31 +0100 Subject: [PATCH] Draw: Preliminary stencil implementation. Two-sided only implemented for Vulkan. --- ext/native/thin3d/thin3d.h | 127 ++++++++++++++++------------ ext/native/thin3d/thin3d_d3d9.cpp | 44 +++++++++- ext/native/thin3d/thin3d_gl.cpp | 37 +++++++- ext/native/thin3d/thin3d_vulkan.cpp | 55 +++++++----- 4 files changed, 186 insertions(+), 77 deletions(-) diff --git a/ext/native/thin3d/thin3d.h b/ext/native/thin3d/thin3d.h index aa6fbc2e87..4e8e7742a6 100644 --- a/ext/native/thin3d/thin3d.h +++ b/ext/native/thin3d/thin3d.h @@ -84,6 +84,17 @@ enum BlendFactor : int { FIXED_COLOR, }; +enum class StencilOp { + KEEP = 0, + ZERO = 1, + REPLACE = 2, + INCREMENT_AND_CLAMP = 3, + DECREMENT_AND_CLAMP = 4, + INVERT = 5, + INCREMENT_AND_WRAP = 6, + DECREMENT_AND_WRAP = 7, +}; + enum class TextureFilter : int { NEAREST, LINEAR, @@ -205,6 +216,57 @@ enum class DataFormat : uint8_t { D32F_S8, }; +enum class ShaderStage { + VERTEX, + FRAGMENT, + GEOMETRY, + CONTROL, // HULL + EVALUATION, // DOMAIN + COMPUTE, +}; + +enum class CullMode : uint8_t { + NONE, + FRONT, + BACK, + FRONT_AND_BACK, // Not supported on D3D9 +}; + +enum class Facing { + CCW, + CW, +}; + +enum BorderColor { + DONT_CARE, + TRANSPARENT_BLACK, + OPAQUE_BLACK, + OPAQUE_WHITE, +}; + +enum { + COLOR_MASK_R = 1, + COLOR_MASK_G = 2, + COLOR_MASK_B = 4, + COLOR_MASK_A = 8, +}; + +enum class TextureAddressMode { + REPEAT, + REPEAT_MIRROR, + CLAMP_TO_EDGE, + CLAMP_TO_BORDER, +}; + +enum class ShaderLanguage { + GLSL_ES_200, + GLSL_ES_300, + GLSL_410, + GLSL_VULKAN, + HLSL_D3D9, + HLSL_D3D11, +}; + enum ImageFileType { PNG, JPEG, @@ -299,24 +361,6 @@ struct InputLayoutDesc { class InputLayout : public RefCountedObject { }; -enum class ShaderStage { - VERTEX, - FRAGMENT, - GEOMETRY, - CONTROL, // HULL - EVALUATION, // DOMAIN - COMPUTE, -}; - -enum class ShaderLanguage { - GLSL_ES_200, - GLSL_ES_300, - GLSL_410, - GLSL_VULKAN, - HLSL_D3D9, - HLSL_D3D11, -}; - enum class UniformType : int8_t { FLOAT, FLOAT2, FLOAT3, FLOAT4, MATRIX4X4, @@ -350,11 +394,23 @@ public: class RasterState : public RefCountedObject {}; +struct StencilSide { + StencilOp failOp; + StencilOp passOp; + StencilOp depthFailOp; + Comparison compareOp; + uint8_t compareMask; + uint8_t writeMask; + uint8_t reference; +}; + struct DepthStencilStateDesc { bool depthTestEnabled; bool depthWriteEnabled; Comparison depthCompare; - // Ignore stencil for now, will need soon. + bool stencilEnabled; + StencilSide front; + StencilSide back; }; struct BlendStateDesc { @@ -370,27 +426,6 @@ struct BlendStateDesc { LogicOp logicOp; }; -enum { - COLOR_MASK_R = 1, - COLOR_MASK_G = 2, - COLOR_MASK_B = 4, - COLOR_MASK_A = 8, -}; - -enum BorderColor { - DONT_CARE, - TRANSPARENT_BLACK, - OPAQUE_BLACK, - OPAQUE_WHITE, -}; - -enum class TextureAddressMode { - REPEAT, - REPEAT_MIRROR, - CLAMP_TO_EDGE, - CLAMP_TO_BORDER, -}; - struct SamplerStateDesc { TextureFilter magFilter; TextureFilter minFilter; @@ -405,18 +440,6 @@ struct SamplerStateDesc { BorderColor borderColor; }; -enum class CullMode : uint8_t { - NONE, - FRONT, - BACK, - FRONT_AND_BACK, // Not supported on D3D9 -}; - -enum class Facing { - CCW, - CW, -}; - struct RasterStateDesc { CullMode cull; Facing facing; diff --git a/ext/native/thin3d/thin3d_d3d9.cpp b/ext/native/thin3d/thin3d_d3d9.cpp index 83ebd3dcc4..5a51e74140 100644 --- a/ext/native/thin3d/thin3d_d3d9.cpp +++ b/ext/native/thin3d/thin3d_d3d9.cpp @@ -83,6 +83,17 @@ static const D3DPRIMITIVETYPE primToD3D9[] = { D3DPT_POINTLIST, }; +static const D3DSTENCILOP stencilOpToD3D9[] = { + D3DSTENCILOP_KEEP, + D3DSTENCILOP_ZERO, + D3DSTENCILOP_REPLACE, + D3DSTENCILOP_INCRSAT, + D3DSTENCILOP_DECRSAT, + D3DSTENCILOP_INVERT, + D3DSTENCILOP_INCR, + D3DSTENCILOP_DECR, +}; + static const int primCountDivisor[] = { 1, 2, @@ -101,11 +112,30 @@ public: BOOL depthTestEnabled; BOOL depthWriteEnabled; D3DCMPFUNC depthCompare; - + BOOL stencilEnabled; + D3DSTENCILOP stencilFail; + D3DSTENCILOP stencilZFail; + D3DSTENCILOP stencilPass; + D3DCMPFUNC stencilCompareOp; + uint8_t stencilReference; + uint8_t stencilCompareMask; + uint8_t stencilWriteMask; void Apply(LPDIRECT3DDEVICE9 device) { device->SetRenderState(D3DRS_ZENABLE, depthTestEnabled); - device->SetRenderState(D3DRS_ZWRITEENABLE, depthWriteEnabled); - device->SetRenderState(D3DRS_ZFUNC, depthCompare); + if (depthTestEnabled) { + device->SetRenderState(D3DRS_ZWRITEENABLE, depthWriteEnabled); + device->SetRenderState(D3DRS_ZFUNC, depthCompare); + } + device->SetRenderState(D3DRS_STENCILENABLE, stencilEnabled); + if (stencilEnabled) { + device->SetRenderState(D3DRS_STENCILFAIL, stencilFail); + device->SetRenderState(D3DRS_STENCILZFAIL, stencilZFail); + 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); + } } }; @@ -591,6 +621,14 @@ DepthStencilState *D3D9Context::CreateDepthStencilState(const DepthStencilStateD ds->depthTestEnabled = desc.depthTestEnabled; 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->stencilReference = desc.front.reference; + ds->stencilCompareMask = desc.front.compareMask; return ds; } diff --git a/ext/native/thin3d/thin3d_gl.cpp b/ext/native/thin3d/thin3d_gl.cpp index 2565f5e96c..3dd0ac21b0 100644 --- a/ext/native/thin3d/thin3d_gl.cpp +++ b/ext/native/thin3d/thin3d_gl.cpp @@ -83,6 +83,17 @@ static const unsigned short logicOpToGL[] = { }; #endif +static const GLuint stencilOpToGL[8] = { + GL_KEEP, + GL_ZERO, + GL_REPLACE, + GL_INCR, + GL_DECR, + GL_INVERT, + GL_INCR_WRAP, + GL_DECR_WRAP, +}; + static const unsigned short primToGL[] = { GL_POINTS, GL_LINES, @@ -166,7 +177,15 @@ public: bool depthTestEnabled; bool depthWriteEnabled; GLuint depthComp; - // bool stencilTestEnabled; TODO + // TODO: Two-sided + GLboolean stencilEnabled; + GLuint stencilFail; + GLuint stencilZFail; + GLuint stencilPass; + GLuint stencilCompareOp; + uint8_t stencilReference; + uint8_t stencilCompareMask; + uint8_t stencilWriteMask; void Apply() { if (depthTestEnabled) { @@ -176,6 +195,14 @@ public: } else { glDisable(GL_DEPTH_TEST); } + if (stencilEnabled) { + glEnable(GL_STENCIL_TEST); + glStencilOpSeparate(GL_FRONT_AND_BACK, stencilFail, stencilZFail, stencilPass); + glStencilFuncSeparate(GL_FRONT_AND_BACK, stencilCompareOp, stencilReference, stencilCompareMask); + glStencilMaskSeparate(GL_FRONT_AND_BACK, stencilWriteMask); + } else { + glDisable(GL_STENCIL_TEST); + } glDisable(GL_STENCIL_TEST); } }; @@ -737,6 +764,14 @@ DepthStencilState *OpenGLContext::CreateDepthStencilState(const DepthStencilStat ds->depthTestEnabled = desc.depthTestEnabled; 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->stencilReference = desc.front.reference; + ds->stencilCompareMask = desc.front.compareMask; return ds; } diff --git a/ext/native/thin3d/thin3d_vulkan.cpp b/ext/native/thin3d/thin3d_vulkan.cpp index 807b0d8b7e..fbc04b5ab4 100644 --- a/ext/native/thin3d/thin3d_vulkan.cpp +++ b/ext/native/thin3d/thin3d_vulkan.cpp @@ -112,6 +112,18 @@ static const VkPrimitiveTopology primToVK[] = { VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP_WITH_ADJACENCY, }; + +static const VkStencilOp stencilOpToVK[8] = { + VK_STENCIL_OP_KEEP, + VK_STENCIL_OP_ZERO, + VK_STENCIL_OP_REPLACE, + VK_STENCIL_OP_INCREMENT_AND_CLAMP, + VK_STENCIL_OP_DECREMENT_AND_CLAMP, + VK_STENCIL_OP_INVERT, + VK_STENCIL_OP_INCREMENT_AND_WRAP, + VK_STENCIL_OP_DECREMENT_AND_WRAP, +}; + static inline void Uint8x4ToFloat4(uint32_t u, float f[4]) { f[0] = ((u >> 0) & 0xFF) * (1.0f / 255.0f); f[1] = ((u >> 8) & 0xFF) * (1.0f / 255.0f); @@ -121,25 +133,13 @@ static inline void Uint8x4ToFloat4(uint32_t u, float f[4]) { class VKBlendState : public BlendState { public: - VkPipelineColorBlendStateCreateInfo info{}; + VkPipelineColorBlendStateCreateInfo info{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO }; std::vector attachments; }; class VKDepthStencilState : public DepthStencilState { public: - bool depthTestEnabled; - bool depthWriteEnabled; - VkCompareOp depthComp; - - void ToVulkan(VkPipelineDepthStencilStateCreateInfo *info) const { - memset(info, 0, sizeof(*info)); - info->sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; - info->depthCompareOp = depthComp; - info->depthTestEnable = depthTestEnabled; - info->depthWriteEnable = depthWriteEnabled; - info->stencilTestEnable = false; - info->depthBoundsTestEnable = false; - } + VkPipelineDepthStencilStateCreateInfo info{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO }; }; class VKRasterState : public RasterState { @@ -819,9 +819,6 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { stage.flags = 0; } - VkPipelineDepthStencilStateCreateInfo depthStencil; - depth->ToVulkan(&depthStencil); - VkPipelineInputAssemblyStateCreateInfo inputAssembly = { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO }; inputAssembly.topology = primToVK[(int)desc.prim]; inputAssembly.primitiveRestartEnable = false; @@ -852,7 +849,7 @@ Pipeline *VKContext::CreateGraphicsPipeline(const PipelineDesc &desc) { info.stageCount = (uint32_t)stages.size(); info.pStages = stages.data(); info.pColorBlendState = &blend->info; - info.pDepthStencilState = &depthStencil; + info.pDepthStencilState = &depth->info; info.pDynamicState = &dynamicInfo; info.pInputAssemblyState = &inputAssembly; info.pTessellationState = nullptr; @@ -957,11 +954,27 @@ void VKTexture::Finalize(int zim_flags) { // TODO } +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]; + dest.passOp = stencilOpToVK[(int)src.passOp]; + dest.depthFailOp = stencilOpToVK[(int)src.depthFailOp]; +} + DepthStencilState *VKContext::CreateDepthStencilState(const DepthStencilStateDesc &desc) { VKDepthStencilState *ds = new VKDepthStencilState(); - ds->depthTestEnabled = desc.depthTestEnabled; - ds->depthWriteEnabled = desc.depthWriteEnabled; - ds->depthComp = compToVK[(int)desc.depthCompare]; + ds->info.depthCompareOp = compToVK[(int)desc.depthCompare]; + ds->info.depthTestEnable = desc.depthTestEnabled; + ds->info.depthWriteEnable = desc.depthWriteEnabled; + ds->info.stencilTestEnable = false; + ds->info.depthBoundsTestEnable = false; + if (ds->info.stencilTestEnable) { + CopySide(ds->info.front, desc.front); + CopySide(ds->info.back, desc.back); + } return ds; }