From 4d36f0cc87d2cc2bc40ec1c36a65623dc3822f01 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 7 Sep 2017 23:00:12 +1000 Subject: [PATCH 1/7] Bitfield: Cast value to storage type in assignment operator This allows us to use enum classes in bitfields. --- Source/Core/Common/BitField.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Core/Common/BitField.h b/Source/Core/Common/BitField.h index 5832fbcc3f..c8a81a092a 100644 --- a/Source/Core/Common/BitField.h +++ b/Source/Core/Common/BitField.h @@ -136,7 +136,7 @@ public: __forceinline BitField& operator=(T val) { - storage = (storage & ~GetMask()) | ((val << position) & GetMask()); + storage = (storage & ~GetMask()) | ((static_cast(val) << position) & GetMask()); return *this; } From 2869c570f1d0b67d2ee4304ea528bef3ef4b563e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 30 Apr 2017 15:54:45 +1000 Subject: [PATCH 2/7] Renderer: Move depth state to VideoCommon and seperate from bpmem --- Source/Core/VideoBackends/D3D/D3DState.cpp | 4 +- Source/Core/VideoBackends/D3D/D3DState.h | 2 +- Source/Core/VideoBackends/D3D/Render.cpp | 6 +-- Source/Core/VideoBackends/D3D/Render.h | 2 +- Source/Core/VideoBackends/OGL/Render.cpp | 10 ++-- Source/Core/VideoBackends/OGL/Render.h | 2 +- Source/Core/VideoBackends/Vulkan/Constants.h | 10 ---- .../Vulkan/FramebufferManager.cpp | 8 +-- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 50 +++---------------- Source/Core/VideoBackends/Vulkan/Renderer.h | 2 +- .../Core/VideoBackends/Vulkan/ShaderCache.cpp | 15 ++++-- .../Core/VideoBackends/Vulkan/ShaderCache.h | 2 +- .../VideoBackends/Vulkan/StateTracker.cpp | 16 +++--- .../Core/VideoBackends/Vulkan/StateTracker.h | 9 ++-- Source/Core/VideoBackends/Vulkan/Util.cpp | 16 +++--- Source/Core/VideoBackends/Vulkan/Util.h | 4 +- Source/Core/VideoCommon/BPFunctions.cpp | 6 ++- Source/Core/VideoCommon/RenderBase.h | 2 +- Source/Core/VideoCommon/RenderState.cpp | 7 +++ Source/Core/VideoCommon/RenderState.h | 11 ++++ 20 files changed, 80 insertions(+), 104 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index b21af1f217..fe1337918d 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -456,10 +456,9 @@ ID3D11RasterizerState* StateCache::Get(RasterizerState state) return res; } -ID3D11DepthStencilState* StateCache::Get(ZMode state) +ID3D11DepthStencilState* StateCache::Get(DepthState state) { auto it = m_depth.find(state.hex); - if (it != m_depth.end()) return it->second; @@ -472,6 +471,7 @@ ID3D11DepthStencilState* StateCache::Get(ZMode state) depthdc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK; depthdc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK; + // Less/greater are swapped due to inverted depth. const D3D11_COMPARISON_FUNC d3dCmpFuncs[8] = { D3D11_COMPARISON_NEVER, D3D11_COMPARISON_GREATER, D3D11_COMPARISON_EQUAL, D3D11_COMPARISON_GREATER_EQUAL, D3D11_COMPARISON_LESS, D3D11_COMPARISON_NOT_EQUAL, diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 6b3838c661..30b018c114 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -49,7 +49,7 @@ public: ID3D11SamplerState* Get(SamplerState state); ID3D11BlendState* Get(BlendingState state); ID3D11RasterizerState* Get(RasterizerState state); - ID3D11DepthStencilState* Get(ZMode state); + ID3D11DepthStencilState* Get(DepthState state); // Release all cached states and clear hash tables. void Clear(); diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index ae50045c26..9877b8f0a5 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -60,7 +60,7 @@ struct GXPipelineState { std::array samplers; BlendingState blend; - ZMode zmode; + DepthState zmode; RasterizerState raster; }; @@ -916,9 +916,9 @@ void Renderer::SetGenerationMode() s_gx_state.raster.cull_mode = d3d_cull_modes[bpmem.genMode.cullmode]; } -void Renderer::SetDepthMode() +void Renderer::SetDepthState(const DepthState& state) { - s_gx_state.zmode.hex = bpmem.zmode.hex; + s_gx_state.zmode.hex = state.hex; } void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 907c9e2b18..8ca3b69396 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -22,7 +22,7 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; void SetGenerationMode() override; - void SetDepthMode() override; + void SetDepthState(const DepthState& state) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 8953b10831..0ac9f03a06 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1787,7 +1787,7 @@ void Renderer::RestoreAPIState() } SetGenerationMode(); BPFunctions::SetScissor(); - SetDepthMode(); + BPFunctions::SetDepthMode(); BPFunctions::SetBlendMode(); SetViewport(); @@ -1813,16 +1813,16 @@ void Renderer::SetGenerationMode() } } -void Renderer::SetDepthMode() +void Renderer::SetDepthState(const DepthState& state) { const GLenum glCmpFuncs[8] = {GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL, GL_GEQUAL, GL_ALWAYS}; - if (bpmem.zmode.testenable) + if (state.testenable) { glEnable(GL_DEPTH_TEST); - glDepthMask(bpmem.zmode.updateenable ? GL_TRUE : GL_FALSE); - glDepthFunc(glCmpFuncs[bpmem.zmode.func]); + glDepthMask(state.updateenable ? GL_TRUE : GL_FALSE); + glDepthFunc(glCmpFuncs[state.func]); } else { diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index 668b15c51f..c89abea63f 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -80,7 +80,7 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; void SetGenerationMode() override; - void SetDepthMode() override; + void SetDepthState(const DepthState& state) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/Vulkan/Constants.h b/Source/Core/VideoBackends/Vulkan/Constants.h index 9d1ab3fecd..e51c54e18c 100644 --- a/Source/Core/VideoBackends/Vulkan/Constants.h +++ b/Source/Core/VideoBackends/Vulkan/Constants.h @@ -135,16 +135,6 @@ union RasterizationState u32 bits; }; -// Depth state info -union DepthStencilState -{ - BitField<0, 1, VkBool32> test_enable; - BitField<1, 1, VkBool32> write_enable; - BitField<2, 3, VkCompareOp> compare_op; - - u32 bits; -}; - // Sampler info union SamplerState { diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index dec6d9e952..45d17a17e3 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -1164,16 +1164,16 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t pipeline_info.render_pass = m_efb_load_render_pass; pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits; pipeline_info.rasterization_state.samples = m_efb_samples; - pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; + pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; pipeline_info.blend_state.colorupdate = write_color; pipeline_info.blend_state.alphaupdate = write_color; pipeline_info.primitive_topology = m_poke_primitive_topology; if (write_depth) { - pipeline_info.depth_stencil_state.test_enable = VK_TRUE; - pipeline_info.depth_stencil_state.write_enable = VK_TRUE; - pipeline_info.depth_stencil_state.compare_op = VK_COMPARE_OP_ALWAYS; + pipeline_info.depth_state.testenable = true; + pipeline_info.depth_state.updateenable = true; + pipeline_info.depth_state.func = ZMode::ALWAYS; } VkPipeline pipeline = g_shader_cache->GetPipeline(pipeline_info); diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 7a94572b1e..97c23ca2ef 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -459,10 +459,10 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha blend_state.colorupdate = color_enable; blend_state.alphaupdate = alpha_enable; - DepthStencilState depth_state = Util::GetNoDepthTestingDepthStencilState(); - depth_state.test_enable = z_enable ? VK_TRUE : VK_FALSE; - depth_state.write_enable = z_enable ? VK_TRUE : VK_FALSE; - depth_state.compare_op = VK_COMPARE_OP_ALWAYS; + DepthState depth_state = Util::GetNoDepthTestingDepthStencilState(); + depth_state.testenable = z_enable; + depth_state.updateenable = z_enable; + depth_state.func = ZMode::ALWAYS; RasterizationState rs_state = Util::GetNoCullRasterizationState(); rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; @@ -476,7 +476,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha g_shader_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader); draw.SetRasterizationState(rs_state); - draw.SetDepthStencilState(depth_state); + draw.SetDepthState(depth_state); draw.SetBlendState(blend_state); draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(), @@ -1303,45 +1303,9 @@ void Renderer::SetGenerationMode() StateTracker::GetInstance()->SetRasterizationState(new_rs_state); } -void Renderer::SetDepthMode() +void Renderer::SetDepthState(const DepthState& state) { - DepthStencilState new_ds_state = {}; - new_ds_state.test_enable = bpmem.zmode.testenable ? VK_TRUE : VK_FALSE; - new_ds_state.write_enable = bpmem.zmode.updateenable ? VK_TRUE : VK_FALSE; - - // Inverted depth, hence these are swapped - switch (bpmem.zmode.func) - { - case ZMode::NEVER: - new_ds_state.compare_op = VK_COMPARE_OP_NEVER; - break; - case ZMode::LESS: - new_ds_state.compare_op = VK_COMPARE_OP_GREATER; - break; - case ZMode::EQUAL: - new_ds_state.compare_op = VK_COMPARE_OP_EQUAL; - break; - case ZMode::LEQUAL: - new_ds_state.compare_op = VK_COMPARE_OP_GREATER_OR_EQUAL; - break; - case ZMode::GREATER: - new_ds_state.compare_op = VK_COMPARE_OP_LESS; - break; - case ZMode::NEQUAL: - new_ds_state.compare_op = VK_COMPARE_OP_NOT_EQUAL; - break; - case ZMode::GEQUAL: - new_ds_state.compare_op = VK_COMPARE_OP_LESS_OR_EQUAL; - break; - case ZMode::ALWAYS: - new_ds_state.compare_op = VK_COMPARE_OP_ALWAYS; - break; - default: - new_ds_state.compare_op = VK_COMPARE_OP_ALWAYS; - break; - } - - StateTracker::GetInstance()->SetDepthStencilState(new_ds_state); + StateTracker::GetInstance()->SetDepthState(state); } void Renderer::SetBlendingState(const BlendingState& state) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 5ec1be8277..12272e57a0 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -59,7 +59,7 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; void SetGenerationMode() override; - void SetDepthMode() override; + void SetDepthState(const DepthState& state) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp index 7d5c3e2379..fb62560ad9 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp @@ -122,16 +122,21 @@ GetVulkanMultisampleState(const RasterizationState& rs_state) }; } -static VkPipelineDepthStencilStateCreateInfo -GetVulkanDepthStencilState(const DepthStencilState& state) +static VkPipelineDepthStencilStateCreateInfo GetVulkanDepthStencilState(const DepthState& state) { + // Less/greater are swapped due to inverted depth. + static constexpr std::array funcs = { + {VK_COMPARE_OP_NEVER, VK_COMPARE_OP_GREATER, VK_COMPARE_OP_EQUAL, + VK_COMPARE_OP_GREATER_OR_EQUAL, VK_COMPARE_OP_LESS, VK_COMPARE_OP_NOT_EQUAL, + VK_COMPARE_OP_LESS_OR_EQUAL, VK_COMPARE_OP_ALWAYS}}; + return { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO, // VkStructureType sType nullptr, // const void* pNext 0, // VkPipelineDepthStencilStateCreateFlags flags - state.test_enable, // VkBool32 depthTestEnable - state.write_enable, // VkBool32 depthWriteEnable - state.compare_op, // VkCompareOp depthCompareOp + state.testenable, // VkBool32 depthTestEnable + state.updateenable, // VkBool32 depthWriteEnable + funcs[state.func], // VkCompareOp depthCompareOp VK_FALSE, // VkBool32 depthBoundsTestEnable VK_FALSE, // VkBool32 stencilTestEnable {}, // VkStencilOpState front diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.h b/Source/Core/VideoBackends/Vulkan/ShaderCache.h index 56f888d363..34813687f5 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.h +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.h @@ -49,7 +49,7 @@ struct PipelineInfo VkRenderPass render_pass; BlendingState blend_state; RasterizationState rasterization_state; - DepthStencilState depth_stencil_state; + DepthState depth_state; VkPrimitiveTopology primitive_topology; }; diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index ae583374e8..5e09f6838e 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -58,9 +58,9 @@ bool StateTracker::Initialize() m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE; m_pipeline_state.rasterization_state.per_sample_shading = VK_FALSE; m_pipeline_state.rasterization_state.depth_clamp = VK_FALSE; - m_pipeline_state.depth_stencil_state.test_enable = VK_TRUE; - m_pipeline_state.depth_stencil_state.write_enable = VK_TRUE; - m_pipeline_state.depth_stencil_state.compare_op = VK_COMPARE_OP_LESS; + m_pipeline_state.depth_state.testenable = true; + m_pipeline_state.depth_state.updateenable = true; + m_pipeline_state.depth_state.func = ZMode::ALWAYS; m_pipeline_state.blend_state.hex = 0; m_pipeline_state.blend_state.blendenable = false; m_pipeline_state.blend_state.srcfactor = BlendMode::ONE; @@ -167,7 +167,7 @@ void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info) SerializedPipelineUID sinfo; sinfo.blend_state_bits = info.blend_state.hex; sinfo.rasterizer_state_bits = info.rasterization_state.bits; - sinfo.depth_stencil_state_bits = info.depth_stencil_state.bits; + sinfo.depth_state_bits = info.depth_state.hex; sinfo.vertex_decl = m_pipeline_state.vertex_format->GetVertexDeclaration(); sinfo.vs_uid = m_vs_uid; sinfo.gs_uid = m_gs_uid; @@ -212,7 +212,7 @@ bool StateTracker::PrecachePipelineUID(const SerializedPipelineUID& uid) } pinfo.render_pass = m_load_render_pass; pinfo.rasterization_state.bits = uid.rasterizer_state_bits; - pinfo.depth_stencil_state.bits = uid.depth_stencil_state_bits; + pinfo.depth_state.hex = uid.depth_state_bits; pinfo.blend_state.hex = uid.blend_state_bits; pinfo.primitive_topology = uid.primitive_topology; @@ -316,12 +316,12 @@ void StateTracker::SetRasterizationState(const RasterizationState& state) m_dirty_flags |= DIRTY_FLAG_PIPELINE; } -void StateTracker::SetDepthStencilState(const DepthStencilState& state) +void StateTracker::SetDepthState(const DepthState& state) { - if (m_pipeline_state.depth_stencil_state.bits == state.bits) + if (m_pipeline_state.depth_state.hex == state.hex) return; - m_pipeline_state.depth_stencil_state.bits = state.bits; + m_pipeline_state.depth_state.hex = state.hex; m_dirty_flags |= DIRTY_FLAG_PIPELINE; } diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index 73da3ad646..8b0602ddb1 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -39,10 +39,7 @@ public: { return m_pipeline_state.rasterization_state; } - const DepthStencilState& GetDepthStencilState() const - { - return m_pipeline_state.depth_stencil_state; - } + const DepthState& GetDepthStencilState() const { return m_pipeline_state.depth_state; } const BlendingState& GetBlendState() const { return m_pipeline_state.blend_state; } void SetVertexBuffer(VkBuffer buffer, VkDeviceSize offset); void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); @@ -58,7 +55,7 @@ public: void DisableBackFaceCulling(); void SetRasterizationState(const RasterizationState& state); - void SetDepthStencilState(const DepthStencilState& state); + void SetDepthState(const DepthState& state); void SetBlendState(const BlendingState& state); bool CheckForShaderChanges(u32 gx_primitive_type); @@ -130,7 +127,7 @@ private: struct SerializedPipelineUID { u32 rasterizer_state_bits; - u32 depth_stencil_state_bits; + u32 depth_state_bits; u32 blend_state_bits; PortableVertexDeclaration vertex_decl; VertexShaderUid vs_uid; diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 9796811978..b935acd8ef 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -195,12 +195,12 @@ RasterizationState GetNoCullRasterizationState() return state; } -DepthStencilState GetNoDepthTestingDepthStencilState() +DepthState GetNoDepthTestingDepthStencilState() { - DepthStencilState state = {}; - state.test_enable = VK_FALSE; - state.write_enable = VK_FALSE; - state.compare_op = VK_COMPARE_OP_ALWAYS; + DepthState state = {}; + state.testenable = false; + state.updateenable = false; + state.func = ZMode::ALWAYS; return state; } @@ -346,7 +346,7 @@ UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer, m_pipeline_info.gs = geometry_shader; m_pipeline_info.ps = pixel_shader; m_pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits; - m_pipeline_info.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; + m_pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; } @@ -450,9 +450,9 @@ void UtilityShaderDraw::SetRasterizationState(const RasterizationState& state) m_pipeline_info.rasterization_state.bits = state.bits; } -void UtilityShaderDraw::SetDepthStencilState(const DepthStencilState& state) +void UtilityShaderDraw::SetDepthState(const DepthState& state) { - m_pipeline_info.depth_stencil_state.bits = state.bits; + m_pipeline_info.depth_state.hex = state.hex; } void UtilityShaderDraw::SetBlendState(const BlendingState& state) diff --git a/Source/Core/VideoBackends/Vulkan/Util.h b/Source/Core/VideoBackends/Vulkan/Util.h index c99f0e968c..4f84d8a645 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.h +++ b/Source/Core/VideoBackends/Vulkan/Util.h @@ -39,7 +39,7 @@ VkRect2D ClampRect2D(const VkRect2D& rect, u32 width, u32 height); VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor); RasterizationState GetNoCullRasterizationState(); -DepthStencilState GetNoDepthTestingDepthStencilState(); +DepthState GetNoDepthTestingDepthStencilState(); BlendingState GetNoBlendingBlendState(); // Combines viewport and scissor updates @@ -151,7 +151,7 @@ public: void SetPSTexelBuffer(VkBufferView view); void SetRasterizationState(const RasterizationState& state); - void SetDepthStencilState(const DepthStencilState& state); + void SetDepthState(const DepthState& state); void SetBlendState(const BlendingState& state); void BeginRenderPass(VkFramebuffer framebuffer, const VkRect2D& region, diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index b74b6f84d4..a482f72fbd 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -68,12 +68,14 @@ void SetScissor() void SetDepthMode() { - g_renderer->SetDepthMode(); + DepthState state = {}; + state.Generate(bpmem); + g_renderer->SetDepthState(state); } void SetBlendMode() { - BlendingState state; + BlendingState state = {}; state.Generate(bpmem); g_renderer->SetBlendingState(state); } diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 7b7f43b7f6..838585323c 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -67,7 +67,7 @@ public: virtual void SetBlendingState(const BlendingState& state) {} virtual void SetScissorRect(const EFBRectangle& rc) {} virtual void SetGenerationMode() {} - virtual void SetDepthMode() {} + virtual void SetDepthState(const DepthState& state) {} virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} virtual void SetInterlacingMode() {} virtual void SetViewport() {} diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp index 7e6d845ccb..344ec5b32a 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -4,6 +4,13 @@ #include "VideoCommon/RenderState.h" +void DepthState::Generate(const BPMemory& bp) +{ + testenable = bp.zmode.testenable.Value(); + updateenable = bp.zmode.updateenable.Value(); + func = bp.zmode.func.Value(); +} + // If the framebuffer format has no alpha channel, it is assumed to // ONE on blending. As the backends may emulate this framebuffer // configuration with an alpha channel, we just drop all references diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h index 25a55ba17a..d1af098f25 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -9,6 +9,17 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/BPStructs.h" +union DepthState +{ + void Generate(const BPMemory& bp); + + BitField<0, 1, u32> testenable; + BitField<1, 1, u32> updateenable; + BitField<2, 3, ZMode::CompareMode> func; + + u32 hex; +}; + union BlendingState { void Generate(const BPMemory& bp); From 836b9b9acbc2ff2d10d6f3c81e64b7b10b22f023 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sun, 30 Apr 2017 18:07:57 +1000 Subject: [PATCH 3/7] Renderer: Move cull mode to a rasterization state object Also moves logic for primitive handling to VideoCommon. --- Source/Core/VideoBackends/D3D/D3DState.cpp | 28 ++- Source/Core/VideoBackends/D3D/D3DState.h | 12 +- .../VideoBackends/D3D/GeometryShaderCache.cpp | 2 +- .../VideoBackends/D3D/GeometryShaderCache.h | 2 +- Source/Core/VideoBackends/D3D/Render.cpp | 31 +-- Source/Core/VideoBackends/D3D/Render.h | 5 +- .../Core/VideoBackends/D3D/VertexManager.cpp | 18 -- .../Core/VideoBackends/Null/ShaderCache.cpp | 2 +- Source/Core/VideoBackends/Null/ShaderCache.h | 10 +- .../VideoBackends/OGL/ProgramShaderCache.cpp | 17 +- .../VideoBackends/OGL/ProgramShaderCache.h | 6 +- Source/Core/VideoBackends/OGL/Render.cpp | 8 +- Source/Core/VideoBackends/OGL/Render.h | 2 +- .../Core/VideoBackends/OGL/VertexManager.cpp | 17 +- .../VideoBackends/Software/SWVertexLoader.cpp | 20 +- Source/Core/VideoBackends/Vulkan/Constants.h | 13 +- .../Vulkan/FramebufferManager.cpp | 191 ++++++++++-------- .../VideoBackends/Vulkan/FramebufferManager.h | 17 +- .../Core/VideoBackends/Vulkan/RasterFont.cpp | 6 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 41 +--- Source/Core/VideoBackends/Vulkan/Renderer.h | 2 +- .../Core/VideoBackends/Vulkan/ShaderCache.cpp | 87 ++++---- .../Core/VideoBackends/Vulkan/ShaderCache.h | 2 +- .../VideoBackends/Vulkan/StateTracker.cpp | 63 ++---- .../Core/VideoBackends/Vulkan/StateTracker.h | 10 +- .../VideoBackends/Vulkan/TextureConverter.cpp | 6 +- Source/Core/VideoBackends/Vulkan/Util.cpp | 39 ++-- Source/Core/VideoBackends/Vulkan/Util.h | 10 +- .../VideoBackends/Vulkan/VertexManager.cpp | 28 +-- Source/Core/VideoCommon/BPFunctions.cpp | 4 +- Source/Core/VideoCommon/GeometryShaderGen.cpp | 41 ++-- Source/Core/VideoCommon/GeometryShaderGen.h | 5 +- Source/Core/VideoCommon/RenderBase.h | 2 +- Source/Core/VideoCommon/RenderState.cpp | 10 + Source/Core/VideoCommon/RenderState.h | 18 ++ Source/Core/VideoCommon/VertexManagerBase.cpp | 51 +++-- Source/Core/VideoCommon/VertexManagerBase.h | 12 +- Source/Core/VideoCommon/VideoConfig.h | 1 + 38 files changed, 389 insertions(+), 450 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index fe1337918d..7664eb9938 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -434,25 +434,27 @@ ID3D11BlendState* StateCache::Get(BlendingState state) return res; } -ID3D11RasterizerState* StateCache::Get(RasterizerState state) +ID3D11RasterizerState* StateCache::Get(RasterizationState state) { - auto it = m_raster.find(state.packed); - + auto it = m_raster.find(state.hex); if (it != m_raster.end()) return it->second; - D3D11_RASTERIZER_DESC rastdc = CD3D11_RASTERIZER_DESC(D3D11_FILL_SOLID, state.cull_mode, false, 0, - 0.f, 0, false, true, false, false); + static constexpr std::array cull_modes = { + {D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_BACK}}; + + D3D11_RASTERIZER_DESC desc = {}; + desc.FillMode = D3D11_FILL_SOLID; + desc.CullMode = cull_modes[state.cullmode]; + desc.ScissorEnable = TRUE; ID3D11RasterizerState* res = nullptr; - - HRESULT hr = D3D::device->CreateRasterizerState(&rastdc, &res); + HRESULT hr = D3D::device->CreateRasterizerState(&desc, &res); if (FAILED(hr)) PanicAlert("Failed to create rasterizer state at %s %d\n", __FILE__, __LINE__); D3D::SetDebugObjectName(res, "rasterizer state used to emulate the GX pipeline"); - m_raster.emplace(state.packed, res); - + m_raster.emplace(state.hex, res); return res; } @@ -531,4 +533,12 @@ void StateCache::Clear() m_sampler.clear(); } +D3D11_PRIMITIVE_TOPOLOGY StateCache::GetPrimitiveTopology(PrimitiveType primitive) +{ + static constexpr std::array primitives = { + {D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, D3D11_PRIMITIVE_TOPOLOGY_LINELIST, + D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP}}; + return primitives[static_cast(primitive)]; +} + } // namespace DX11 diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 30b018c114..1c9e0fa0fb 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -20,13 +20,6 @@ struct ID3D11RasterizerState; namespace DX11 { -union RasterizerState -{ - BitField<0, 2, D3D11_CULL_MODE> cull_mode; - - u32 packed; -}; - union SamplerState { BitField<0, 3, u64> min_filter; @@ -48,12 +41,15 @@ public: // Returned objects is owned by the cache and does not need to be released. ID3D11SamplerState* Get(SamplerState state); ID3D11BlendState* Get(BlendingState state); - ID3D11RasterizerState* Get(RasterizerState state); + ID3D11RasterizerState* Get(RasterizationState state); ID3D11DepthStencilState* Get(DepthState state); // Release all cached states and clear hash tables. void Clear(); + // Convert RasterState primitive type to D3D11 primitive topology. + static D3D11_PRIMITIVE_TOPOLOGY GetPrimitiveTopology(PrimitiveType primitive); + private: std::unordered_map m_depth; std::unordered_map m_raster; diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp index 5f4072022b..ecb8b7b1bb 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.cpp @@ -207,7 +207,7 @@ void GeometryShaderCache::Shutdown() g_gs_disk_cache.Close(); } -bool GeometryShaderCache::SetShader(u32 primitive_type) +bool GeometryShaderCache::SetShader(PrimitiveType primitive_type) { GeometryShaderUid uid = GetGeometryShaderUid(primitive_type); if (last_entry && uid == last_uid) diff --git a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h index 6bebf0a2a4..fdd3d053f2 100644 --- a/Source/Core/VideoBackends/D3D/GeometryShaderCache.h +++ b/Source/Core/VideoBackends/D3D/GeometryShaderCache.h @@ -18,7 +18,7 @@ public: static void Reload(); static void Clear(); static void Shutdown(); - static bool SetShader(u32 primitive_type); + static bool SetShader(PrimitiveType primitive_type); static bool CompileShader(const GeometryShaderUid& uid); static bool InsertByteCode(const GeometryShaderUid& uid, const u8* bytecode, size_t len); static void PrecompileShaders(); diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index 9877b8f0a5..dcf55d03c8 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -61,7 +61,7 @@ struct GXPipelineState std::array samplers; BlendingState blend; DepthState zmode; - RasterizerState raster; + RasterizationState raster; }; static u32 s_last_multisamples = 1; @@ -254,8 +254,7 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH s_gx_state.zmode.testenable = false; s_gx_state.zmode.updateenable = false; s_gx_state.zmode.func = ZMode::NEVER; - - s_gx_state.raster.cull_mode = D3D11_CULL_NONE; + s_gx_state.raster.cullmode = GenMode::CULL_NONE; // Clear EFB textures constexpr std::array clear_color{{0.f, 0.f, 0.f, 1.f}}; @@ -867,6 +866,8 @@ void Renderer::ApplyState() D3D::stateman->PushBlendState(s_gx_state_cache.Get(s_gx_state.blend)); D3D::stateman->PushDepthState(s_gx_state_cache.Get(s_gx_state.zmode)); D3D::stateman->PushRasterizerState(s_gx_state_cache.Get(s_gx_state.raster)); + D3D::stateman->SetPrimitiveTopology( + StateCache::GetPrimitiveTopology(s_gx_state.raster.primitive)); FramebufferManager::SetIntegerEFBRenderTarget(s_gx_state.blend.logicopenable); for (size_t stage = 0; stage < s_gx_state.samplers.size(); stage++) @@ -891,29 +892,9 @@ void Renderer::RestoreState() D3D::stateman->PopRasterizerState(); } -void Renderer::ApplyCullDisable() +void Renderer::SetRasterizationState(const RasterizationState& state) { - RasterizerState rast = s_gx_state.raster; - rast.cull_mode = D3D11_CULL_NONE; - - ID3D11RasterizerState* raststate = s_gx_state_cache.Get(rast); - D3D::stateman->PushRasterizerState(raststate); -} - -void Renderer::RestoreCull() -{ - D3D::stateman->PopRasterizerState(); -} - -void Renderer::SetGenerationMode() -{ - constexpr std::array d3d_cull_modes{{ - D3D11_CULL_NONE, D3D11_CULL_BACK, D3D11_CULL_FRONT, D3D11_CULL_BACK, - }}; - - // rastdc.FrontCounterClockwise must be false for this to work - // TODO: GX_CULL_ALL not supported, yet! - s_gx_state.raster.cull_mode = d3d_cull_modes[bpmem.genMode.cullmode]; + s_gx_state.raster.hex = state.hex; } void Renderer::SetDepthState(const DepthState& state) diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 8ca3b69396..2db2740fb0 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -21,7 +21,7 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; + void SetRasterizationState(const RasterizationState& state) override; void SetDepthState(const DepthState& state) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetInterlacingMode() override; @@ -33,9 +33,6 @@ public: void ApplyState() override; void RestoreState() override; - void ApplyCullDisable(); - void RestoreCull(); - void RenderText(const std::string& text, int left, int top, u32 color) override; u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) override; diff --git a/Source/Core/VideoBackends/D3D/VertexManager.cpp b/Source/Core/VideoBackends/D3D/VertexManager.cpp index 4edcf78165..d4aec17bf4 100644 --- a/Source/Core/VideoBackends/D3D/VertexManager.cpp +++ b/Source/Core/VideoBackends/D3D/VertexManager.cpp @@ -127,28 +127,10 @@ void VertexManager::Draw(u32 stride) u32 baseVertex = m_vertexDrawOffset / stride; u32 startIndex = m_indexDrawOffset / sizeof(u16); - switch (m_current_primitive_type) - { - case PRIMITIVE_POINTS: - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); - static_cast(g_renderer.get())->ApplyCullDisable(); - break; - case PRIMITIVE_LINES: - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); - static_cast(g_renderer.get())->ApplyCullDisable(); - break; - case PRIMITIVE_TRIANGLES: - D3D::stateman->SetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); - break; - } - D3D::stateman->Apply(); D3D::context->DrawIndexed(indices, startIndex, baseVertex); INCSTAT(stats.thisFrame.numDrawCalls); - - if (m_current_primitive_type != PRIMITIVE_TRIANGLES) - static_cast(g_renderer.get())->RestoreCull(); } void VertexManager::vFlush() diff --git a/Source/Core/VideoBackends/Null/ShaderCache.cpp b/Source/Core/VideoBackends/Null/ShaderCache.cpp index a8decc6f58..0a5ef30595 100644 --- a/Source/Core/VideoBackends/Null/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Null/ShaderCache.cpp @@ -33,7 +33,7 @@ void ShaderCache::Clear() } template -bool ShaderCache::SetShader(u32 primitive_type) +bool ShaderCache::SetShader(PrimitiveType primitive_type) { Uid uid = GetUid(primitive_type, APIType::OpenGL); diff --git a/Source/Core/VideoBackends/Null/ShaderCache.h b/Source/Core/VideoBackends/Null/ShaderCache.h index 68627f9e2c..b55185c952 100644 --- a/Source/Core/VideoBackends/Null/ShaderCache.h +++ b/Source/Core/VideoBackends/Null/ShaderCache.h @@ -22,10 +22,10 @@ public: virtual ~ShaderCache(); void Clear(); - bool SetShader(u32 primitive_type); + bool SetShader(PrimitiveType primitive_type); protected: - virtual Uid GetUid(u32 primitive_type, APIType api_type) = 0; + virtual Uid GetUid(PrimitiveType primitive_type, APIType api_type) = 0; virtual ShaderCode GenerateCode(APIType api_type, Uid uid) = 0; private: @@ -40,7 +40,7 @@ public: static std::unique_ptr s_instance; protected: - VertexShaderUid GetUid(u32 primitive_type, APIType api_type) override + VertexShaderUid GetUid(PrimitiveType primitive_type, APIType api_type) override { return GetVertexShaderUid(); } @@ -56,7 +56,7 @@ public: static std::unique_ptr s_instance; protected: - GeometryShaderUid GetUid(u32 primitive_type, APIType api_type) override + GeometryShaderUid GetUid(PrimitiveType primitive_type, APIType api_type) override { return GetGeometryShaderUid(primitive_type); } @@ -72,7 +72,7 @@ public: static std::unique_ptr s_instance; protected: - PixelShaderUid GetUid(u32 primitive_type, APIType api_type) override + PixelShaderUid GetUid(PrimitiveType primitive_type, APIType api_type) override { return GetPixelShaderUid(); } diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index 5617a928a9..c82a0cba01 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -221,7 +221,8 @@ void ProgramShaderCache::UploadConstants() } } -SHADER* ProgramShaderCache::SetShader(u32 primitive_type, const GLVertexFormat* vertex_format) +SHADER* ProgramShaderCache::SetShader(PrimitiveType primitive_type, + const GLVertexFormat* vertex_format) { if (g_ActiveConfig.bDisableSpecializedShaders) return SetUberShader(primitive_type, vertex_format); @@ -292,7 +293,8 @@ SHADER* ProgramShaderCache::SetShader(u32 primitive_type, const GLVertexFormat* return &last_entry->shader; } -SHADER* ProgramShaderCache::SetUberShader(u32 primitive_type, const GLVertexFormat* vertex_format) +SHADER* ProgramShaderCache::SetUberShader(PrimitiveType primitive_type, + const GLVertexFormat* vertex_format) { UBERSHADERUID uid; std::memset(&uid, 0, sizeof(uid)); @@ -1295,7 +1297,7 @@ void ProgramShaderCache::DestroyPrerenderArrays(SharedContextData* data) } } -void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, u32 primitive_type) +void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, PrimitiveType primitive_type) { // This is called on a worker thread, so we don't want to use the normal binding process. glUseProgram(shader.glprogid); @@ -1303,15 +1305,18 @@ void ProgramShaderCache::DrawPrerenderArray(const SHADER& shader, u32 primitive_ // The number of primitives drawn depends on the type. switch (primitive_type) { - case PRIMITIVE_POINTS: + case PrimitiveType::Points: glDrawElements(GL_POINTS, 1, GL_UNSIGNED_SHORT, nullptr); break; - case PRIMITIVE_LINES: + case PrimitiveType::Lines: glDrawElements(GL_LINES, 2, GL_UNSIGNED_SHORT, nullptr); break; - case PRIMITIVE_TRIANGLES: + case PrimitiveType::Triangles: glDrawElements(GL_TRIANGLES, 3, GL_UNSIGNED_SHORT, nullptr); break; + case PrimitiveType::TriangleStrip: + glDrawElements(GL_TRIANGLE_STRIP, 3, GL_UNSIGNED_SHORT, nullptr); + break; } // Has to be finished by the time the main thread picks it up. diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h index d45b2e4cbb..83f9d0e817 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.h +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.h @@ -94,8 +94,8 @@ public: }; static PCacheEntry GetShaderProgram(); - static SHADER* SetShader(u32 primitive_type, const GLVertexFormat* vertex_format); - static SHADER* SetUberShader(u32 primitive_type, const GLVertexFormat* vertex_format); + static SHADER* SetShader(PrimitiveType primitive_type, const GLVertexFormat* vertex_format); + static SHADER* SetUberShader(PrimitiveType primitive_type, const GLVertexFormat* vertex_format); static void BindVertexFormat(const GLVertexFormat* vertex_format); static void InvalidateVertexFormat(); static void BindLastVertexFormat(); @@ -198,7 +198,7 @@ private: static void DestroyShaders(); static void CreatePrerenderArrays(SharedContextData* data); static void DestroyPrerenderArrays(SharedContextData* data); - static void DrawPrerenderArray(const SHADER& shader, u32 primitive_type); + static void DrawPrerenderArray(const SHADER& shader, PrimitiveType primitive_type); static PCache pshaders; static UberPCache ubershaders; diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index 0ac9f03a06..b3535709f2 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1785,7 +1785,7 @@ void Renderer::RestoreAPIState() glEnable(GL_CLIP_DISTANCE0); glEnable(GL_CLIP_DISTANCE1); } - SetGenerationMode(); + BPFunctions::SetGenerationMode(); BPFunctions::SetScissor(); BPFunctions::SetDepthMode(); BPFunctions::SetBlendMode(); @@ -1798,14 +1798,14 @@ void Renderer::RestoreAPIState() OGLTexture::SetStage(); } -void Renderer::SetGenerationMode() +void Renderer::SetRasterizationState(const RasterizationState& state) { // none, ccw, cw, ccw - if (bpmem.genMode.cullmode > 0) + if (state.cullmode != GenMode::CULL_NONE) { // TODO: GX_CULL_ALL not supported, yet! glEnable(GL_CULL_FACE); - glFrontFace(bpmem.genMode.cullmode == 2 ? GL_CCW : GL_CW); + glFrontFace(state.cullmode == GenMode::CULL_FRONT ? GL_CCW : GL_CW); } else { diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index c89abea63f..e52a1193e1 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -79,7 +79,7 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; + void SetRasterizationState(const RasterizationState& state) override; void SetDepthState(const DepthState& state) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetInterlacingMode() override; diff --git a/Source/Core/VideoBackends/OGL/VertexManager.cpp b/Source/Core/VideoBackends/OGL/VertexManager.cpp index 19b9734be2..fd005e4860 100644 --- a/Source/Core/VideoBackends/OGL/VertexManager.cpp +++ b/Source/Core/VideoBackends/OGL/VertexManager.cpp @@ -114,17 +114,17 @@ void VertexManager::Draw(u32 stride) switch (m_current_primitive_type) { - case PRIMITIVE_POINTS: + case PrimitiveType::Points: primitive_mode = GL_POINTS; - glDisable(GL_CULL_FACE); break; - case PRIMITIVE_LINES: + case PrimitiveType::Lines: primitive_mode = GL_LINES; - glDisable(GL_CULL_FACE); break; - case PRIMITIVE_TRIANGLES: - primitive_mode = - g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? GL_TRIANGLE_STRIP : GL_TRIANGLES; + case PrimitiveType::Triangles: + primitive_mode = GL_TRIANGLES; + break; + case PrimitiveType::TriangleStrip: + primitive_mode = GL_TRIANGLE_STRIP; break; } @@ -140,9 +140,6 @@ void VertexManager::Draw(u32 stride) } INCSTAT(stats.thisFrame.numDrawCalls); - - if (m_current_primitive_type != PRIMITIVE_TRIANGLES) - static_cast(g_renderer.get())->SetGenerationMode(); } void VertexManager::vFlush() diff --git a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp index 5442785934..a00fc057d8 100644 --- a/Source/Core/VideoBackends/Software/SWVertexLoader.cpp +++ b/Source/Core/VideoBackends/Software/SWVertexLoader.cpp @@ -62,16 +62,17 @@ void SWVertexLoader::vFlush() u8 primitiveType = 0; switch (m_current_primitive_type) { - case PRIMITIVE_POINTS: + case PrimitiveType::Points: primitiveType = OpcodeDecoder::GX_DRAW_POINTS; break; - case PRIMITIVE_LINES: + case PrimitiveType::Lines: primitiveType = OpcodeDecoder::GX_DRAW_LINES; break; - case PRIMITIVE_TRIANGLES: - primitiveType = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? - OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP : - OpcodeDecoder::GX_DRAW_TRIANGLES; + case PrimitiveType::Triangles: + primitiveType = OpcodeDecoder::GX_DRAW_TRIANGLES; + break; + case PrimitiveType::TriangleStrip: + primitiveType = OpcodeDecoder::GX_DRAW_TRIANGLE_STRIP; break; } @@ -89,13 +90,6 @@ void SWVertexLoader::vFlush() for (u32 i = 0; i < IndexGenerator::GetIndexLen(); i++) { const u16 index = m_local_index_buffer[i]; - - if (index == 0xffff) - { - // primitive restart - m_setup_unit.Init(primitiveType); - continue; - } memset(&m_vertex, 0, sizeof(m_vertex)); // Super Mario Sunshine requires those to be zero for those debug boxes. diff --git a/Source/Core/VideoBackends/Vulkan/Constants.h b/Source/Core/VideoBackends/Vulkan/Constants.h index e51c54e18c..9086c1a690 100644 --- a/Source/Core/VideoBackends/Vulkan/Constants.h +++ b/Source/Core/VideoBackends/Vulkan/Constants.h @@ -124,15 +124,12 @@ constexpr u32 PUSH_CONSTANT_BUFFER_SIZE = 128; // Minimum number of draw calls per command buffer when attempting to preempt a readback operation. constexpr u32 MINIMUM_DRAW_CALLS_PER_COMMAND_BUFFER_FOR_READBACK = 10; -// Rasterization state info -union RasterizationState +// Multisampling state info that we don't expose in VideoCommon. +union MultisamplingState { - BitField<0, 2, VkCullModeFlags> cull_mode; - BitField<2, 7, VkSampleCountFlagBits> samples; - BitField<9, 1, VkBool32> per_sample_shading; - BitField<10, 1, VkBool32> depth_clamp; - - u32 bits; + BitField<0, 5, u32> samples; // 1-16 + BitField<0, 1, u32> per_sample_shading; // SSAA + u32 hex; }; // Sampler info diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 45d17a17e3..8a7745732f 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -61,6 +61,39 @@ FramebufferManager* FramebufferManager::GetInstance() return static_cast(g_framebuffer_manager.get()); } +u32 FramebufferManager::GetEFBWidth() const +{ + return m_efb_color_texture->GetWidth(); +} + +u32 FramebufferManager::GetEFBHeight() const +{ + return m_efb_color_texture->GetHeight(); +} + +u32 FramebufferManager::GetEFBLayers() const +{ + return m_efb_color_texture->GetLayers(); +} + +VkSampleCountFlagBits FramebufferManager::GetEFBSamples() const +{ + return m_efb_color_texture->GetSamples(); +} + +MultisamplingState FramebufferManager::GetEFBMultisamplingState() const +{ + MultisamplingState ms = {}; + ms.per_sample_shading = g_ActiveConfig.MultisamplingEnabled() && g_ActiveConfig.bSSAA; + ms.samples = static_cast(GetEFBSamples()); + return ms; +} + +std::pair FramebufferManager::GetTargetSize() const +{ + return std::make_pair(GetEFBWidth(), GetEFBHeight()); +} + bool FramebufferManager::Initialize() { if (!CreateEFBRenderPass()) @@ -117,22 +150,17 @@ bool FramebufferManager::Initialize() return true; } -std::pair FramebufferManager::GetTargetSize() const -{ - return std::make_pair(m_efb_width, m_efb_height); -} - bool FramebufferManager::CreateEFBRenderPass() { - m_efb_samples = static_cast(g_ActiveConfig.iMultisamples); + VkSampleCountFlagBits samples = static_cast(g_ActiveConfig.iMultisamples); // render pass for rendering to the efb VkAttachmentDescription attachments[] = { - {0, EFB_COLOR_TEXTURE_FORMAT, m_efb_samples, VK_ATTACHMENT_LOAD_OP_LOAD, + {0, EFB_COLOR_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL}, - {0, EFB_DEPTH_TEXTURE_FORMAT, m_efb_samples, VK_ATTACHMENT_LOAD_OP_LOAD, + {0, EFB_DEPTH_TEXTURE_FORMAT, samples, VK_ATTACHMENT_LOAD_OP_LOAD, VK_ATTACHMENT_STORE_OP_STORE, VK_ATTACHMENT_LOAD_OP_DONT_CARE, VK_ATTACHMENT_STORE_OP_DONT_CARE, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL}}; @@ -177,7 +205,7 @@ bool FramebufferManager::CreateEFBRenderPass() } // render pass for resolving depth, since we can't do it with vkCmdResolveImage - if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT) + if (g_ActiveConfig.MultisamplingEnabled()) { VkAttachmentDescription resolve_attachment = {0, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, @@ -228,30 +256,32 @@ void FramebufferManager::DestroyEFBRenderPass() bool FramebufferManager::CreateEFBFramebuffer() { - m_efb_width = static_cast(std::max(g_renderer->GetTargetWidth(), 1)); - m_efb_height = static_cast(std::max(g_renderer->GetTargetHeight(), 1)); - m_efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1; - INFO_LOG(VIDEO, "EFB size: %ux%ux%u", m_efb_width, m_efb_height, m_efb_layers); + u32 efb_width = static_cast(std::max(g_renderer->GetTargetWidth(), 1)); + u32 efb_height = static_cast(std::max(g_renderer->GetTargetHeight(), 1)); + u32 efb_layers = (g_ActiveConfig.iStereoMode != STEREO_OFF) ? 2 : 1; + VkSampleCountFlagBits efb_samples = + static_cast(g_ActiveConfig.iMultisamples); + INFO_LOG(VIDEO, "EFB size: %ux%ux%u", efb_width, efb_height, efb_layers); // Update the static variable in the base class. Why does this even exist? - FramebufferManagerBase::m_EFBLayers = m_efb_layers; + FramebufferManagerBase::m_EFBLayers = g_ActiveConfig.iMultisamples; // Allocate EFB render targets m_efb_color_texture = - Texture2D::Create(m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT, - m_efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, + Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); // We need a second texture to swap with for changing pixel formats m_efb_convert_color_texture = - Texture2D::Create(m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT, - m_efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, + Texture2D::Create(efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, efb_samples, + VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); m_efb_depth_texture = Texture2D::Create( - m_efb_width, m_efb_height, 1, m_efb_layers, EFB_DEPTH_TEXTURE_FORMAT, m_efb_samples, + efb_width, efb_height, 1, efb_layers, EFB_DEPTH_TEXTURE_FORMAT, efb_samples, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); @@ -260,16 +290,16 @@ bool FramebufferManager::CreateEFBFramebuffer() return false; // Create resolved textures if MSAA is on - if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT) + if (g_ActiveConfig.MultisamplingEnabled()) { m_efb_resolve_color_texture = Texture2D::Create( - m_efb_width, m_efb_height, 1, m_efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT, + efb_width, efb_height, 1, efb_layers, EFB_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); m_efb_resolve_depth_texture = Texture2D::Create( - m_efb_width, m_efb_height, 1, m_efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, + efb_width, efb_height, 1, efb_layers, EFB_DEPTH_AS_COLOR_TEXTURE_FORMAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_VIEW_TYPE_2D_ARRAY, VK_IMAGE_TILING_OPTIMAL, VK_IMAGE_USAGE_TRANSFER_SRC_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT); @@ -284,9 +314,9 @@ bool FramebufferManager::CreateEFBFramebuffer() m_depth_resolve_render_pass, 1, &attachment, - m_efb_width, - m_efb_height, - m_efb_layers}; + efb_width, + efb_height, + efb_layers}; VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, &m_depth_resolve_framebuffer); @@ -307,9 +337,9 @@ bool FramebufferManager::CreateEFBFramebuffer() m_efb_load_render_pass, static_cast(ArraySize(framebuffer_attachments)), framebuffer_attachments, - m_efb_width, - m_efb_height, - m_efb_layers}; + efb_width, + efb_height, + efb_layers}; VkResult res = vkCreateFramebuffer(g_vulkan_context->GetDevice(), &framebuffer_info, nullptr, &m_efb_framebuffer); @@ -338,8 +368,8 @@ bool FramebufferManager::CreateEFBFramebuffer() // Clear the contents of the buffers. static const VkClearColorValue clear_color = {{0.0f, 0.0f, 0.0f, 0.0f}}; static const VkClearDepthStencilValue clear_depth = {0.0f, 0}; - VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, m_efb_layers}; - VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, m_efb_layers}; + VkImageSubresourceRange clear_color_range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, efb_layers}; + VkImageSubresourceRange clear_depth_range = {VK_IMAGE_ASPECT_DEPTH_BIT, 0, 1, 0, efb_layers}; vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &clear_color_range); @@ -438,16 +468,12 @@ void FramebufferManager::ReinterpretPixelData(int convtype) m_efb_load_render_pass, g_shader_cache->GetScreenQuadVertexShader(), g_shader_cache->GetScreenQuadGeometryShader(), pixel_shader); - RasterizationState rs_state = Util::GetNoCullRasterizationState(); - rs_state.samples = m_efb_samples; - rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; - draw.SetRasterizationState(rs_state); - - VkRect2D region = {{0, 0}, {m_efb_width, m_efb_height}}; + VkRect2D region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; + draw.SetMultisamplingState(GetEFBMultisamplingState()); draw.BeginRenderPass(m_efb_convert_framebuffer, region); draw.SetPSSampler(0, m_efb_color_texture->GetView(), g_object_cache->GetPointSampler()); - draw.SetViewportAndScissor(0, 0, m_efb_width, m_efb_height); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.SetViewportAndScissor(0, 0, GetEFBWidth(), GetEFBHeight()); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); // Swap EFB texture pointers @@ -458,7 +484,7 @@ void FramebufferManager::ReinterpretPixelData(int convtype) Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region) { // Return the normal EFB texture if multisampling is off. - if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT) + if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT) return m_efb_color_texture.get(); // Can't resolve within a render pass. @@ -467,8 +493,8 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region) // It's not valid to resolve out-of-bounds coordinates. // Ensuring the region is within the image is the caller's responsibility. _assert_(region.offset.x >= 0 && region.offset.y >= 0 && - (static_cast(region.offset.x) + region.extent.width) <= m_efb_width && - (static_cast(region.offset.y) + region.extent.height) <= m_efb_height); + (static_cast(region.offset.x) + region.extent.width) <= GetEFBWidth() && + (static_cast(region.offset.y) + region.extent.height) <= GetEFBHeight()); // Resolving is considered to be a transfer operation. m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), @@ -478,11 +504,11 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region) // Resolve to our already-created texture. VkImageResolve resolve = { - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, m_efb_layers}, // VkImageSubresourceLayers srcSubresource - {region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset - {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, m_efb_layers}, // VkImageSubresourceLayers dstSubresource - {region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset - {region.extent.width, region.extent.height, m_efb_layers} // VkExtent3D extent + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers srcSubresource + {region.offset.x, region.offset.y, 0}, // VkOffset3D srcOffset + {VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, GetEFBLayers()}, // VkImageSubresourceLayers dstSubresource + {region.offset.x, region.offset.y, 0}, // VkOffset3D dstOffset + {region.extent.width, region.extent.height, GetEFBLayers()} // VkExtent3D extent }; vkCmdResolveImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, @@ -498,7 +524,7 @@ Texture2D* FramebufferManager::ResolveEFBColorTexture(const VkRect2D& region) Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region) { // Return the normal EFB texture if multisampling is off. - if (m_efb_samples == VK_SAMPLE_COUNT_1_BIT) + if (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT) return m_efb_depth_texture.get(); // Can't resolve within a render pass. @@ -516,7 +542,7 @@ Texture2D* FramebufferManager::ResolveEFBDepthTexture(const VkRect2D& region) draw.SetPSSampler(0, m_efb_depth_texture->GetView(), g_object_cache->GetPointSampler()); draw.SetViewportAndScissor(region.offset.x, region.offset.y, region.extent.width, region.extent.height); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); // Restore MSAA texture ready for rendering again @@ -646,11 +672,11 @@ bool FramebufferManager::CompileConversionShaders() m_ps_rgb8_to_rgba6 = Util::CompileAndCreateFragmentShader(header + RGB8_TO_RGBA6_SHADER_SOURCE); m_ps_rgba6_to_rgb8 = Util::CompileAndCreateFragmentShader(header + RGBA6_TO_RGB8_SHADER_SOURCE); - if (m_efb_samples != VK_SAMPLE_COUNT_1_BIT) + if (GetEFBSamples() != VK_SAMPLE_COUNT_1_BIT) m_ps_depth_resolve = Util::CompileAndCreateFragmentShader(header + DEPTH_RESOLVE_SHADER_SOURCE); return (m_ps_rgba6_to_rgb8 != VK_NULL_HANDLE && m_ps_rgb8_to_rgba6 != VK_NULL_HANDLE && - (m_efb_samples == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE)); + (GetEFBSamples() == VK_SAMPLE_COUNT_1_BIT || m_ps_depth_resolve != VK_NULL_HANDLE)); } void FramebufferManager::DestroyConversionShaders() @@ -685,13 +711,13 @@ bool FramebufferManager::PopulateColorReadbackTexture() StateTracker::GetInstance()->OnReadback(); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. - VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}}; + VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; Texture2D* src_texture = m_efb_color_texture.get(); VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_COLOR_BIT; - if (m_efb_samples > 1) + if (GetEFBSamples() > 1) src_texture = ResolveEFBColorTexture(src_region); - if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT) + if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT) { m_color_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -709,7 +735,7 @@ bool FramebufferManager::PopulateColorReadbackTexture() VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler()); draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); // Restore EFB to color attachment, since we're done with it. @@ -765,16 +791,16 @@ bool FramebufferManager::PopulateDepthReadbackTexture() StateTracker::GetInstance()->OnReadback(); // Issue a copy from framebuffer -> copy texture if we have >1xIR or MSAA on. - VkRect2D src_region = {{0, 0}, {m_efb_width, m_efb_height}}; + VkRect2D src_region = {{0, 0}, {GetEFBWidth(), GetEFBHeight()}}; Texture2D* src_texture = m_efb_depth_texture.get(); VkImageAspectFlags src_aspect = VK_IMAGE_ASPECT_DEPTH_BIT; - if (m_efb_samples > 1) + if (GetEFBSamples() > 1) { // EFB depth resolves are written out as color textures src_texture = ResolveEFBDepthTexture(src_region); src_aspect = VK_IMAGE_ASPECT_COLOR_BIT; } - if (m_efb_width != EFB_WIDTH || m_efb_height != EFB_HEIGHT) + if (GetEFBWidth() != EFB_WIDTH || GetEFBHeight() != EFB_HEIGHT) { m_depth_copy_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); @@ -792,7 +818,7 @@ bool FramebufferManager::PopulateDepthReadbackTexture() VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); draw.SetPSSampler(0, src_texture->GetView(), g_object_cache->GetPointSampler()); draw.SetViewportAndScissor(0, 0, EFB_WIDTH, EFB_HEIGHT); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); // Restore EFB to depth attachment, since we're done with it. @@ -905,12 +931,12 @@ bool FramebufferManager::CreateReadbackRenderPasses() g_vulkan_context->GetDeviceLimits().pointSizeRange[0] > 1 || g_vulkan_context->GetDeviceLimits().pointSizeRange[1] < 16) { - m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP; + m_poke_primitive = PrimitiveType::TriangleStrip; } else { // Points should be okay. - m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; + m_poke_primitive = PrimitiveType::Points; } return true; @@ -1108,29 +1134,28 @@ void FramebufferManager::PokeEFBDepth(u32 x, u32 y, float depth) void FramebufferManager::CreatePokeVertices(std::vector* destination_list, u32 x, u32 y, float z, u32 color) { - // Some devices don't support point sizes >1 (e.g. Adreno). - if (m_poke_primitive_topology == VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP) - { - // generate quad from the single point (clip-space coordinates) - float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f; - float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f; - float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f; - float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f; - destination_list->push_back({{x1, y1, z, 1.0f}, color}); - destination_list->push_back({{x2, y1, z, 1.0f}, color}); - destination_list->push_back({{x1, y2, z, 1.0f}, color}); - destination_list->push_back({{x1, y2, z, 1.0f}, color}); - destination_list->push_back({{x2, y1, z, 1.0f}, color}); - destination_list->push_back({{x2, y2, z, 1.0f}, color}); - } - else + if (m_poke_primitive == PrimitiveType::Points) { // GPU will expand the point to a quad. float cs_x = float(x) * 2.0f / EFB_WIDTH - 1.0f; float cs_y = float(y) * 2.0f / EFB_HEIGHT - 1.0f; - float point_size = m_efb_width / static_cast(EFB_WIDTH); + float point_size = GetEFBWidth() / static_cast(EFB_WIDTH); destination_list->push_back({{cs_x, cs_y, z, point_size}, color}); + return; } + + // Some devices don't support point sizes >1 (e.g. Adreno). + // Generate quad from the single point (clip-space coordinates). + float x1 = float(x) * 2.0f / EFB_WIDTH - 1.0f; + float y1 = float(y) * 2.0f / EFB_HEIGHT - 1.0f; + float x2 = float(x + 1) * 2.0f / EFB_WIDTH - 1.0f; + float y2 = float(y + 1) * 2.0f / EFB_HEIGHT - 1.0f; + destination_list->push_back({{x1, y1, z, 1.0f}, color}); + destination_list->push_back({{x2, y1, z, 1.0f}, color}); + destination_list->push_back({{x1, y2, z, 1.0f}, color}); + destination_list->push_back({{x1, y2, z, 1.0f}, color}); + destination_list->push_back({{x2, y1, z, 1.0f}, color}); + destination_list->push_back({{x2, y2, z, 1.0f}, color}); } void FramebufferManager::FlushEFBPokes() @@ -1159,16 +1184,16 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t pipeline_info.vertex_format = m_poke_vertex_format.get(); pipeline_info.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); pipeline_info.vs = m_poke_vertex_shader; - pipeline_info.gs = (m_efb_layers > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE; + pipeline_info.gs = (GetEFBLayers() > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE; pipeline_info.ps = m_poke_fragment_shader; pipeline_info.render_pass = m_efb_load_render_pass; - pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits; - pipeline_info.rasterization_state.samples = m_efb_samples; + pipeline_info.rasterization_state.hex = Util::GetNoCullRasterizationState().hex; + pipeline_info.rasterization_state.primitive = m_poke_primitive; + pipeline_info.multisampling_state.hex = GetEFBMultisamplingState().hex; pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; pipeline_info.blend_state.colorupdate = write_color; pipeline_info.blend_state.alphaupdate = write_color; - pipeline_info.primitive_topology = m_poke_primitive_topology; if (write_depth) { pipeline_info.depth_state.testenable = true; @@ -1209,7 +1234,7 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t StateTracker::GetInstance()->EndClearRenderPass(); StateTracker::GetInstance()->BeginRenderPass(); StateTracker::GetInstance()->SetPendingRebind(); - Util::SetViewportAndScissor(command_buffer, 0, 0, m_efb_width, m_efb_height); + Util::SetViewportAndScissor(command_buffer, 0, 0, GetEFBWidth(), GetEFBHeight()); vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline); vkCmdBindVertexBuffers(command_buffer, 0, 1, &vb_buffer, &vb_offset); vkCmdDraw(command_buffer, static_cast(vertex_count), 1, 0, 0); @@ -1310,7 +1335,7 @@ bool FramebufferManager::CompilePokeShaders() )"; std::string source = g_shader_cache->GetUtilityShaderHeader(); - if (m_poke_primitive_topology == VK_PRIMITIVE_TOPOLOGY_POINT_LIST) + if (m_poke_primitive == PrimitiveType::Points) source += "#define USE_POINT_SIZE 1\n"; source += POKE_VERTEX_SHADER_SOURCE; m_poke_vertex_shader = Util::CompileAndCreateVertexShader(source); diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h index db4455756d..ca7065c3bb 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.h +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.h @@ -11,6 +11,7 @@ #include "VideoBackends/Vulkan/Constants.h" #include "VideoBackends/Vulkan/TextureCache.h" #include "VideoCommon/FramebufferManagerBase.h" +#include "VideoCommon/RenderState.h" namespace Vulkan { @@ -34,13 +35,14 @@ public: VkRenderPass GetEFBLoadRenderPass() const { return m_efb_load_render_pass; } VkRenderPass GetEFBClearRenderPass() const { return m_efb_clear_render_pass; } - u32 GetEFBWidth() const { return m_efb_width; } - u32 GetEFBHeight() const { return m_efb_height; } - u32 GetEFBLayers() const { return m_efb_layers; } - VkSampleCountFlagBits GetEFBSamples() const { return m_efb_samples; } Texture2D* GetEFBColorTexture() const { return m_efb_color_texture.get(); } Texture2D* GetEFBDepthTexture() const { return m_efb_depth_texture.get(); } VkFramebuffer GetEFBFramebuffer() const { return m_efb_framebuffer; } + u32 GetEFBWidth() const; + u32 GetEFBHeight() const; + u32 GetEFBLayers() const; + VkSampleCountFlagBits GetEFBSamples() const; + MultisamplingState GetEFBMultisamplingState() const; std::pair GetTargetSize() const override; std::unique_ptr CreateXFBSource(unsigned int target_width, @@ -124,11 +126,6 @@ private: VkRenderPass m_efb_clear_render_pass = VK_NULL_HANDLE; VkRenderPass m_depth_resolve_render_pass = VK_NULL_HANDLE; - u32 m_efb_width = 0; - u32 m_efb_height = 0; - u32 m_efb_layers = 1; - VkSampleCountFlagBits m_efb_samples = VK_SAMPLE_COUNT_1_BIT; - std::unique_ptr m_efb_color_texture; std::unique_ptr m_efb_convert_color_texture; std::unique_ptr m_efb_depth_texture; @@ -160,7 +157,7 @@ private: std::unique_ptr m_poke_vertex_stream_buffer; std::vector m_color_poke_vertices; std::vector m_depth_poke_vertices; - VkPrimitiveTopology m_poke_primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + PrimitiveType m_poke_primitive = PrimitiveType::TriangleStrip; VkRenderPass m_copy_color_render_pass = VK_NULL_HANDLE; VkRenderPass m_copy_depth_render_pass = VK_NULL_HANDLE; diff --git a/Source/Core/VideoBackends/Vulkan/RasterFont.cpp b/Source/Core/VideoBackends/Vulkan/RasterFont.cpp index 97ab4dd6d8..39534cbf5d 100644 --- a/Source/Core/VideoBackends/Vulkan/RasterFont.cpp +++ b/Source/Core/VideoBackends/Vulkan/RasterFont.cpp @@ -310,10 +310,10 @@ void RasterFont::PrintMultiLineText(VkRenderPass render_pass, const std::string& UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_PUSH_CONSTANT), - render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader); + render_pass, m_vertex_shader, VK_NULL_HANDLE, m_fragment_shader, + PrimitiveType::Triangles); - UtilityShaderVertex* vertices = - draw.ReserveVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, text.length() * 6); + UtilityShaderVertex* vertices = draw.ReserveVertices(text.length() * 6); size_t num_vertices = 0; if (!vertices) return; diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 97c23ca2ef..07c0242751 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -464,10 +464,6 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha depth_state.updateenable = z_enable; depth_state.func = ZMode::ALWAYS; - RasterizationState rs_state = Util::GetNoCullRasterizationState(); - rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; - rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples(); - // No need to start a new render pass, but we do need to restore viewport state UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD), @@ -475,7 +471,7 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha g_shader_cache->GetPassthroughVertexShader(), g_shader_cache->GetPassthroughGeometryShader(), m_clear_fragment_shader); - draw.SetRasterizationState(rs_state); + draw.SetMultisamplingState(FramebufferManager::GetInstance()->GetEFBMultisamplingState()); draw.SetDepthState(depth_state); draw.SetBlendState(blend_state); @@ -1227,13 +1223,8 @@ void Renderer::BindEFBToStateTracker() FramebufferManager::GetInstance()->GetEFBClearRenderPass()); StateTracker::GetInstance()->SetFramebuffer( FramebufferManager::GetInstance()->GetEFBFramebuffer(), framebuffer_size); - - // Update rasterization state with MSAA info - RasterizationState rs_state = {}; - rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits; - rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples(); - rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; - StateTracker::GetInstance()->SetRasterizationState(rs_state); + StateTracker::GetInstance()->SetMultisamplingstate( + FramebufferManager::GetInstance()->GetEFBMultisamplingState()); } void Renderer::ResizeEFBTextures() @@ -1276,31 +1267,9 @@ void Renderer::RestoreAPIState() StateTracker::GetInstance()->SetPendingRebind(); } -void Renderer::SetGenerationMode() +void Renderer::SetRasterizationState(const RasterizationState& state) { - RasterizationState new_rs_state = {}; - new_rs_state.bits = StateTracker::GetInstance()->GetRasterizationState().bits; - - switch (bpmem.genMode.cullmode) - { - case GenMode::CULL_NONE: - new_rs_state.cull_mode = VK_CULL_MODE_NONE; - break; - case GenMode::CULL_BACK: - new_rs_state.cull_mode = VK_CULL_MODE_BACK_BIT; - break; - case GenMode::CULL_FRONT: - new_rs_state.cull_mode = VK_CULL_MODE_FRONT_BIT; - break; - case GenMode::CULL_ALL: - new_rs_state.cull_mode = VK_CULL_MODE_FRONT_AND_BACK; - break; - default: - new_rs_state.cull_mode = VK_CULL_MODE_NONE; - break; - } - - StateTracker::GetInstance()->SetRasterizationState(new_rs_state); + StateTracker::GetInstance()->SetRasterizationState(state); } void Renderer::SetDepthState(const DepthState& state) diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 12272e57a0..103c28a64e 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -58,7 +58,7 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; + void SetRasterizationState(const RasterizationState& state) override; void SetDepthState(const DepthState& state) override; void SetSamplerState(int stage, int texindex, bool custom_tex) override; void SetInterlacingMode() override; diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp index fb62560ad9..f32ca869ef 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp @@ -89,36 +89,43 @@ static bool IsStripPrimitiveTopology(VkPrimitiveTopology topology) static VkPipelineRasterizationStateCreateInfo GetVulkanRasterizationState(const RasterizationState& state) { + static constexpr std::array cull_modes = { + {VK_CULL_MODE_NONE, VK_CULL_MODE_BACK_BIT, VK_CULL_MODE_FRONT_BIT, + VK_CULL_MODE_FRONT_AND_BACK}}; + + bool depth_clamp = g_ActiveConfig.backend_info.bSupportsDepthClamp; + return { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkPipelineRasterizationStateCreateFlags flags - state.depth_clamp, // VkBool32 depthClampEnable - VK_FALSE, // VkBool32 rasterizerDiscardEnable - VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode - state.cull_mode, // VkCullModeFlags cullMode - VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace - VK_FALSE, // VkBool32 depthBiasEnable - 0.0f, // float depthBiasConstantFactor - 0.0f, // float depthBiasClamp - 0.0f, // float depthBiasSlopeFactor - 1.0f // float lineWidth + nullptr, // const void* pNext + 0, // VkPipelineRasterizationStateCreateFlags flags + depth_clamp, // VkBool32 depthClampEnable + VK_FALSE, // VkBool32 rasterizerDiscardEnable + VK_POLYGON_MODE_FILL, // VkPolygonMode polygonMode + cull_modes[state.cullmode], // VkCullModeFlags cullMode + VK_FRONT_FACE_CLOCKWISE, // VkFrontFace frontFace + VK_FALSE, // VkBool32 depthBiasEnable + 0.0f, // float depthBiasConstantFactor + 0.0f, // float depthBiasClamp + 0.0f, // float depthBiasSlopeFactor + 1.0f // float lineWidth }; } static VkPipelineMultisampleStateCreateInfo -GetVulkanMultisampleState(const RasterizationState& rs_state) +GetVulkanMultisampleState(const MultisamplingState& state) { return { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkPipelineMultisampleStateCreateFlags flags - rs_state.samples, // VkSampleCountFlagBits rasterizationSamples - rs_state.per_sample_shading, // VkBool32 sampleShadingEnable - 1.0f, // float minSampleShading - nullptr, // const VkSampleMask* pSampleMask; - VK_FALSE, // VkBool32 alphaToCoverageEnable - VK_FALSE // VkBool32 alphaToOneEnable + nullptr, // const void* pNext + 0, // VkPipelineMultisampleStateCreateFlags flags + static_cast( + state.samples.Value()), // VkSampleCountFlagBits rasterizationSamples + state.per_sample_shading, // VkBool32 sampleShadingEnable + 1.0f, // float minSampleShading + nullptr, // const VkSampleMask* pSampleMask; + VK_FALSE, // VkBool32 alphaToCoverageEnable + VK_FALSE // VkBool32 alphaToOneEnable }; } @@ -261,13 +268,13 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info) info.vertex_format ? info.vertex_format->GetVertexInputStateInfo() : empty_vertex_input_state; // Input assembly + static constexpr std::array vk_primitive_topologies = { + {VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, + VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST, VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP}}; VkPipelineInputAssemblyStateCreateInfo input_assembly_state = { - VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkPipelineInputAssemblyStateCreateFlags flags - info.primitive_topology, // VkPrimitiveTopology topology - VK_FALSE // VkBool32 primitiveRestartEnable - }; + VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO, nullptr, 0, + vk_primitive_topologies[static_cast(info.rasterization_state.primitive.Value())], + VK_FALSE}; // See Vulkan spec, section 19: // If topology is VK_PRIMITIVE_TOPOLOGY_POINT_LIST, VK_PRIMITIVE_TOPOLOGY_LINE_LIST, @@ -275,7 +282,7 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info) // VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST_WITH_ADJACENCY or VK_PRIMITIVE_TOPOLOGY_PATCH_LIST, // primitiveRestartEnable must be VK_FALSE if (g_ActiveConfig.backend_info.bSupportsPrimitiveRestart && - IsStripPrimitiveTopology(info.primitive_topology)) + IsStripPrimitiveTopology(input_assembly_state.topology)) { input_assembly_state.primitiveRestartEnable = VK_TRUE; } @@ -315,9 +322,9 @@ VkPipeline ShaderCache::CreatePipeline(const PipelineInfo& info) VkPipelineRasterizationStateCreateInfo rasterization_state = GetVulkanRasterizationState(info.rasterization_state); VkPipelineMultisampleStateCreateInfo multisample_state = - GetVulkanMultisampleState(info.rasterization_state); + GetVulkanMultisampleState(info.multisampling_state); VkPipelineDepthStencilStateCreateInfo depth_stencil_state = - GetVulkanDepthStencilState(info.depth_stencil_state); + GetVulkanDepthStencilState(info.depth_state); VkPipelineColorBlendAttachmentState blend_attachment_state = GetVulkanAttachmentBlendState(info.blend_state); VkPipelineColorBlendStateCreateInfo blend_state = @@ -1203,23 +1210,11 @@ void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid, VK_NULL_HANDLE; pinfo.ps = GetPixelUberShaderForUid(puid); pinfo.render_pass = FramebufferManager::GetInstance()->GetEFBLoadRenderPass(); - pinfo.rasterization_state.bits = Util::GetNoCullRasterizationState().bits; - pinfo.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; + pinfo.rasterization_state.hex = Util::GetNoCullRasterizationState().hex; + pinfo.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; pinfo.blend_state.hex = Util::GetNoBlendingBlendState().hex; - switch (guid.GetUidData()->primitive_type) - { - case PRIMITIVE_POINTS: - pinfo.primitive_topology = VK_PRIMITIVE_TOPOLOGY_POINT_LIST; - break; - case PRIMITIVE_LINES: - pinfo.primitive_topology = VK_PRIMITIVE_TOPOLOGY_LINE_LIST; - break; - case PRIMITIVE_TRIANGLES: - pinfo.primitive_topology = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP : - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; - break; - } + pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex; + pinfo.rasterization_state.primitive = guid.GetUidData()->primitive_type; GetPipelineWithCacheResultAsync(pinfo); } diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.h b/Source/Core/VideoBackends/Vulkan/ShaderCache.h index 34813687f5..4c0de4a94d 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.h +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.h @@ -50,7 +50,7 @@ struct PipelineInfo BlendingState blend_state; RasterizationState rasterization_state; DepthState depth_state; - VkPrimitiveTopology primitive_topology; + MultisamplingState multisampling_state; }; struct PipelineInfoHash diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index 5e09f6838e..ae76ea51c3 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.cpp +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp @@ -11,7 +11,6 @@ #include "VideoBackends/Vulkan/CommandBufferManager.h" #include "VideoBackends/Vulkan/Constants.h" -#include "VideoBackends/Vulkan/FramebufferManager.h" #include "VideoBackends/Vulkan/ObjectCache.h" #include "VideoBackends/Vulkan/ShaderCache.h" #include "VideoBackends/Vulkan/StreamBuffer.h" @@ -54,26 +53,6 @@ void StateTracker::DestroyInstance() bool StateTracker::Initialize() { - // Set some sensible defaults - m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE; - m_pipeline_state.rasterization_state.per_sample_shading = VK_FALSE; - m_pipeline_state.rasterization_state.depth_clamp = VK_FALSE; - m_pipeline_state.depth_state.testenable = true; - m_pipeline_state.depth_state.updateenable = true; - m_pipeline_state.depth_state.func = ZMode::ALWAYS; - m_pipeline_state.blend_state.hex = 0; - m_pipeline_state.blend_state.blendenable = false; - m_pipeline_state.blend_state.srcfactor = BlendMode::ONE; - m_pipeline_state.blend_state.srcfactoralpha = BlendMode::ONE; - m_pipeline_state.blend_state.dstfactor = BlendMode::ZERO; - m_pipeline_state.blend_state.dstfactoralpha = BlendMode::ZERO; - m_pipeline_state.blend_state.colorupdate = true; - m_pipeline_state.blend_state.alphaupdate = true; - - // Enable depth clamping if supported by driver. - if (g_ActiveConfig.backend_info.bSupportsDepthClamp) - m_pipeline_state.rasterization_state.depth_clamp = VK_TRUE; - // BBox is disabled by default. m_pipeline_state.pipeline_layout = g_object_cache->GetPipelineLayout(PIPELINE_LAYOUT_STANDARD); m_num_active_descriptor_sets = NUM_GX_DRAW_DESCRIPTOR_SETS; @@ -166,13 +145,12 @@ void StateTracker::AppendToPipelineUIDCache(const PipelineInfo& info) { SerializedPipelineUID sinfo; sinfo.blend_state_bits = info.blend_state.hex; - sinfo.rasterizer_state_bits = info.rasterization_state.bits; + sinfo.rasterizer_state_bits = info.rasterization_state.hex; sinfo.depth_state_bits = info.depth_state.hex; sinfo.vertex_decl = m_pipeline_state.vertex_format->GetVertexDeclaration(); sinfo.vs_uid = m_vs_uid; sinfo.gs_uid = m_gs_uid; sinfo.ps_uid = m_ps_uid; - sinfo.primitive_topology = info.primitive_topology; u32 dummy_value = 0; m_uid_cache.Append(sinfo, &dummy_value, 1); @@ -211,10 +189,10 @@ bool StateTracker::PrecachePipelineUID(const SerializedPipelineUID& uid) return false; } pinfo.render_pass = m_load_render_pass; - pinfo.rasterization_state.bits = uid.rasterizer_state_bits; + pinfo.rasterization_state.hex = uid.rasterizer_state_bits; pinfo.depth_state.hex = uid.depth_state_bits; pinfo.blend_state.hex = uid.blend_state_bits; - pinfo.primitive_topology = uid.primitive_topology; + pinfo.multisampling_state.hex = m_pipeline_state.multisampling_state.hex; if (g_ActiveConfig.bBackgroundShaderCompiling) { @@ -289,30 +267,21 @@ void StateTracker::SetVertexFormat(const VertexFormat* vertex_format) UpdatePipelineVertexFormat(); } -void StateTracker::SetPrimitiveTopology(VkPrimitiveTopology primitive_topology) -{ - if (m_pipeline_state.primitive_topology == primitive_topology) - return; - - m_pipeline_state.primitive_topology = primitive_topology; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - -void StateTracker::DisableBackFaceCulling() -{ - if (m_pipeline_state.rasterization_state.cull_mode == VK_CULL_MODE_NONE) - return; - - m_pipeline_state.rasterization_state.cull_mode = VK_CULL_MODE_NONE; - m_dirty_flags |= DIRTY_FLAG_PIPELINE; -} - void StateTracker::SetRasterizationState(const RasterizationState& state) { - if (m_pipeline_state.rasterization_state.bits == state.bits) + if (m_pipeline_state.rasterization_state.hex == state.hex) return; - m_pipeline_state.rasterization_state.bits = state.bits; + m_pipeline_state.rasterization_state.hex = state.hex; + m_dirty_flags |= DIRTY_FLAG_PIPELINE; +} + +void StateTracker::SetMultisamplingstate(const MultisamplingState& state) +{ + if (m_pipeline_state.multisampling_state.hex == state.hex) + return; + + m_pipeline_state.multisampling_state.hex = state.hex; m_dirty_flags |= DIRTY_FLAG_PIPELINE; } @@ -334,7 +303,7 @@ void StateTracker::SetBlendState(const BlendingState& state) m_dirty_flags |= DIRTY_FLAG_PIPELINE; } -bool StateTracker::CheckForShaderChanges(u32 gx_primitive_type) +bool StateTracker::CheckForShaderChanges() { VertexShaderUid vs_uid = GetVertexShaderUid(); PixelShaderUid ps_uid = GetPixelShaderUid(); @@ -418,7 +387,7 @@ bool StateTracker::CheckForShaderChanges(u32 gx_primitive_type) if (g_vulkan_context->SupportsGeometryShaders()) { - GeometryShaderUid gs_uid = GetGeometryShaderUid(gx_primitive_type); + GeometryShaderUid gs_uid = GetGeometryShaderUid(m_pipeline_state.rasterization_state.primitive); if (gs_uid != m_gs_uid) { m_gs_uid = gs_uid; diff --git a/Source/Core/VideoBackends/Vulkan/StateTracker.h b/Source/Core/VideoBackends/Vulkan/StateTracker.h index 8b0602ddb1..c3dbf5b7e8 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -45,20 +45,15 @@ public: void SetIndexBuffer(VkBuffer buffer, VkDeviceSize offset, VkIndexType type); void SetRenderPass(VkRenderPass load_render_pass, VkRenderPass clear_render_pass); - void SetFramebuffer(VkFramebuffer framebuffer, const VkRect2D& render_area); - void SetVertexFormat(const VertexFormat* vertex_format); - void SetPrimitiveTopology(VkPrimitiveTopology primitive_topology); - - void DisableBackFaceCulling(); - void SetRasterizationState(const RasterizationState& state); + void SetMultisamplingstate(const MultisamplingState& state); void SetDepthState(const DepthState& state); void SetBlendState(const BlendingState& state); - bool CheckForShaderChanges(u32 gx_primitive_type); + bool CheckForShaderChanges(); void ClearShaders(); void UpdateVertexShaderConstants(); @@ -133,7 +128,6 @@ private: VertexShaderUid vs_uid; GeometryShaderUid gs_uid; PixelShaderUid ps_uid; - VkPrimitiveTopology primitive_topology; }; // Number of descriptor sets for game draws. diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index fc5a7c20f2..eee9a13272 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -214,7 +214,7 @@ void TextureConverter::ConvertTexture(TextureCacheBase::TCacheEntry* dst_entry, g_object_cache->GetPointSampler()); draw.SetPSTexelBuffer(m_texel_buffer_view_r16_uint); draw.SetViewportAndScissor(0, 0, dst_entry->GetWidth(), dst_entry->GetHeight()); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); } @@ -261,7 +261,7 @@ void TextureConverter::EncodeTextureToMemory(VkImageView src_texture, u8* dest_p VkRect2D render_region = {{0, 0}, {render_width, render_height}}; draw.BeginRenderPass(m_encoding_render_framebuffer, render_region); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); // Transition the image before copying @@ -382,7 +382,7 @@ void TextureConverter::DecodeYUYVTextureFromMemory(VKTexture* dst_texture, const draw.SetViewportAndScissor(0, 0, static_cast(src_width), static_cast(src_height)); draw.SetPSTexelBuffer(m_texel_buffer_view_rgba8_unorm); draw.SetPushConstants(&push_constants, sizeof(push_constants)); - draw.DrawWithoutVertexBuffer(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, 4); + draw.DrawWithoutVertexBuffer(4); draw.EndRenderPass(); } diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index b935acd8ef..0f8c17c384 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -188,10 +188,7 @@ VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor) RasterizationState GetNoCullRasterizationState() { RasterizationState state = {}; - state.cull_mode = VK_CULL_MODE_NONE; - state.samples = VK_SAMPLE_COUNT_1_BIT; - state.per_sample_shading = VK_FALSE; - state.depth_clamp = VK_FALSE; + state.cullmode = GenMode::CULL_NONE; return state; } @@ -335,7 +332,7 @@ VkShaderModule CompileAndCreateComputeShader(const std::string& source_code, boo UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout, VkRenderPass render_pass, VkShaderModule vertex_shader, VkShaderModule geometry_shader, - VkShaderModule pixel_shader) + VkShaderModule pixel_shader, PrimitiveType primitive) : m_command_buffer(command_buffer) { // Populate minimal pipeline state @@ -345,16 +342,16 @@ UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer, m_pipeline_info.vs = vertex_shader; m_pipeline_info.gs = geometry_shader; m_pipeline_info.ps = pixel_shader; - m_pipeline_info.rasterization_state.bits = Util::GetNoCullRasterizationState().bits; + m_pipeline_info.rasterization_state.hex = Util::GetNoCullRasterizationState().hex; + m_pipeline_info.rasterization_state.primitive = primitive; m_pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; - m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + m_pipeline_info.multisampling_state.per_sample_shading = false; + m_pipeline_info.multisampling_state.samples = 1; } -UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(VkPrimitiveTopology topology, size_t count) +UtilityShaderVertex* UtilityShaderDraw::ReserveVertices(size_t count) { - m_pipeline_info.primitive_topology = topology; - if (!g_object_cache->GetUtilityShaderVertexBuffer()->ReserveMemory( sizeof(UtilityShaderVertex) * count, sizeof(UtilityShaderVertex), true, true, true)) PanicAlert("Failed to allocate space for vertices in backend shader"); @@ -372,10 +369,9 @@ void UtilityShaderDraw::CommitVertices(size_t count) m_vertex_count = static_cast(count); } -void UtilityShaderDraw::UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices, - size_t count) +void UtilityShaderDraw::UploadVertices(UtilityShaderVertex* vertices, size_t count) { - UtilityShaderVertex* upload_vertices = ReserveVertices(topology, count); + UtilityShaderVertex* upload_vertices = ReserveVertices(count); memcpy(upload_vertices, vertices, sizeof(UtilityShaderVertex) * count); CommitVertices(count); } @@ -447,7 +443,12 @@ void UtilityShaderDraw::SetPSTexelBuffer(VkBufferView view) void UtilityShaderDraw::SetRasterizationState(const RasterizationState& state) { - m_pipeline_info.rasterization_state.bits = state.bits; + m_pipeline_info.rasterization_state.hex = state.hex; +} + +void UtilityShaderDraw::SetMultisamplingState(const MultisamplingState& state) +{ + m_pipeline_info.multisampling_state.hex = state.hex; } void UtilityShaderDraw::SetDepthState(const DepthState& state) @@ -506,7 +507,7 @@ void UtilityShaderDraw::DrawQuad(int x, int y, int width, int height, float z) vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f); Util::SetViewportAndScissor(m_command_buffer, x, y, width, height); - UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices)); + UploadVertices(vertices, ArraySize(vertices)); Draw(); } @@ -535,7 +536,7 @@ void UtilityShaderDraw::DrawQuad(int dst_x, int dst_y, int dst_width, int dst_he vertices[3].SetColor(1.0f, 1.0f, 1.0f, 1.0f); Util::SetViewportAndScissor(m_command_buffer, dst_x, dst_y, dst_width, dst_height); - UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices)); + UploadVertices(vertices, ArraySize(vertices)); Draw(); } @@ -562,7 +563,7 @@ void UtilityShaderDraw::DrawColoredQuad(int x, int y, int width, int height, u32 vertices[3].SetColor(color); Util::SetViewportAndScissor(m_command_buffer, x, y, width, height); - UploadVertices(VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP, vertices, ArraySize(vertices)); + UploadVertices(vertices, ArraySize(vertices)); Draw(); } @@ -571,11 +572,9 @@ void UtilityShaderDraw::SetViewportAndScissor(int x, int y, int width, int heigh Util::SetViewportAndScissor(m_command_buffer, x, y, width, height, 0.0f, 1.0f); } -void UtilityShaderDraw::DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology, - u32 vertex_count) +void UtilityShaderDraw::DrawWithoutVertexBuffer(u32 vertex_count) { m_pipeline_info.vertex_format = nullptr; - m_pipeline_info.primitive_topology = primitive_topology; BindDescriptors(); if (!BindPipeline()) diff --git a/Source/Core/VideoBackends/Vulkan/Util.h b/Source/Core/VideoBackends/Vulkan/Util.h index 4f84d8a645..2cb253423f 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.h +++ b/Source/Core/VideoBackends/Vulkan/Util.h @@ -131,12 +131,13 @@ class UtilityShaderDraw public: UtilityShaderDraw(VkCommandBuffer command_buffer, VkPipelineLayout pipeline_layout, VkRenderPass render_pass, VkShaderModule vertex_shader, - VkShaderModule geometry_shader, VkShaderModule pixel_shader); + VkShaderModule geometry_shader, VkShaderModule pixel_shader, + PrimitiveType primitive = PrimitiveType::TriangleStrip); - UtilityShaderVertex* ReserveVertices(VkPrimitiveTopology topology, size_t count); + UtilityShaderVertex* ReserveVertices(size_t count); void CommitVertices(size_t count); - void UploadVertices(VkPrimitiveTopology topology, UtilityShaderVertex* vertices, size_t count); + void UploadVertices(UtilityShaderVertex* vertices, size_t count); u8* AllocateVSUniforms(size_t size); void CommitVSUniforms(size_t size); @@ -151,6 +152,7 @@ public: void SetPSTexelBuffer(VkBufferView view); void SetRasterizationState(const RasterizationState& state); + void SetMultisamplingState(const MultisamplingState& state); void SetDepthState(const DepthState& state); void SetBlendState(const BlendingState& state); @@ -177,7 +179,7 @@ public: // Draw without a vertex buffer. Assumes viewport has been initialized separately. void SetViewportAndScissor(int x, int y, int width, int height); - void DrawWithoutVertexBuffer(VkPrimitiveTopology primitive_topology, u32 vertex_count); + void DrawWithoutVertexBuffer(u32 vertex_count); private: void BindVertexBuffer(); diff --git a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp index a1d72f3011..c9aad0254c 100644 --- a/Source/Core/VideoBackends/Vulkan/VertexManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/VertexManager.cpp @@ -138,33 +138,9 @@ void VertexManager::vFlush() // Figure out the number of indices to draw u32 index_count = IndexGenerator::GetIndexLen(); - // Update assembly state + // Update tracked state StateTracker::GetInstance()->SetVertexFormat(vertex_format); - switch (m_current_primitive_type) - { - case PRIMITIVE_POINTS: - StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_POINT_LIST); - StateTracker::GetInstance()->DisableBackFaceCulling(); - break; - - case PRIMITIVE_LINES: - StateTracker::GetInstance()->SetPrimitiveTopology(VK_PRIMITIVE_TOPOLOGY_LINE_LIST); - StateTracker::GetInstance()->DisableBackFaceCulling(); - break; - - case PRIMITIVE_TRIANGLES: - StateTracker::GetInstance()->SetPrimitiveTopology( - g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_STRIP : - VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST); - g_renderer->SetGenerationMode(); - break; - } - - // Check for any shader stage changes - StateTracker::GetInstance()->CheckForShaderChanges(m_current_primitive_type); - - // Update any changed constants + StateTracker::GetInstance()->CheckForShaderChanges(); StateTracker::GetInstance()->UpdateVertexShaderConstants(); StateTracker::GetInstance()->UpdateGeometryShaderConstants(); StateTracker::GetInstance()->UpdatePixelShaderConstants(); diff --git a/Source/Core/VideoCommon/BPFunctions.cpp b/Source/Core/VideoCommon/BPFunctions.cpp index a482f72fbd..a937a9037e 100644 --- a/Source/Core/VideoCommon/BPFunctions.cpp +++ b/Source/Core/VideoCommon/BPFunctions.cpp @@ -27,7 +27,9 @@ void FlushPipeline() void SetGenerationMode() { - g_renderer->SetGenerationMode(); + RasterizationState state = {}; + state.Generate(bpmem, g_vertex_manager->GetCurrentPrimitiveType()); + g_renderer->SetRasterizationState(state); } void SetScissor() diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 4b06c0f7f3..4c6fb1c559 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -14,18 +14,18 @@ #include "VideoCommon/VideoConfig.h" #include "VideoCommon/XFMemory.h" -static const char* primitives_ogl[] = {"points", "lines", "triangles"}; - -static const char* primitives_d3d[] = {"point", "line", "triangle"}; +constexpr std::array primitives_ogl = { + {"points", "lines", "triangles", "triangles"}}; +constexpr std::array primitives_d3d = {{"point", "line", "triangle", "triangle"}}; bool geometry_shader_uid_data::IsPassthrough() const { const bool stereo = g_ActiveConfig.iStereoMode > 0; const bool wireframe = g_ActiveConfig.bWireFrame; - return primitive_type == PRIMITIVE_TRIANGLES && !stereo && !wireframe; + return primitive_type >= PrimitiveType::Triangles && !stereo && !wireframe; } -GeometryShaderUid GetGeometryShaderUid(u32 primitive_type) +GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type) { ShaderUid out; geometry_shader_uid_data* uid_data = out.GetUidData(); @@ -56,8 +56,9 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h const bool msaa = host_config.msaa; const bool ssaa = host_config.ssaa; const bool stereo = host_config.stereo; - const unsigned int vertex_in = uid_data->primitive_type + 1; - unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; + const unsigned primitive_type_index = static_cast(uid_data->primitive_type); + const unsigned vertex_in = std::min(static_cast(primitive_type_index) + 1, 3u); + unsigned vertex_out = uid_data->primitive_type == PrimitiveType::TriangleStrip ? 3 : 4; if (wireframe) vertex_out++; @@ -67,14 +68,14 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h // Insert layout parameters if (host_config.backend_gs_instancing) { - out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[uid_data->primitive_type], + out.Write("layout(%s, invocations = %d) in;\n", primitives_ogl[primitive_type_index], stereo ? 2 : 1); out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle", vertex_out); } else { - out.Write("layout(%s) in;\n", primitives_ogl[uid_data->primitive_type]); + out.Write("layout(%s) in;\n", primitives_ogl[primitive_type_index]); out.Write("layout(%s_strip, max_vertices = %d) out;\n", wireframe ? "line" : "triangle", stereo ? vertex_out * 2 : vertex_out); } @@ -133,21 +134,19 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h out.Write("[maxvertexcount(%d)]\n[instance(%d)]\n", vertex_out, stereo ? 2 : 1); out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output, in uint " "InstanceID : SV_GSInstanceID)\n{\n", - primitives_d3d[uid_data->primitive_type], vertex_in, - wireframe ? "Line" : "Triangle"); + primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle"); } else { out.Write("[maxvertexcount(%d)]\n", stereo ? vertex_out * 2 : vertex_out); out.Write("void main(%s VS_OUTPUT o[%d], inout %sStream output)\n{\n", - primitives_d3d[uid_data->primitive_type], vertex_in, - wireframe ? "Line" : "Triangle"); + primitives_d3d[primitive_type_index], vertex_in, wireframe ? "Line" : "Triangle"); } out.Write("\tVertexData ps;\n"); } - if (uid_data->primitive_type == PRIMITIVE_LINES) + if (uid_data->primitive_type == PrimitiveType::Lines) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -178,7 +177,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h "\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" "\t}\n"); } - else if (uid_data->primitive_type == PRIMITIVE_POINTS) + else if (uid_data->primitive_type == PrimitiveType::Points) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -248,7 +247,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h out.Write("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n"); } - if (uid_data->primitive_type == PRIMITIVE_LINES) + if (uid_data->primitive_type == PrimitiveType::Lines) { out.Write("\tVS_OUTPUT l = f;\n" "\tVS_OUTPUT r = f;\n"); @@ -269,7 +268,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true); EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting); } - else if (uid_data->primitive_type == PRIMITIVE_POINTS) + else if (uid_data->primitive_type == PrimitiveType::Points) { out.Write("\tVS_OUTPUT ll = f;\n" "\tVS_OUTPUT lr = f;\n" @@ -370,9 +369,11 @@ void EnumerateGeometryShaderUids(const std::function primitive_lut = { - {PRIMITIVE_TRIANGLES, PRIMITIVE_LINES, PRIMITIVE_POINTS}}; - for (u32 primitive : primitive_lut) + const std::array primitive_lut = { + {g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? PrimitiveType::TriangleStrip : + PrimitiveType::Triangles, + PrimitiveType::Lines, PrimitiveType::Points}}; + for (PrimitiveType primitive : primitive_lut) { auto* guid = uid.GetUidData(); guid->primitive_type = primitive; diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h index f138207e14..b23441f3d3 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.h +++ b/Source/Core/VideoCommon/GeometryShaderGen.h @@ -6,6 +6,7 @@ #include #include "Common/CommonTypes.h" +#include "VideoCommon/RenderState.h" #include "VideoCommon/ShaderGenCommon.h" #include "VideoCommon/VertexManagerBase.h" @@ -19,7 +20,7 @@ struct geometry_shader_uid_data bool IsPassthrough() const; u32 numTexGens : 4; - u32 primitive_type : 2; + PrimitiveType primitive_type : 2; }; #pragma pack() @@ -28,5 +29,5 @@ typedef ShaderUid GeometryShaderUid; ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& host_config, const geometry_shader_uid_data* uid_data); -GeometryShaderUid GetGeometryShaderUid(u32 primitive_type); +GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type); void EnumerateGeometryShaderUids(const std::function& callback); diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 838585323c..6c264cd04b 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -66,7 +66,7 @@ public: virtual void SetBlendingState(const BlendingState& state) {} virtual void SetScissorRect(const EFBRectangle& rc) {} - virtual void SetGenerationMode() {} + virtual void SetRasterizationState(const RasterizationState& state) {} virtual void SetDepthState(const DepthState& state) {} virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} virtual void SetInterlacingMode() {} diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp index 344ec5b32a..d019214206 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -4,6 +4,16 @@ #include "VideoCommon/RenderState.h" +void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_type) +{ + cullmode = bp.genMode.cullmode; + primitive = primitive_type; + + // Back-face culling should be disabled for points/lines. + if (primitive_type != PrimitiveType::Triangles && primitive_type != PrimitiveType::TriangleStrip) + cullmode = GenMode::CULL_NONE; +} + void DepthState::Generate(const BPMemory& bp) { testenable = bp.zmode.testenable.Value(); diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h index d1af098f25..03af1f1f3e 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -9,6 +9,24 @@ #include "VideoCommon/BPMemory.h" #include "VideoCommon/BPStructs.h" +enum class PrimitiveType : u32 +{ + Points, + Lines, + Triangles, + TriangleStrip, +}; + +union RasterizationState +{ + void Generate(const BPMemory& bp, PrimitiveType primitive_type); + + BitField<0, 2, GenMode::CullMode> cullmode; + BitField<3, 2, PrimitiveType> primitive; + + u32 hex; +}; + union DepthState { void Generate(const BPMemory& bp); diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 7807cdb98c..95f31f86a4 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -4,6 +4,7 @@ #include "VideoCommon/VertexManagerBase.h" +#include #include #include @@ -32,15 +33,28 @@ std::unique_ptr g_vertex_manager; -static const PrimitiveType primitive_from_gx[8] = { - PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS - PRIMITIVE_TRIANGLES, // GX_DRAW_QUADS_2 - PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLES - PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_STRIP - PRIMITIVE_TRIANGLES, // GX_DRAW_TRIANGLE_FAN - PRIMITIVE_LINES, // GX_DRAW_LINES - PRIMITIVE_LINES, // GX_DRAW_LINE_STRIP - PRIMITIVE_POINTS, // GX_DRAW_POINTS +// GX primitive -> RenderState primitive, no primitive restart +constexpr std::array primitive_from_gx = { + PrimitiveType::Triangles, // GX_DRAW_QUADS + PrimitiveType::Triangles, // GX_DRAW_QUADS_2 + PrimitiveType::Triangles, // GX_DRAW_TRIANGLES + PrimitiveType::Triangles, // GX_DRAW_TRIANGLE_STRIP + PrimitiveType::Triangles, // GX_DRAW_TRIANGLE_FAN + PrimitiveType::Lines, // GX_DRAW_LINES + PrimitiveType::Lines, // GX_DRAW_LINE_STRIP + PrimitiveType::Points, // GX_DRAW_POINTS +}; + +// GX primitive -> RenderState primitive, using primitive restart +constexpr std::array primitive_from_gx_pr = { + PrimitiveType::TriangleStrip, // GX_DRAW_QUADS + PrimitiveType::TriangleStrip, // GX_DRAW_QUADS_2 + PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLES + PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLE_STRIP + PrimitiveType::TriangleStrip, // GX_DRAW_TRIANGLE_FAN + PrimitiveType::Lines, // GX_DRAW_LINES + PrimitiveType::Lines, // GX_DRAW_LINE_STRIP + PrimitiveType::Points, // GX_DRAW_POINTS }; // Due to the BT.601 standard which the GameCube is based on being a compromise @@ -80,9 +94,19 @@ DataReader VertexManagerBase::PrepareForAdditionalData(int primitive, u32 count, u32 const needed_vertex_bytes = count * stride + 4; // We can't merge different kinds of primitives, so we have to flush here - if (m_current_primitive_type != primitive_from_gx[primitive]) + PrimitiveType new_primitive_type = g_ActiveConfig.backend_info.bSupportsPrimitiveRestart ? + primitive_from_gx_pr[primitive] : + primitive_from_gx[primitive]; + if (m_current_primitive_type != new_primitive_type) + { Flush(); - m_current_primitive_type = primitive_from_gx[primitive]; + + // Have to update the rasterization state for point/line cull modes. + RasterizationState raster_state = {}; + raster_state.Generate(bpmem, new_primitive_type); + g_renderer->SetRasterizationState(raster_state); + m_current_primitive_type = new_primitive_type; + } // Check for size in buffer, if the buffer gets full, call Flush() if (!m_is_flushed && @@ -332,8 +356,11 @@ void VertexManagerBase::CalculateZSlope(NativeVertexFormat* format) float viewOffset[2] = {xfmem.viewport.xOrig - bpmem.scissorOffset.x * 2, xfmem.viewport.yOrig - bpmem.scissorOffset.y * 2}; - if (m_current_primitive_type != PRIMITIVE_TRIANGLES) + if (m_current_primitive_type != PrimitiveType::Triangles && + m_current_primitive_type != PrimitiveType::TriangleStrip) + { return; + } // Global matrix ID. u32 mtxIdx = g_main_cp_state.matrix_index_a.PosNormalMtxIdx; diff --git a/Source/Core/VideoCommon/VertexManagerBase.h b/Source/Core/VideoCommon/VertexManagerBase.h index dae639a47d..22c9b0d2a6 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.h +++ b/Source/Core/VideoCommon/VertexManagerBase.h @@ -9,19 +9,13 @@ #include "Common/CommonFuncs.h" #include "Common/CommonTypes.h" +#include "VideoCommon/RenderState.h" class DataReader; class NativeVertexFormat; class PointerWrap; struct PortableVertexDeclaration; -enum PrimitiveType -{ - PRIMITIVE_POINTS, - PRIMITIVE_LINES, - PRIMITIVE_TRIANGLES, -}; - struct Slope { float dfdx; @@ -51,6 +45,7 @@ public: // needs to be virtual for DX11's dtor virtual ~VertexManagerBase(); + PrimitiveType GetCurrentPrimitiveType() const { return m_current_primitive_type; } DataReader PrepareForAdditionalData(int primitive, u32 count, u32 stride, bool cullall); void FlushData(u32 count, u32 stride); @@ -65,8 +60,6 @@ public: protected: virtual void vDoState(PointerWrap& p) {} - PrimitiveType m_current_primitive_type = PrimitiveType::PRIMITIVE_POINTS; - virtual void ResetBuffer(u32 stride) = 0; u8* m_cur_buffer_pointer = nullptr; @@ -80,6 +73,7 @@ protected: void CalculateZSlope(NativeVertexFormat* format); bool m_cull_all = false; + PrimitiveType m_current_primitive_type = PrimitiveType::Points; private: bool m_is_flushed = true; diff --git a/Source/Core/VideoCommon/VideoConfig.h b/Source/Core/VideoCommon/VideoConfig.h index e9fcece3e8..9fbe78d5c5 100644 --- a/Source/Core/VideoCommon/VideoConfig.h +++ b/Source/Core/VideoCommon/VideoConfig.h @@ -229,6 +229,7 @@ struct VideoConfig final // Utility bool RealXFBEnabled() const { return bUseXFB && bUseRealXFB; } bool VirtualXFBEnabled() const { return bUseXFB && !bUseRealXFB; } + bool MultisamplingEnabled() const { return iMultisamples > 1; } bool ExclusiveFullscreenEnabled() const { return backend_info.bSupportsExclusiveFullscreen && !bBorderlessFullscreen; From e5840908224c1bcf6d948ec11d56b918e3ebee89 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 7 Sep 2017 23:41:37 +1000 Subject: [PATCH 4/7] Vulkan: Fix interface mismatch in RGB->YUYV shader --- Source/Core/VideoBackends/Vulkan/TextureConverter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp index eee9a13272..e0376c3cae 100644 --- a/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp +++ b/Source/Core/VideoBackends/Vulkan/TextureConverter.cpp @@ -801,6 +801,7 @@ bool TextureConverter::CompileYUYVConversionShaders() static const char RGB_TO_YUYV_SHADER_SOURCE[] = R"( SAMPLER_BINDING(0) uniform sampler2DArray source; layout(location = 0) in vec3 uv0; + layout(location = 1) in vec4 col0; layout(location = 0) out vec4 ocol0; const vec3 y_const = vec3(0.257,0.504,0.098); From b7a099814a6cfcd1db4d7091e01bf4538be67e5e Mon Sep 17 00:00:00 2001 From: Stenzek Date: Thu, 7 Sep 2017 23:42:44 +1000 Subject: [PATCH 5/7] Vulkan: Clear contents of EFB convert framebuffer at create time Fixes a validation layer warning when converting pixel formats. --- Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 8a7745732f..7ab7c6ecd3 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -362,6 +362,8 @@ bool FramebufferManager::CreateEFBFramebuffer() // Transition to state that can be used to clear m_efb_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); + m_efb_convert_color_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); m_efb_depth_texture->TransitionToLayout(g_command_buffer_mgr->GetCurrentCommandBuffer(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL); @@ -373,6 +375,9 @@ bool FramebufferManager::CreateEFBFramebuffer() vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_efb_color_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &clear_color_range); + vkCmdClearColorImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), + m_efb_convert_color_texture->GetImage(), + VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_color, 1, &clear_color_range); vkCmdClearDepthStencilImage(g_command_buffer_mgr->GetCurrentCommandBuffer(), m_efb_depth_texture->GetImage(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, &clear_depth, 1, &clear_depth_range); From 340aabbb06404481b8a496f506ebc9bae75fad6c Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 9 Sep 2017 00:10:40 +1000 Subject: [PATCH 6/7] VideoCommon: Add helpers for generating common render states --- .../Vulkan/FramebufferManager.cpp | 6 ++-- .../Core/VideoBackends/Vulkan/RasterFont.cpp | 2 +- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 4 +-- .../Core/VideoBackends/Vulkan/ShaderCache.cpp | 6 ++-- Source/Core/VideoBackends/Vulkan/Util.cpp | 36 ++----------------- Source/Core/VideoBackends/Vulkan/Util.h | 4 --- Source/Core/VideoCommon/RenderState.cpp | 34 ++++++++++++++++++ Source/Core/VideoCommon/RenderState.h | 7 ++++ 8 files changed, 53 insertions(+), 46 deletions(-) diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index 7ab7c6ecd3..53351e0325 100644 --- a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp +++ b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp @@ -1192,11 +1192,11 @@ void FramebufferManager::DrawPokeVertices(const EFBPokeVertex* vertices, size_t pipeline_info.gs = (GetEFBLayers() > 1) ? m_poke_geometry_shader : VK_NULL_HANDLE; pipeline_info.ps = m_poke_fragment_shader; pipeline_info.render_pass = m_efb_load_render_pass; - pipeline_info.rasterization_state.hex = Util::GetNoCullRasterizationState().hex; + pipeline_info.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; pipeline_info.rasterization_state.primitive = m_poke_primitive; pipeline_info.multisampling_state.hex = GetEFBMultisamplingState().hex; - pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; - pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; + pipeline_info.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; + pipeline_info.blend_state.hex = RenderState::GetNoBlendingBlendState().hex; pipeline_info.blend_state.colorupdate = write_color; pipeline_info.blend_state.alphaupdate = write_color; if (write_depth) diff --git a/Source/Core/VideoBackends/Vulkan/RasterFont.cpp b/Source/Core/VideoBackends/Vulkan/RasterFont.cpp index 39534cbf5d..7410ba5c86 100644 --- a/Source/Core/VideoBackends/Vulkan/RasterFont.cpp +++ b/Source/Core/VideoBackends/Vulkan/RasterFont.cpp @@ -400,7 +400,7 @@ void RasterFont::PrintMultiLineText(VkRenderPass render_pass, const std::string& draw.SetPSSampler(0, m_texture->GetView(), g_object_cache->GetLinearSampler()); // Setup alpha blending - BlendingState blend_state = Util::GetNoBlendingBlendState(); + BlendingState blend_state = RenderState::GetNoBlendingBlendState(); blend_state.blendenable = true; blend_state.srcfactor = BlendMode::SRCALPHA; blend_state.dstfactor = BlendMode::INVSRCALPHA; diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index 07c0242751..fc3eb59c39 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -455,11 +455,11 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool color_enable, bool alpha StateTracker::GetInstance()->SetPendingRebind(); // Mask away the appropriate colors and use a shader - BlendingState blend_state = Util::GetNoBlendingBlendState(); + BlendingState blend_state = RenderState::GetNoBlendingBlendState(); blend_state.colorupdate = color_enable; blend_state.alphaupdate = alpha_enable; - DepthState depth_state = Util::GetNoDepthTestingDepthStencilState(); + DepthState depth_state = RenderState::GetNoDepthTestingDepthStencilState(); depth_state.testenable = z_enable; depth_state.updateenable = z_enable; depth_state.func = ZMode::ALWAYS; diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp index f32ca869ef..9bd41b882f 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp @@ -1210,9 +1210,9 @@ void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid, VK_NULL_HANDLE; pinfo.ps = GetPixelUberShaderForUid(puid); pinfo.render_pass = FramebufferManager::GetInstance()->GetEFBLoadRenderPass(); - pinfo.rasterization_state.hex = Util::GetNoCullRasterizationState().hex; - pinfo.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; - pinfo.blend_state.hex = Util::GetNoBlendingBlendState().hex; + pinfo.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; + pinfo.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; + pinfo.blend_state.hex = RenderState::GetNoBlendingBlendState().hex; pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex; pinfo.rasterization_state.primitive = guid.GetUidData()->primitive_type; GetPipelineWithCacheResultAsync(pinfo); diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 0f8c17c384..8a94dd42ad 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -185,36 +185,6 @@ VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor) } } -RasterizationState GetNoCullRasterizationState() -{ - RasterizationState state = {}; - state.cullmode = GenMode::CULL_NONE; - return state; -} - -DepthState GetNoDepthTestingDepthStencilState() -{ - DepthState state = {}; - state.testenable = false; - state.updateenable = false; - state.func = ZMode::ALWAYS; - return state; -} - -BlendingState GetNoBlendingBlendState() -{ - BlendingState state = {}; - state.blendenable = false; - state.srcfactor = BlendMode::ONE; - state.srcfactoralpha = BlendMode::ZERO; - state.dstfactor = BlendMode::ONE; - state.dstfactoralpha = BlendMode::ZERO; - state.logicopenable = false; - state.colorupdate = true; - state.alphaupdate = true; - return state; -} - void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height, float min_depth /*= 0.0f*/, float max_depth /*= 1.0f*/) { @@ -342,10 +312,10 @@ UtilityShaderDraw::UtilityShaderDraw(VkCommandBuffer command_buffer, m_pipeline_info.vs = vertex_shader; m_pipeline_info.gs = geometry_shader; m_pipeline_info.ps = pixel_shader; - m_pipeline_info.rasterization_state.hex = Util::GetNoCullRasterizationState().hex; + m_pipeline_info.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; m_pipeline_info.rasterization_state.primitive = primitive; - m_pipeline_info.depth_state.hex = Util::GetNoDepthTestingDepthStencilState().hex; - m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; + m_pipeline_info.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; + m_pipeline_info.blend_state.hex = RenderState::GetNoBlendingBlendState().hex; m_pipeline_info.multisampling_state.per_sample_shading = false; m_pipeline_info.multisampling_state.samples = 1; } diff --git a/Source/Core/VideoBackends/Vulkan/Util.h b/Source/Core/VideoBackends/Vulkan/Util.h index 2cb253423f..413e3b96c5 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.h +++ b/Source/Core/VideoBackends/Vulkan/Util.h @@ -38,10 +38,6 @@ VkRect2D ClampRect2D(const VkRect2D& rect, u32 width, u32 height); // Map {SRC,DST}_COLOR to {SRC,DST}_ALPHA VkBlendFactor GetAlphaBlendFactor(VkBlendFactor factor); -RasterizationState GetNoCullRasterizationState(); -DepthState GetNoDepthTestingDepthStencilState(); -BlendingState GetNoBlendingBlendState(); - // Combines viewport and scissor updates void SetViewportAndScissor(VkCommandBuffer command_buffer, int x, int y, int width, int height, float min_depth = 0.0f, float max_depth = 1.0f); diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp index d019214206..d8cd5e7f11 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -144,3 +144,37 @@ void BlendingState::Generate(const BPMemory& bp) } } } + +namespace RenderState +{ +RasterizationState GetNoCullRasterizationState() +{ + RasterizationState state = {}; + state.cullmode = GenMode::CULL_NONE; + return state; +} + +DepthState GetNoDepthTestingDepthStencilState() +{ + DepthState state = {}; + state.testenable = false; + state.updateenable = false; + state.func = ZMode::ALWAYS; + return state; +} + +BlendingState GetNoBlendingBlendState() +{ + BlendingState state = {}; + state.usedualsrc = false; + state.blendenable = false; + state.srcfactor = BlendMode::ONE; + state.srcfactoralpha = BlendMode::ONE; + state.dstfactor = BlendMode::ZERO; + state.dstfactoralpha = BlendMode::ZERO; + state.logicopenable = false; + state.colorupdate = true; + state.alphaupdate = true; + return state; +} +} diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h index 03af1f1f3e..d3a006a887 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -58,3 +58,10 @@ union BlendingState u32 hex; }; + +namespace RenderState +{ +RasterizationState GetNoCullRasterizationState(); +DepthState GetNoDepthTestingDepthStencilState(); +BlendingState GetNoBlendingBlendState(); +} From 24ddea04ce3c843dd1de3d34d775e9a49d195225 Mon Sep 17 00:00:00 2001 From: Stenzek Date: Sat, 9 Sep 2017 18:30:15 +1000 Subject: [PATCH 7/7] VideoBackends: Move SamplerState to common --- Source/Core/VideoBackends/D3D/D3DState.cpp | 101 ++++------- Source/Core/VideoBackends/D3D/D3DState.h | 16 +- Source/Core/VideoBackends/D3D/Render.cpp | 41 +---- Source/Core/VideoBackends/D3D/Render.h | 2 +- .../VideoBackends/OGL/ProgramShaderCache.cpp | 6 +- Source/Core/VideoBackends/OGL/Render.cpp | 12 +- Source/Core/VideoBackends/OGL/Render.h | 2 +- .../Core/VideoBackends/OGL/SamplerCache.cpp | 163 +++++++----------- Source/Core/VideoBackends/OGL/SamplerCache.h | 45 +---- Source/Core/VideoBackends/Vulkan/Constants.h | 16 -- .../Core/VideoBackends/Vulkan/ObjectCache.cpp | 45 +++-- Source/Core/VideoBackends/Vulkan/Renderer.cpp | 59 +------ Source/Core/VideoBackends/Vulkan/Renderer.h | 2 +- .../Core/VideoBackends/Vulkan/ShaderCache.cpp | 35 +--- .../Core/VideoBackends/Vulkan/ShaderCache.h | 4 - Source/Core/VideoCommon/GeometryShaderGen.cpp | 17 +- Source/Core/VideoCommon/GeometryShaderGen.h | 2 +- Source/Core/VideoCommon/RenderBase.h | 2 +- Source/Core/VideoCommon/RenderState.cpp | 82 +++++++++ Source/Core/VideoCommon/RenderState.h | 52 ++++++ Source/Core/VideoCommon/VertexManagerBase.cpp | 49 +++++- 21 files changed, 352 insertions(+), 401 deletions(-) diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index 7664eb9938..56bcb58fa1 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.cpp +++ b/Source/Core/VideoBackends/D3D/D3DState.cpp @@ -12,7 +12,7 @@ #include "VideoBackends/D3D/D3DBase.h" #include "VideoBackends/D3D/D3DState.h" -#include "VideoCommon/SamplerCommon.h" +#include "VideoCommon/VideoConfig.h" namespace DX11 { @@ -265,90 +265,55 @@ void StateManager::SetTextureByMask(u32 textureSlotMask, ID3D11ShaderResourceVie ID3D11SamplerState* StateCache::Get(SamplerState state) { - auto it = m_sampler.find(state.packed); - + auto it = m_sampler.find(state.hex); if (it != m_sampler.end()) - { return it->second; - } - - const unsigned int d3dMipFilters[4] = { - TexMode0::TEXF_NONE, TexMode0::TEXF_POINT, TexMode0::TEXF_LINEAR, - TexMode0::TEXF_NONE, // reserved - }; - const D3D11_TEXTURE_ADDRESS_MODE d3dClamps[4] = { - D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR, - D3D11_TEXTURE_ADDRESS_WRAP // reserved - }; D3D11_SAMPLER_DESC sampdc = CD3D11_SAMPLER_DESC(CD3D11_DEFAULT()); - - unsigned int mip = d3dMipFilters[state.min_filter & 3]; - - if (state.max_anisotropy > 1 && !SamplerCommon::IsBpTexMode0PointFiltering(state)) + if (state.mipmap_filter == SamplerState::Filter::Linear) { - sampdc.Filter = D3D11_FILTER_ANISOTROPIC; - sampdc.MaxAnisotropy = (u32)state.max_anisotropy; + if (state.min_filter == SamplerState::Filter::Linear) + sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ? + D3D11_FILTER_MIN_MAG_MIP_LINEAR : + D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; + else + sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ? + D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR : + D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; } - else if (state.min_filter & 4) // linear min filter + else { - if (state.mag_filter) // linear mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_LINEAR_MAG_POINT_MIP_LINEAR; - } - } - else // point min filter - { - if (state.mag_filter) // linear mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_POINT_MAG_MIP_LINEAR; - } - else // point mag filter - { - if (mip == TexMode0::TEXF_NONE) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_POINT) - sampdc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT; - else if (mip == TexMode0::TEXF_LINEAR) - sampdc.Filter = D3D11_FILTER_MIN_MAG_POINT_MIP_LINEAR; - } + if (state.min_filter == SamplerState::Filter::Linear) + sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ? + D3D11_FILTER_MIN_MAG_LINEAR_MIP_POINT : + D3D11_FILTER_MIN_LINEAR_MAG_MIP_POINT; + else + sampdc.Filter = (state.mag_filter == SamplerState::Filter::Linear) ? + D3D11_FILTER_MIN_POINT_MAG_LINEAR_MIP_POINT : + D3D11_FILTER_MIN_MAG_MIP_POINT; } - sampdc.AddressU = d3dClamps[state.wrap_s]; - sampdc.AddressV = d3dClamps[state.wrap_t]; - - sampdc.MaxLOD = SamplerCommon::AreBpTexMode0MipmapsEnabled(state) ? state.max_lod / 16.f : 0.f; - sampdc.MinLOD = std::min(state.min_lod / 16.f, sampdc.MaxLOD); + static constexpr std::array address_modes = { + {D3D11_TEXTURE_ADDRESS_CLAMP, D3D11_TEXTURE_ADDRESS_WRAP, D3D11_TEXTURE_ADDRESS_MIRROR}}; + sampdc.AddressU = address_modes[static_cast(state.wrap_u.Value())]; + sampdc.AddressV = address_modes[static_cast(state.wrap_v.Value())]; + sampdc.MaxLOD = state.max_lod / 16.f; + sampdc.MinLOD = state.min_lod / 16.f; sampdc.MipLODBias = (s32)state.lod_bias / 32.0f; - ID3D11SamplerState* res = nullptr; + if (state.anisotropic_filtering) + { + sampdc.Filter = D3D11_FILTER_ANISOTROPIC; + sampdc.MaxAnisotropy = 1u << g_ActiveConfig.iMaxAnisotropy; + } + ID3D11SamplerState* res = nullptr; HRESULT hr = D3D::device->CreateSamplerState(&sampdc, &res); if (FAILED(hr)) PanicAlert("Fail %s %d\n", __FILE__, __LINE__); D3D::SetDebugObjectName(res, "sampler state used to emulate the GX pipeline"); - m_sampler.emplace(state.packed, res); - + m_sampler.emplace(state.hex, res); return res; } diff --git a/Source/Core/VideoBackends/D3D/D3DState.h b/Source/Core/VideoBackends/D3D/D3DState.h index 1c9e0fa0fb..fc7cda88b3 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -20,20 +20,6 @@ struct ID3D11RasterizerState; namespace DX11 { -union SamplerState -{ - BitField<0, 3, u64> min_filter; - BitField<3, 1, u64> mag_filter; - BitField<4, 8, u64> min_lod; - BitField<12, 8, u64> max_lod; - BitField<20, 8, s64> lod_bias; - BitField<28, 2, u64> wrap_s; - BitField<30, 2, u64> wrap_t; - BitField<32, 5, u64> max_anisotropy; - - u64 packed; -}; - class StateCache { public: @@ -54,7 +40,7 @@ private: std::unordered_map m_depth; std::unordered_map m_raster; std::unordered_map m_blend; - std::unordered_map m_sampler; + std::unordered_map m_sampler; }; namespace D3D diff --git a/Source/Core/VideoBackends/D3D/Render.cpp b/Source/Core/VideoBackends/D3D/Render.cpp index dcf55d03c8..5fce3ab961 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -249,7 +249,7 @@ Renderer::Renderer() : ::Renderer(D3D::GetBackBufferWidth(), D3D::GetBackBufferH // Setup GX pipeline state for (auto& sampler : s_gx_state.samplers) - sampler.packed = 0; + sampler.hex = RenderState::GetPointSamplerState().hex; s_gx_state.zmode.testenable = false; s_gx_state.zmode.updateenable = false; @@ -870,12 +870,8 @@ void Renderer::ApplyState() StateCache::GetPrimitiveTopology(s_gx_state.raster.primitive)); FramebufferManager::SetIntegerEFBRenderTarget(s_gx_state.blend.logicopenable); - for (size_t stage = 0; stage < s_gx_state.samplers.size(); stage++) - { - // TODO: cache SamplerState directly, not d3d object - s_gx_state.samplers[stage].max_anisotropy = UINT64_C(1) << g_ActiveConfig.iMaxAnisotropy; + for (u32 stage = 0; stage < static_cast(s_gx_state.samplers.size()); stage++) D3D::stateman->SetSampler(stage, s_gx_state_cache.Get(s_gx_state.samplers[stage])); - } ID3D11Buffer* vertexConstants = VertexShaderCache::GetConstantBuffer(); @@ -902,38 +898,9 @@ void Renderer::SetDepthState(const DepthState& state) s_gx_state.zmode.hex = state.hex; } -void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) +void Renderer::SetSamplerState(u32 index, const SamplerState& state) { - const FourTexUnits& tex = bpmem.tex[texindex]; - const TexMode0& tm0 = tex.texMode0[stage]; - const TexMode1& tm1 = tex.texMode1[stage]; - - if (texindex) - stage += 4; - - if (g_ActiveConfig.bForceFiltering) - { - // Only use mipmaps if the game says they are available. - s_gx_state.samplers[stage].min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; - s_gx_state.samplers[stage].mag_filter = 1; // linear mag - } - else - { - s_gx_state.samplers[stage].min_filter = (u32)tm0.min_filter; - s_gx_state.samplers[stage].mag_filter = (u32)tm0.mag_filter; - } - - s_gx_state.samplers[stage].wrap_s = (u32)tm0.wrap_s; - s_gx_state.samplers[stage].wrap_t = (u32)tm0.wrap_t; - s_gx_state.samplers[stage].max_lod = (u32)tm1.max_lod; - s_gx_state.samplers[stage].min_lod = (u32)tm1.min_lod; - s_gx_state.samplers[stage].lod_bias = (s32)tm0.lod_bias; - - // custom textures may have higher resolution, so disable the max_lod - if (custom_tex) - { - s_gx_state.samplers[stage].max_lod = 255; - } + s_gx_state.samplers[index].hex = state.hex; } void Renderer::SetInterlacingMode() diff --git a/Source/Core/VideoBackends/D3D/Render.h b/Source/Core/VideoBackends/D3D/Render.h index 2db2740fb0..a33eba7cd2 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -23,7 +23,7 @@ public: void SetScissorRect(const EFBRectangle& rc) override; void SetRasterizationState(const RasterizationState& state) override; void SetDepthState(const DepthState& state) override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetSamplerState(u32 index, const SamplerState& state) override; void SetInterlacingMode() override; void SetViewport() override; void SetFullscreen(bool enable_fullscreen) override; diff --git a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp index c82a0cba01..a5133023af 100644 --- a/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp +++ b/Source/Core/VideoBackends/OGL/ProgramShaderCache.cpp @@ -1119,7 +1119,8 @@ bool ProgramShaderCache::ShaderCompileWorkItem::Compile() gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData()); CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer()); - DrawPrerenderArray(m_program, m_uid.guid.GetUidData()->primitive_type); + DrawPrerenderArray(m_program, + static_cast(m_uid.guid.GetUidData()->primitive_type)); return true; } @@ -1157,7 +1158,8 @@ bool ProgramShaderCache::UberShaderCompileWorkItem::Compile() gcode = GenerateGeometryShaderCode(APIType::OpenGL, host_config, m_uid.guid.GetUidData()); CompileShader(m_program, vcode.GetBuffer(), pcode.GetBuffer(), gcode.GetBuffer()); - DrawPrerenderArray(m_program, m_uid.guid.GetUidData()->primitive_type); + DrawPrerenderArray(m_program, + static_cast(m_uid.guid.GetUidData()->primitive_type)); return true; } diff --git a/Source/Core/VideoBackends/OGL/Render.cpp b/Source/Core/VideoBackends/OGL/Render.cpp index b3535709f2..ccf89b45f2 100644 --- a/Source/Core/VideoBackends/OGL/Render.cpp +++ b/Source/Core/VideoBackends/OGL/Render.cpp @@ -1503,9 +1503,13 @@ void Renderer::SwapImpl(u32 xfbAddr, u32 fbWidth, u32 fbStride, u32 fbHeight, g_Config.iSaveTargetId = 0; + int old_anisotropy = g_ActiveConfig.iMaxAnisotropy; UpdateActiveConfig(); g_texture_cache->OnConfigChanged(g_ActiveConfig); + if (old_anisotropy != g_ActiveConfig.iMaxAnisotropy) + g_sampler_cache->Clear(); + // Invalidate shader cache when the host config changes. if (CheckForHostConfigChanges()) ProgramShaderCache::Reload(); @@ -1834,13 +1838,9 @@ void Renderer::SetDepthState(const DepthState& state) } } -void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) +void Renderer::SetSamplerState(u32 index, const SamplerState& state) { - auto const& tex = bpmem.tex[texindex]; - auto const& tm0 = tex.texMode0[stage]; - auto const& tm1 = tex.texMode1[stage]; - - g_sampler_cache->SetSamplerState((texindex * 4) + stage, tm0, tm1, custom_tex); + g_sampler_cache->SetSamplerState(index, state); } void Renderer::SetInterlacingMode() diff --git a/Source/Core/VideoBackends/OGL/Render.h b/Source/Core/VideoBackends/OGL/Render.h index e52a1193e1..8efea70bec 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -81,7 +81,7 @@ public: void SetScissorRect(const EFBRectangle& rc) override; void SetRasterizationState(const RasterizationState& state) override; void SetDepthState(const DepthState& state) override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetSamplerState(u32 index, const SamplerState& state) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.cpp b/Source/Core/VideoBackends/OGL/SamplerCache.cpp index cbde39be6c..59d3d3a842 100644 --- a/Source/Core/VideoBackends/OGL/SamplerCache.cpp +++ b/Source/Core/VideoBackends/OGL/SamplerCache.cpp @@ -15,141 +15,106 @@ namespace OGL { std::unique_ptr g_sampler_cache; -SamplerCache::SamplerCache() : m_last_max_anisotropy() +SamplerCache::SamplerCache() { - glGenSamplers(2, m_sampler_id); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_sampler_id[0], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glSamplerParameteri(m_sampler_id[1], GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glGenSamplers(1, &m_point_sampler); + glGenSamplers(1, &m_linear_sampler); + glSamplerParameteri(m_point_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(m_point_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(m_point_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_point_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_linear_sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glSamplerParameteri(m_linear_sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glSamplerParameteri(m_linear_sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glSamplerParameteri(m_linear_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } SamplerCache::~SamplerCache() { Clear(); - glDeleteSamplers(2, m_sampler_id); + glDeleteSamplers(1, &m_point_sampler); + glDeleteSamplers(1, &m_linear_sampler); } void SamplerCache::BindNearestSampler(int stage) { - glBindSampler(stage, m_sampler_id[0]); + glBindSampler(stage, m_point_sampler); } void SamplerCache::BindLinearSampler(int stage) { - glBindSampler(stage, m_sampler_id[1]); + glBindSampler(stage, m_linear_sampler); } -void SamplerCache::SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, - bool custom_tex) +void SamplerCache::SetSamplerState(u32 stage, const SamplerState& state) { - // TODO: can this go somewhere else? - if (m_last_max_anisotropy != g_ActiveConfig.iMaxAnisotropy) + if (m_active_samplers[stage].first == state && m_active_samplers[stage].second != 0) + return; + + auto it = m_cache.find(state); + if (it == m_cache.end()) { - m_last_max_anisotropy = g_ActiveConfig.iMaxAnisotropy; - Clear(); + GLuint sampler; + glGenSamplers(1, &sampler); + SetParameters(sampler, state); + it = m_cache.emplace(state, sampler).first; } - Params params(tm0, tm1); - - // take equivalent forced linear when bForceFiltering - if (g_ActiveConfig.bForceFiltering) - { - params.tm0.min_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? 6 : 4; - params.tm0.mag_filter = 1; - } - - // custom textures may have higher resolution, so disable the max_lod - if (custom_tex) - { - params.tm1.max_lod = 255; - } - - // TODO: Should keep a circular buffer for each stage of recently used samplers. - - auto& active_sampler = m_active_samplers[stage]; - if (active_sampler.first != params || !active_sampler.second.sampler_id) - { - // Active sampler does not match parameters (or is invalid), bind the proper one. - active_sampler.first = params; - active_sampler.second = GetEntry(params); - glBindSampler(stage, active_sampler.second.sampler_id); - } + m_active_samplers[stage].first = state; + m_active_samplers[stage].second = it->second; + glBindSampler(stage, it->second); } -SamplerCache::Value& SamplerCache::GetEntry(const Params& params) +void SamplerCache::InvalidateBinding(u32 stage) { - auto& val = m_cache[params]; - if (!val.sampler_id) - { - // Sampler not found in cache, create it. - glGenSamplers(1, &val.sampler_id); - SetParameters(val.sampler_id, params); - - // TODO: Maybe kill old samplers if the cache gets huge. It doesn't seem to get huge though. - // ERROR_LOG(VIDEO, "Sampler cache size is now %ld.", m_cache.size()); - } - - return val; + m_active_samplers[stage].second = 0; } -void SamplerCache::SetParameters(GLuint sampler_id, const Params& params) +void SamplerCache::SetParameters(GLuint sampler_id, const SamplerState& params) { - static const GLint min_filters[8] = { - GL_NEAREST, GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR, GL_NEAREST, - GL_LINEAR, GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR, GL_LINEAR, - }; - - static const GLint wrap_settings[4] = { - GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT, GL_REPEAT, - }; - - auto& tm0 = params.tm0; - auto& tm1 = params.tm1; - - glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, wrap_settings[tm0.wrap_s]); - glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, wrap_settings[tm0.wrap_t]); - - glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, tm1.min_lod / 16.f); - glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, tm1.max_lod / 16.f); - - if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) - glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, (s32)tm0.lod_bias / 32.f); - - GLint min_filter = min_filters[tm0.min_filter]; - GLint mag_filter = tm0.mag_filter ? GL_LINEAR : GL_NEAREST; - - if (g_ActiveConfig.iMaxAnisotropy > 0 && g_ogl_config.bSupportsAniso && - !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) + GLenum min_filter; + GLenum mag_filter = (params.mag_filter == SamplerState::Filter::Point) ? GL_NEAREST : GL_LINEAR; + if (params.mipmap_filter == SamplerState::Filter::Linear) { - // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt - // For predictable results on all hardware/drivers, only use one of: - // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) - // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) - // Letting the game set other combinations will have varying arbitrary results; - // possibly being interpreted as equal to bilinear/trilinear, implicitly - // disabling anisotropy, or changing the anisotropic algorithm employed. - min_filter = - SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR; - mag_filter = GL_LINEAR; - glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, - (float)(1 << g_ActiveConfig.iMaxAnisotropy)); + min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_LINEAR : + GL_LINEAR_MIPMAP_LINEAR; + } + else + { + min_filter = (params.min_filter == SamplerState::Filter::Point) ? GL_NEAREST_MIPMAP_NEAREST : + GL_LINEAR_MIPMAP_NEAREST; } glSamplerParameteri(sampler_id, GL_TEXTURE_MIN_FILTER, min_filter); glSamplerParameteri(sampler_id, GL_TEXTURE_MAG_FILTER, mag_filter); + + static constexpr std::array address_modes = { + {GL_CLAMP_TO_EDGE, GL_REPEAT, GL_MIRRORED_REPEAT}}; + + glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_S, + address_modes[static_cast(params.wrap_u.Value())]); + glSamplerParameteri(sampler_id, GL_TEXTURE_WRAP_T, + address_modes[static_cast(params.wrap_v.Value())]); + + glSamplerParameterf(sampler_id, GL_TEXTURE_MIN_LOD, params.min_lod / 16.f); + glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_LOD, params.max_lod / 16.f); + + if (GLInterface->GetMode() == GLInterfaceMode::MODE_OPENGL) + glSamplerParameterf(sampler_id, GL_TEXTURE_LOD_BIAS, params.lod_bias / 32.f); + + if (params.anisotropic_filtering && g_ogl_config.bSupportsAniso) + { + glSamplerParameterf(sampler_id, GL_TEXTURE_MAX_ANISOTROPY_EXT, + static_cast(1 << g_ActiveConfig.iMaxAnisotropy)); + } } void SamplerCache::Clear() { for (auto& p : m_cache) - { - glDeleteSamplers(1, &p.second.sampler_id); - } + glDeleteSamplers(1, &p.second); + for (auto& p : m_active_samplers) + p.second = 0; m_cache.clear(); } } diff --git a/Source/Core/VideoBackends/OGL/SamplerCache.h b/Source/Core/VideoBackends/OGL/SamplerCache.h index c6bd76dae1..7b437e326b 100644 --- a/Source/Core/VideoBackends/OGL/SamplerCache.h +++ b/Source/Core/VideoBackends/OGL/SamplerCache.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -24,49 +25,21 @@ public: SamplerCache(SamplerCache&&) = delete; SamplerCache& operator=(SamplerCache&&) = delete; - void SetSamplerState(int stage, const TexMode0& tm0, const TexMode1& tm1, bool custom_tex); + void SetSamplerState(u32 stage, const SamplerState& state); + void InvalidateBinding(u32 stage); + void Clear(); void BindNearestSampler(int stage); void BindLinearSampler(int stage); private: - struct Params - { - union - { - struct - { - TexMode0 tm0; - TexMode1 tm1; - }; + static void SetParameters(GLuint sampler_id, const SamplerState& params); - u64 hex; - }; + std::map m_cache; + std::array, 8> m_active_samplers{}; - Params() : hex() {} - Params(const TexMode0& _tm0, const TexMode1& _tm1) : tm0(_tm0), tm1(_tm1) - { - static_assert(sizeof(Params) == 8, "Assuming I can treat this as a 64bit int."); - } - - bool operator<(const Params& other) const { return hex < other.hex; } - bool operator!=(const Params& other) const { return hex != other.hex; } - }; - - struct Value - { - Value() : sampler_id() {} - GLuint sampler_id; - }; - - void SetParameters(GLuint sampler_id, const Params& params); - Value& GetEntry(const Params& params); - - std::map m_cache; - std::pair m_active_samplers[8]; - - int m_last_max_anisotropy; - u32 m_sampler_id[2]; + GLuint m_point_sampler; + GLuint m_linear_sampler; }; extern std::unique_ptr g_sampler_cache; diff --git a/Source/Core/VideoBackends/Vulkan/Constants.h b/Source/Core/VideoBackends/Vulkan/Constants.h index 9086c1a690..3e4012fe17 100644 --- a/Source/Core/VideoBackends/Vulkan/Constants.h +++ b/Source/Core/VideoBackends/Vulkan/Constants.h @@ -132,20 +132,4 @@ union MultisamplingState u32 hex; }; -// Sampler info -union SamplerState -{ - BitField<0, 1, VkFilter> min_filter; - BitField<1, 1, VkFilter> mag_filter; - BitField<2, 1, VkSamplerMipmapMode> mipmap_mode; - BitField<3, 2, VkSamplerAddressMode> wrap_u; - BitField<5, 2, VkSamplerAddressMode> wrap_v; - BitField<7, 8, u32> min_lod; - BitField<15, 8, u32> max_lod; - BitField<23, 8, s32> lod_bias; - BitField<31, 1, u32> enable_anisotropic_filtering; - - u32 bits; -}; - } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp index 6c932c350d..c0196cb7d6 100644 --- a/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ObjectCache.cpp @@ -312,29 +312,36 @@ VkSampler ObjectCache::GetSampler(const SamplerState& info) if (iter != m_sampler_cache.end()) return iter->second; + static constexpr std::array filters = {{VK_FILTER_NEAREST, VK_FILTER_LINEAR}}; + static constexpr std::array mipmap_modes = { + {VK_SAMPLER_MIPMAP_MODE_NEAREST, VK_SAMPLER_MIPMAP_MODE_LINEAR}}; + static constexpr std::array address_modes = { + {VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT, + VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT}}; + VkSamplerCreateInfo create_info = { - VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType - nullptr, // const void* pNext - 0, // VkSamplerCreateFlags flags - info.mag_filter, // VkFilter magFilter - info.min_filter, // VkFilter minFilter - info.mipmap_mode, // VkSamplerMipmapMode mipmapMode - info.wrap_u, // VkSamplerAddressMode addressModeU - info.wrap_v, // VkSamplerAddressMode addressModeV - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW - static_cast(info.lod_bias / 32.0f), // float mipLodBias - VK_FALSE, // VkBool32 anisotropyEnable - 0.0f, // float maxAnisotropy - VK_FALSE, // VkBool32 compareEnable - VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp - static_cast(info.min_lod / 16.0f), // float minLod - static_cast(info.max_lod / 16.0f), // float maxLod - VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor - VK_FALSE // VkBool32 unnormalizedCoordinates + VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO, // VkStructureType sType + nullptr, // const void* pNext + 0, // VkSamplerCreateFlags flags + filters[static_cast(info.mag_filter.Value())], // VkFilter magFilter + filters[static_cast(info.min_filter.Value())], // VkFilter minFilter + mipmap_modes[static_cast(info.mipmap_filter.Value())], // VkSamplerMipmapMode mipmapMode + address_modes[static_cast(info.wrap_u.Value())], // VkSamplerAddressMode addressModeU + address_modes[static_cast(info.wrap_v.Value())], // VkSamplerAddressMode addressModeV + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, // VkSamplerAddressMode addressModeW + info.lod_bias / 32.0f, // float mipLodBias + VK_FALSE, // VkBool32 anisotropyEnable + 0.0f, // float maxAnisotropy + VK_FALSE, // VkBool32 compareEnable + VK_COMPARE_OP_ALWAYS, // VkCompareOp compareOp + info.min_lod / 16.0f, // float minLod + info.max_lod / 16.0f, // float maxLod + VK_BORDER_COLOR_FLOAT_TRANSPARENT_BLACK, // VkBorderColor borderColor + VK_FALSE // VkBool32 unnormalizedCoordinates }; // Can we use anisotropic filtering with this sampler? - if (info.enable_anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering()) + if (info.anisotropic_filtering && g_vulkan_context->SupportsAnisotropicFiltering()) { // Cap anisotropy to device limits. create_info.anisotropyEnable = VK_TRUE; diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.cpp b/Source/Core/VideoBackends/Vulkan/Renderer.cpp index fc3eb59c39..2a90da6f9a 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.cpp +++ b/Source/Core/VideoBackends/Vulkan/Renderer.cpp @@ -52,10 +52,8 @@ Renderer::Renderer(std::unique_ptr swap_chain) m_swap_chain(std::move(swap_chain)) { UpdateActiveConfig(); - - // Set to something invalid, forcing all states to be re-initialized. for (size_t i = 0; i < m_sampler_states.size(); i++) - m_sampler_states[i].bits = std::numeric_limits::max(); + m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex; } Renderer::~Renderer() @@ -1282,65 +1280,22 @@ void Renderer::SetBlendingState(const BlendingState& state) StateTracker::GetInstance()->SetBlendState(state); } -void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) +void Renderer::SetSamplerState(u32 index, const SamplerState& state) { - const FourTexUnits& tex = bpmem.tex[texindex]; - const TexMode0& tm0 = tex.texMode0[stage]; - const TexMode1& tm1 = tex.texMode1[stage]; - SamplerState new_state = {}; - - if (g_ActiveConfig.bForceFiltering) - { - new_state.min_filter = VK_FILTER_LINEAR; - new_state.mag_filter = VK_FILTER_LINEAR; - new_state.mipmap_mode = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? - VK_SAMPLER_MIPMAP_MODE_LINEAR : - VK_SAMPLER_MIPMAP_MODE_NEAREST; - } - else - { - // Constants for these? - new_state.min_filter = (tm0.min_filter & 4) != 0 ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; - new_state.mipmap_mode = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? - VK_SAMPLER_MIPMAP_MODE_LINEAR : - VK_SAMPLER_MIPMAP_MODE_NEAREST; - new_state.mag_filter = tm0.mag_filter != 0 ? VK_FILTER_LINEAR : VK_FILTER_NEAREST; - } - - // If mipmaps are disabled, clamp min/max lod - new_state.max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0; - new_state.min_lod = std::min(new_state.max_lod.Value(), tm1.min_lod); - new_state.lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias : 0; - - // Custom textures may have a greater number of mips - if (custom_tex) - new_state.max_lod = 255; - - // Address modes - static const VkSamplerAddressMode address_modes[] = { - VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_SAMPLER_ADDRESS_MODE_REPEAT, - VK_SAMPLER_ADDRESS_MODE_MIRRORED_REPEAT, VK_SAMPLER_ADDRESS_MODE_REPEAT}; - new_state.wrap_u = address_modes[tm0.wrap_s]; - new_state.wrap_v = address_modes[tm0.wrap_t]; - - // Only use anisotropic filtering for textures that would be linearly filtered. - new_state.enable_anisotropic_filtering = SamplerCommon::IsBpTexMode0PointFiltering(tm0) ? 0 : 1; - // Skip lookup if the state hasn't changed. - size_t bind_index = (texindex * 4) + stage; - if (m_sampler_states[bind_index].bits == new_state.bits) + if (m_sampler_states[index].hex == state.hex) return; // Look up new state and replace in state tracker. - VkSampler sampler = g_object_cache->GetSampler(new_state); + VkSampler sampler = g_object_cache->GetSampler(state); if (sampler == VK_NULL_HANDLE) { ERROR_LOG(VIDEO, "Failed to create sampler"); sampler = g_object_cache->GetPointSampler(); } - StateTracker::GetInstance()->SetSampler(bind_index, sampler); - m_sampler_states[bind_index].bits = new_state.bits; + StateTracker::GetInstance()->SetSampler(index, sampler); + m_sampler_states[index].hex = state.hex; } void Renderer::ResetSamplerStates() @@ -1352,7 +1307,7 @@ void Renderer::ResetSamplerStates() // Invalidate all sampler states, next draw will re-initialize them. for (size_t i = 0; i < m_sampler_states.size(); i++) { - m_sampler_states[i].bits = std::numeric_limits::max(); + m_sampler_states[i].hex = RenderState::GetPointSamplerState().hex; StateTracker::GetInstance()->SetSampler(i, g_object_cache->GetPointSampler()); } diff --git a/Source/Core/VideoBackends/Vulkan/Renderer.h b/Source/Core/VideoBackends/Vulkan/Renderer.h index 103c28a64e..593c2cd887 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -60,7 +60,7 @@ public: void SetScissorRect(const EFBRectangle& rc) override; void SetRasterizationState(const RasterizationState& state) override; void SetDepthState(const DepthState& state) override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetSamplerState(u32 index, const SamplerState& state) override; void SetInterlacingMode() override; void SetViewport() override; diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp index 9bd41b882f..ad5cdf523a 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp @@ -977,18 +977,6 @@ std::string ShaderCache::GetUtilityShaderHeader() const return ss.str(); } -// Comparison operators for PipelineInfos -// Since these all boil down to POD types, we can just memcmp the entire thing for speed -// The is_trivially_copyable check fails on MSVC due to BitField. -// TODO: Can we work around this any way? -#if defined(__GNUC__) && !defined(__clang__) && __GNUC__ < 5 && !defined(_MSC_VER) -static_assert(std::has_trivial_copy_constructor::value, - "PipelineInfo is trivially copyable"); -#elif !defined(_MSC_VER) -static_assert(std::is_trivially_copyable::value, - "PipelineInfo is trivially copyable"); -#endif - std::size_t PipelineInfoHash::operator()(const PipelineInfo& key) const { return static_cast(XXH64(&key, sizeof(key), 0)); @@ -1014,26 +1002,6 @@ bool operator>(const PipelineInfo& lhs, const PipelineInfo& rhs) return std::memcmp(&lhs, &rhs, sizeof(lhs)) > 0; } -bool operator==(const SamplerState& lhs, const SamplerState& rhs) -{ - return lhs.bits == rhs.bits; -} - -bool operator!=(const SamplerState& lhs, const SamplerState& rhs) -{ - return !operator==(lhs, rhs); -} - -bool operator>(const SamplerState& lhs, const SamplerState& rhs) -{ - return lhs.bits > rhs.bits; -} - -bool operator<(const SamplerState& lhs, const SamplerState& rhs) -{ - return lhs.bits < rhs.bits; -} - std::size_t ComputePipelineInfoHash::operator()(const ComputePipelineInfo& key) const { return static_cast(XXH64(&key, sizeof(key), 0)); @@ -1214,7 +1182,8 @@ void ShaderCache::CreateDummyPipeline(const UberShader::VertexShaderUid& vuid, pinfo.depth_state.hex = RenderState::GetNoDepthTestingDepthStencilState().hex; pinfo.blend_state.hex = RenderState::GetNoBlendingBlendState().hex; pinfo.multisampling_state.hex = FramebufferManager::GetInstance()->GetEFBMultisamplingState().hex; - pinfo.rasterization_state.primitive = guid.GetUidData()->primitive_type; + pinfo.rasterization_state.primitive = + static_cast(guid.GetUidData()->primitive_type); GetPipelineWithCacheResultAsync(pinfo); } diff --git a/Source/Core/VideoBackends/Vulkan/ShaderCache.h b/Source/Core/VideoBackends/Vulkan/ShaderCache.h index 4c0de4a94d..0ad080a3fc 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.h +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.h @@ -62,10 +62,6 @@ bool operator==(const PipelineInfo& lhs, const PipelineInfo& rhs); bool operator!=(const PipelineInfo& lhs, const PipelineInfo& rhs); bool operator<(const PipelineInfo& lhs, const PipelineInfo& rhs); bool operator>(const PipelineInfo& lhs, const PipelineInfo& rhs); -bool operator==(const SamplerState& lhs, const SamplerState& rhs); -bool operator!=(const SamplerState& lhs, const SamplerState& rhs); -bool operator>(const SamplerState& lhs, const SamplerState& rhs); -bool operator<(const SamplerState& lhs, const SamplerState& rhs); struct ComputePipelineInfo { diff --git a/Source/Core/VideoCommon/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 4c6fb1c559..98335386fa 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -22,7 +22,7 @@ bool geometry_shader_uid_data::IsPassthrough() const { const bool stereo = g_ActiveConfig.iStereoMode > 0; const bool wireframe = g_ActiveConfig.bWireFrame; - return primitive_type >= PrimitiveType::Triangles && !stereo && !wireframe; + return primitive_type >= static_cast(PrimitiveType::Triangles) && !stereo && !wireframe; } GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type) @@ -31,7 +31,7 @@ GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type) geometry_shader_uid_data* uid_data = out.GetUidData(); memset(uid_data, 0, sizeof(geometry_shader_uid_data)); - uid_data->primitive_type = primitive_type; + uid_data->primitive_type = static_cast(primitive_type); uid_data->numTexGens = xfmem.numTexGen.numTexGens; return out; @@ -56,9 +56,10 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h const bool msaa = host_config.msaa; const bool ssaa = host_config.ssaa; const bool stereo = host_config.stereo; + const PrimitiveType primitive_type = static_cast(uid_data->primitive_type); const unsigned primitive_type_index = static_cast(uid_data->primitive_type); const unsigned vertex_in = std::min(static_cast(primitive_type_index) + 1, 3u); - unsigned vertex_out = uid_data->primitive_type == PrimitiveType::TriangleStrip ? 3 : 4; + unsigned vertex_out = primitive_type == PrimitiveType::TriangleStrip ? 3 : 4; if (wireframe) vertex_out++; @@ -146,7 +147,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h out.Write("\tVertexData ps;\n"); } - if (uid_data->primitive_type == PrimitiveType::Lines) + if (primitive_type == PrimitiveType::Lines) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -177,7 +178,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h "\t\toffset = float2(0, -" I_LINEPTPARAMS ".z / " I_LINEPTPARAMS ".y);\n" "\t}\n"); } - else if (uid_data->primitive_type == PrimitiveType::Points) + else if (primitive_type == PrimitiveType::Points) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -247,7 +248,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h out.Write("\tf.pos.x += hoffset * (f.pos.w - " I_STEREOPARAMS ".z);\n"); } - if (uid_data->primitive_type == PrimitiveType::Lines) + if (primitive_type == PrimitiveType::Lines) { out.Write("\tVS_OUTPUT l = f;\n" "\tVS_OUTPUT r = f;\n"); @@ -268,7 +269,7 @@ ShaderCode GenerateGeometryShaderCode(APIType ApiType, const ShaderHostConfig& h EmitVertex(out, host_config, uid_data, "l", ApiType, wireframe, pixel_lighting, true); EmitVertex(out, host_config, uid_data, "r", ApiType, wireframe, pixel_lighting); } - else if (uid_data->primitive_type == PrimitiveType::Points) + else if (primitive_type == PrimitiveType::Points) { out.Write("\tVS_OUTPUT ll = f;\n" "\tVS_OUTPUT lr = f;\n" @@ -376,7 +377,7 @@ void EnumerateGeometryShaderUids(const std::function(); - guid->primitive_type = primitive; + guid->primitive_type = static_cast(primitive); for (u32 texgens = 0; texgens <= 8; texgens++) { diff --git a/Source/Core/VideoCommon/GeometryShaderGen.h b/Source/Core/VideoCommon/GeometryShaderGen.h index b23441f3d3..ace05baca7 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.h +++ b/Source/Core/VideoCommon/GeometryShaderGen.h @@ -20,7 +20,7 @@ struct geometry_shader_uid_data bool IsPassthrough() const; u32 numTexGens : 4; - PrimitiveType primitive_type : 2; + u32 primitive_type : 2; }; #pragma pack() diff --git a/Source/Core/VideoCommon/RenderBase.h b/Source/Core/VideoCommon/RenderBase.h index 6c264cd04b..1c6bc44171 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -68,7 +68,7 @@ public: virtual void SetScissorRect(const EFBRectangle& rc) {} virtual void SetRasterizationState(const RasterizationState& state) {} virtual void SetDepthState(const DepthState& state) {} - virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} + virtual void SetSamplerState(u32 index, const SamplerState& state) {} virtual void SetInterlacingMode() {} virtual void SetViewport() {} virtual void SetFullscreen(bool enable_fullscreen) {} diff --git a/Source/Core/VideoCommon/RenderState.cpp b/Source/Core/VideoCommon/RenderState.cpp index d8cd5e7f11..8f8d421730 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -3,6 +3,9 @@ // Refer to the license.txt file included. #include "VideoCommon/RenderState.h" +#include +#include +#include "VideoCommon/SamplerCommon.h" void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_type) { @@ -14,6 +17,12 @@ void RasterizationState::Generate(const BPMemory& bp, PrimitiveType primitive_ty cullmode = GenMode::CULL_NONE; } +RasterizationState& RasterizationState::operator=(const RasterizationState& rhs) +{ + hex = rhs.hex; + return *this; +} + void DepthState::Generate(const BPMemory& bp) { testenable = bp.zmode.testenable.Value(); @@ -21,6 +30,12 @@ void DepthState::Generate(const BPMemory& bp) func = bp.zmode.func.Value(); } +DepthState& DepthState::operator=(const DepthState& rhs) +{ + hex = rhs.hex; + return *this; +} + // If the framebuffer format has no alpha channel, it is assumed to // ONE on blending. As the backends may emulate this framebuffer // configuration with an alpha channel, we just drop all references @@ -145,6 +160,43 @@ void BlendingState::Generate(const BPMemory& bp) } } +BlendingState& BlendingState::operator=(const BlendingState& rhs) +{ + hex = rhs.hex; + return *this; +} + +void SamplerState::Generate(const BPMemory& bp, u32 index) +{ + const FourTexUnits& tex = bpmem.tex[index / 4]; + const TexMode0& tm0 = tex.texMode0[index % 4]; + const TexMode1& tm1 = tex.texMode1[index % 4]; + + // GX can configure the mip filter to none. However, D3D and Vulkan can't express this in their + // sampler states. Therefore, we set the min/max LOD to zero if this option is used. + min_filter = (tm0.min_filter & 4) != 0 ? Filter::Linear : Filter::Point; + mipmap_filter = (tm0.min_filter & 3) == TexMode0::TEXF_LINEAR ? Filter::Linear : Filter::Point; + mag_filter = tm0.mag_filter != 0 ? Filter::Linear : Filter::Point; + + // If mipmaps are disabled, clamp min/max lod + max_lod = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm1.max_lod : 0; + min_lod = std::min(max_lod.Value(), tm1.min_lod); + lod_bias = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? tm0.lod_bias : 0; + + // Address modes + static constexpr std::array address_modes = { + {AddressMode::Clamp, AddressMode::Repeat, AddressMode::MirroredRepeat, AddressMode::Repeat}}; + wrap_u = address_modes[tm0.wrap_s]; + wrap_v = address_modes[tm0.wrap_t]; + anisotropic_filtering = 0; +} + +SamplerState& SamplerState::operator=(const SamplerState& rhs) +{ + hex = rhs.hex; + return *this; +} + namespace RenderState { RasterizationState GetNoCullRasterizationState() @@ -177,4 +229,34 @@ BlendingState GetNoBlendingBlendState() state.alphaupdate = true; return state; } + +SamplerState GetPointSamplerState() +{ + SamplerState state = {}; + state.min_filter = SamplerState::Filter::Point; + state.mag_filter = SamplerState::Filter::Point; + state.mipmap_filter = SamplerState::Filter::Point; + state.wrap_u = SamplerState::AddressMode::Clamp; + state.wrap_v = SamplerState::AddressMode::Clamp; + state.min_lod = 0; + state.max_lod = 255; + state.lod_bias = 0; + state.anisotropic_filtering = false; + return state; +} + +SamplerState GetLinearSamplerState() +{ + SamplerState state = {}; + state.min_filter = SamplerState::Filter::Linear; + state.mag_filter = SamplerState::Filter::Linear; + state.mipmap_filter = SamplerState::Filter::Linear; + state.wrap_u = SamplerState::AddressMode::Clamp; + state.wrap_v = SamplerState::AddressMode::Clamp; + state.min_lod = 0; + state.max_lod = 255; + state.lod_bias = 0; + state.anisotropic_filtering = false; + return state; +} } diff --git a/Source/Core/VideoCommon/RenderState.h b/Source/Core/VideoCommon/RenderState.h index d3a006a887..76482b6bb9 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -21,6 +21,11 @@ union RasterizationState { void Generate(const BPMemory& bp, PrimitiveType primitive_type); + RasterizationState& operator=(const RasterizationState& rhs); + + bool operator==(const RasterizationState& rhs) const { return hex == rhs.hex; } + bool operator!=(const RasterizationState& rhs) const { return hex != rhs.hex; } + bool operator<(const RasterizationState& rhs) const { return hex < rhs.hex; } BitField<0, 2, GenMode::CullMode> cullmode; BitField<3, 2, PrimitiveType> primitive; @@ -31,6 +36,11 @@ union DepthState { void Generate(const BPMemory& bp); + DepthState& operator=(const DepthState& rhs); + + bool operator==(const DepthState& rhs) const { return hex == rhs.hex; } + bool operator!=(const DepthState& rhs) const { return hex != rhs.hex; } + bool operator<(const DepthState& rhs) const { return hex < rhs.hex; } BitField<0, 1, u32> testenable; BitField<1, 1, u32> updateenable; BitField<2, 3, ZMode::CompareMode> func; @@ -42,6 +52,11 @@ union BlendingState { void Generate(const BPMemory& bp); + BlendingState& operator=(const BlendingState& rhs); + + bool operator==(const BlendingState& rhs) const { return hex == rhs.hex; } + bool operator!=(const BlendingState& rhs) const { return hex != rhs.hex; } + bool operator<(const BlendingState& rhs) const { return hex < rhs.hex; } BitField<0, 1, u32> blendenable; BitField<1, 1, u32> logicopenable; BitField<2, 1, u32> dstalpha; @@ -59,9 +74,46 @@ union BlendingState u32 hex; }; +union SamplerState +{ + enum class Filter : u32 + { + Point, + Linear + }; + + enum class AddressMode : u32 + { + Clamp, + Repeat, + MirroredRepeat + }; + + void Generate(const BPMemory& bp, u32 index); + + SamplerState& operator=(const SamplerState& rhs); + + bool operator==(const SamplerState& rhs) const { return hex == rhs.hex; } + bool operator!=(const SamplerState& rhs) const { return hex != rhs.hex; } + bool operator<(const SamplerState& rhs) const { return hex < rhs.hex; } + BitField<0, 1, Filter> min_filter; + BitField<1, 1, Filter> mag_filter; + BitField<2, 1, Filter> mipmap_filter; + BitField<3, 2, AddressMode> wrap_u; + BitField<5, 2, AddressMode> wrap_v; + BitField<7, 8, u32> min_lod; // multiplied by 16 + BitField<15, 8, u32> max_lod; // multiplied by 16 + BitField<23, 8, s32> lod_bias; // multiplied by 32 + BitField<31, 1, u32> anisotropic_filtering; + + u32 hex; +}; + namespace RenderState { RasterizationState GetNoCullRasterizationState(); DepthState GetNoDepthTestingDepthStencilState(); BlendingState GetNoBlendingBlendState(); +SamplerState GetPointSamplerState(); +SamplerState GetLinearSamplerState(); } diff --git a/Source/Core/VideoCommon/VertexManagerBase.cpp b/Source/Core/VideoCommon/VertexManagerBase.cpp index 95f31f86a4..9138b0db09 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -24,6 +24,7 @@ #include "VideoCommon/PerfQueryBase.h" #include "VideoCommon/PixelShaderManager.h" #include "VideoCommon/RenderBase.h" +#include "VideoCommon/SamplerCommon.h" #include "VideoCommon/TextureCacheBase.h" #include "VideoCommon/VertexLoaderManager.h" #include "VideoCommon/VertexShaderManager.h" @@ -208,6 +209,52 @@ std::pair VertexManagerBase::ResetFlushAspectRatioCount() return val; } +static void SetSamplerState(u32 index, bool custom_tex) +{ + const FourTexUnits& tex = bpmem.tex[index / 4]; + const TexMode0& tm0 = tex.texMode0[index % 4]; + + SamplerState state = {}; + state.Generate(bpmem, index); + + // Force texture filtering config option. + if (g_ActiveConfig.bForceFiltering) + { + state.min_filter = SamplerState::Filter::Linear; + state.mag_filter = SamplerState::Filter::Linear; + state.mipmap_filter = SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0) ? + SamplerState::Filter::Linear : + SamplerState::Filter::Point; + } + + // Custom textures may have a greater number of mips + if (custom_tex) + state.max_lod = 255; + + // Anisotropic filtering option. + if (g_ActiveConfig.iMaxAnisotropy != 0 && !SamplerCommon::IsBpTexMode0PointFiltering(tm0)) + { + // https://www.opengl.org/registry/specs/EXT/texture_filter_anisotropic.txt + // For predictable results on all hardware/drivers, only use one of: + // GL_LINEAR + GL_LINEAR (No Mipmaps [Bilinear]) + // GL_LINEAR + GL_LINEAR_MIPMAP_LINEAR (w/ Mipmaps [Trilinear]) + // Letting the game set other combinations will have varying arbitrary results; + // possibly being interpreted as equal to bilinear/trilinear, implicitly + // disabling anisotropy, or changing the anisotropic algorithm employed. + state.min_filter = SamplerState::Filter::Linear; + state.mag_filter = SamplerState::Filter::Linear; + if (SamplerCommon::AreBpTexMode0MipmapsEnabled(tm0)) + state.mipmap_filter = SamplerState::Filter::Linear; + state.anisotropic_filtering = 1; + } + else + { + state.anisotropic_filtering = 0; + } + + g_renderer->SetSamplerState(index, state); +} + void VertexManagerBase::Flush() { if (m_is_flushed) @@ -276,7 +323,7 @@ void VertexManagerBase::Flush() if (tentry) { - g_renderer->SetSamplerState(i & 3, i >> 2, tentry->is_custom_tex); + SetSamplerState(i, tentry->is_custom_tex); PixelShaderManager::SetTexDims(i, tentry->native_width, tentry->native_height); } else