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; } diff --git a/Source/Core/VideoBackends/D3D/D3DState.cpp b/Source/Core/VideoBackends/D3D/D3DState.cpp index b21af1f217..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; } @@ -434,32 +399,33 @@ 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; } -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 +438,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, @@ -531,4 +498,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 6b3838c661..fc7cda88b3 100644 --- a/Source/Core/VideoBackends/D3D/D3DState.h +++ b/Source/Core/VideoBackends/D3D/D3DState.h @@ -20,27 +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; - 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: @@ -48,17 +27,20 @@ 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); - ID3D11DepthStencilState* Get(ZMode 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; std::unordered_map m_blend; - std::unordered_map m_sampler; + std::unordered_map m_sampler; }; namespace D3D 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 ae50045c26..5fce3ab961 100644 --- a/Source/Core/VideoBackends/D3D/Render.cpp +++ b/Source/Core/VideoBackends/D3D/Render.cpp @@ -60,8 +60,8 @@ struct GXPipelineState { std::array samplers; BlendingState blend; - ZMode zmode; - RasterizerState raster; + DepthState zmode; + RasterizationState raster; }; static u32 s_last_multisamples = 1; @@ -249,13 +249,12 @@ 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; 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,14 +866,12 @@ 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++) - { - // 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(); @@ -891,68 +888,19 @@ 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); + s_gx_state.raster.hex = state.hex; } -void Renderer::RestoreCull() +void Renderer::SetDepthState(const DepthState& state) { - D3D::stateman->PopRasterizerState(); + s_gx_state.zmode.hex = state.hex; } -void Renderer::SetGenerationMode() +void Renderer::SetSamplerState(u32 index, const SamplerState& state) { - 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]; -} - -void Renderer::SetDepthMode() -{ - s_gx_state.zmode.hex = bpmem.zmode.hex; -} - -void Renderer::SetSamplerState(int stage, int texindex, bool custom_tex) -{ - 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 907c9e2b18..a33eba7cd2 100644 --- a/Source/Core/VideoBackends/D3D/Render.h +++ b/Source/Core/VideoBackends/D3D/Render.h @@ -21,9 +21,9 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; - void SetDepthMode() override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetRasterizationState(const RasterizationState& state) override; + void SetDepthState(const DepthState& state) override; + void SetSamplerState(u32 index, const SamplerState& state) override; void SetInterlacingMode() override; void SetViewport() override; void SetFullscreen(bool enable_fullscreen) 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..a5133023af 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)); @@ -1117,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; } @@ -1155,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; } @@ -1295,7 +1299,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 +1307,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 8953b10831..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(); @@ -1785,9 +1789,9 @@ void Renderer::RestoreAPIState() glEnable(GL_CLIP_DISTANCE0); glEnable(GL_CLIP_DISTANCE1); } - SetGenerationMode(); + BPFunctions::SetGenerationMode(); BPFunctions::SetScissor(); - SetDepthMode(); + BPFunctions::SetDepthMode(); BPFunctions::SetBlendMode(); SetViewport(); @@ -1798,14 +1802,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 { @@ -1813,16 +1817,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 { @@ -1834,13 +1838,9 @@ void Renderer::SetDepthMode() } } -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 668b15c51f..8efea70bec 100644 --- a/Source/Core/VideoBackends/OGL/Render.h +++ b/Source/Core/VideoBackends/OGL/Render.h @@ -79,9 +79,9 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; - void SetDepthMode() override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetRasterizationState(const RasterizationState& state) override; + void SetDepthState(const DepthState& state) 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/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 9d1ab3fecd..3e4012fe17 100644 --- a/Source/Core/VideoBackends/Vulkan/Constants.h +++ b/Source/Core/VideoBackends/Vulkan/Constants.h @@ -124,41 +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; -}; - -// 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 -{ - 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; + BitField<0, 5, u32> samples; // 1-16 + BitField<0, 1, u32> per_sample_shading; // SSAA + u32 hex; }; } // namespace Vulkan diff --git a/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp b/Source/Core/VideoBackends/Vulkan/FramebufferManager.cpp index dec6d9e952..53351e0325 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); @@ -332,17 +362,22 @@ 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); // 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); + 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); @@ -438,16 +473,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 +489,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 +498,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 +509,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 +529,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 +547,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 +677,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 +716,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 +740,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 +796,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 +823,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 +936,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 +1139,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,21 +1189,21 @@ 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.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; - pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().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 = 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; - 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); @@ -1209,7 +1239,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 +1340,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/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/RasterFont.cpp b/Source/Core/VideoBackends/Vulkan/RasterFont.cpp index 97ab4dd6d8..7410ba5c86 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; @@ -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 7a94572b1e..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() @@ -455,18 +453,14 @@ 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; - 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; - - RasterizationState rs_state = Util::GetNoCullRasterizationState(); - rs_state.per_sample_shading = g_ActiveConfig.bSSAA ? VK_TRUE : VK_FALSE; - rs_state.samples = FramebufferManager::GetInstance()->GetEFBSamples(); + DepthState depth_state = RenderState::GetNoDepthTestingDepthStencilState(); + depth_state.testenable = z_enable; + depth_state.updateenable = z_enable; + depth_state.func = ZMode::ALWAYS; // No need to start a new render pass, but we do need to restore viewport state UtilityShaderDraw draw(g_command_buffer_mgr->GetCurrentCommandBuffer(), @@ -475,8 +469,8 @@ 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.SetDepthStencilState(depth_state); + draw.SetMultisamplingState(FramebufferManager::GetInstance()->GetEFBMultisamplingState()); + draw.SetDepthState(depth_state); draw.SetBlendState(blend_state); draw.DrawColoredQuad(target_rc.left, target_rc.top, target_rc.GetWidth(), target_rc.GetHeight(), @@ -1227,13 +1221,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,72 +1265,14 @@ 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::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) @@ -1349,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() @@ -1419,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 5ec1be8277..593c2cd887 100644 --- a/Source/Core/VideoBackends/Vulkan/Renderer.h +++ b/Source/Core/VideoBackends/Vulkan/Renderer.h @@ -58,9 +58,9 @@ public: void SetBlendingState(const BlendingState& state) override; void SetScissorRect(const EFBRectangle& rc) override; - void SetGenerationMode() override; - void SetDepthMode() override; - void SetSamplerState(int stage, int texindex, bool custom_tex) override; + void SetRasterizationState(const RasterizationState& state) override; + void SetDepthState(const DepthState& state) 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 7d5c3e2379..ad5cdf523a 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.cpp @@ -89,49 +89,61 @@ 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 }; } -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 @@ -256,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, @@ -270,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; } @@ -310,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 = @@ -965,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)); @@ -1002,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)); @@ -1198,23 +1178,12 @@ 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.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.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 = + 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 56f888d363..0ad080a3fc 100644 --- a/Source/Core/VideoBackends/Vulkan/ShaderCache.h +++ b/Source/Core/VideoBackends/Vulkan/ShaderCache.h @@ -49,8 +49,8 @@ struct PipelineInfo VkRenderPass render_pass; BlendingState blend_state; RasterizationState rasterization_state; - DepthStencilState depth_stencil_state; - VkPrimitiveTopology primitive_topology; + DepthState depth_state; + MultisamplingState multisampling_state; }; struct PipelineInfoHash @@ -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/VideoBackends/Vulkan/StateTracker.cpp b/Source/Core/VideoBackends/Vulkan/StateTracker.cpp index ae583374e8..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_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.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.depth_stencil_state_bits = info.depth_stencil_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.depth_stencil_state.bits = uid.depth_stencil_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,39 +267,30 @@ 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::SetDepthStencilState(const DepthStencilState& state) +void StateTracker::SetMultisamplingstate(const MultisamplingState& state) { - if (m_pipeline_state.depth_stencil_state.bits == state.bits) + if (m_pipeline_state.multisampling_state.hex == state.hex) return; - m_pipeline_state.depth_stencil_state.bits = state.bits; + m_pipeline_state.multisampling_state.hex = state.hex; + m_dirty_flags |= DIRTY_FLAG_PIPELINE; +} + +void StateTracker::SetDepthState(const DepthState& state) +{ + if (m_pipeline_state.depth_state.hex == state.hex) + return; + + m_pipeline_state.depth_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 73da3ad646..c3dbf5b7e8 100644 --- a/Source/Core/VideoBackends/Vulkan/StateTracker.h +++ b/Source/Core/VideoBackends/Vulkan/StateTracker.h @@ -39,29 +39,21 @@ 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); 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 SetDepthStencilState(const DepthStencilState& 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(); @@ -130,13 +122,12 @@ 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; 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..e0376c3cae 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(); } @@ -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); diff --git a/Source/Core/VideoBackends/Vulkan/Util.cpp b/Source/Core/VideoBackends/Vulkan/Util.cpp index 9796811978..8a94dd42ad 100644 --- a/Source/Core/VideoBackends/Vulkan/Util.cpp +++ b/Source/Core/VideoBackends/Vulkan/Util.cpp @@ -185,39 +185,6 @@ 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; - return state; -} - -DepthStencilState GetNoDepthTestingDepthStencilState() -{ - DepthStencilState state = {}; - state.test_enable = VK_FALSE; - state.write_enable = VK_FALSE; - state.compare_op = VK_COMPARE_OP_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*/) { @@ -335,7 +302,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 +312,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.depth_stencil_state.bits = Util::GetNoDepthTestingDepthStencilState().bits; - m_pipeline_info.blend_state.hex = Util::GetNoBlendingBlendState().hex; - m_pipeline_info.primitive_topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + m_pipeline_info.rasterization_state.hex = RenderState::GetNoCullRasterizationState().hex; + m_pipeline_info.rasterization_state.primitive = primitive; + 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; } -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 +339,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,12 +413,17 @@ 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::SetDepthStencilState(const DepthStencilState& state) +void UtilityShaderDraw::SetMultisamplingState(const MultisamplingState& state) { - m_pipeline_info.depth_stencil_state.bits = state.bits; + m_pipeline_info.multisampling_state.hex = state.hex; +} + +void UtilityShaderDraw::SetDepthState(const DepthState& state) +{ + m_pipeline_info.depth_state.hex = state.hex; } void UtilityShaderDraw::SetBlendState(const BlendingState& state) @@ -506,7 +477,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 +506,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 +533,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 +542,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 c99f0e968c..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(); -DepthStencilState 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); @@ -131,12 +127,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,7 +148,8 @@ public: void SetPSTexelBuffer(VkBufferView view); void SetRasterizationState(const RasterizationState& state); - void SetDepthStencilState(const DepthStencilState& state); + void SetMultisamplingState(const MultisamplingState& state); + void SetDepthState(const DepthState& state); void SetBlendState(const BlendingState& state); void BeginRenderPass(VkFramebuffer framebuffer, const VkRect2D& region, @@ -177,7 +175,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 b74b6f84d4..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() @@ -68,12 +70,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/GeometryShaderGen.cpp b/Source/Core/VideoCommon/GeometryShaderGen.cpp index 4b06c0f7f3..98335386fa 100644 --- a/Source/Core/VideoCommon/GeometryShaderGen.cpp +++ b/Source/Core/VideoCommon/GeometryShaderGen.cpp @@ -14,24 +14,24 @@ #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 >= static_cast(PrimitiveType::Triangles) && !stereo && !wireframe; } -GeometryShaderUid GetGeometryShaderUid(u32 primitive_type) +GeometryShaderUid GetGeometryShaderUid(PrimitiveType primitive_type) { ShaderUid out; 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,8 +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 unsigned int vertex_in = uid_data->primitive_type + 1; - unsigned int vertex_out = uid_data->primitive_type == PRIMITIVE_TRIANGLES ? 3 : 4; + 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 = primitive_type == PrimitiveType::TriangleStrip ? 3 : 4; if (wireframe) vertex_out++; @@ -67,14 +69,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 +135,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 (primitive_type == PrimitiveType::Lines) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -178,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 == PRIMITIVE_POINTS) + else if (primitive_type == PrimitiveType::Points) { if (ApiType == APIType::OpenGL || ApiType == APIType::Vulkan) { @@ -248,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 == PRIMITIVE_LINES) + if (primitive_type == PrimitiveType::Lines) { out.Write("\tVS_OUTPUT l = f;\n" "\tVS_OUTPUT r = f;\n"); @@ -269,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 == PRIMITIVE_POINTS) + else if (primitive_type == PrimitiveType::Points) { out.Write("\tVS_OUTPUT ll = f;\n" "\tVS_OUTPUT lr = f;\n" @@ -370,12 +370,14 @@ 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; + 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 f138207e14..ace05baca7 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" @@ -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 7b7f43b7f6..1c6bc44171 100644 --- a/Source/Core/VideoCommon/RenderBase.h +++ b/Source/Core/VideoCommon/RenderBase.h @@ -66,9 +66,9 @@ public: virtual void SetBlendingState(const BlendingState& state) {} virtual void SetScissorRect(const EFBRectangle& rc) {} - virtual void SetGenerationMode() {} - virtual void SetDepthMode() {} - virtual void SetSamplerState(int stage, int texindex, bool custom_tex) {} + virtual void SetRasterizationState(const RasterizationState& state) {} + virtual void SetDepthState(const DepthState& state) {} + 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 7e6d845ccb..8f8d421730 100644 --- a/Source/Core/VideoCommon/RenderState.cpp +++ b/Source/Core/VideoCommon/RenderState.cpp @@ -3,6 +3,38 @@ // 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) +{ + 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; +} + +RasterizationState& RasterizationState::operator=(const RasterizationState& rhs) +{ + hex = rhs.hex; + return *this; +} + +void DepthState::Generate(const BPMemory& bp) +{ + testenable = bp.zmode.testenable.Value(); + updateenable = bp.zmode.updateenable.Value(); + 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 @@ -127,3 +159,104 @@ 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() +{ + 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; +} + +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 25a55ba17a..76482b6bb9 100644 --- a/Source/Core/VideoCommon/RenderState.h +++ b/Source/Core/VideoCommon/RenderState.h @@ -9,10 +9,54 @@ #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); + + 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; + + u32 hex; +}; + +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; + + u32 hex; +}; + 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; @@ -29,3 +73,47 @@ 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 7807cdb98c..9138b0db09 100644 --- a/Source/Core/VideoCommon/VertexManagerBase.cpp +++ b/Source/Core/VideoCommon/VertexManagerBase.cpp @@ -4,6 +4,7 @@ #include "VideoCommon/VertexManagerBase.h" +#include #include #include @@ -23,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" @@ -32,15 +34,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 +95,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 && @@ -184,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) @@ -252,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 @@ -332,8 +403,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;