Index: ps/trunk/binaries/data/mods/public/shaders/effects/terrain_blend.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/effects/terrain_blend.xml +++ ps/trunk/binaries/data/mods/public/shaders/effects/terrain_blend.xml @@ -7,6 +7,7 @@ + @@ -16,15 +17,18 @@ + + + @@ -34,6 +38,7 @@ + @@ -42,6 +47,7 @@ + @@ -49,6 +55,7 @@ + Index: ps/trunk/binaries/data/mods/public/shaders/effects/terrain_decal.xml =================================================================== --- ps/trunk/binaries/data/mods/public/shaders/effects/terrain_decal.xml +++ ps/trunk/binaries/data/mods/public/shaders/effects/terrain_decal.xml @@ -7,6 +7,7 @@ + @@ -16,6 +17,7 @@ + @@ -26,6 +28,7 @@ + @@ -35,6 +38,7 @@ + @@ -43,6 +47,7 @@ + @@ -50,6 +55,7 @@ + Index: ps/trunk/source/graphics/Canvas2D.cpp =================================================================== --- ps/trunk/source/graphics/Canvas2D.cpp +++ ps/trunk/source/graphics/Canvas2D.cpp @@ -98,7 +98,7 @@ // The canvas technique must be loaded because we can't render UI without it. ENSURE(Tech); DeviceCommandContext->SetGraphicsPipelineState( - Tech->GetGraphicsPipelineStateDesc()); + Tech->GetGraphicsPipelineState()); DeviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = Tech->GetShader(); Index: ps/trunk/source/graphics/LOSTexture.cpp =================================================================== --- ps/trunk/source/graphics/LOSTexture.cpp +++ ps/trunk/source/graphics/LOSTexture.cpp @@ -146,7 +146,7 @@ deviceCommandContext->BeginFramebufferPass(m_SmoothFramebuffers[m_WhichTexture].get()); deviceCommandContext->SetGraphicsPipelineState( - m_SmoothTech->GetGraphicsPipelineStateDesc()); + m_SmoothTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = m_SmoothTech->GetShader(); Index: ps/trunk/source/graphics/MiniMapTexture.h =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.h +++ ps/trunk/source/graphics/MiniMapTexture.h @@ -19,6 +19,7 @@ #define INCLUDED_MINIMAPTEXTURE #include "graphics/Color.h" +#include "graphics/ShaderTechniquePtr.h" #include "graphics/Texture.h" #include "maths/Vector2D.h" #include "renderer/backend/IDeviceCommandContext.h" @@ -123,6 +124,8 @@ VertexArray m_InstanceVertexArray; VertexArray::Attribute m_InstanceAttributePosition; + CShaderTechniquePtr m_TerritoryTechnique; + size_t m_EntitiesDrawn = 0; double m_PingDuration = 25.0; Index: ps/trunk/source/graphics/MiniMapTexture.cpp =================================================================== --- ps/trunk/source/graphics/MiniMapTexture.cpp +++ ps/trunk/source/graphics/MiniMapTexture.cpp @@ -282,6 +282,26 @@ m_InstanceVertexArray.Upload(); m_InstanceVertexArray.FreeBackingStore(); } + + CShaderDefines baseDefines; + baseDefines.Add(str_MINIMAP_BASE, str_1); + + m_TerritoryTechnique = g_Renderer.GetShaderManager().LoadEffect( + str_minimap, baseDefines, + [](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + pipelineStateDesc.blendState.colorWriteMask = + Renderer::Backend::ColorWriteMask::RED | + Renderer::Backend::ColorWriteMask::GREEN | + Renderer::Backend::ColorWriteMask::BLUE; + }); } CMiniMapTexture::~CMiniMapTexture() @@ -480,7 +500,7 @@ tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); shader = tech->GetShader(); @@ -513,20 +533,9 @@ DrawTexture(deviceCommandContext); deviceCommandContext->EndPass(); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - tech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - pipelineStateDesc.blendState.colorWriteMask = - Renderer::Backend::ColorWriteMask::RED | - Renderer::Backend::ColorWriteMask::GREEN | - Renderer::Backend::ColorWriteMask::BLUE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->SetGraphicsPipelineState( + m_TerritoryTechnique->GetGraphicsPipelineState()); + shader = m_TerritoryTechnique->GetShader(); deviceCommandContext->BeginPass(); // Draw territory boundaries @@ -548,7 +557,7 @@ tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap_los, CShaderDefines()); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); shader = tech->GetShader(); @@ -765,7 +774,7 @@ pointDefines.Add(str_USE_GPU_INSTANCING, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, pointDefines); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = tech->GetShader(); Index: ps/trunk/source/graphics/ShaderManager.h =================================================================== --- ps/trunk/source/graphics/ShaderManager.h +++ ps/trunk/source/graphics/ShaderManager.h @@ -21,7 +21,9 @@ #include "graphics/ShaderDefines.h" #include "graphics/ShaderProgram.h" #include "graphics/ShaderTechnique.h" +#include "renderer/backend/PipelineState.h" +#include #include #include #include @@ -48,11 +50,19 @@ CShaderTechniquePtr LoadEffect(CStrIntern name, const CShaderDefines& defines); /** - * Load a shader effect, with default system defines (from CRenderer::GetSystemShaderDefines). + * Load a shader effect, with empty defines. */ CShaderTechniquePtr LoadEffect(CStrIntern name); /** + * Load a shader effect with the pipeline state description overwriting. + * TODO: we should set all needed states in XML. + */ + using PipelineStateDescCallback = CShaderTechnique::PipelineStateDescCallback; + CShaderTechniquePtr LoadEffect( + CStrIntern name, const CShaderDefines& defines, const PipelineStateDescCallback& callback); + + /** * Returns the number of shader effects that are currently loaded. */ size_t GetNumEffectsLoaded() const; @@ -71,7 +81,7 @@ } }; - // A CShaderProgram contains expensive GL state, so we ought to cache it. + // A CShaderProgram contains expensive backend state, so we ought to cache it. // The compiled state depends solely on the filename and list of defines, // so we store that in CacheKey. // TODO: is this cache useful when we already have an effect cache? Index: ps/trunk/source/graphics/ShaderManager.cpp =================================================================== --- ps/trunk/source/graphics/ShaderManager.cpp +++ ps/trunk/source/graphics/ShaderManager.cpp @@ -116,7 +116,8 @@ // First time we've seen this key, so construct a new effect: const VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name.string()) + L".xml"; - CShaderTechniquePtr tech(new CShaderTechnique(xmlFilename, defines)); + CShaderTechniquePtr tech = std::make_shared( + xmlFilename, defines, PipelineStateDescCallback{}); if (!LoadTechnique(tech)) { LOGERROR("Failed to load effect '%s'", name.c_str()); @@ -127,6 +128,20 @@ return tech; } +CShaderTechniquePtr CShaderManager::LoadEffect( + CStrIntern name, const CShaderDefines& defines, const PipelineStateDescCallback& callback) +{ + // We don't cache techniques with callbacks. + const VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name.string()) + L".xml"; + CShaderTechniquePtr technique = std::make_shared(xmlFilename, defines, callback); + if (!LoadTechnique(technique)) + { + LOGERROR("Failed to load effect '%s'", name.c_str()); + return {}; + } + return technique; +} + bool CShaderManager::LoadTechnique(CShaderTechniquePtr& tech) { PROFILE2("loading technique"); @@ -144,9 +159,14 @@ // By default we assume that we have techinques for every dummy shader. if (device->GetBackend() == Renderer::Backend::Backend::DUMMY) { - const Renderer::Backend::GraphicsPipelineStateDesc passPipelineStateDesc = + CShaderProgramPtr shaderProgram = LoadProgram("dummy", tech->GetShaderDefines()); + std::vector techPasses; + Renderer::Backend::SGraphicsPipelineStateDesc passPipelineStateDesc = Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); - tech->SetPasses({{passPipelineStateDesc, LoadProgram("dummy", tech->GetShaderDefines())}}); + passPipelineStateDesc.shaderProgram = shaderProgram->GetBackendShaderProgram(); + techPasses.emplace_back( + device->CreateGraphicsPipelineState(passPipelineStateDesc), shaderProgram); + tech->SetPasses(std::move(techPasses)); return true; } @@ -267,7 +287,7 @@ { CShaderDefines passDefines = techDefines; - Renderer::Backend::GraphicsPipelineStateDesc passPipelineStateDesc = + Renderer::Backend::SGraphicsPipelineStateDesc passPipelineStateDesc = Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); XERO_ITER_EL(Child, Element) @@ -410,7 +430,11 @@ { for (const VfsPath& shaderProgramPath : shaderProgram->GetFileDependencies()) AddTechniqueFileDependency(tech, shaderProgramPath); - techPasses.emplace_back(passPipelineStateDesc, shaderProgram); + if (tech->GetPipelineStateDescCallback()) + tech->GetPipelineStateDescCallback()(passPipelineStateDesc); + passPipelineStateDesc.shaderProgram = shaderProgram->GetBackendShaderProgram(); + techPasses.emplace_back( + device->CreateGraphicsPipelineState(passPipelineStateDesc), shaderProgram); } } } Index: ps/trunk/source/graphics/ShaderTechnique.h =================================================================== --- ps/trunk/source/graphics/ShaderTechnique.h +++ ps/trunk/source/graphics/ShaderTechnique.h @@ -21,29 +21,35 @@ #include "graphics/ShaderDefines.h" #include "graphics/ShaderProgram.h" #include "graphics/ShaderTechniquePtr.h" +#include "lib/code_annotation.h" #include "lib/file/vfs/vfs_path.h" #include "renderer/backend/PipelineState.h" +#include +#include #include /** - * Implements a render pass consisting of various GL state changes and a shader, + * Implements a render pass consisting of a pipeline state and a shader, * used by CShaderTechnique. */ class CShaderPass { public: - CShaderPass(const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, const CShaderProgramPtr& shader); + CShaderPass( + std::unique_ptr pipelineState, + const CShaderProgramPtr& shader); + MOVABLE(CShaderPass); - Renderer::Backend::IShaderProgram* GetShader() const { return m_Shader->GetBackendShaderProgram(); } + const CShaderProgramPtr& GetShaderProgram() const noexcept { return m_Shader; } - const Renderer::Backend::GraphicsPipelineStateDesc& - GetPipelineStateDesc() const { return m_PipelineStateDesc; } + Renderer::Backend::IGraphicsPipelineState* + GetPipelineState() const noexcept { return m_PipelineState.get(); } private: CShaderProgramPtr m_Shader; - Renderer::Backend::GraphicsPipelineStateDesc m_PipelineStateDesc{}; + std::unique_ptr m_PipelineState; }; /** @@ -53,7 +59,10 @@ class CShaderTechnique { public: - CShaderTechnique(const VfsPath& path, const CShaderDefines& defines); + using PipelineStateDescCallback = + std::function; + + CShaderTechnique(const VfsPath& path, const CShaderDefines& defines, const PipelineStateDescCallback& callback); void SetPasses(std::vector&& passes); @@ -61,8 +70,8 @@ Renderer::Backend::IShaderProgram* GetShader(int pass = 0) const; - const Renderer::Backend::GraphicsPipelineStateDesc& - GetGraphicsPipelineStateDesc(int pass = 0) const; + Renderer::Backend::IGraphicsPipelineState* + GetGraphicsPipelineState(int pass = 0) const; /** * Whether this technique uses alpha blending that requires objects to be @@ -76,6 +85,8 @@ const CShaderDefines& GetShaderDefines() { return m_Defines; } + const PipelineStateDescCallback& GetPipelineStateDescCallback() const { return m_PipelineStateDescCallback; }; + private: std::vector m_Passes; @@ -84,6 +95,8 @@ // We need additional data to reload the technique. VfsPath m_Path; CShaderDefines m_Defines; + + PipelineStateDescCallback m_PipelineStateDescCallback; }; #endif // INCLUDED_SHADERTECHNIQUE Index: ps/trunk/source/graphics/ShaderTechnique.cpp =================================================================== --- ps/trunk/source/graphics/ShaderTechnique.cpp +++ ps/trunk/source/graphics/ShaderTechnique.cpp @@ -20,17 +20,20 @@ #include "ShaderTechnique.h" #include "graphics/ShaderProgram.h" +#include "renderer/backend/IDevice.h" CShaderPass::CShaderPass( - const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, + std::unique_ptr pipelineState, const CShaderProgramPtr& shader) - : m_PipelineStateDesc(pipelineStateDesc), m_Shader(shader) + : m_Shader(shader), m_PipelineState(std::move(pipelineState)) { - m_PipelineStateDesc.shaderProgram = m_Shader->GetBackendShaderProgram(); + ENSURE(shader); } -CShaderTechnique::CShaderTechnique(const VfsPath& path, const CShaderDefines& defines) - : m_Path(path), m_Defines(defines) +CShaderTechnique::CShaderTechnique( + const VfsPath& path, const CShaderDefines& defines, + const PipelineStateDescCallback& callback) + : m_Path(path), m_Defines(defines), m_PipelineStateDescCallback(callback) { } @@ -47,14 +50,14 @@ Renderer::Backend::IShaderProgram* CShaderTechnique::GetShader(int pass) const { ENSURE(0 <= pass && pass < (int)m_Passes.size()); - return m_Passes[pass].GetShader(); + return m_Passes[pass].GetPipelineState()->GetShaderProgram(); } -const Renderer::Backend::GraphicsPipelineStateDesc& -CShaderTechnique::GetGraphicsPipelineStateDesc(int pass) const +Renderer::Backend::IGraphicsPipelineState* +CShaderTechnique::GetGraphicsPipelineState(int pass) const { ENSURE(0 <= pass && pass < static_cast(m_Passes.size())); - return m_Passes[pass].GetPipelineStateDesc(); + return m_Passes[pass].GetPipelineState(); } bool CShaderTechnique::GetSortByDistance() const Index: ps/trunk/source/ps/CStrInternStatic.h =================================================================== --- ps/trunk/source/ps/CStrInternStatic.h +++ ps/trunk/source/ps/CStrInternStatic.h @@ -164,6 +164,9 @@ X(solid) X(sunColor) X(sunDir) +X(terrain_base) +X(terrain_blend) +X(terrain_decal) X(terrain_solid) X(tex) X(texSize) Index: ps/trunk/source/renderer/DebugRenderer.h =================================================================== --- ps/trunk/source/renderer/DebugRenderer.h +++ ps/trunk/source/renderer/DebugRenderer.h @@ -18,6 +18,10 @@ #ifndef INCLUDED_DEBUGRENDERER #define INCLUDED_DEBUGRENDERER +#include "graphics/ShaderTechniquePtr.h" +#include "ps/CStrIntern.h" + +#include #include class CBoundingBoxAligned; @@ -64,6 +68,29 @@ * Render the surfaces of the brush as triangles. */ void DrawBrush(const CBrush& brush, const CColor& color, bool wireframe = false); + +private: + const CShaderTechniquePtr& GetShaderTechnique( + const CStrIntern name, const CColor& color, const bool depthTestEnabled = true, + const bool wireframe = false); + + struct ShaderTechniqueKey + { + CStrIntern name; + bool transparent; + bool depthTestEnabled; + bool wireframe; + }; + struct ShaderTechniqueKeyHash + { + size_t operator()(const ShaderTechniqueKey& key) const; + }; + struct ShaderTechniqueKeyEqual + { + bool operator()(const ShaderTechniqueKey& lhs, const ShaderTechniqueKey& rhs) const; + }; + std::unordered_map + m_ShaderTechniqueMapping; }; #endif // INCLUDED_DEBUGRENDERER Index: ps/trunk/source/renderer/DebugRenderer.cpp =================================================================== --- ps/trunk/source/renderer/DebugRenderer.cpp +++ ps/trunk/source/renderer/DebugRenderer.cpp @@ -23,6 +23,7 @@ #include "graphics/Color.h" #include "graphics/ShaderManager.h" #include "graphics/ShaderProgram.h" +#include "lib/hash.h" #include "maths/BoundingBoxAligned.h" #include "maths/Brush.h" #include "maths/Matrix3D.h" @@ -34,36 +35,6 @@ #include -namespace -{ - -void SetGraphicsPipelineStateFromTechAndColor( - Renderer::Backend::IDeviceCommandContext* deviceCommandContext, - const CShaderTechniquePtr& tech, const CColor& color, const bool depthTestEnabled = true, - const bool wireframe = false) -{ - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = tech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthTestEnabled = depthTestEnabled; - if (color.a != 1.0f) - { - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - } - else - pipelineStateDesc.blendState.enabled = false; - if (wireframe) - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); -} - -} // anonymous namespace - void CDebugRenderer::DrawLine( const CVector3D& from, const CVector3D& to, const CColor& color, const float width, const bool depthTestEnabled) @@ -81,12 +52,13 @@ if (line.size() <= 1) return; - CShaderTechniquePtr debugLineTech = - g_Renderer.GetShaderManager().LoadEffect(str_debug_line); Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); - SetGraphicsPipelineStateFromTechAndColor( - deviceCommandContext, debugLineTech, color, depthTestEnabled); + + CShaderTechniquePtr debugLineTech = + GetShaderTechnique(str_debug_line, color, depthTestEnabled); + deviceCommandContext->SetGraphicsPipelineState( + debugLineTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -142,11 +114,13 @@ void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, const CColor& color) { CShaderTechniquePtr debugCircleTech = - g_Renderer.GetShaderManager().LoadEffect(str_debug_line); + GetShaderTechnique(str_debug_line, color); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); - SetGraphicsPipelineStateFromTechAndColor( - deviceCommandContext, debugCircleTech, color); + + deviceCommandContext->SetGraphicsPipelineState( + debugCircleTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -208,11 +182,12 @@ } CShaderTechniquePtr overlayTech = - g_Renderer.GetShaderManager().LoadEffect(str_debug_line); + GetShaderTechnique(str_debug_line, color, true, wireframe); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); - SetGraphicsPipelineStateFromTechAndColor( - deviceCommandContext, overlayTech, color, true, wireframe); + deviceCommandContext->SetGraphicsPipelineState( + overlayTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); @@ -311,11 +286,13 @@ const CBoundingBoxAligned& boundingBox, const CColor& color, const CMatrix3D& transform, bool wireframe) { - CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); + CShaderTechniquePtr shaderTech = + GetShaderTechnique(str_debug_line, color, true, wireframe); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); - SetGraphicsPipelineStateFromTechAndColor( - deviceCommandContext, shaderTech, color, true, wireframe); + deviceCommandContext->SetGraphicsPipelineState( + shaderTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); @@ -360,11 +337,13 @@ void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wireframe) { - CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); + CShaderTechniquePtr shaderTech = + GetShaderTechnique(str_debug_line, color, true, wireframe); + Renderer::Backend::IDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); - SetGraphicsPipelineStateFromTechAndColor( - deviceCommandContext, shaderTech, color, true, wireframe); + deviceCommandContext->SetGraphicsPipelineState( + shaderTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); @@ -412,3 +391,56 @@ deviceCommandContext->EndPass(); } +size_t CDebugRenderer::ShaderTechniqueKeyHash::operator()( + const ShaderTechniqueKey& key) const +{ + size_t seed = 0; + hash_combine(seed, key.name.GetHash()); + hash_combine(seed, key.transparent); + hash_combine(seed, key.depthTestEnabled); + hash_combine(seed, key.wireframe); + return seed; +} + +bool CDebugRenderer::ShaderTechniqueKeyEqual::operator()( + const ShaderTechniqueKey& lhs, const ShaderTechniqueKey& rhs) const +{ + return + lhs.name == rhs.name && lhs.transparent == rhs.transparent && + lhs.depthTestEnabled == rhs.depthTestEnabled && + lhs.wireframe == rhs.wireframe; +} + +const CShaderTechniquePtr& CDebugRenderer::GetShaderTechnique( + const CStrIntern name, const CColor& color, const bool depthTestEnabled, + const bool wireframe) +{ + const ShaderTechniqueKey key{ + name, color.a != 1.0f, depthTestEnabled, wireframe}; + CShaderTechniquePtr& shaderTechnique = m_ShaderTechniqueMapping[key]; + if (shaderTechnique) + return shaderTechnique; + + shaderTechnique = g_Renderer.GetShaderManager().LoadEffect( + name, {}, + [key](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + pipelineStateDesc.depthStencilState.depthTestEnabled = key.depthTestEnabled; + if (key.transparent) + { + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + } + else + pipelineStateDesc.blendState.enabled = false; + if (key.wireframe) + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + }); + return shaderTechnique; +} Index: ps/trunk/source/renderer/DecalRData.cpp =================================================================== --- ps/trunk/source/renderer/DecalRData.cpp +++ ps/trunk/source/renderer/DecalRData.cpp @@ -152,8 +152,9 @@ CShaderDefines defines = contextDecal; defines.SetMany(itTechBegin->shaderDefines); + // TODO: move enabling blend to XML. CShaderTechniquePtr techBase = g_Renderer.GetShaderManager().LoadEffect( - itTechBegin->shaderEffect, defines); + itTechBegin->shaderEffect == str_terrain_base ? str_terrain_decal : itTechBegin->shaderEffect, defines); if (!techBase) { LOGERROR("Terrain renderer failed to load shader effect (%s)\n", @@ -164,17 +165,8 @@ const int numPasses = techBase->GetNumPasses(); for (int pass = 0; pass < numPasses; ++pass) { - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - techBase->GetGraphicsPipelineStateDesc(pass); - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - pipelineStateDesc.depthStencilState.depthWriteEnabled = false; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->SetGraphicsPipelineState( + techBase->GetGraphicsPipelineState(pass)); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); Index: ps/trunk/source/renderer/ModelRenderer.cpp =================================================================== --- ps/trunk/source/renderer/ModelRenderer.cpp +++ ps/trunk/source/renderer/ModelRenderer.cpp @@ -615,7 +615,7 @@ for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass) { deviceCommandContext->SetGraphicsPipelineState( - currentTech->GetGraphicsPipelineStateDesc(pass)); + currentTech->GetGraphicsPipelineState(pass)); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = currentTech->GetShader(pass); Index: ps/trunk/source/renderer/OverlayRenderer.h =================================================================== --- ps/trunk/source/renderer/OverlayRenderer.h +++ ps/trunk/source/renderer/OverlayRenderer.h @@ -135,7 +135,7 @@ /** * Helper method; renders all overlay lines currently registered in the internals. Batch- * renders textured overlay lines batched according to their visibility status by delegating - * to RenderTexturedOverlayLines(CShaderProgramPtr, bool). + * to RenderTexturedOverlayLines(IShaderProgram, bool). */ void RenderTexturedOverlayLines(Renderer::Backend::IDeviceCommandContext* deviceCommandContext); Index: ps/trunk/source/renderer/OverlayRenderer.cpp =================================================================== --- ps/trunk/source/renderer/OverlayRenderer.cpp +++ ps/trunk/source/renderer/OverlayRenderer.cpp @@ -31,6 +31,7 @@ #include "ps/CStrInternStatic.h" #include "ps/Game.h" #include "ps/Profile.h" +#include "renderer/backend/PipelineState.h" #include "renderer/DebugRenderer.h" #include "renderer/Renderer.h" #include "renderer/SceneRenderer.h" @@ -47,12 +48,50 @@ namespace { -CShaderTechniquePtr GetOverlayLineShaderTechnique(const CShaderDefines& defines) +struct Shader { - return g_Renderer.GetShaderManager().LoadEffect(str_overlay_line, defines); + CShaderTechniquePtr technique, techniqueWireframe; + + const CShaderTechniquePtr& GetTechnique() const + { + return g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME + ? techniqueWireframe : technique; + } +}; + +void AdjustOverlayGraphicsPipelineState(Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) +{ + pipelineStateDesc.depthStencilState.depthWriteEnabled = false; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; } -} // anonymous namespace +Shader CreateShader( + const CStrIntern name, const CShaderDefines& defines) +{ + Shader shader; + + shader.technique = g_Renderer.GetShaderManager().LoadEffect( + name, defines, + [](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + AdjustOverlayGraphicsPipelineState(pipelineStateDesc); + }); + shader.techniqueWireframe = g_Renderer.GetShaderManager().LoadEffect( + name, defines, + [](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + AdjustOverlayGraphicsPipelineState(pipelineStateDesc); + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + }); + + return shader; +} /** * Key used to group quads into batches for more efficient rendering. Currently groups by the combination @@ -104,12 +143,16 @@ size_t m_NumRenderQuads; }; +} // anonymous namespace + struct OverlayRendererInternals { using QuadBatchMap = std::unordered_map; OverlayRendererInternals(); - ~OverlayRendererInternals(){ } + ~OverlayRendererInternals() = default; + + Renderer::Backend::IDevice* device = nullptr; std::vector lines; std::vector texlines; @@ -139,6 +182,12 @@ CShaderDefines defsOverlayLineAlwaysVisible; CShaderDefines defsQuadOverlay; + Shader shaderTexLineNormal; + Shader shaderTexLineAlwaysVisible; + Shader shaderQuadOverlay; + Shader shaderForegroundOverlay; + Shader shaderOverlaySolid; + // Geometry for a unit sphere std::vector sphereVertexes; std::vector sphereIndexes; @@ -202,6 +251,17 @@ } quadIndices.Upload(); quadIndices.FreeBackingStore(); + + shaderTexLineNormal = + CreateShader(str_overlay_line, defsOverlayLineNormal); + shaderTexLineAlwaysVisible = + CreateShader(str_overlay_line, defsOverlayLineAlwaysVisible); + shaderQuadOverlay = + CreateShader(str_overlay_line, defsQuadOverlay); + shaderForegroundOverlay = + CreateShader(str_foreground_overlay, {}); + shaderOverlaySolid = + CreateShader(str_overlay_solid, {}); } OverlayRenderer::OverlayRenderer() @@ -407,25 +467,14 @@ CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - CShaderTechniquePtr shaderTechTexLineNormal = GetOverlayLineShaderTechnique(m->defsOverlayLineNormal); - if (shaderTechTexLineNormal) + if (m->shaderTexLineNormal.technique) { - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - shaderTechTexLineNormal->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthWriteEnabled = false; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = m->shaderTexLineNormal.GetTechnique(); + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* shaderTexLineNormal = shaderTechTexLineNormal->GetShader(); + Renderer::Backend::IShaderProgram* shaderTexLineNormal = shaderTechnique->GetShader(); deviceCommandContext->SetTexture( shaderTexLineNormal->GetBindingSlot(str_losTex), los.GetTexture()); @@ -444,25 +493,15 @@ deviceCommandContext->EndPass(); } - CShaderTechniquePtr shaderTechTexLineAlwaysVisible = GetOverlayLineShaderTechnique(m->defsOverlayLineAlwaysVisible); - if (shaderTechTexLineAlwaysVisible) + if (m->shaderTexLineAlwaysVisible.technique) { - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - shaderTechTexLineAlwaysVisible->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthWriteEnabled = false; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = m->shaderTexLineAlwaysVisible.GetTechnique(); + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* shaderTexLineAlwaysVisible = shaderTechTexLineAlwaysVisible->GetShader(); + Renderer::Backend::IShaderProgram* shaderTexLineAlwaysVisible = + shaderTechnique->GetShader(); // TODO: losTex and losTransform are unused in the always visible shader; see if these can be safely omitted deviceCommandContext->SetTexture( @@ -506,27 +545,15 @@ if (m->quadBatchMap.empty()) return; - CShaderTechniquePtr shaderTech = GetOverlayLineShaderTechnique(m->defsQuadOverlay); - - if (!shaderTech) + if (!m->shaderQuadOverlay.technique) return; - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - shaderTech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthWriteEnabled = false; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = m->shaderQuadOverlay.GetTechnique(); + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + Renderer::Backend::IShaderProgram* shader = shaderTechnique->GetShader(); CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); @@ -601,23 +628,12 @@ const CVector3D right = -viewCamera.GetOrientation().GetLeft(); const CVector3D up = viewCamera.GetOrientation().GetUp(); - CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_foreground_overlay); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - tech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthTestEnabled = false; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = m->shaderForegroundOverlay.GetTechnique(); + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + Renderer::Backend::IShaderProgram* shader = shaderTechnique->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); @@ -750,27 +766,15 @@ { PROFILE3_GPU("overlays (spheres)"); - if (m->spheres.empty()) + if (m->spheres.empty() || m->shaderOverlaySolid.technique) return; - Renderer::Backend::IShaderProgram* shader = nullptr; - CShaderTechniquePtr tech; - - tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - tech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthWriteEnabled = false; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = m->shaderOverlaySolid.GetTechnique(); + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - shader = tech->GetShader(); + Renderer::Backend::IShaderProgram* shader = shaderTechnique->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); Index: ps/trunk/source/renderer/ParticleRenderer.cpp =================================================================== --- ps/trunk/source/renderer/ParticleRenderer.cpp +++ ps/trunk/source/renderer/ParticleRenderer.cpp @@ -161,7 +161,7 @@ if (lastTech) deviceCommandContext->EndPass(); lastTech = currentTech; - deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = lastTech->GetShader(); Index: ps/trunk/source/renderer/PatchRData.cpp =================================================================== --- ps/trunk/source/renderer/PatchRData.cpp +++ ps/trunk/source/renderer/PatchRData.cpp @@ -772,7 +772,7 @@ for (int pass = 0; pass < numPasses; ++pass) { deviceCommandContext->SetGraphicsPipelineState( - techBase->GetGraphicsPipelineStateDesc(pass)); + techBase->GetGraphicsPipelineState(pass)); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); @@ -978,8 +978,12 @@ { CShaderDefines defines = contextBlend; defines.SetMany(bestTex->GetMaterial().GetShaderDefines()); + // TODO: move enabling blend to XML. + const CStrIntern shaderEffect = bestTex->GetMaterial().GetShaderEffect(); + if (shaderEffect != str_terrain_base) + ONCE(LOGWARNING("Shader effect '%s' doesn't support semi-transparent terrain rendering.", shaderEffect.c_str())); layer.m_ShaderTech = g_Renderer.GetShaderManager().LoadEffect( - bestTex->GetMaterial().GetShaderEffect(), defines); + shaderEffect == str_terrain_base ? str_terrain_blend : shaderEffect, defines); } batches.push_back(layer); } @@ -997,16 +1001,8 @@ const int numPasses = techBase->GetNumPasses(); for (int pass = 0; pass < numPasses; ++pass) { - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - techBase->GetGraphicsPipelineStateDesc(pass); - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->SetGraphicsPipelineState( + techBase->GetGraphicsPipelineState(pass)); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); Index: ps/trunk/source/renderer/PostprocManager.cpp =================================================================== --- ps/trunk/source/renderer/PostprocManager.cpp +++ ps/trunk/source/renderer/PostprocManager.cpp @@ -230,7 +230,7 @@ CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = tech->GetShader(); @@ -300,7 +300,7 @@ CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines2); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = tech->GetShader(); deviceCommandContext->SetTexture( @@ -357,7 +357,7 @@ defines3.Add(str_BLOOM_PASS_V, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines3); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); shader = tech->GetShader(); @@ -445,7 +445,7 @@ deviceCommandContext->SetViewports(1, &viewportRect); deviceCommandContext->SetGraphicsPipelineState( - shaderTech->GetGraphicsPipelineStateDesc(pass)); + shaderTech->GetGraphicsPipelineState(pass)); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(pass); Index: ps/trunk/source/renderer/Renderer.cpp =================================================================== --- ps/trunk/source/renderer/Renderer.cpp +++ ps/trunk/source/renderer/Renderer.cpp @@ -457,9 +457,6 @@ { g_Game->GetView()->Prepare(m->deviceCommandContext.get()); - m->deviceCommandContext->SetGraphicsPipelineState( - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); - Renderer::Backend::IFramebuffer* framebuffer = nullptr; CPostprocManager& postprocManager = g_Renderer.GetPostprocManager(); Index: ps/trunk/source/renderer/SceneRenderer.cpp =================================================================== --- ps/trunk/source/renderer/SceneRenderer.cpp +++ ps/trunk/source/renderer/SceneRenderer.cpp @@ -575,8 +575,6 @@ screenScissor.x2 = static_cast(ceil((reflectionScissor[1].X * 0.5f + 0.5f) * vpWidth)); screenScissor.y2 = static_cast(ceil((reflectionScissor[1].Y * 0.5f + 0.5f) * vpHeight)); - deviceCommandContext->SetGraphicsPipelineState( - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->BeginFramebufferPass(wm.m_ReflectionFramebuffer.get()); Renderer::Backend::IDeviceCommandContext::Rect viewportRect{}; @@ -652,8 +650,6 @@ screenScissor.x2 = static_cast(ceil((refractionScissor[1].X * 0.5f + 0.5f) * vpWidth)); screenScissor.y2 = static_cast(ceil((refractionScissor[1].Y * 0.5f + 0.5f) * vpHeight)); - deviceCommandContext->SetGraphicsPipelineState( - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->BeginFramebufferPass(wm.m_RefractionFramebuffer.get()); Renderer::Backend::IDeviceCommandContext::Rect viewportRect{}; @@ -704,8 +700,6 @@ // inverted depth test so any behind an occluder will get drawn in a constant // color. - deviceCommandContext->SetGraphicsPipelineState( - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->ClearFramebuffer(false, true, true); // Render occluders: Index: ps/trunk/source/renderer/ShadowMap.cpp =================================================================== --- ps/trunk/source/renderer/ShadowMap.cpp +++ ps/trunk/source/renderer/ShadowMap.cpp @@ -586,9 +586,6 @@ void ShadowMap::BeginRender( Renderer::Backend::IDeviceCommandContext* deviceCommandContext) { - deviceCommandContext->SetGraphicsPipelineState( - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); - ENSURE(m->Framebuffer); deviceCommandContext->BeginFramebufferPass(m->Framebuffer.get()); Index: ps/trunk/source/renderer/SilhouetteRenderer.h =================================================================== --- ps/trunk/source/renderer/SilhouetteRenderer.h +++ ps/trunk/source/renderer/SilhouetteRenderer.h @@ -19,6 +19,7 @@ #define INCLUDED_SILHOUETTERENDERER #include "graphics/Overlay.h" +#include "graphics/ShaderTechniquePtr.h" #include "maths/BoundingBoxAligned.h" #include "renderer/backend/IDeviceCommandContext.h" @@ -75,6 +76,8 @@ std::vector m_DebugRects; std::vector m_DebugSpheres; + + CShaderTechniquePtr m_ShaderTech; }; #endif // INCLUDED_SILHOUETTERENDERER Index: ps/trunk/source/renderer/SilhouetteRenderer.cpp =================================================================== --- ps/trunk/source/renderer/SilhouetteRenderer.cpp +++ ps/trunk/source/renderer/SilhouetteRenderer.cpp @@ -469,15 +469,22 @@ proj.SetOrtho(0.f, g_MaxCoord, 0.f, g_MaxCoord, -1.f, 1000.f); m = proj * m; - CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - shaderTech->GetGraphicsPipelineStateDesc(); + if (!m_ShaderTech) + { + m_ShaderTech = g_Renderer.GetShaderManager().LoadEffect( + str_solid, {}, + [](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + }); + } + deviceCommandContext->BeginPass(); - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->SetGraphicsPipelineState( + m_ShaderTech->GetGraphicsPipelineState()); - Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + Renderer::Backend::IShaderProgram* shader = m_ShaderTech->GetShader(); deviceCommandContext->SetUniform( shader->GetBindingSlot(str_transform), proj.AsFloatArray()); Index: ps/trunk/source/renderer/SkyManager.cpp =================================================================== --- ps/trunk/source/renderer/SkyManager.cpp +++ ps/trunk/source/renderer/SkyManager.cpp @@ -222,7 +222,7 @@ CShaderTechniquePtr skytech = g_Renderer.GetShaderManager().LoadEffect(str_sky_simple); deviceCommandContext->SetGraphicsPipelineState( - skytech->GetGraphicsPipelineStateDesc()); + skytech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = skytech->GetShader(); deviceCommandContext->SetTexture( Index: ps/trunk/source/renderer/TerrainOverlay.h =================================================================== --- ps/trunk/source/renderer/TerrainOverlay.h +++ ps/trunk/source/renderer/TerrainOverlay.h @@ -23,8 +23,10 @@ #ifndef INCLUDED_TERRAINOVERLAY #define INCLUDED_TERRAINOVERLAY +#include "graphics/ShaderTechniquePtr.h" #include "renderer/backend/ITexture.h" #include "renderer/backend/IDeviceCommandContext.h" +#include "renderer/backend/PipelineState.h" struct CColor; struct SColor4ub; @@ -179,6 +181,9 @@ ssize_t m_i, m_j; CTerrain* m_Terrain; + + CShaderTechniquePtr m_OverlayTechTile, m_OverlayTechTileHidden; + CShaderTechniquePtr m_OverlayTechOutline, m_OverlayTechOutlineHidden; }; /** Index: ps/trunk/source/renderer/TerrainOverlay.cpp =================================================================== --- ps/trunk/source/renderer/TerrainOverlay.cpp +++ ps/trunk/source/renderer/TerrainOverlay.cpp @@ -39,9 +39,55 @@ #include +namespace +{ + // Global overlay list management: +std::vector> g_TerrainOverlayList; + +void AdjustOverlayGraphicsPipelineState( + Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc, const bool drawHidden) +{ + pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; + pipelineStateDesc.blendState.enabled = true; + pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = + Renderer::Backend::BlendFactor::SRC_ALPHA; + pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = + Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; + pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = + Renderer::Backend::BlendOp::ADD; + pipelineStateDesc.rasterizationState.cullMode = + drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; +} + + CShaderTechniquePtr CreateOverlayTileShaderTechnique(const bool drawHidden) +{ + return g_Renderer.GetShaderManager().LoadEffect( + str_debug_line, {}, + [drawHidden](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + AdjustOverlayGraphicsPipelineState(pipelineStateDesc, drawHidden); + // To ensure that outlines are drawn on top of the terrain correctly (and + // don't Z-fight and flicker nastily), use detph bias to pull them towards + // the camera. + pipelineStateDesc.rasterizationState.depthBiasEnabled = true; + pipelineStateDesc.rasterizationState.depthBiasConstantFactor = -1.0f; + pipelineStateDesc.rasterizationState.depthBiasSlopeFactor = -1.0f; + }); +} + +CShaderTechniquePtr CreateOverlayOutlineShaderTechnique(const bool drawHidden) +{ + return g_Renderer.GetShaderManager().LoadEffect( + str_debug_line, {}, + [drawHidden](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + AdjustOverlayGraphicsPipelineState(pipelineStateDesc, drawHidden); + pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; + }); +} -static std::vector > g_TerrainOverlayList; +} // anonymous namespace ITerrainOverlay::ITerrainOverlay(int priority) { @@ -93,9 +139,15 @@ ////////////////////////////////////////////////////////////////////////// -TerrainOverlay::TerrainOverlay(const CSimContext& simContext, int priority /* = 100 */) +TerrainOverlay::TerrainOverlay( + const CSimContext& simContext, int priority /* = 100 */) : ITerrainOverlay(priority), m_Terrain(&simContext.GetTerrain()) { + m_OverlayTechTile = CreateOverlayTileShaderTechnique(false); + m_OverlayTechTileHidden = CreateOverlayTileShaderTechnique(true); + + m_OverlayTechOutline = CreateOverlayOutlineShaderTechnique(false); + m_OverlayTechOutlineHidden = CreateOverlayOutlineShaderTechnique(true); } void TerrainOverlay::StartRender() @@ -188,30 +240,12 @@ } #undef ADD - CShaderTechniquePtr overlayTech = - g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - overlayTech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - pipelineStateDesc.rasterizationState.cullMode = - drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; - // To ensure that outlines are drawn on top of the terrain correctly (and - // don't Z-fight and flicker nastily), use detph bias to pull them towards - // the camera. - pipelineStateDesc.rasterizationState.depthBiasEnabled = true; - pipelineStateDesc.rasterizationState.depthBiasConstantFactor = -1.0f; - pipelineStateDesc.rasterizationState.depthBiasSlopeFactor = -1.0f; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = drawHidden ? m_OverlayTechTileHidden : m_OverlayTechTile; + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); + Renderer::Backend::IShaderProgram* overlayShader = shaderTechnique->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); @@ -260,25 +294,12 @@ ADD(i, j + 1); #undef ADD - CShaderTechniquePtr overlayTech = - g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - overlayTech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthTestEnabled = !drawHidden; - pipelineStateDesc.blendState.enabled = true; - pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = - Renderer::Backend::BlendFactor::SRC_ALPHA; - pipelineStateDesc.blendState.dstColorBlendFactor = pipelineStateDesc.blendState.dstAlphaBlendFactor = - Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; - pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = - Renderer::Backend::BlendOp::ADD; - pipelineStateDesc.rasterizationState.cullMode = - drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; - pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + const CShaderTechniquePtr& shaderTechnique = drawHidden ? m_OverlayTechOutlineHidden : m_OverlayTechOutline; + deviceCommandContext->SetGraphicsPipelineState( + shaderTechnique->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); + Renderer::Backend::IShaderProgram* overlayShader = shaderTechnique->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); Index: ps/trunk/source/renderer/TerrainRenderer.cpp =================================================================== --- ps/trunk/source/renderer/TerrainRenderer.cpp +++ ps/trunk/source/renderer/TerrainRenderer.cpp @@ -40,6 +40,7 @@ #include "ps/Profile.h" #include "ps/World.h" #include "renderer/backend/IDevice.h" +#include "renderer/backend/PipelineState.h" #include "renderer/DecalRData.h" #include "renderer/PatchRData.h" #include "renderer/Renderer.h" @@ -50,6 +51,8 @@ #include "renderer/VertexArray.h" #include "renderer/WaterManager.h" +#include + /** * TerrainRenderer keeps track of which phase it is in, to detect * when Submit, PrepareForRendering etc. are called in the wrong order. @@ -78,6 +81,8 @@ /// Fancy water shader CShaderTechniquePtr fancyWaterTech; + CShaderTechniquePtr shaderTechniqueSolid, shaderTechniqueSolidDepthTest; + CSimulation2* simulation; }; @@ -173,7 +178,7 @@ CShaderTechniquePtr debugOverlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_overlay); deviceCommandContext->SetGraphicsPipelineState( - debugOverlayTech->GetGraphicsPipelineStateDesc()); + debugOverlayTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* debugOverlayShader = debugOverlayTech->GetShader(); @@ -284,15 +289,22 @@ if (visiblePatches.empty() && visibleDecals.empty()) return; + if (!m->shaderTechniqueSolid) + { + m->shaderTechniqueSolid = g_Renderer.GetShaderManager().LoadEffect( + str_solid, {}, + [](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + }); + } + // render the solid black sides of the map first - CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_solid); - Renderer::Backend::GraphicsPipelineStateDesc solidPipelineStateDesc = - techSolid->GetGraphicsPipelineStateDesc(); - solidPipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; - deviceCommandContext->SetGraphicsPipelineState(solidPipelineStateDesc); + deviceCommandContext->SetGraphicsPipelineState( + m->shaderTechniqueSolid->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* shaderSolid = techSolid->GetShader(); + Renderer::Backend::IShaderProgram* shaderSolid = m->shaderTechniqueSolid->GetShader(); const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( @@ -328,7 +340,7 @@ CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_terrain_solid, defines); deviceCommandContext->SetGraphicsPipelineState( - solidTech->GetGraphicsPipelineStateDesc()); + solidTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* solidShader = solidTech->GetShader(); @@ -436,7 +448,7 @@ const float repeatPeriod = waterManager.m_RepeatPeriod; deviceCommandContext->SetGraphicsPipelineState( - m->fancyWaterTech->GetGraphicsPipelineStateDesc()); + m->fancyWaterTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader(); @@ -622,7 +634,7 @@ CShaderTechniquePtr waterSimpleTech = g_Renderer.GetShaderManager().LoadEffect(str_water_simple, context); deviceCommandContext->SetGraphicsPipelineState( - waterSimpleTech->GetGraphicsPipelineStateDesc()); + waterSimpleTech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* waterSimpleShader = waterSimpleTech->GetShader(); @@ -680,21 +692,28 @@ if (!waterManager.WillRenderFancyWater()) return; + if (!m->shaderTechniqueSolidDepthTest) + { + m->shaderTechniqueSolidDepthTest = g_Renderer.GetShaderManager().LoadEffect( + str_solid, {}, + [](Renderer::Backend::SGraphicsPipelineStateDesc& pipelineStateDesc) + { + pipelineStateDesc.depthStencilState.depthTestEnabled = true; + pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; + }); + } + GPU_SCOPED_LABEL(deviceCommandContext, "Render water foam occluders"); // Render normals and foam to a framebuffer if we're using fancy effects. deviceCommandContext->BeginFramebufferPass(waterManager.m_FancyEffectsFramebuffer.get()); // Overwrite waves that would be behind the ground. - CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = - dummyTech->GetGraphicsPipelineStateDesc(); - pipelineStateDesc.depthStencilState.depthTestEnabled = true; - pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; - deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->SetGraphicsPipelineState( + m->shaderTechniqueSolidDepthTest->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); - Renderer::Backend::IShaderProgram* dummyShader = dummyTech->GetShader(); + Renderer::Backend::IShaderProgram* dummyShader = m->shaderTechniqueSolidDepthTest->GetShader(); const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); deviceCommandContext->SetUniform( Index: ps/trunk/source/renderer/WaterManager.cpp =================================================================== --- ps/trunk/source/renderer/WaterManager.cpp +++ ps/trunk/source/renderer/WaterManager.cpp @@ -840,13 +840,11 @@ GPU_SCOPED_LABEL(deviceCommandContext, "Render Waves"); - deviceCommandContext->SetGraphicsPipelineState( - Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->BeginFramebufferPass(m_FancyEffectsFramebuffer.get()); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_water_waves); deviceCommandContext->SetGraphicsPipelineState( - tech->GetGraphicsPipelineStateDesc()); + tech->GetGraphicsPipelineState()); deviceCommandContext->BeginPass(); Renderer::Backend::IShaderProgram* shader = tech->GetShader(); Index: ps/trunk/source/renderer/backend/IDevice.h =================================================================== --- ps/trunk/source/renderer/backend/IDevice.h +++ ps/trunk/source/renderer/backend/IDevice.h @@ -27,6 +27,7 @@ #include "renderer/backend/IFramebuffer.h" #include "renderer/backend/IShaderProgram.h" #include "renderer/backend/ITexture.h" +#include "renderer/backend/PipelineState.h" #include "scriptinterface/ScriptForward.h" #include @@ -74,6 +75,13 @@ virtual std::unique_ptr CreateCommandContext() = 0; + /** + * Creates a graphics pipeline state. It's a caller responsibility to + * guarantee a lifespan of IShaderProgram stored in the description. + */ + virtual std::unique_ptr CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) = 0; + virtual std::unique_ptr CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, Index: ps/trunk/source/renderer/backend/IDeviceCommandContext.h =================================================================== --- ps/trunk/source/renderer/backend/IDeviceCommandContext.h +++ ps/trunk/source/renderer/backend/IDeviceCommandContext.h @@ -40,7 +40,7 @@ class IDeviceCommandContext : public IDeviceObject { public: - virtual void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) = 0; + virtual void SetGraphicsPipelineState(IGraphicsPipelineState* pipelineState) = 0; virtual void BlitFramebuffer( IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) = 0; Index: ps/trunk/source/renderer/backend/PipelineState.h =================================================================== --- ps/trunk/source/renderer/backend/PipelineState.h +++ ps/trunk/source/renderer/backend/PipelineState.h @@ -20,6 +20,7 @@ #include "graphics/Color.h" #include "renderer/backend/CompareOp.h" +#include "renderer/backend/IDeviceObject.h" #include "renderer/backend/IShaderProgram.h" class CStr; @@ -53,7 +54,7 @@ DECREMENT_AND_WRAP }; -struct StencilOpState +struct SStencilOpState { StencilOp failOp; StencilOp passOp; @@ -61,7 +62,7 @@ CompareOp compareOp; }; -struct DepthStencilStateDesc +struct SDepthStencilStateDesc { bool depthTestEnabled; CompareOp depthCompareOp; @@ -70,8 +71,8 @@ uint32_t stencilReadMask; uint32_t stencilWriteMask; uint32_t stencilReference; - StencilOpState stencilFrontFace; - StencilOpState stencilBackFace; + SStencilOpState stencilFrontFace; + SStencilOpState stencilBackFace; }; // TODO: add per constant description. @@ -118,7 +119,7 @@ constexpr uint8_t ALPHA = 0x08; } // namespace ColorWriteMask -struct BlendStateDesc +struct SBlendStateDesc { bool enabled; BlendFactor srcColorBlendFactor; @@ -150,7 +151,7 @@ CLOCKWISE }; -struct RasterizationStateDesc +struct SRasterizationStateDesc { PolygonMode polygonMode; CullMode cullMode; @@ -160,19 +161,19 @@ float depthBiasSlopeFactor; }; -struct GraphicsPipelineStateDesc +struct SGraphicsPipelineStateDesc { // It's a backend client reponsibility to keep the shader program alive // while it's bound. IShaderProgram* shaderProgram; - DepthStencilStateDesc depthStencilState; - BlendStateDesc blendState; - RasterizationStateDesc rasterizationState; + SDepthStencilStateDesc depthStencilState; + SBlendStateDesc blendState; + SRasterizationStateDesc rasterizationState; }; // We don't provide additional helpers intentionally because all custom states // should be described with a related shader and should be switched together. -GraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc(); +SGraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc(); StencilOp ParseStencilOp(const CStr& str); @@ -183,6 +184,15 @@ CullMode ParseCullMode(const CStr& str); FrontFace ParseFrontFace(const CStr& str); +/** + * A holder for precompiled graphics pipeline description. + */ +class IGraphicsPipelineState : public IDeviceObject +{ +public: + virtual IShaderProgram* GetShaderProgram() const = 0; +}; + } // namespace Backend } // namespace Renderer Index: ps/trunk/source/renderer/backend/PipelineState.cpp =================================================================== --- ps/trunk/source/renderer/backend/PipelineState.cpp +++ ps/trunk/source/renderer/backend/PipelineState.cpp @@ -27,9 +27,9 @@ namespace Backend { -GraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc() +SGraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc() { - GraphicsPipelineStateDesc desc{}; + SGraphicsPipelineStateDesc desc{}; desc.shaderProgram = nullptr; Index: ps/trunk/source/renderer/backend/dummy/Device.h =================================================================== --- ps/trunk/source/renderer/backend/dummy/Device.h +++ ps/trunk/source/renderer/backend/dummy/Device.h @@ -21,6 +21,10 @@ #include "renderer/backend/dummy/DeviceForward.h" #include "renderer/backend/IDevice.h" +#include +#include +#include + class CShaderDefines; namespace Renderer @@ -51,6 +55,9 @@ std::unique_ptr CreateCommandContext() override; + std::unique_ptr CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) override; + std::unique_ptr CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, Index: ps/trunk/source/renderer/backend/dummy/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/dummy/Device.cpp +++ ps/trunk/source/renderer/backend/dummy/Device.cpp @@ -22,6 +22,7 @@ #include "renderer/backend/dummy/Buffer.h" #include "renderer/backend/dummy/DeviceCommandContext.h" #include "renderer/backend/dummy/Framebuffer.h" +#include "renderer/backend/dummy/PipelineState.h" #include "renderer/backend/dummy/ShaderProgram.h" #include "renderer/backend/dummy/Texture.h" #include "scriptinterface/JSON.h" @@ -73,6 +74,12 @@ return CDeviceCommandContext::Create(this); } +std::unique_ptr CDevice::CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) +{ + return CGraphicsPipelineState::Create(this, pipelineStateDesc); +} + std::unique_ptr CDevice::CreateTexture( const char* UNUSED(name), const CTexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, Index: ps/trunk/source/renderer/backend/dummy/DeviceCommandContext.h =================================================================== --- ps/trunk/source/renderer/backend/dummy/DeviceCommandContext.h +++ ps/trunk/source/renderer/backend/dummy/DeviceCommandContext.h @@ -46,7 +46,7 @@ IDevice* GetDevice() override; - void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) override; + void SetGraphicsPipelineState(IGraphicsPipelineState* pipelineState) override; void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override; Index: ps/trunk/source/renderer/backend/dummy/DeviceCommandContext.cpp =================================================================== --- ps/trunk/source/renderer/backend/dummy/DeviceCommandContext.cpp +++ ps/trunk/source/renderer/backend/dummy/DeviceCommandContext.cpp @@ -52,7 +52,7 @@ } void CDeviceCommandContext::SetGraphicsPipelineState( - const GraphicsPipelineStateDesc&) + IGraphicsPipelineState*) { } Index: ps/trunk/source/renderer/backend/dummy/PipelineState.h =================================================================== --- ps/trunk/source/renderer/backend/dummy/PipelineState.h +++ ps/trunk/source/renderer/backend/dummy/PipelineState.h @@ -0,0 +1,67 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_DUMMY_PIPELINESTATE +#define INCLUDED_RENDERER_BACKEND_DUMMY_PIPELINESTATE + +#include "renderer/backend/PipelineState.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +class CDevice; + +class CGraphicsPipelineState final : public IGraphicsPipelineState +{ +public: + ~CGraphicsPipelineState() override = default; + + IDevice* GetDevice() override; + + IShaderProgram* GetShaderProgram() const override { return m_Desc.shaderProgram; } + + const SGraphicsPipelineStateDesc& GetDesc() const { return m_Desc; } + +private: + friend class CDevice; + + static std::unique_ptr Create( + CDevice* device, const SGraphicsPipelineStateDesc& desc); + + CGraphicsPipelineState() = default; + + CDevice* m_Device = nullptr; + + SGraphicsPipelineStateDesc m_Desc{}; +}; + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_DUMMY_PIPELINESTATE Index: ps/trunk/source/renderer/backend/dummy/PipelineState.cpp =================================================================== --- ps/trunk/source/renderer/backend/dummy/PipelineState.cpp +++ ps/trunk/source/renderer/backend/dummy/PipelineState.cpp @@ -0,0 +1,52 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "PipelineState.h" + +#include "renderer/backend/dummy/Device.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace Dummy +{ + +// static +std::unique_ptr CGraphicsPipelineState::Create( + CDevice* device, const SGraphicsPipelineStateDesc& desc) +{ + std::unique_ptr pipelineState{new CGraphicsPipelineState()}; + pipelineState->m_Device = device; + pipelineState->m_Desc = desc; + return pipelineState; +} + +IDevice* CGraphicsPipelineState::GetDevice() +{ + return m_Device; +} + +} // namespace Dummy + +} // namespace Backend + +} // namespace Renderer Index: ps/trunk/source/renderer/backend/gl/Device.h =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.h +++ ps/trunk/source/renderer/backend/gl/Device.h @@ -68,6 +68,9 @@ std::unique_ptr CreateCommandContext() override; + std::unique_ptr CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) override; + CDeviceCommandContext* GetActiveCommandContext() { return m_ActiveCommandContext; } std::unique_ptr CreateTexture( Index: ps/trunk/source/renderer/backend/gl/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/Device.cpp +++ ps/trunk/source/renderer/backend/gl/Device.cpp @@ -26,6 +26,7 @@ #include "ps/ConfigDB.h" #include "ps/Profile.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/PipelineState.h" #include "renderer/backend/gl/Texture.h" #include "scriptinterface/JSON.h" #include "scriptinterface/Object.h" @@ -868,6 +869,12 @@ return commandContet; } +std::unique_ptr CDevice::CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) +{ + return CGraphicsPipelineState::Create(this, pipelineStateDesc); +} + std::unique_ptr CDevice::CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.h @@ -53,7 +53,9 @@ IDevice* GetDevice() override; - void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) override; + void SetGraphicsPipelineState(const SGraphicsPipelineStateDesc& pipelineState); + + void SetGraphicsPipelineState(IGraphicsPipelineState* pipelineState) override; void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override; @@ -155,14 +157,14 @@ void ResetStates(); void SetGraphicsPipelineStateImpl( - const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force); + const SGraphicsPipelineStateDesc& pipelineStateDesc, const bool force); void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle); void BindBuffer(const IBuffer::Type type, CBuffer* buffer); CDevice* m_Device = nullptr; - GraphicsPipelineStateDesc m_GraphicsPipelineStateDesc{}; + SGraphicsPipelineStateDesc m_GraphicsPipelineStateDesc{}; CFramebuffer* m_Framebuffer = nullptr; CShaderProgram* m_ShaderProgram = nullptr; uint32_t m_ScissorCount = 0; Index: ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp +++ ps/trunk/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -24,6 +24,7 @@ #include "renderer/backend/gl/Device.h" #include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/Mapping.h" +#include "renderer/backend/gl/PipelineState.h" #include "renderer/backend/gl/ShaderProgram.h" #include "renderer/backend/gl/Texture.h" @@ -43,7 +44,7 @@ namespace { -bool operator==(const StencilOpState& lhs, const StencilOpState& rhs) +bool operator==(const SStencilOpState& lhs, const SStencilOpState& rhs) { return lhs.failOp == rhs.failOp && @@ -51,7 +52,7 @@ lhs.depthFailOp == rhs.depthFailOp && lhs.compareOp == rhs.compareOp; } -bool operator!=(const StencilOpState& lhs, const StencilOpState& rhs) +bool operator!=(const SStencilOpState& lhs, const SStencilOpState& rhs) { return !operator==(lhs, rhs); } @@ -259,9 +260,17 @@ } void CDeviceCommandContext::SetGraphicsPipelineState( - const GraphicsPipelineStateDesc& pipelineStateDesc) + const SGraphicsPipelineStateDesc& pipelineState) { - SetGraphicsPipelineStateImpl(pipelineStateDesc, false); + SetGraphicsPipelineStateImpl(pipelineState, false); +} + +void CDeviceCommandContext::SetGraphicsPipelineState( + IGraphicsPipelineState* pipelineState) +{ + ENSURE(pipelineState); + SetGraphicsPipelineStateImpl( + pipelineState->As()->GetDesc(), false); } void CDeviceCommandContext::UploadTexture( @@ -556,7 +565,7 @@ } void CDeviceCommandContext::SetGraphicsPipelineStateImpl( - const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force) + const SGraphicsPipelineStateDesc& pipelineStateDesc, const bool force) { ENSURE(!m_InsidePass); @@ -589,8 +598,8 @@ m_ShaderProgram = nextShaderProgram; } - const DepthStencilStateDesc& currentDepthStencilStateDesc = m_GraphicsPipelineStateDesc.depthStencilState; - const DepthStencilStateDesc& nextDepthStencilStateDesc = pipelineStateDesc.depthStencilState; + const SDepthStencilStateDesc& currentDepthStencilStateDesc = m_GraphicsPipelineStateDesc.depthStencilState; + const SDepthStencilStateDesc& nextDepthStencilStateDesc = pipelineStateDesc.depthStencilState; if (force || currentDepthStencilStateDesc.depthTestEnabled != nextDepthStencilStateDesc.depthTestEnabled) { if (nextDepthStencilStateDesc.depthTestEnabled) @@ -675,8 +684,8 @@ } } - const BlendStateDesc& currentBlendStateDesc = m_GraphicsPipelineStateDesc.blendState; - const BlendStateDesc& nextBlendStateDesc = pipelineStateDesc.blendState; + const SBlendStateDesc& currentBlendStateDesc = m_GraphicsPipelineStateDesc.blendState; + const SBlendStateDesc& nextBlendStateDesc = pipelineStateDesc.blendState; if (force || currentBlendStateDesc.enabled != nextBlendStateDesc.enabled) { if (nextBlendStateDesc.enabled) @@ -739,9 +748,9 @@ ApplyColorMask(nextBlendStateDesc.colorWriteMask); } - const RasterizationStateDesc& currentRasterizationStateDesc = + const SRasterizationStateDesc& currentRasterizationStateDesc = m_GraphicsPipelineStateDesc.rasterizationState; - const RasterizationStateDesc& nextRasterizationStateDesc = + const SRasterizationStateDesc& nextRasterizationStateDesc = pipelineStateDesc.rasterizationState; if (force || currentRasterizationStateDesc.polygonMode != nextRasterizationStateDesc.polygonMode) @@ -867,6 +876,9 @@ void CDeviceCommandContext::BeginFramebufferPass(IFramebuffer* framebuffer) { + SetGraphicsPipelineStateImpl( + MakeDefaultGraphicsPipelineStateDesc(), false); + ENSURE(!m_InsideFramebufferPass); m_InsideFramebufferPass = true; ENSURE(framebuffer); Index: ps/trunk/source/renderer/backend/gl/PipelineState.h =================================================================== --- ps/trunk/source/renderer/backend/gl/PipelineState.h +++ ps/trunk/source/renderer/backend/gl/PipelineState.h @@ -0,0 +1,68 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_PIPELINESTATE +#define INCLUDED_RENDERER_BACKEND_GL_PIPELINESTATE + +#include "lib/ogl.h" +#include "renderer/backend/PipelineState.h" + +#include +#include + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +class CGraphicsPipelineState final : public IGraphicsPipelineState +{ +public: + ~CGraphicsPipelineState() override = default; + + IDevice* GetDevice() override; + + IShaderProgram* GetShaderProgram() const override { return m_Desc.shaderProgram; } + + const SGraphicsPipelineStateDesc& GetDesc() const { return m_Desc; } + +private: + friend class CDevice; + + static std::unique_ptr Create( + CDevice* device, const SGraphicsPipelineStateDesc& desc); + + CGraphicsPipelineState() = default; + + CDevice* m_Device = nullptr; + + SGraphicsPipelineStateDesc m_Desc{}; +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_PIPELINESTATE Index: ps/trunk/source/renderer/backend/gl/PipelineState.cpp =================================================================== --- ps/trunk/source/renderer/backend/gl/PipelineState.cpp +++ ps/trunk/source/renderer/backend/gl/PipelineState.cpp @@ -0,0 +1,52 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "PipelineState.h" + +#include "renderer/backend/gl/Device.h" + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +// static +std::unique_ptr CGraphicsPipelineState::Create( + CDevice* device, const SGraphicsPipelineStateDesc& desc) +{ + std::unique_ptr pipelineState{new CGraphicsPipelineState()}; + pipelineState->m_Device = device; + pipelineState->m_Desc = desc; + return pipelineState; +} + +IDevice* CGraphicsPipelineState::GetDevice() +{ + return m_Device; +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer Index: ps/trunk/source/renderer/backend/vulkan/Device.h =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Device.h +++ ps/trunk/source/renderer/backend/vulkan/Device.h @@ -56,6 +56,9 @@ std::unique_ptr CreateCommandContext() override; + std::unique_ptr CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) override; + std::unique_ptr CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height, Index: ps/trunk/source/renderer/backend/vulkan/Device.cpp =================================================================== --- ps/trunk/source/renderer/backend/vulkan/Device.cpp +++ ps/trunk/source/renderer/backend/vulkan/Device.cpp @@ -79,6 +79,13 @@ return nullptr; } +std::unique_ptr CDevice::CreateGraphicsPipelineState( + const SGraphicsPipelineStateDesc& pipelineStateDesc) +{ + UNUSED2(pipelineStateDesc); + return nullptr; +} + std::unique_ptr CDevice::CreateTexture( const char* name, const ITexture::Type type, const uint32_t usage, const Format format, const uint32_t width, const uint32_t height,