diff --git a/binaries/data/mods/public/shaders/effects/terrain_blend.xml b/binaries/data/mods/public/shaders/effects/terrain_blend.xml
index 88e2dd6f7b..3ca646775f 100644
--- a/binaries/data/mods/public/shaders/effects/terrain_blend.xml
+++ b/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 @@
+
diff --git a/binaries/data/mods/public/shaders/effects/terrain_decal.xml b/binaries/data/mods/public/shaders/effects/terrain_decal.xml
index c1116c7bf4..93fa5f3878 100644
--- a/binaries/data/mods/public/shaders/effects/terrain_decal.xml
+++ b/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 @@
+
diff --git a/source/graphics/Canvas2D.cpp b/source/graphics/Canvas2D.cpp
index 26853460bf..ffbe7ff5c1 100644
--- a/source/graphics/Canvas2D.cpp
+++ b/source/graphics/Canvas2D.cpp
@@ -98,7 +98,7 @@ public:
// 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();
diff --git a/source/graphics/LOSTexture.cpp b/source/graphics/LOSTexture.cpp
index 1088d2b782..5ce6fb1bb1 100644
--- a/source/graphics/LOSTexture.cpp
+++ b/source/graphics/LOSTexture.cpp
@@ -146,7 +146,7 @@ void CLOSTexture::InterpolateLOS(Renderer::Backend::IDeviceCommandContext* devic
deviceCommandContext->BeginFramebufferPass(m_SmoothFramebuffers[m_WhichTexture].get());
deviceCommandContext->SetGraphicsPipelineState(
- m_SmoothTech->GetGraphicsPipelineStateDesc());
+ m_SmoothTech->GetGraphicsPipelineState());
deviceCommandContext->BeginPass();
Renderer::Backend::IShaderProgram* shader = m_SmoothTech->GetShader();
diff --git a/source/graphics/MiniMapTexture.cpp b/source/graphics/MiniMapTexture.cpp
index 08cf830e65..b8e6ccbc7f 100644
--- a/source/graphics/MiniMapTexture.cpp
+++ b/source/graphics/MiniMapTexture.cpp
@@ -282,6 +282,26 @@ CMiniMapTexture::CMiniMapTexture(CSimulation2& simulation)
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 @@ void CMiniMapTexture::RenderFinalTexture(
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines);
deviceCommandContext->SetGraphicsPipelineState(
- tech->GetGraphicsPipelineStateDesc());
+ tech->GetGraphicsPipelineState());
deviceCommandContext->BeginPass();
shader = tech->GetShader();
@@ -513,20 +533,9 @@ void CMiniMapTexture::RenderFinalTexture(
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 @@ void CMiniMapTexture::RenderFinalTexture(
tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap_los, CShaderDefines());
deviceCommandContext->SetGraphicsPipelineState(
- tech->GetGraphicsPipelineStateDesc());
+ tech->GetGraphicsPipelineState());
deviceCommandContext->BeginPass();
shader = tech->GetShader();
@@ -765,7 +774,7 @@ void CMiniMapTexture::DrawEntities(
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();
diff --git a/source/graphics/MiniMapTexture.h b/source/graphics/MiniMapTexture.h
index b00eb4b578..a8456e65c5 100644
--- a/source/graphics/MiniMapTexture.h
+++ b/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 @@ private:
VertexArray m_InstanceVertexArray;
VertexArray::Attribute m_InstanceAttributePosition;
+ CShaderTechniquePtr m_TerritoryTechnique;
+
size_t m_EntitiesDrawn = 0;
double m_PingDuration = 25.0;
diff --git a/source/graphics/ShaderManager.cpp b/source/graphics/ShaderManager.cpp
index 4c5262da55..b1cab27c62 100644
--- a/source/graphics/ShaderManager.cpp
+++ b/source/graphics/ShaderManager.cpp
@@ -116,7 +116,8 @@ CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDef
// 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 @@ CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDef
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 @@ bool CShaderManager::LoadTechnique(CShaderTechniquePtr& tech)
// 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 @@ bool CShaderManager::LoadTechnique(CShaderTechniquePtr& tech)
{
CShaderDefines passDefines = techDefines;
- Renderer::Backend::GraphicsPipelineStateDesc passPipelineStateDesc =
+ Renderer::Backend::SGraphicsPipelineStateDesc passPipelineStateDesc =
Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc();
XERO_ITER_EL(Child, Element)
@@ -410,7 +430,11 @@ bool CShaderManager::LoadTechnique(CShaderTechniquePtr& tech)
{
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);
}
}
}
diff --git a/source/graphics/ShaderManager.h b/source/graphics/ShaderManager.h
index 17a70cfc2e..bae91147f5 100644
--- a/source/graphics/ShaderManager.h
+++ b/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,10 +50,18 @@ public:
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.
*/
@@ -71,7 +81,7 @@ private:
}
};
- // 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?
diff --git a/source/graphics/ShaderTechnique.cpp b/source/graphics/ShaderTechnique.cpp
index b7b6f19ee0..cb199d3bd6 100644
--- a/source/graphics/ShaderTechnique.cpp
+++ b/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 @@ int CShaderTechnique::GetNumPasses() const
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
diff --git a/source/graphics/ShaderTechnique.h b/source/graphics/ShaderTechnique.h
index 73d2eb3c17..7b939adf0b 100644
--- a/source/graphics/ShaderTechnique.h
+++ b/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 @@ private:
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 @@ public:
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 @@ public:
const CShaderDefines& GetShaderDefines() { return m_Defines; }
+ const PipelineStateDescCallback& GetPipelineStateDescCallback() const { return m_PipelineStateDescCallback; };
+
private:
std::vector m_Passes;
@@ -84,6 +95,8 @@ private:
// We need additional data to reload the technique.
VfsPath m_Path;
CShaderDefines m_Defines;
+
+ PipelineStateDescCallback m_PipelineStateDescCallback;
};
#endif // INCLUDED_SHADERTECHNIQUE
diff --git a/source/ps/CStrInternStatic.h b/source/ps/CStrInternStatic.h
index 2c67f51321..5966279b17 100644
--- a/source/ps/CStrInternStatic.h
+++ b/source/ps/CStrInternStatic.h
@@ -164,6 +164,9 @@ X(sky_simple)
X(solid)
X(sunColor)
X(sunDir)
+X(terrain_base)
+X(terrain_blend)
+X(terrain_decal)
X(terrain_solid)
X(tex)
X(texSize)
diff --git a/source/renderer/DebugRenderer.cpp b/source/renderer/DebugRenderer.cpp
index 50b9e1454c..54917f8566 100644
--- a/source/renderer/DebugRenderer.cpp
+++ b/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 @@ void CDebugRenderer::DrawLine(
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::DrawLine(
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 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo
}
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 @@ void CDebugRenderer::DrawBoundingBox(
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::DrawBoundingBox(
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 @@ void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wi
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;
+}
diff --git a/source/renderer/DebugRenderer.h b/source/renderer/DebugRenderer.h
index 0545b8ab74..84ee8a0f61 100644
--- a/source/renderer/DebugRenderer.h
+++ b/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 @@ public:
* 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
diff --git a/source/renderer/DecalRData.cpp b/source/renderer/DecalRData.cpp
index 60e103cac4..87d2c4a31d 100644
--- a/source/renderer/DecalRData.cpp
+++ b/source/renderer/DecalRData.cpp
@@ -152,8 +152,9 @@ void CDecalRData::RenderDecals(
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 @@ void CDecalRData::RenderDecals(
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);
diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp
index 2917bb7496..410149ecd5 100644
--- a/source/renderer/ModelRenderer.cpp
+++ b/source/renderer/ModelRenderer.cpp
@@ -615,7 +615,7 @@ void ShaderModelRenderer::Render(
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);
diff --git a/source/renderer/OverlayRenderer.cpp b/source/renderer/OverlayRenderer.cpp
index 6438b071ba..199e73e826 100644
--- a/source/renderer/OverlayRenderer.cpp
+++ b/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 @@ public:
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 @@ struct OverlayRendererInternals
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 @@ void OverlayRendererInternals::Initialize()
}
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 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::IDeviceComma
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 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::IDeviceComma
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 @@ void OverlayRenderer::RenderQuadOverlays(
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 @@ void OverlayRenderer::RenderForegroundOverlays(
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 @@ void OverlayRenderer::RenderSphereOverlays(
{
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();
diff --git a/source/renderer/OverlayRenderer.h b/source/renderer/OverlayRenderer.h
index c1c4b055ba..33a6999803 100644
--- a/source/renderer/OverlayRenderer.h
+++ b/source/renderer/OverlayRenderer.h
@@ -135,7 +135,7 @@ private:
/**
* 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);
diff --git a/source/renderer/ParticleRenderer.cpp b/source/renderer/ParticleRenderer.cpp
index c0be7a970f..d176d04705 100644
--- a/source/renderer/ParticleRenderer.cpp
+++ b/source/renderer/ParticleRenderer.cpp
@@ -161,7 +161,7 @@ void ParticleRenderer::RenderParticles(
if (lastTech)
deviceCommandContext->EndPass();
lastTech = currentTech;
- deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineStateDesc());
+ deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineState());
deviceCommandContext->BeginPass();
Renderer::Backend::IShaderProgram* shader = lastTech->GetShader();
diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp
index a92881656f..d6aacc037c 100644
--- a/source/renderer/PatchRData.cpp
+++ b/source/renderer/PatchRData.cpp
@@ -772,7 +772,7 @@ void CPatchRData::RenderBases(
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 @@ void CPatchRData::RenderBlends(
{
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 @@ void CPatchRData::RenderBlends(
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);
diff --git a/source/renderer/PostprocManager.cpp b/source/renderer/PostprocManager.cpp
index 7906148c4c..dd4a9ed56c 100644
--- a/source/renderer/PostprocManager.cpp
+++ b/source/renderer/PostprocManager.cpp
@@ -230,7 +230,7 @@ void CPostprocManager::ApplyBlurDownscale2x(
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 @@ void CPostprocManager::ApplyBlurGauss(
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 @@ void CPostprocManager::ApplyBlurGauss(
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 @@ void CPostprocManager::ApplyEffect(
deviceCommandContext->SetViewports(1, &viewportRect);
deviceCommandContext->SetGraphicsPipelineState(
- shaderTech->GetGraphicsPipelineStateDesc(pass));
+ shaderTech->GetGraphicsPipelineState(pass));
deviceCommandContext->BeginPass();
Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(pass);
diff --git a/source/renderer/Renderer.cpp b/source/renderer/Renderer.cpp
index f7690a4f08..5d30a85575 100644
--- a/source/renderer/Renderer.cpp
+++ b/source/renderer/Renderer.cpp
@@ -457,9 +457,6 @@ void CRenderer::RenderFrameImpl(const bool renderGUI, const bool renderLogger)
{
g_Game->GetView()->Prepare(m->deviceCommandContext.get());
- m->deviceCommandContext->SetGraphicsPipelineState(
- Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc());
-
Renderer::Backend::IFramebuffer* framebuffer = nullptr;
CPostprocManager& postprocManager = g_Renderer.GetPostprocManager();
diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp
index 35b6c44cd7..1dec77e4d7 100644
--- a/source/renderer/SceneRenderer.cpp
+++ b/source/renderer/SceneRenderer.cpp
@@ -575,8 +575,6 @@ void CSceneRenderer::RenderReflections(
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 @@ void CSceneRenderer::RenderRefractions(
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 @@ void CSceneRenderer::RenderSilhouettes(
// 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:
diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp
index fbd0e7efe4..b0a980d6d1 100644
--- a/source/renderer/ShadowMap.cpp
+++ b/source/renderer/ShadowMap.cpp
@@ -586,9 +586,6 @@ void ShadowMapInternals::CreateTexture()
void ShadowMap::BeginRender(
Renderer::Backend::IDeviceCommandContext* deviceCommandContext)
{
- deviceCommandContext->SetGraphicsPipelineState(
- Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc());
-
ENSURE(m->Framebuffer);
deviceCommandContext->BeginFramebufferPass(m->Framebuffer.get());
diff --git a/source/renderer/SilhouetteRenderer.cpp b/source/renderer/SilhouetteRenderer.cpp
index 1c72523aa4..c3b514013e 100644
--- a/source/renderer/SilhouetteRenderer.cpp
+++ b/source/renderer/SilhouetteRenderer.cpp
@@ -469,15 +469,22 @@ void SilhouetteRenderer::RenderDebugOverlays(
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();
- deviceCommandContext->BeginPass();
- pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE;
- pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE;
- deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc);
+ 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;
+ });
+ }
- Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader();
+ deviceCommandContext->BeginPass();
+ deviceCommandContext->SetGraphicsPipelineState(
+ m_ShaderTech->GetGraphicsPipelineState());
+
+ Renderer::Backend::IShaderProgram* shader = m_ShaderTech->GetShader();
deviceCommandContext->SetUniform(
shader->GetBindingSlot(str_transform), proj.AsFloatArray());
diff --git a/source/renderer/SilhouetteRenderer.h b/source/renderer/SilhouetteRenderer.h
index c0509795a2..fcf3562f66 100644
--- a/source/renderer/SilhouetteRenderer.h
+++ b/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 @@ private:
std::vector m_DebugRects;
std::vector m_DebugSpheres;
+
+ CShaderTechniquePtr m_ShaderTech;
};
#endif // INCLUDED_SILHOUETTERENDERER
diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp
index 72b70f98bc..8598f894f5 100644
--- a/source/renderer/SkyManager.cpp
+++ b/source/renderer/SkyManager.cpp
@@ -222,7 +222,7 @@ void SkyManager::RenderSky(
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(
diff --git a/source/renderer/TerrainOverlay.cpp b/source/renderer/TerrainOverlay.cpp
index c980f47929..f5439206e6 100644
--- a/source/renderer/TerrainOverlay.cpp
+++ b/source/renderer/TerrainOverlay.cpp
@@ -39,9 +39,55 @@
#include
-// Global overlay list management:
+namespace
+{
-static std::vector > g_TerrainOverlayList;
+// 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;
+ });
+}
+
+} // anonymous namespace
ITerrainOverlay::ITerrainOverlay(int priority)
{
@@ -93,9 +139,15 @@ void ITerrainOverlay::RenderOverlaysAfterWater(
//////////////////////////////////////////////////////////////////////////
-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 @@ void TerrainOverlay::RenderTile(
}
#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 @@ void TerrainOverlay::RenderTileOutline(
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();
diff --git a/source/renderer/TerrainOverlay.h b/source/renderer/TerrainOverlay.h
index cd23830c8f..8322133b2c 100644
--- a/source/renderer/TerrainOverlay.h
+++ b/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 @@ private:
ssize_t m_i, m_j;
CTerrain* m_Terrain;
+
+ CShaderTechniquePtr m_OverlayTechTile, m_OverlayTechTileHidden;
+ CShaderTechniquePtr m_OverlayTechOutline, m_OverlayTechOutlineHidden;
};
/**
diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp
index 73e7deb258..6c47ac99e5 100644
--- a/source/renderer/TerrainRenderer.cpp
+++ b/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 @@ struct TerrainRendererInternals
/// Fancy water shader
CShaderTechniquePtr fancyWaterTech;
+ CShaderTechniquePtr shaderTechniqueSolid, shaderTechniqueSolidDepthTest;
+
CSimulation2* simulation;
};
@@ -173,7 +178,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture(
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 @@ void TerrainRenderer::RenderTerrainShader(
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 @@ void TerrainRenderer::RenderPatches(
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 @@ bool TerrainRenderer::RenderFancyWater(
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 @@ void TerrainRenderer::RenderSimpleWater(
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 @@ void TerrainRenderer::RenderWaterFoamOccluders(
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(
diff --git a/source/renderer/WaterManager.cpp b/source/renderer/WaterManager.cpp
index 084592629d..14c5306cd3 100644
--- a/source/renderer/WaterManager.cpp
+++ b/source/renderer/WaterManager.cpp
@@ -840,13 +840,11 @@ void WaterManager::RenderWaves(
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();
diff --git a/source/renderer/backend/IDevice.h b/source/renderer/backend/IDevice.h
index c6769f6c86..5eec59f649 100644
--- a/source/renderer/backend/IDevice.h
+++ b/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 @@ public:
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,
diff --git a/source/renderer/backend/IDeviceCommandContext.h b/source/renderer/backend/IDeviceCommandContext.h
index d8263019d7..c3c6c41ee5 100644
--- a/source/renderer/backend/IDeviceCommandContext.h
+++ b/source/renderer/backend/IDeviceCommandContext.h
@@ -40,7 +40,7 @@ class ITexture;
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;
diff --git a/source/renderer/backend/PipelineState.cpp b/source/renderer/backend/PipelineState.cpp
index 7b815649bc..13a4f72051 100644
--- a/source/renderer/backend/PipelineState.cpp
+++ b/source/renderer/backend/PipelineState.cpp
@@ -27,9 +27,9 @@ namespace Renderer
namespace Backend
{
-GraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc()
+SGraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc()
{
- GraphicsPipelineStateDesc desc{};
+ SGraphicsPipelineStateDesc desc{};
desc.shaderProgram = nullptr;
diff --git a/source/renderer/backend/PipelineState.h b/source/renderer/backend/PipelineState.h
index 67229165dd..40868fc2a2 100644
--- a/source/renderer/backend/PipelineState.h
+++ b/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 @@ enum class StencilOp
DECREMENT_AND_WRAP
};
-struct StencilOpState
+struct SStencilOpState
{
StencilOp failOp;
StencilOp passOp;
@@ -61,7 +62,7 @@ struct StencilOpState
CompareOp compareOp;
};
-struct DepthStencilStateDesc
+struct SDepthStencilStateDesc
{
bool depthTestEnabled;
CompareOp depthCompareOp;
@@ -70,8 +71,8 @@ struct DepthStencilStateDesc
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 BLUE = 0x04;
constexpr uint8_t ALPHA = 0x08;
} // namespace ColorWriteMask
-struct BlendStateDesc
+struct SBlendStateDesc
{
bool enabled;
BlendFactor srcColorBlendFactor;
@@ -150,7 +151,7 @@ enum class FrontFace
CLOCKWISE
};
-struct RasterizationStateDesc
+struct SRasterizationStateDesc
{
PolygonMode polygonMode;
CullMode cullMode;
@@ -160,19 +161,19 @@ struct RasterizationStateDesc
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 @@ PolygonMode ParsePolygonMode(const CStr& str);
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
diff --git a/source/renderer/backend/dummy/Device.cpp b/source/renderer/backend/dummy/Device.cpp
index 0789289014..07e5dd887a 100644
--- a/source/renderer/backend/dummy/Device.cpp
+++ b/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 @@ std::unique_ptr CDevice::CreateCommandContext()
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,
diff --git a/source/renderer/backend/dummy/Device.h b/source/renderer/backend/dummy/Device.h
index 366d528364..fb949da5ae 100644
--- a/source/renderer/backend/dummy/Device.h
+++ b/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 @@ public:
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,
diff --git a/source/renderer/backend/dummy/DeviceCommandContext.cpp b/source/renderer/backend/dummy/DeviceCommandContext.cpp
index cbb6f8626f..53f4d1f817 100644
--- a/source/renderer/backend/dummy/DeviceCommandContext.cpp
+++ b/source/renderer/backend/dummy/DeviceCommandContext.cpp
@@ -52,7 +52,7 @@ IDevice* CDeviceCommandContext::GetDevice()
}
void CDeviceCommandContext::SetGraphicsPipelineState(
- const GraphicsPipelineStateDesc&)
+ IGraphicsPipelineState*)
{
}
diff --git a/source/renderer/backend/dummy/DeviceCommandContext.h b/source/renderer/backend/dummy/DeviceCommandContext.h
index 56b80bab21..f291c4e80c 100644
--- a/source/renderer/backend/dummy/DeviceCommandContext.h
+++ b/source/renderer/backend/dummy/DeviceCommandContext.h
@@ -46,7 +46,7 @@ public:
IDevice* GetDevice() override;
- void SetGraphicsPipelineState(const GraphicsPipelineStateDesc& pipelineStateDesc) override;
+ void SetGraphicsPipelineState(IGraphicsPipelineState* pipelineState) override;
void BlitFramebuffer(IFramebuffer* destinationFramebuffer, IFramebuffer* sourceFramebuffer) override;
diff --git a/source/renderer/backend/dummy/PipelineState.cpp b/source/renderer/backend/dummy/PipelineState.cpp
new file mode 100644
index 0000000000..ccd21cbd58
--- /dev/null
+++ b/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
diff --git a/source/renderer/backend/dummy/PipelineState.h b/source/renderer/backend/dummy/PipelineState.h
new file mode 100644
index 0000000000..34f06e56b5
--- /dev/null
+++ b/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
diff --git a/source/renderer/backend/gl/Device.cpp b/source/renderer/backend/gl/Device.cpp
index 807a3b89ca..d62410e081 100644
--- a/source/renderer/backend/gl/Device.cpp
+++ b/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 @@ std::unique_ptr CDevice::CreateCommandContext()
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,
diff --git a/source/renderer/backend/gl/Device.h b/source/renderer/backend/gl/Device.h
index 148d2a8a9f..5fe163500e 100644
--- a/source/renderer/backend/gl/Device.h
+++ b/source/renderer/backend/gl/Device.h
@@ -68,6 +68,9 @@ public:
std::unique_ptr CreateCommandContext() override;
+ std::unique_ptr CreateGraphicsPipelineState(
+ const SGraphicsPipelineStateDesc& pipelineStateDesc) override;
+
CDeviceCommandContext* GetActiveCommandContext() { return m_ActiveCommandContext; }
std::unique_ptr CreateTexture(
diff --git a/source/renderer/backend/gl/DeviceCommandContext.cpp b/source/renderer/backend/gl/DeviceCommandContext.cpp
index 0cde4e6800..53d8d3c66c 100644
--- a/source/renderer/backend/gl/DeviceCommandContext.cpp
+++ b/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 GL
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 @@ bool operator==(const StencilOpState& lhs, const StencilOpState& rhs)
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 @@ IDevice* CDeviceCommandContext::GetDevice()
}
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::ResetStates()
}
void CDeviceCommandContext::SetGraphicsPipelineStateImpl(
- const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force)
+ const SGraphicsPipelineStateDesc& pipelineStateDesc, const bool force)
{
ENSURE(!m_InsidePass);
@@ -589,8 +598,8 @@ void CDeviceCommandContext::SetGraphicsPipelineStateImpl(
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 @@ void CDeviceCommandContext::SetGraphicsPipelineStateImpl(
}
}
- 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 @@ void CDeviceCommandContext::SetGraphicsPipelineStateImpl(
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::ClearFramebuffer(const bool color, const bool depth,
void CDeviceCommandContext::BeginFramebufferPass(IFramebuffer* framebuffer)
{
+ SetGraphicsPipelineStateImpl(
+ MakeDefaultGraphicsPipelineStateDesc(), false);
+
ENSURE(!m_InsideFramebufferPass);
m_InsideFramebufferPass = true;
ENSURE(framebuffer);
diff --git a/source/renderer/backend/gl/DeviceCommandContext.h b/source/renderer/backend/gl/DeviceCommandContext.h
index 4a4ad80bc8..6a9135ed8f 100644
--- a/source/renderer/backend/gl/DeviceCommandContext.h
+++ b/source/renderer/backend/gl/DeviceCommandContext.h
@@ -53,7 +53,9 @@ public:
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 @@ private:
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;
diff --git a/source/renderer/backend/gl/PipelineState.cpp b/source/renderer/backend/gl/PipelineState.cpp
new file mode 100644
index 0000000000..0a8bdcc0ea
--- /dev/null
+++ b/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
diff --git a/source/renderer/backend/gl/PipelineState.h b/source/renderer/backend/gl/PipelineState.h
new file mode 100644
index 0000000000..2bca7bdebd
--- /dev/null
+++ b/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
diff --git a/source/renderer/backend/vulkan/Device.cpp b/source/renderer/backend/vulkan/Device.cpp
index ed2ccd417f..f362396577 100644
--- a/source/renderer/backend/vulkan/Device.cpp
+++ b/source/renderer/backend/vulkan/Device.cpp
@@ -79,6 +79,13 @@ std::unique_ptr CDevice::CreateCommandContext()
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,
diff --git a/source/renderer/backend/vulkan/Device.h b/source/renderer/backend/vulkan/Device.h
index c112745786..985d4aac82 100644
--- a/source/renderer/backend/vulkan/Device.h
+++ b/source/renderer/backend/vulkan/Device.h
@@ -56,6 +56,9 @@ public:
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,