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;