Index: binaries/data/mods/public/shaders/arb/los_interp.xml =================================================================== --- binaries/data/mods/public/shaders/arb/los_interp.xml +++ binaries/data/mods/public/shaders/arb/los_interp.xml @@ -5,7 +5,7 @@ - + Index: binaries/data/mods/public/shaders/arb/terrain_base.xml =================================================================== --- binaries/data/mods/public/shaders/arb/terrain_base.xml +++ binaries/data/mods/public/shaders/arb/terrain_base.xml @@ -3,11 +3,11 @@ - + - + Index: binaries/data/mods/public/shaders/arb/terrain_blend.xml =================================================================== --- binaries/data/mods/public/shaders/arb/terrain_blend.xml +++ binaries/data/mods/public/shaders/arb/terrain_blend.xml @@ -5,11 +5,11 @@ - + - + Index: binaries/data/mods/public/shaders/arb/terrain_common.vp =================================================================== --- binaries/data/mods/public/shaders/arb/terrain_common.vp +++ binaries/data/mods/public/shaders/arb/terrain_common.vp @@ -12,6 +12,11 @@ TEMP lighting; +TEMP terrainTextureTransform; +MOV terrainTextureTransform, textureTransform; +MOV terrainTextureTransform.z, -textureTransform.y; +MOV terrainTextureTransform.w, 0; + //// Compute position and normal: ATTRIB position = vertex.position; @@ -40,8 +45,8 @@ // Compute texcoords from position and terrain-texture-dependent transform. // textureTransform is stored as [c, -s, s, 0], // and we want texcoord = (x*c + z*-s, x*-s + z*-c, 0, 1) - DP3 result.texcoord[0].x, textureTransform.xyww, position.xzww; - DP3 result.texcoord[0].y, -textureTransform.zxww, position.xzww; + DP3 result.texcoord[0].x, terrainTextureTransform.xyww, position.xzww; + DP3 result.texcoord[0].y, -terrainTextureTransform.zxww, position.xzww; MOV result.texcoord[0].z, 0; MOV result.texcoord[0].w, 1; #endif Index: binaries/data/mods/public/shaders/arb/terrain_decal.xml =================================================================== --- binaries/data/mods/public/shaders/arb/terrain_decal.xml +++ binaries/data/mods/public/shaders/arb/terrain_decal.xml @@ -5,11 +5,11 @@ - + - + Index: binaries/data/mods/public/shaders/arb/water_simple.xml =================================================================== --- binaries/data/mods/public/shaders/arb/water_simple.xml +++ binaries/data/mods/public/shaders/arb/water_simple.xml @@ -4,7 +4,7 @@ - + Index: binaries/data/mods/public/shaders/glsl/los_interp.fs =================================================================== --- binaries/data/mods/public/shaders/glsl/los_interp.fs +++ binaries/data/mods/public/shaders/glsl/los_interp.fs @@ -4,7 +4,7 @@ uniform sampler2D losTex1, losTex2; -uniform vec3 delta; +uniform float delta; void main(void) @@ -12,6 +12,6 @@ float los2 = texture2D(losTex1, v_tex).a; float los1 = texture2D(losTex2, v_tex).a; - gl_FragColor.a = mix(los1, los2, clamp(delta.r, 0.0, 1.0)); + gl_FragColor.a = mix(los1, los2, clamp(delta, 0.0, 1.0)); } Index: binaries/data/mods/public/shaders/glsl/model_common.vs =================================================================== --- binaries/data/mods/public/shaders/glsl/model_common.vs +++ binaries/data/mods/public/shaders/glsl/model_common.vs @@ -15,7 +15,7 @@ uniform mat4 instancingTransform; #if USE_WIND - uniform vec4 sim_time; + uniform float sim_time; uniform vec4 windData; #endif @@ -112,9 +112,9 @@ vec4 cosVec; // these determine the speed of the wind's "cosine" waves. cosVec.w = 0.0; - cosVec.x = sim_time.x * modelPos[0] + position.x; - cosVec.y = sim_time.x * modelPos[2] / 3.0 + instancingTransform[3][0]; - cosVec.z = sim_time.x * abswind / 4.0 + position.z; + cosVec.x = sim_time * modelPos[0] + position.x; + cosVec.y = sim_time * modelPos[2] / 3.0 + instancingTransform[3][0]; + cosVec.z = sim_time * abswind / 4.0 + position.z; // calculate "cosines" in parallel, using a smoothed triangle wave cosVec = fakeCos(cosVec); Index: source/graphics/Canvas2D.cpp =================================================================== --- source/graphics/Canvas2D.cpp +++ source/graphics/Canvas2D.cpp @@ -37,14 +37,24 @@ // Array of 2D elements unrolled into 1D array. using PlaneArray2D = std::array; +struct SBindingSlots +{ + int32_t transform; + int32_t colorAdd; + int32_t colorMul; + int32_t grayscaleFactor; + int32_t tex; +}; + inline void DrawTextureImpl( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const CTexturePtr& texture, - const PlaneArray2D& vertices, PlaneArray2D uvs, - const CColor& multiply, const CColor& add, const float grayscaleFactor) + const CTexturePtr& texture, const PlaneArray2D& vertices, PlaneArray2D uvs, + const CColor& multiply, const CColor& add, const float grayscaleFactor, + const SBindingSlots& bindingSlots) { texture->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_tex, texture->GetBackendTexture()); + deviceCommandContext->SetTexture( + bindingSlots.tex, texture->GetBackendTexture()); for (size_t idx = 0; idx < uvs.size(); idx += 2) { if (texture->GetWidth() > 0.0f) @@ -53,9 +63,9 @@ uvs[idx + 1] /= texture->GetHeight(); } - shader->Uniform(str_colorAdd, add); - shader->Uniform(str_colorMul, multiply); - shader->Uniform(str_grayscaleFactor, grayscaleFactor); + deviceCommandContext->SetUniform(bindingSlots.colorAdd, add.AsFloatArray()); + deviceCommandContext->SetUniform(bindingSlots.colorMul, multiply.AsFloatArray()); + deviceCommandContext->SetUniform(bindingSlots.grayscaleFactor, grayscaleFactor); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, @@ -87,12 +97,22 @@ CShaderDefines defines; Tech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d, defines); + // The canvas technique must be loaded because we can't render UI without it. ENSURE(Tech); DeviceCommandContext->SetGraphicsPipelineState( Tech->GetGraphicsPipelineStateDesc()); DeviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = Tech->GetShader(); - shader->Uniform(str_transform, GetDefaultGuiMatrix()); + Renderer::Backend::IShaderProgram* shader = Tech->GetShader(); + + BindingSlots.transform = shader->GetBindingSlot(str_transform); + BindingSlots.colorAdd = shader->GetBindingSlot(str_colorAdd); + BindingSlots.colorMul = shader->GetBindingSlot(str_colorMul); + BindingSlots.grayscaleFactor = shader->GetBindingSlot(str_grayscaleFactor); + BindingSlots.tex = shader->GetBindingSlot(str_tex); + + const CMatrix3D transform = GetDefaultGuiMatrix(); + DeviceCommandContext->SetUniform( + BindingSlots.transform, transform.AsFloatArray()); } void UnbindTech() @@ -106,6 +126,10 @@ Renderer::Backend::GL::CDeviceCommandContext* DeviceCommandContext; CShaderTechniquePtr Tech; + + // We assume that the shader can't be destroyed while it's bound. So these + // bindings remain valid while the shader is alive. + SBindingSlots BindingSlots; }; CCanvas2D::CCanvas2D( @@ -251,11 +275,16 @@ m->BindTechIfNeeded(); - Renderer::Backend::GL::CShaderProgram* shader = m->Tech->GetShader(); - shader->BindTexture(str_tex, g_Renderer.GetTextureManager().GetAlphaGradientTexture()->GetBackendTexture()); - shader->Uniform(str_colorAdd, CColor(0.0f, 0.0f, 0.0f, 0.0f)); - shader->Uniform(str_colorMul, color); - shader->Uniform(str_grayscaleFactor, 0.0f); + m->DeviceCommandContext->SetTexture( + m->BindingSlots.tex, + g_Renderer.GetTextureManager().GetAlphaGradientTexture()->GetBackendTexture()); + const CColor colorAdd(0.0f, 0.0f, 0.0f, 0.0f); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.colorAdd, colorAdd.AsFloatArray()); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.colorMul, color.AsFloatArray()); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.grayscaleFactor, 0.0f); m->DeviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, @@ -290,9 +319,10 @@ m->BindTechIfNeeded(); DrawTextureImpl( - m->DeviceCommandContext, m->Tech->GetShader(), + m->DeviceCommandContext, g_Renderer.GetTextureManager().GetTransparentTexture(), - vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color, 0.0f); + vertices, uvs, CColor(0.0f, 0.0f, 0.0f, 0.0f), color, 0.0f, + m->BindingSlots); } void CCanvas2D::DrawTexture(CTexturePtr texture, const CRect& destination) @@ -326,18 +356,19 @@ }; m->BindTechIfNeeded(); - DrawTextureImpl(m->DeviceCommandContext, m->Tech->GetShader(), - texture, vertices, uvs, multiply, add, grayscaleFactor); + DrawTextureImpl( + m->DeviceCommandContext, texture, vertices, uvs, + multiply, add, grayscaleFactor, m->BindingSlots); } void CCanvas2D::DrawText(CTextRenderer& textRenderer) { m->BindTechIfNeeded(); - Renderer::Backend::GL::CShaderProgram* shader = m->Tech->GetShader(); - shader->Uniform(str_grayscaleFactor, 0.0f); + m->DeviceCommandContext->SetUniform( + m->BindingSlots.grayscaleFactor, 0.0f); - textRenderer.Render(m->DeviceCommandContext, shader, GetDefaultGuiMatrix()); + textRenderer.Render(m->DeviceCommandContext, m->Tech->GetShader(), GetDefaultGuiMatrix()); } void CCanvas2D::Flush() Index: source/graphics/Color.h =================================================================== --- source/graphics/Color.h +++ source/graphics/Color.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* 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 @@ -21,6 +21,7 @@ #include "graphics/SColor.h" #include "maths/Vector3D.h" #include "maths/Vector4D.h" +#include "ps/containers/Span.h" #include "ps/CStrForward.h" // Simple defines for 3 and 4 component floating point colors - just map to @@ -66,7 +67,7 @@ } // For passing to uniform as vec3/vec4. - const float* AsFloatArray() const + PS::span AsFloatArray() const { // Additional check to prevent a weird compiler has a different // alignement for an array and a class members. @@ -77,7 +78,7 @@ offsetof(CColor, b) == sizeof(float) * 2u && offsetof(CColor, a) == sizeof(float) * 3u, "CColor should be properly layouted to use AsFloatArray"); - return &r; + return PS::span(&r, 4); } // For passing to CRenderer: Index: source/graphics/LOSTexture.cpp =================================================================== --- source/graphics/LOSTexture.cpp +++ source/graphics/LOSTexture.cpp @@ -80,7 +80,7 @@ bool CLOSTexture::CreateShader() { m_SmoothTech = g_Renderer.GetShaderManager().LoadEffect(str_los_interp); - Renderer::Backend::GL::CShaderProgram* shader = m_SmoothTech->GetShader(); + Renderer::Backend::IShaderProgram* shader = m_SmoothTech->GetShader(); m_ShaderInitialized = m_SmoothTech && shader; @@ -145,12 +145,16 @@ m_SmoothTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = m_SmoothTech->GetShader(); + Renderer::Backend::IShaderProgram* shader = m_SmoothTech->GetShader(); - shader->BindTexture(str_losTex1, m_Texture.get()); - shader->BindTexture(str_losTex2, m_SmoothTextures[m_WhichTexture].get()); - - shader->Uniform(str_delta, (float)g_Renderer.GetTimeManager().GetFrameDelta() * 4.0f, 0.0f, 0.0f, 0.0f); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex1), m_Texture.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex2), m_SmoothTextures[m_WhichTexture].get()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_delta), + static_cast(g_Renderer.GetTimeManager().GetFrameDelta()) * 4.0f); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = Index: source/graphics/MiniMapTexture.cpp =================================================================== --- source/graphics/MiniMapTexture.cpp +++ source/graphics/MiniMapTexture.cpp @@ -366,7 +366,7 @@ const float invTileMapSize = 1.0f / static_cast(TERRAIN_TILE_SIZE * m_MapSize); const float texCoordMax = m_TerrainTexture ? static_cast(m_MapSize - 1) / m_TerrainTexture->GetWidth() : 1.0f; - Renderer::Backend::GL::CShaderProgram* shader; + Renderer::Backend::IShaderProgram* shader = nullptr; CShaderTechniquePtr tech; CShaderDefines baseDefines; @@ -380,7 +380,10 @@ shader = tech->GetShader(); if (m_TerrainTexture) - shader->BindTexture(str_baseTex, m_TerrainTexture.get()); + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), m_TerrainTexture.get()); + } CMatrix3D baseTransform; baseTransform.SetIdentity(); @@ -390,8 +393,10 @@ CMatrix3D terrainTransform; terrainTransform.SetIdentity(); terrainTransform.Scale(texCoordMax, texCoordMax, 1.0f); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, terrainTransform); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), terrainTransform.AsFloatArray()); if (m_TerrainTexture) DrawTexture(deviceCommandContext); @@ -414,9 +419,13 @@ // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); - shader->BindTexture(str_baseTex, territoryTexture.GetTexture()); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, territoryTexture.GetMinimapTextureMatrix()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), territoryTexture.GetTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), + territoryTexture.GetMinimapTextureMatrix().AsFloatArray()); DrawTexture(deviceCommandContext); deviceCommandContext->EndPass(); @@ -427,9 +436,13 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - shader->BindTexture(str_baseTex, losTexture.GetTexture()); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, losTexture.GetMinimapTextureMatrix()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), losTexture.GetTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), + losTexture.GetMinimapTextureMatrix().AsFloatArray()); DrawTexture(deviceCommandContext); @@ -442,7 +455,8 @@ tech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); shader = tech->GetShader(); - shader->Uniform(str_transform, baseTransform); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); CMatrix3D unitMatrix; unitMatrix.SetIdentity(); @@ -451,7 +465,8 @@ unitMatrix.Scale(unitScale * 2.0f, unitScale * 2.0f, 1.0f); // Offset the coordinates to [-1, 1]. unitMatrix.Translate(CVector3D(-1.0f, -1.0f, 0.0f)); - shader->Uniform(str_transform, unitMatrix); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), unitMatrix.AsFloatArray()); if (doUpdate) { Index: source/graphics/ModelDef.cpp =================================================================== --- source/graphics/ModelDef.cpp +++ source/graphics/ModelDef.cpp @@ -200,7 +200,7 @@ const CMatrix3D& mtx = newPoseMatrices[blendIndices[j]]; // Loads matrix to xmm registers. - const float* data = mtx.AsFloatArray(); + const float* data = mtx.AsFloatArray().data(); col0 = _mm_load_ps(data); col1 = _mm_load_ps(data + 4); col2 = _mm_load_ps(data + 8); Index: source/graphics/ParticleEmitter.h =================================================================== --- source/graphics/ParticleEmitter.h +++ source/graphics/ParticleEmitter.h @@ -22,7 +22,7 @@ #include "graphics/ParticleEmitterType.h" #include "maths/Quaternion.h" #include "renderer/backend/gl/DeviceCommandContext.h" -#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/VertexArray.h" #include @@ -124,14 +124,13 @@ */ void Bind( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader); + Renderer::Backend::IShaderProgram* shader); /** * Draw the vertex array. */ void RenderArray( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); /** * Stop this emitter emitting new particles, and pass responsibility for rendering Index: source/graphics/ParticleEmitter.cpp =================================================================== --- source/graphics/ParticleEmitter.cpp +++ source/graphics/ParticleEmitter.cpp @@ -176,25 +176,32 @@ void CParticleEmitter::Bind( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader) + Renderer::Backend::IShaderProgram* shader) { m_Type->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTextureSmooth()); - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); const CLightEnv& lightEnv = g_Renderer.GetSceneRenderer().GetLightEnv(); - shader->Uniform(str_sunColor, lightEnv.m_SunColor); - shader->Uniform(str_fogColor, lightEnv.m_FogColor); - shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); - shader->BindTexture(str_baseTex, m_Type->m_Texture->GetBackendTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunColor), lightEnv.m_SunColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogColor), lightEnv.m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogParams), lightEnv.m_FogFactor, lightEnv.m_FogMax); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), m_Type->m_Texture->GetBackendTexture()); } void CParticleEmitter::RenderArray( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* UNUSED(shader)) + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { if (m_Particles.empty()) return; Index: source/graphics/ShaderDefines.h =================================================================== --- source/graphics/ShaderDefines.h +++ source/graphics/ShaderDefines.h @@ -20,7 +20,8 @@ #include "ps/CStr.h" #include "ps/CStrIntern.h" -#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/IShaderProgram.h" #include #include @@ -178,7 +179,9 @@ /** * Bind the collection of uniforms onto the given shader. */ - void BindUniforms(Renderer::Backend::GL::CShaderProgram* shader) const; + void BindUniforms( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const; }; // Add here the types of queries we can make in the renderer Index: source/graphics/ShaderDefines.cpp =================================================================== --- source/graphics/ShaderDefines.cpp +++ source/graphics/ShaderDefines.cpp @@ -225,13 +225,15 @@ return CVector4D(); } -void CShaderUniforms::BindUniforms(Renderer::Backend::GL::CShaderProgram* shader) const -{ - const std::vector& items = m_Items->items; - for (size_t i = 0; i < items.size(); ++i) - { - const CVector4D& v = items[i].second; - shader->Uniform(items[i].first, v.X, v.Y, v.Z, v.W); +void CShaderUniforms::BindUniforms( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const +{ + for (const SItems::Item& item : m_Items->items) + { + const CVector4D& v = item.second; + deviceCommandContext->SetUniform( + shader->GetBindingSlot(item.first), v.AsFloatArray()); } } Index: source/graphics/ShaderProgram.h =================================================================== --- source/graphics/ShaderProgram.h +++ source/graphics/ShaderProgram.h @@ -22,7 +22,6 @@ #include "graphics/ShaderProgramPtr.h" #include "lib/file/vfs/vfs_path.h" #include "ps/CStr.h" -#include "renderer/backend/gl/ShaderProgram.h" #include "renderer/backend/IShaderProgram.h" #include @@ -42,7 +41,7 @@ std::vector GetFileDependencies() const; - Renderer::Backend::GL::CShaderProgram* GetBackendShaderProgram() { return m_BackendShaderProgram.get(); } + Renderer::Backend::IShaderProgram* GetBackendShaderProgram() { return m_BackendShaderProgram.get(); } // TODO: add reloadable handles. @@ -51,7 +50,7 @@ CStr m_Name; CShaderDefines m_Defines; - std::unique_ptr m_BackendShaderProgram; + std::unique_ptr m_BackendShaderProgram; }; #endif // INCLUDED_SHADERPROGRAM Index: source/graphics/ShaderProgram.cpp =================================================================== --- source/graphics/ShaderProgram.cpp +++ source/graphics/ShaderProgram.cpp @@ -35,7 +35,7 @@ void CShaderProgram::Reload() { - std::unique_ptr backendShaderProgram = + std::unique_ptr backendShaderProgram = g_VideoMode.GetBackendDevice()->CreateShaderProgram(m_Name, m_Defines); if (backendShaderProgram) m_BackendShaderProgram = std::move(backendShaderProgram); Index: source/graphics/ShaderTechnique.h =================================================================== --- source/graphics/ShaderTechnique.h +++ source/graphics/ShaderTechnique.h @@ -33,7 +33,7 @@ public: CShaderPass(const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, const CShaderProgramPtr& shader); - Renderer::Backend::GL::CShaderProgram* GetShader() const { return m_Shader->GetBackendShaderProgram(); } + Renderer::Backend::IShaderProgram* GetShader() const { return m_Shader->GetBackendShaderProgram(); } const Renderer::Backend::GraphicsPipelineStateDesc& GetPipelineStateDesc() const { return m_PipelineStateDesc; } @@ -56,7 +56,7 @@ int GetNumPasses() const; - Renderer::Backend::GL::CShaderProgram* GetShader(int pass = 0) const; + Renderer::Backend::IShaderProgram* GetShader(int pass = 0) const; const Renderer::Backend::GraphicsPipelineStateDesc& GetGraphicsPipelineStateDesc(int pass = 0) const; Index: source/graphics/ShaderTechnique.cpp =================================================================== --- source/graphics/ShaderTechnique.cpp +++ source/graphics/ShaderTechnique.cpp @@ -41,7 +41,7 @@ return m_Passes.size(); } -Renderer::Backend::GL::CShaderProgram* CShaderTechnique::GetShader(int pass) const +Renderer::Backend::IShaderProgram* CShaderTechnique::GetShader(int pass) const { ENSURE(0 <= pass && pass < (int)m_Passes.size()); return m_Passes[pass].GetShader(); Index: source/graphics/TextRenderer.h =================================================================== --- source/graphics/TextRenderer.h +++ source/graphics/TextRenderer.h @@ -105,7 +105,7 @@ */ void Render( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const CMatrix3D& transform); + Renderer::Backend::IShaderProgram* shader, const CMatrix3D& transform); private: friend struct SBatchCompare; Index: source/graphics/TextRenderer.cpp =================================================================== --- source/graphics/TextRenderer.cpp +++ source/graphics/TextRenderer.cpp @@ -204,7 +204,7 @@ void CTextRenderer::Render( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const CMatrix3D& transform) + Renderer::Backend::IShaderProgram* shader, const CMatrix3D& transform) { std::vector indexes; std::vector vertexes; @@ -225,6 +225,11 @@ ++it; } + const int32_t texBindingSlot = shader->GetBindingSlot(str_tex); + const int32_t transformBindingSlot = shader->GetBindingSlot(str_transform); + const int32_t colorAddBindingSlot = shader->GetBindingSlot(str_colorAdd); + const int32_t colorMulBindingSlot = shader->GetBindingSlot(str_colorMul); + bool transformChanged = false; CTexture* lastTexture = nullptr; @@ -238,25 +243,26 @@ { lastTexture = batch.font->GetTexture().get(); lastTexture->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_tex, lastTexture->GetBackendTexture()); + deviceCommandContext->SetTexture(texBindingSlot, lastTexture->GetBackendTexture()); } if (batch.translate.X != 0.0f || batch.translate.Y != 0.0f) { - CMatrix3D translation; - translation.SetTranslation(batch.translate.X, batch.translate.Y, 0.0f); - shader->Uniform(str_transform, transform * translation); + CMatrix3D localTransform; + localTransform.SetTranslation(batch.translate.X, batch.translate.Y, 0.0f); + localTransform = transform * localTransform; + deviceCommandContext->SetUniform(transformBindingSlot, localTransform.AsFloatArray()); transformChanged = true; } // ALPHA-only textures will have .rgb sampled as 0, so we need to // replace it with white (but not affect RGBA textures) if (batch.font->HasRGB()) - shader->Uniform(str_colorAdd, CColor(0.0f, 0.0f, 0.0f, 0.0f)); + deviceCommandContext->SetUniform(colorAddBindingSlot, 0.0f, 0.0f, 0.0f, 0.0f); else - shader->Uniform(str_colorAdd, CColor(batch.color.r, batch.color.g, batch.color.b, 0.0f)); + deviceCommandContext->SetUniform(colorAddBindingSlot, batch.color.r, batch.color.g, batch.color.b, 0.0f); - shader->Uniform(str_colorMul, batch.color); + deviceCommandContext->SetUniform(colorMulBindingSlot, batch.color.AsFloatArray()); vertexes.resize(std::min(MAX_CHAR_COUNT_PER_BATCH, batch.chars) * 4); indexes.resize(std::min(MAX_CHAR_COUNT_PER_BATCH, batch.chars) * 6); @@ -339,5 +345,5 @@ m_Batches.clear(); if (transformChanged) - shader->Uniform(str_transform, transform); + deviceCommandContext->SetUniform(transformBindingSlot, transform.AsFloatArray()); } Index: source/gui/ObjectTypes/CMiniMap.cpp =================================================================== --- source/gui/ObjectTypes/CMiniMap.cpp +++ source/gui/ObjectTypes/CMiniMap.cpp @@ -415,13 +415,10 @@ CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture(); if (miniMapTexture.GetTexture()) { - Renderer::Backend::GL::CShaderProgram* shader; - CShaderTechniquePtr tech; - CShaderDefines baseDefines; baseDefines.Add(str_MINIMAP_BASE, str_1); - tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines); + CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = tech->GetGraphicsPipelineStateDesc(); pipelineStateDesc.blendState.enabled = true; @@ -435,14 +432,20 @@ g_Renderer.GetDeviceCommandContext(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - shader = tech->GetShader(); - shader->BindTexture(str_baseTex, miniMapTexture.GetTexture()); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), miniMapTexture.GetTexture()); + const CMatrix3D baseTransform = GetDefaultGuiMatrix(); CMatrix3D baseTextureTransform; baseTextureTransform.SetIdentity(); - shader->Uniform(str_transform, baseTransform); - shader->Uniform(str_textureTransform, baseTextureTransform); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), baseTransform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_textureTransform), baseTextureTransform.AsFloatArray()); const float x = m_CachedActualSize.left, y = m_CachedActualSize.bottom; const float x2 = m_CachedActualSize.right, y2 = m_CachedActualSize.top; Index: source/maths/Matrix3D.h =================================================================== --- source/maths/Matrix3D.h +++ source/maths/Matrix3D.h @@ -25,6 +25,7 @@ #include "maths/Vector3D.h" #include "maths/Vector4D.h" +#include "ps/containers/Span.h" class CQuaternion; @@ -323,7 +324,7 @@ CVector3D RotateTransposed(const CVector3D& vector) const; // Returns 16 element array of floats, e.g. for mat4 uniforms. - const float* AsFloatArray() const + PS::span AsFloatArray() const { // Additional check to prevent a weird compiler has a different // alignement for an array and a class members. @@ -333,7 +334,7 @@ offsetof(CMatrix3D, _11) == 0 && offsetof(CMatrix3D, _44) == sizeof(float) * 15u, "CMatrix3D should be properly layouted to use AsFloatArray"); - return _data; + return PS::span(_data, 16); } }; Index: source/maths/Vector3D.h =================================================================== --- source/maths/Vector3D.h +++ source/maths/Vector3D.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2021 Wildfire Games. +/* 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 @@ -23,6 +23,8 @@ #ifndef INCLUDED_VECTOR3D #define INCLUDED_VECTOR3D +#include "ps/containers/Span.h" + class CFixedVector3D; class CVector3D @@ -121,7 +123,7 @@ CVector3D Normalized() const; // Returns 3 element array of floats, e.g. for vec3 uniforms. - const float* AsFloatArray() const + PS::span AsFloatArray() const { // Additional check to prevent a weird compiler has a different // alignement for an array and a class members. @@ -131,7 +133,7 @@ offsetof(CVector3D, Y) == sizeof(float) && offsetof(CVector3D, Z) == sizeof(float) * 2u, "Vector3D should be properly layouted to use AsFloatArray"); - return &X; + return PS::span(&X, 3); } }; Index: source/maths/Vector4D.h =================================================================== --- source/maths/Vector4D.h +++ source/maths/Vector4D.h @@ -1,4 +1,4 @@ -/* Copyright (C) 2012 Wildfire Games. +/* 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 @@ -23,6 +23,8 @@ #ifndef INCLUDED_VECTOR4D #define INCLUDED_VECTOR4D +#include "ps/containers/Span.h" + #include class CVector4D @@ -124,8 +126,20 @@ return X*a.X + Y*a.Y + Z*a.Z + W*a.W; } + // Returns 4 element array of floats, e.g. for vec4 uniforms. + PS::span AsFloatArray() const + { + // Additional check to prevent a weird compiler has a different + // alignement for an array and a class members. + static_assert( + sizeof(CVector4D) == sizeof(float) * 4u && + offsetof(CVector4D, X) == 0 && + offsetof(CVector4D, W) == sizeof(float) * 3u, + "CVector4D should be properly layouted to use AsFloatArray"); + return PS::span(&X, 4); + } float X, Y, Z, W; }; -#endif +#endif // INCLUDED_VECTOR4D Index: source/ps/containers/Span.h =================================================================== --- source/ps/containers/Span.h +++ source/ps/containers/Span.h @@ -0,0 +1,76 @@ +/* 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_PS_SPAN +#define INCLUDED_PS_SPAN + +#include +#include +#include + +namespace PS +{ + +/** + * Simplifed version of std::span (C++20) as we don't support the original one + * yet. The naming intentionally follows the STL version to make the future + * replacement easier with less blame changing. + * It supports only very basic subset of std::span functionality. + * TODO: remove as soon as std::stan become available. + */ +template +class span +{ +public: + using element_type = T; + using value_type = std::remove_cv_t; + using size_type = std::size_t; + using pointer = T*; + using reference = T&; + using iterator = pointer; + + constexpr span() + : m_Pointer(nullptr), m_Extent(0) {} + + constexpr span(iterator first, size_type extent) + : m_Pointer(first), m_Extent(extent) {} + + constexpr span(iterator first, iterator last) + : m_Pointer(first), m_Extent(static_cast(last - first)) {} + + constexpr span(const span& other) = default; + + constexpr span& operator=(const span& other) = default; + + ~span() = default; + + constexpr size_type size() const { return m_Extent; } + constexpr bool empty() const { return size() == 0; } + constexpr reference operator[](size_type index) const { return *(m_Pointer + index); } + constexpr pointer data() const { return m_Pointer; } + + constexpr iterator begin() const { return m_Pointer; } + constexpr iterator end() const { return m_Pointer + m_Extent; } + +private: + pointer m_Pointer; + size_type m_Extent; +}; + +} // namespace PS + +#endif // INCLUDED_PS_SPAN Index: source/renderer/DebugRenderer.cpp =================================================================== --- source/renderer/DebugRenderer.cpp +++ source/renderer/DebugRenderer.cpp @@ -89,9 +89,12 @@ const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); - Renderer::Backend::GL::CShaderProgram* debugLineShader = debugLineTech->GetShader(); - debugLineShader->Uniform(str_transform, viewCamera.GetViewProjection()); - debugLineShader->Uniform(str_color, color); + Renderer::Backend::IShaderProgram* debugLineShader = debugLineTech->GetShader(); + const CMatrix3D transform = viewCamera.GetViewProjection(); + deviceCommandContext->SetUniform( + debugLineShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + debugLineShader->GetBindingSlot(str_color), color.AsFloatArray()); const CVector3D cameraIn = viewCamera.GetOrientation().GetIn(); @@ -144,9 +147,13 @@ const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); - Renderer::Backend::GL::CShaderProgram* debugCircleShader = debugCircleTech->GetShader(); - debugCircleShader->Uniform(str_transform, camera.GetViewProjection()); - debugCircleShader->Uniform(str_color, color); + Renderer::Backend::IShaderProgram* debugCircleShader = debugCircleTech->GetShader(); + + const CMatrix3D transform = camera.GetViewProjection(); + deviceCommandContext->SetUniform( + debugCircleShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + debugCircleShader->GetBindingSlot(str_color), color.AsFloatArray()); const CVector3D cameraUp = camera.GetOrientation().GetUp(); const CVector3D cameraLeft = camera.GetOrientation().GetLeft(); @@ -202,9 +209,13 @@ deviceCommandContext, overlayTech, color, true, wireframe); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* overlayShader = overlayTech->GetShader(); - overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - overlayShader->Uniform(str_color, color); + Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); + + const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); std::vector vertices; #define ADD(position) \ @@ -297,9 +308,12 @@ deviceCommandContext, shaderTech, color, true, wireframe); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); - shader->Uniform(str_color, color); - shader->Uniform(str_transform, transform); + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_color), color.AsFloatArray()); std::vector data; @@ -341,9 +355,13 @@ deviceCommandContext, shaderTech, color, true, wireframe); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); - shader->Uniform(str_color, color); - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + + const CMatrix3D transform = g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_color), color.AsFloatArray()); std::vector data; Index: source/renderer/DecalRData.cpp =================================================================== --- source/renderer/DecalRData.cpp +++ source/renderer/DecalRData.cpp @@ -176,11 +176,14 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = techBase->GetShader(pass); - TerrainRenderer::PrepareShader(shader, shadow); + Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); + TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); CColor shadingColor(1.0f, 1.0f, 1.0f, 1.0f); - shader->Uniform(str_shadingColor, shadingColor); + const int32_t shadingColorBindingSlot = + shader->GetBindingSlot(str_shadingColor); + deviceCommandContext->SetUniform( + shadingColorBindingSlot, shadingColor.AsFloatArray()); CShaderUniforms currentStaticUniforms; @@ -195,12 +198,16 @@ for (const CMaterial::TextureSampler& sampler : samplers) sampler.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext); for (const CMaterial::TextureSampler& sampler : samplers) - shader->BindTexture(sampler.Name, sampler.Sampler->GetBackendTexture()); + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(sampler.Name), + sampler.Sampler->GetBackendTexture()); + } if (currentStaticUniforms != material.GetStaticUniforms()) { currentStaticUniforms = material.GetStaticUniforms(); - material.GetStaticUniforms().BindUniforms(shader); + material.GetStaticUniforms().BindUniforms(deviceCommandContext, shader); } // TODO: Need to handle floating decals correctly. In particular, we need @@ -215,7 +222,8 @@ if (shadingColor != decal->m_Decal->GetShadingColor()) { shadingColor = decal->m_Decal->GetShadingColor(); - shader->Uniform(str_shadingColor, shadingColor); + deviceCommandContext->SetUniform( + shadingColorBindingSlot, shadingColor.AsFloatArray()); } if (lastVB != batch.vertices->m_Owner) Index: source/renderer/HWLightingModelRenderer.h =================================================================== --- source/renderer/HWLightingModelRenderer.h +++ source/renderer/HWLightingModelRenderer.h @@ -44,10 +44,10 @@ Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) override; void PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const CModelDef& def) override; + const CModelDef& def) override; void RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, CModel* model, CModelRData* data) override; + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* data) override; protected: struct ShaderModelRendererInternals; Index: source/renderer/HWLightingModelRenderer.cpp =================================================================== --- source/renderer/HWLightingModelRenderer.cpp +++ source/renderer/HWLightingModelRenderer.cpp @@ -187,7 +187,7 @@ // Prepare UV coordinates for this modeldef void ShaderModelVertexRenderer::PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* UNUSED(shader), const CModelDef& def) + const CModelDef& def) { m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m); @@ -216,7 +216,7 @@ // Render one model void ShaderModelVertexRenderer::RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* UNUSED(shader), CModel* model, CModelRData* data) + Renderer::Backend::IShaderProgram* UNUSED(shader), CModel* model, CModelRData* data) { const CModelDefPtr& mdldef = model->GetModelDef(); ShaderModel* shadermodel = static_cast(data); Index: source/renderer/InstancingModelRenderer.h =================================================================== --- source/renderer/InstancingModelRenderer.h +++ source/renderer/InstancingModelRenderer.h @@ -42,14 +42,14 @@ CModelRData* CreateModelData(const void* key, CModel* model); void UpdateModelData(CModel* model, CModelRData* data, int updateflags); - void BeginPass(); + void BeginPass() override; void EndPass( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) override; void PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const CModelDef& def); + const CModelDef& def) override; void RenderModel(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, CModel* model, CModelRData* data); + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* data) override; protected: InstancingModelRendererInternals* m; Index: source/renderer/InstancingModelRenderer.cpp =================================================================== --- source/renderer/InstancingModelRenderer.cpp +++ source/renderer/InstancingModelRenderer.cpp @@ -308,7 +308,7 @@ // Prepare UV coordinates for this modeldef void InstancingModelRenderer::PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* UNUSED(shader), const CModelDef& def) + const CModelDef& def) { m->imodeldef = (IModelDef*)def.GetRenderData(m); @@ -369,7 +369,7 @@ // Render one model void InstancingModelRenderer::RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, CModel* model, CModelRData* UNUSED(data)) + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* UNUSED(data)) { const CModelDefPtr& mdldef = model->GetModelDef(); @@ -377,7 +377,11 @@ { // Bind matrices for current animation state. // Add 1 to NumBones because of the special 'root' bone. - shader->Uniform(str_skinBlendMatrices, mdldef->GetNumBones() + 1, model->GetAnimatedBoneMatrices()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_skinBlendMatrices), + PS::span( + model->GetAnimatedBoneMatrices()[0]._data, + 16 * (mdldef->GetNumBones() + 1))); } // Render the lot. Index: source/renderer/ModelRenderer.cpp =================================================================== --- source/renderer/ModelRenderer.cpp +++ source/renderer/ModelRenderer.cpp @@ -580,8 +580,8 @@ // texBindings holds the identifier bindings in the shader, which can no longer be defined // statically in the ShaderRenderModifier class. texBindingNames uses interned strings to // keep track of when bindings need to be reevaluated. - using BindingListAllocator = ProxyAllocator; - std::vector texBindings((BindingListAllocator(arena))); + using BindingListAllocator = ProxyAllocator; + std::vector texBindings((BindingListAllocator(arena))); texBindings.reserve(64); using BindingNamesListAllocator = ProxyAllocator; @@ -607,9 +607,9 @@ currentTech->GetGraphicsPipelineStateDesc(pass)); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = currentTech->GetShader(pass); + Renderer::Backend::IShaderProgram* shader = currentTech->GetShader(pass); - modifier->BeginPass(shader); + modifier->BeginPass(deviceCommandContext, shader); // TODO: Use a more generic approach to handle bound queries. bool boundTime = false; @@ -647,12 +647,12 @@ if (currentTexs.size() != samplersNum) { currentTexs.resize(samplersNum, NULL); - texBindings.resize(samplersNum, Renderer::Backend::GL::CShaderProgram::Binding()); + texBindings.resize(samplersNum, -1); texBindingNames.resize(samplersNum, CStrIntern()); // ensure they are definitely empty - std::fill(texBindings.begin(), texBindings.end(), Renderer::Backend::GL::CShaderProgram::Binding()); - std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL); + std::fill(texBindings.begin(), texBindings.end(), -1); + std::fill(currentTexs.begin(), currentTexs.end(), nullptr); std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern()); } @@ -663,18 +663,19 @@ // check that the handles are current // and reevaluate them if necessary - if (texBindingNames[s] != samp.Name || !texBindings[s].Active()) + if (texBindingNames[s] != samp.Name || texBindings[s] < 0) { - texBindings[s] = shader->GetTextureBinding(samp.Name); + texBindings[s] = shader->GetBindingSlot(samp.Name); texBindingNames[s] = samp.Name; } // same with the actual sampler bindings CTexture* newTex = samp.Sampler.get(); - if (texBindings[s].Active() && newTex != currentTexs[s]) + if (texBindings[s] >= 0 && newTex != currentTexs[s]) { newTex->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(texBindings[s], newTex->GetBackendTexture()); + deviceCommandContext->SetTexture( + texBindings[s], newTex->GetBackendTexture()); currentTexs[s] = newTex; } } @@ -684,7 +685,7 @@ if (newModeldef != currentModeldef) { currentModeldef = newModeldef; - m->vertexRenderer->PrepareModelDef(deviceCommandContext, shader, *currentModeldef); + m->vertexRenderer->PrepareModelDef(deviceCommandContext, *currentModeldef); } // Bind all uniforms when any change @@ -692,7 +693,7 @@ if (newStaticUniforms != currentStaticUniforms) { currentStaticUniforms = newStaticUniforms; - currentStaticUniforms.BindUniforms(shader); + currentStaticUniforms.BindUniforms(deviceCommandContext, shader); } const CShaderRenderQueries& renderQueries = model->GetMaterial().GetRenderQueries(); @@ -704,7 +705,8 @@ { if (!boundTime) { - shader->Uniform(rq.second, time, 0.0f, 0.0f, 0.0f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(rq.second), time); boundTime = true; } } @@ -718,10 +720,16 @@ { const CTexturePtr& waterTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]; waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_waterTex, waterTexture->GetBackendTexture()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_waterTex), + waterTexture->GetBackendTexture()); } else - shader->BindTexture(str_waterTex, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_waterTex), + g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); + } boundWaterTexture = true; } } @@ -729,13 +737,15 @@ { if (!boundSkyCube) { - shader->BindTexture(str_skyCube, g_Renderer.GetSceneRenderer().GetSkyManager().GetSkyCube()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_skyCube), + g_Renderer.GetSceneRenderer().GetSkyManager().GetSkyCube()); boundSkyCube = true; } } } - modifier->PrepareModel(shader, model); + modifier->PrepareModel(deviceCommandContext, model); CModelRData* rdata = static_cast(model->GetRenderData()); ENSURE(rdata->GetKey() == m->vertexRenderer.get()); Index: source/renderer/ModelVertexRenderer.h =================================================================== --- source/renderer/ModelVertexRenderer.h +++ source/renderer/ModelVertexRenderer.h @@ -26,7 +26,7 @@ #include "graphics/MeshManager.h" #include "graphics/ShaderProgramPtr.h" #include "renderer/backend/gl/DeviceCommandContext.h" -#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/IShaderProgram.h" class CModel; class CModelRData; @@ -114,7 +114,7 @@ /** - * PrepareModelDef: Setup OpenGL state for rendering of models that + * PrepareModelDef: Setup backend state for rendering of models that * use the given CModelDef object as base. * * ModelRenderer implementations must call this function before @@ -126,7 +126,7 @@ */ virtual void PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const CModelDef& def) = 0; + const CModelDef& def) = 0; /** @@ -147,7 +147,7 @@ */ virtual void RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, CModel* model, CModelRData* data) = 0; + Renderer::Backend::IShaderProgram* shader, CModel* model, CModelRData* data) = 0; }; Index: source/renderer/OverlayRenderer.h =================================================================== --- source/renderer/OverlayRenderer.h +++ source/renderer/OverlayRenderer.h @@ -140,7 +140,7 @@ */ void RenderTexturedOverlayLines( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, bool alwaysVisible); + Renderer::Backend::IShaderProgram* shader, bool alwaysVisible); /** * Helper method; batch-renders all registered quad overlays, batched by their texture for effiency. Index: source/renderer/OverlayRenderer.cpp =================================================================== --- source/renderer/OverlayRenderer.cpp +++ source/renderer/OverlayRenderer.cpp @@ -401,8 +401,6 @@ CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - // ---------------------------------------------------------------------------------------- - CShaderTechniquePtr shaderTechTexLineNormal = GetOverlayLineShaderTechnique(m->defsOverlayLineNormal); if (shaderTechTexLineNormal) { @@ -421,12 +419,18 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shaderTexLineNormal = shaderTechTexLineNormal->GetShader(); + Renderer::Backend::IShaderProgram* shaderTexLineNormal = shaderTechTexLineNormal->GetShader(); - shaderTexLineNormal->BindTexture(str_losTex, los.GetTexture()); - shaderTexLineNormal->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); + deviceCommandContext->SetTexture( + shaderTexLineNormal->GetBindingSlot(str_losTex), los.GetTexture()); - shaderTexLineNormal->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shaderTexLineNormal->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shaderTexLineNormal->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); // batch render only the non-always-visible overlay lines using the normal shader RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineNormal, false); @@ -434,8 +438,6 @@ deviceCommandContext->EndPass(); } - // ---------------------------------------------------------------------------------------- - CShaderTechniquePtr shaderTechTexLineAlwaysVisible = GetOverlayLineShaderTechnique(m->defsOverlayLineAlwaysVisible); if (shaderTechTexLineAlwaysVisible) { @@ -454,30 +456,30 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shaderTexLineAlwaysVisible = shaderTechTexLineAlwaysVisible->GetShader(); + Renderer::Backend::IShaderProgram* shaderTexLineAlwaysVisible = shaderTechTexLineAlwaysVisible->GetShader(); // TODO: losTex and losTransform are unused in the always visible shader; see if these can be safely omitted - shaderTexLineAlwaysVisible->BindTexture(str_losTex, los.GetTexture()); - shaderTexLineAlwaysVisible->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); + deviceCommandContext->SetTexture( + shaderTexLineAlwaysVisible->GetBindingSlot(str_losTex), los.GetTexture()); - shaderTexLineAlwaysVisible->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shaderTexLineAlwaysVisible->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shaderTexLineAlwaysVisible->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); // batch render only the always-visible overlay lines using the LoS-ignored shader RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineAlwaysVisible, true); deviceCommandContext->EndPass(); } - - // ---------------------------------------------------------------------------------------- - - // TODO: the shaders should probably be responsible for unbinding their textures - deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); - deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0); } void OverlayRenderer::RenderTexturedOverlayLines( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, bool alwaysVisible) + Renderer::Backend::IShaderProgram* shader, bool alwaysVisible) { for (size_t i = 0; i < m->texlines.size(); ++i) { @@ -518,14 +520,20 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTexture()); - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); m->quadVertices.UploadIfNeeded(deviceCommandContext); m->quadIndices.UploadIfNeeded(deviceCommandContext); @@ -533,6 +541,9 @@ const uint32_t vertexStride = m->quadVertices.GetStride(); const uint32_t firstVertexOffset = m->quadVertices.GetOffset() * vertexStride; + const int32_t baseTexBindingSlot = shader->GetBindingSlot(str_baseTex); + const int32_t maskTexBindingSlot = shader->GetBindingSlot(str_maskTex); + for (OverlayRendererInternals::QuadBatchMap::iterator it = m->quadBatchMap.begin(); it != m->quadBatchMap.end(); ++it) { QuadBatchData& batchRenderData = it->second; @@ -545,8 +556,11 @@ maskPair.m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); maskPair.m_TextureMask->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_baseTex, maskPair.m_Texture->GetBackendTexture()); - shader->BindTexture(str_maskTex, maskPair.m_TextureMask->GetBackendTexture()); + + deviceCommandContext->SetTexture( + baseTexBindingSlot, maskPair.m_Texture->GetBackendTexture()); + deviceCommandContext->SetTexture( + maskTexBindingSlot, maskPair.m_TextureMask->GetBackendTexture()); // TODO: move setting format out of the loop, we might want move the offset // to the index offset when it's supported. @@ -573,10 +587,6 @@ } deviceCommandContext->EndPass(); - - // TODO: the shader should probably be responsible for unbinding its textures - deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); - deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, 0); } void OverlayRenderer::RenderForegroundOverlays( @@ -604,9 +614,12 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); const CVector2D uvs[6] = { @@ -627,16 +640,21 @@ deviceCommandContext->SetVertexBufferData(1, &uvs[0]); + const int32_t baseTexBindingSlot = shader->GetBindingSlot(str_baseTex); + const int32_t colorMulBindingSlot = shader->GetBindingSlot(str_colorMul); + for (size_t i = 0; i < m->sprites.size(); ++i) { SOverlaySprite* sprite = m->sprites[i]; if (!i || sprite->m_Texture != m->sprites[i - 1]->m_Texture) { sprite->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_baseTex, sprite->m_Texture->GetBackendTexture()); + deviceCommandContext->SetTexture( + baseTexBindingSlot, sprite->m_Texture->GetBackendTexture()); } - shader->Uniform(str_colorMul, sprite->m_Color); + deviceCommandContext->SetUniform( + colorMulBindingSlot, sprite->m_Color.AsFloatArray()); const CVector3D position[6] = { @@ -728,7 +746,7 @@ if (m->spheres.empty()) return; - Renderer::Backend::GL::CShaderProgram* shader; + Renderer::Backend::IShaderProgram* shader = nullptr; CShaderTechniquePtr tech; tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid); @@ -747,7 +765,10 @@ shader = tech->GetShader(); - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); m->GenerateSphere(); @@ -762,14 +783,18 @@ { SOverlaySphere* sphere = m->spheres[i]; - CMatrix3D transform; - transform.SetIdentity(); - transform.Scale(sphere->m_Radius, sphere->m_Radius, sphere->m_Radius); - transform.Translate(sphere->m_Center); - - shader->Uniform(str_instancingTransform, transform); + CMatrix3D instancingTransform; + instancingTransform.SetIdentity(); + instancingTransform.Scale( + sphere->m_Radius, sphere->m_Radius, sphere->m_Radius); + instancingTransform.Translate(sphere->m_Center); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_instancingTransform), + instancingTransform.AsFloatArray()); - shader->Uniform(str_color, sphere->m_Color); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_color), sphere->m_Color.AsFloatArray()); deviceCommandContext->DrawIndexed(0, m->sphereIndexes.size(), 0); Index: source/renderer/ParticleRenderer.cpp =================================================================== --- source/renderer/ParticleRenderer.cpp +++ source/renderer/ParticleRenderer.cpp @@ -157,12 +157,18 @@ deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = lastTech->GetShader(); - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - shader->Uniform(str_modelViewMatrix, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse()); + Renderer::Backend::IShaderProgram* shader = lastTech->GetShader(); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + const CMatrix3D modelViewMatrix = + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetInverse(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_modelViewMatrix), modelViewMatrix.AsFloatArray()); } emitter->Bind(deviceCommandContext, lastTech->GetShader()); - emitter->RenderArray(deviceCommandContext, lastTech->GetShader()); + emitter->RenderArray(deviceCommandContext); } if (lastTech) Index: source/renderer/PatchRData.h =================================================================== --- source/renderer/PatchRData.h +++ source/renderer/PatchRData.h @@ -23,7 +23,7 @@ #include "maths/Vector2D.h" #include "maths/Vector3D.h" #include "renderer/backend/gl/DeviceCommandContext.h" -#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/IShaderProgram.h" #include "renderer/VertexBufferManager.h" #include @@ -50,10 +50,9 @@ void RenderWaterSurface( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader, const bool bindWaterData); + const bool bindWaterData); void RenderWaterShore( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* shader); + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); CPatch* GetPatch() { return m_Patch; } @@ -67,13 +66,12 @@ const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); static void RenderStreams( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, Renderer::Backend::GL::CShaderProgram* shader, - const bool bindPositionAsTexCoord); + const std::vector& patches, const bool bindPositionAsTexCoord); static void RenderSides( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, Renderer::Backend::GL::CShaderProgram* shader); + const std::vector& patches); - static void PrepareShader(Renderer::Backend::GL::CShaderProgram* shader, ShadowMap* shadow); + static void PrepareShader(ShadowMap* shadow); private: friend struct SBlendStackItem; Index: source/renderer/PatchRData.cpp =================================================================== --- source/renderer/PatchRData.cpp +++ source/renderer/PatchRData.cpp @@ -774,29 +774,43 @@ deviceCommandContext->SetGraphicsPipelineState( techBase->GetGraphicsPipelineStateDesc(pass)); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = techBase->GetShader(pass); - TerrainRenderer::PrepareShader(shader, shadow); + Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); + TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); + + const int32_t baseTexBindingSlot = + shader->GetBindingSlot(str_baseTex); + const int32_t textureTransformBindingSlot = + shader->GetBindingSlot(str_textureTransform); TextureBatches& textureBatches = itTech->second; for (TextureBatches::iterator itt = textureBatches.begin(); itt != textureBatches.end(); ++itt) { if (!itt->first->GetMaterial().GetSamplers().empty()) { - const CMaterial::SamplersVector& samplers = itt->first->GetMaterial().GetSamplers(); + const CMaterial::SamplersVector& samplers = + itt->first->GetMaterial().GetSamplers(); for(const CMaterial::TextureSampler& samp : samplers) samp.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext); for(const CMaterial::TextureSampler& samp : samplers) - shader->BindTexture(samp.Name, samp.Sampler->GetBackendTexture()); + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(samp.Name), + samp.Sampler->GetBackendTexture()); + } - itt->first->GetMaterial().GetStaticUniforms().BindUniforms(shader); + itt->first->GetMaterial().GetStaticUniforms().BindUniforms( + deviceCommandContext, shader); float c = itt->first->GetTextureMatrix()[0]; float ms = itt->first->GetTextureMatrix()[8]; - shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); + deviceCommandContext->SetUniform( + textureTransformBindingSlot, c, ms); } else { - shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); + deviceCommandContext->SetTexture( + baseTexBindingSlot, + g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); } for (VertexBufferBatches::iterator itv = itt->second.begin(); itv != itt->second.end(); ++itv) @@ -970,7 +984,7 @@ PROFILE_END("compute batches"); CVertexBuffer* lastVB = nullptr; - Renderer::Backend::GL::CShaderProgram* previousShader = nullptr; + Renderer::Backend::IShaderProgram* previousShader = nullptr; for (BatchesStack::iterator itTechBegin = batches.begin(), itTechEnd = batches.begin(); itTechBegin != batches.end(); itTechBegin = itTechEnd) { while (itTechEnd != batches.end() && itTechEnd->m_ShaderTech == itTechBegin->m_ShaderTech) @@ -992,11 +1006,18 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = techBase->GetShader(pass); - TerrainRenderer::PrepareShader(shader, shadow); + Renderer::Backend::IShaderProgram* shader = techBase->GetShader(pass); + TerrainRenderer::PrepareShader(deviceCommandContext, shader, shadow); Renderer::Backend::GL::CTexture* lastBlendTex = nullptr; + const int32_t baseTexBindingSlot = + shader->GetBindingSlot(str_baseTex); + const int32_t blendTexBindingSlot = + shader->GetBindingSlot(str_blendTex); + const int32_t textureTransformBindingSlot = + shader->GetBindingSlot(str_textureTransform); + for (BatchesStack::iterator itt = itTechBegin; itt != itTechEnd; ++itt) { if (itt->m_Texture->GetMaterial().GetSamplers().empty()) @@ -1008,24 +1029,31 @@ for (const CMaterial::TextureSampler& samp : samplers) samp.Sampler->UploadBackendTextureIfNeeded(deviceCommandContext); for (const CMaterial::TextureSampler& samp : samplers) - shader->BindTexture(samp.Name, samp.Sampler->GetBackendTexture()); + { + deviceCommandContext->SetTexture( + shader->GetBindingSlot(samp.Name), + samp.Sampler->GetBackendTexture()); + } Renderer::Backend::GL::CTexture* currentBlendTex = itt->m_Texture->m_TerrainAlpha->second.m_CompositeAlphaMap.get(); if (currentBlendTex != lastBlendTex) { - shader->BindTexture(str_blendTex, currentBlendTex); + deviceCommandContext->SetTexture( + blendTexBindingSlot, currentBlendTex); lastBlendTex = currentBlendTex; } - itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(shader); + itt->m_Texture->GetMaterial().GetStaticUniforms().BindUniforms(deviceCommandContext, shader); float c = itt->m_Texture->GetTextureMatrix()[0]; float ms = itt->m_Texture->GetTextureMatrix()[8]; - shader->Uniform(str_textureTransform, c, ms, -ms, 0.f); + deviceCommandContext->SetUniform( + textureTransformBindingSlot, c, ms); } else { - shader->BindTexture(str_baseTex, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); + deviceCommandContext->SetTexture( + baseTexBindingSlot, g_Renderer.GetTextureManager().GetErrorTexture()->GetBackendTexture()); } for (VertexBufferBatches::iterator itv = itt->m_Batches.begin(); itv != itt->m_Batches.end(); ++itv) @@ -1083,8 +1111,7 @@ void CPatchRData::RenderStreams( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, Renderer::Backend::GL::CShaderProgram* UNUSED(shader), - const bool bindPositionAsTexCoord) + const std::vector& patches, const bool bindPositionAsTexCoord) { PROFILE3("render terrain streams"); @@ -1184,7 +1211,7 @@ void CPatchRData::RenderSides( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, Renderer::Backend::GL::CShaderProgram* UNUSED(shader)) + const std::vector& patches) { PROFILE3("render terrain sides"); GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain sides"); @@ -1449,7 +1476,7 @@ void CPatchRData::RenderWaterSurface( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* UNUSED(shader), const bool bindWaterData) + const bool bindWaterData) { ASSERT(m_UpdateFlags == 0); @@ -1484,8 +1511,7 @@ } void CPatchRData::RenderWaterShore( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - Renderer::Backend::GL::CShaderProgram* UNUSED(shader)) + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) { ASSERT(m_UpdateFlags == 0); Index: source/renderer/PostprocManager.cpp =================================================================== --- source/renderer/PostprocManager.cpp +++ source/renderer/PostprocManager.cpp @@ -201,9 +201,10 @@ deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); - shader->BindTexture(str_renderedTex, inTex); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), inTex); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = { 0, 0, inWidth / 2, inHeight / 2 }; @@ -266,9 +267,11 @@ deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); - shader->BindTexture(str_renderedTex, inTex); - shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), inTex); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_texSize), inWidth, inHeight, 0.0f, 0.0f); const SViewPort oldVp = g_Renderer.GetViewport(); const SViewPort vp = { 0, 0, inWidth, inHeight }; @@ -324,8 +327,10 @@ shader = tech->GetShader(); // Our input texture to the shader is the output of the horizontal pass. - shader->BindTexture(str_renderedTex, tempTex); - shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), tempTex); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_texSize), inWidth, inHeight, 0.0f, 0.0f); g_Renderer.SetViewport(vp); @@ -408,33 +413,35 @@ deviceCommandContext->SetGraphicsPipelineState( shaderTech->GetGraphicsPipelineStateDesc(pass)); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(pass); + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(pass); // Use the textures from the current FBO as input to the shader. // We also bind a bunch of other textures and parameters, but since // this only happens once per frame the overhead is negligible. - if (m_WhichBuffer) - shader->BindTexture(str_renderedTex, m_ColorTex1.get()); - else - shader->BindTexture(str_renderedTex, m_ColorTex2.get()); - - shader->BindTexture(str_depthTex, m_DepthTex.get()); - - shader->BindTexture(str_blurTex2, m_BlurScales[0].steps[0].texture.get()); - shader->BindTexture(str_blurTex4, m_BlurScales[1].steps[0].texture.get()); - shader->BindTexture(str_blurTex8, m_BlurScales[2].steps[0].texture.get()); - - shader->Uniform(str_width, m_Width); - shader->Uniform(str_height, m_Height); - shader->Uniform(str_zNear, m_NearPlane); - shader->Uniform(str_zFar, m_FarPlane); - - shader->Uniform(str_sharpness, m_Sharpness); - - shader->Uniform(str_brightness, g_LightEnv.m_Brightness); - shader->Uniform(str_hdr, g_LightEnv.m_Contrast); - shader->Uniform(str_saturation, g_LightEnv.m_Saturation); - shader->Uniform(str_bloom, g_LightEnv.m_Bloom); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_renderedTex), + m_WhichBuffer ? m_ColorTex1.get() : m_ColorTex2.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_depthTex), m_DepthTex.get()); + + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_blurTex2), m_BlurScales[0].steps[0].texture.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_blurTex4), m_BlurScales[1].steps[0].texture.get()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_blurTex8), m_BlurScales[2].steps[0].texture.get()); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_width), m_Width); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_height), m_Height); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_zNear), m_NearPlane); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_zFar), m_FarPlane); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_sharpness), m_Sharpness); + + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_brightness), g_LightEnv.m_Brightness); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_hdr), g_LightEnv.m_Contrast); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_saturation), g_LightEnv.m_Saturation); + deviceCommandContext->SetUniform(shader->GetBindingSlot(str_bloom), g_LightEnv.m_Bloom); float quadVerts[] = { Index: source/renderer/RenderModifiers.h =================================================================== --- source/renderer/RenderModifiers.h +++ source/renderer/RenderModifiers.h @@ -55,23 +55,21 @@ * BeginPass: Setup OpenGL for the given rendering pass. * * Must be implemented by derived classes. - * - * @param pass The current pass number (pass == 0 is the first pass) - * - * @return The streamflags that indicate which vertex components - * are required by the fragment stages (see STREAM_XYZ constants). */ - virtual void BeginPass(Renderer::Backend::GL::CShaderProgram* shader) = 0; + virtual void BeginPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) = 0; /** * PrepareModel: Called before rendering the given model. * * Default behaviour does nothing. * - * @param pass The current pass number (pass == 0 is the first pass) * @param model The model that is about to be rendered. */ - virtual void PrepareModel(Renderer::Backend::GL::CShaderProgram* shader, CModel* model) = 0; + virtual void PrepareModel( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + CModel* model) = 0; }; @@ -122,13 +120,17 @@ ShaderRenderModifier(); // Implementation - void BeginPass(Renderer::Backend::GL::CShaderProgram* shader); - void PrepareModel(Renderer::Backend::GL::CShaderProgram* shader, CModel* model); + void BeginPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) override; + void PrepareModel( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + CModel* model) override; private: - Renderer::Backend::GL::CShaderProgram::Binding m_BindingInstancingTransform; - Renderer::Backend::GL::CShaderProgram::Binding m_BindingShadingColor; - Renderer::Backend::GL::CShaderProgram::Binding m_BindingPlayerColor; + int32_t m_BindingInstancingTransform; + int32_t m_BindingShadingColor; + int32_t m_BindingPlayerColor; CColor m_ShadingColor, m_PlayerColor; }; Index: source/renderer/RenderModifiers.cpp =================================================================== --- source/renderer/RenderModifiers.cpp +++ source/renderer/RenderModifiers.cpp @@ -68,67 +68,96 @@ { } -void ShaderRenderModifier::BeginPass(Renderer::Backend::GL::CShaderProgram* shader) -{ - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - shader->Uniform(str_cameraPos, g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetTranslation()); +void ShaderRenderModifier::BeginPass( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) +{ + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_cameraPos), + g_Renderer.GetSceneRenderer().GetViewCamera().GetOrientation().GetTranslation().AsFloatArray()); if (GetShadowMap()) - GetShadowMap()->BindTo(shader); + GetShadowMap()->BindTo(deviceCommandContext, shader); if (GetLightEnv()) { - shader->Uniform(str_ambient, GetLightEnv()->m_AmbientColor); - shader->Uniform(str_sunDir, GetLightEnv()->GetSunDir()); - shader->Uniform(str_sunColor, GetLightEnv()->m_SunColor); - - shader->Uniform(str_fogColor, GetLightEnv()->m_FogColor); - shader->Uniform(str_fogParams, GetLightEnv()->m_FogFactor, GetLightEnv()->m_FogMax, 0.f, 0.f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_ambient), + GetLightEnv()->m_AmbientColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunDir), + GetLightEnv()->GetSunDir().AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunColor), + GetLightEnv()->m_SunColor.AsFloatArray()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogColor), + GetLightEnv()->m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogParams), + GetLightEnv()->m_FogFactor, GetLightEnv()->m_FogMax); } - if (shader->GetTextureBinding(str_losTex).Active()) + if (shader->GetBindingSlot(str_losTex) >= 0) { CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTextureSmooth()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); // Don't bother sending the whole matrix, we just need two floats (scale and translation) - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); } - m_BindingInstancingTransform = shader->GetUniformBinding(str_instancingTransform); - m_BindingShadingColor = shader->GetUniformBinding(str_shadingColor); - m_BindingPlayerColor = shader->GetUniformBinding(str_playerColor); + m_BindingInstancingTransform = shader->GetBindingSlot(str_instancingTransform); + m_BindingShadingColor = shader->GetBindingSlot(str_shadingColor); + m_BindingPlayerColor = shader->GetBindingSlot(str_playerColor); - if (m_BindingShadingColor.Active()) + if (m_BindingShadingColor >= 0) { m_ShadingColor = CColor(1.0f, 1.0f, 1.0f, 1.0f); - shader->Uniform(m_BindingShadingColor, m_ShadingColor); + deviceCommandContext->SetUniform( + m_BindingShadingColor, m_ShadingColor.AsFloatArray()); } - if (m_BindingPlayerColor.Active()) + if (m_BindingPlayerColor >= 0) { m_PlayerColor = g_Game->GetPlayerColor(0); - shader->Uniform(m_BindingPlayerColor, m_PlayerColor); + deviceCommandContext->SetUniform( + m_BindingPlayerColor, m_PlayerColor.AsFloatArray()); } } -void ShaderRenderModifier::PrepareModel(Renderer::Backend::GL::CShaderProgram* shader, CModel* model) +void ShaderRenderModifier::PrepareModel( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + CModel* model) { - if (m_BindingInstancingTransform.Active()) - shader->Uniform(m_BindingInstancingTransform, model->GetTransform()); + if (m_BindingInstancingTransform >= 0) + { + deviceCommandContext->SetUniform( + m_BindingInstancingTransform, model->GetTransform().AsFloatArray()); + } - if (m_BindingShadingColor.Active() && m_ShadingColor != model->GetShadingColor()) + if (m_BindingShadingColor >= 0 && m_ShadingColor != model->GetShadingColor()) { m_ShadingColor = model->GetShadingColor(); - shader->Uniform(m_BindingShadingColor, m_ShadingColor); + deviceCommandContext->SetUniform( + m_BindingShadingColor, m_ShadingColor.AsFloatArray()); } - if (m_BindingPlayerColor.Active()) + if (m_BindingPlayerColor >= 0) { const CColor& playerColor = g_Game->GetPlayerColor(model->GetPlayerID()); if (m_PlayerColor != playerColor) { m_PlayerColor = playerColor; - shader->Uniform(m_BindingPlayerColor, m_PlayerColor); + deviceCommandContext->SetUniform( + m_BindingPlayerColor, m_PlayerColor.AsFloatArray()); } } } Index: source/renderer/SceneRenderer.cpp =================================================================== --- source/renderer/SceneRenderer.cpp +++ source/renderer/SceneRenderer.cpp @@ -925,16 +925,13 @@ if (g_RenderingOptions.GetDisplayShadowsFrustum()) m->shadow.RenderDebugBounds(); - m->silhouetteRenderer.RenderDebugBounds(deviceCommandContext); - if (g_RenderingOptions.GetDisplayShadowsFrustum()) - m->shadow.RenderDebugTexture(deviceCommandContext); + m->silhouetteRenderer.RenderDebugBounds(deviceCommandContext); m->silhouetteRenderer.RenderDebugOverlays(deviceCommandContext); // render overlays that should appear on top of all other objects m->overlayRenderer.RenderForegroundOverlays(deviceCommandContext, m_ViewCamera); ogl_WarnIfError(); - } void CSceneRenderer::EndFrame() Index: source/renderer/ShadowMap.h =================================================================== --- source/renderer/ShadowMap.h +++ source/renderer/ShadowMap.h @@ -19,7 +19,7 @@ #define INCLUDED_SHADOWMAP #include "renderer/backend/gl/DeviceCommandContext.h" -#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/IShaderProgram.h" class CBoundingBoxAligned; class CCamera; @@ -126,7 +126,9 @@ /** * Binds all needed resources and uniforms to draw shadows using the shader. */ - void BindTo(Renderer::Backend::GL::CShaderProgram* shader) const; + void BindTo( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const; /** * Visualize shadow mapping calculations to help in @@ -134,12 +136,6 @@ */ void RenderDebugBounds(); - /** - * Visualize shadow map texture to help in debugging. - */ - void RenderDebugTexture( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext); - private: ShadowMapInternals* m; }; Index: source/renderer/ShadowMap.cpp =================================================================== --- source/renderer/ShadowMap.cpp +++ source/renderer/ShadowMap.cpp @@ -519,7 +519,7 @@ { case 16: formatName = "Format::D16"; backendFormat = Renderer::Backend::Format::D16; break; case 24: formatName = "Format::D24"; backendFormat = Renderer::Backend::Format::D24; break; - case 32: formatName = "Format::D32"; backendFormat = Renderer::Backend::Format::D32; break; + case 32: formatName = "Format::D32"; backendFormat = Renderer::Backend::Format::D32; break; default: formatName = "Format::D24"; backendFormat = Renderer::Backend::Format::D24; break; } #endif @@ -631,20 +631,29 @@ g_Renderer.SetViewport(vp); } -void ShadowMap::BindTo(Renderer::Backend::GL::CShaderProgram* shader) const +void ShadowMap::BindTo( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader) const { - if (!shader->GetTextureBinding(str_shadowTex).Active() || !m->Texture) + const int32_t shadowTexBindingSlot = shader->GetBindingSlot(str_shadowTex); + if (shadowTexBindingSlot < 0 || !m->Texture) return; - shader->BindTexture(str_shadowTex, m->Texture.get()); - shader->Uniform(str_shadowScale, m->Width, m->Height, 1.0f / m->Width, 1.0f / m->Height); + deviceCommandContext->SetTexture(shadowTexBindingSlot, m->Texture.get()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowScale), m->Width, m->Height, 1.0f / m->Width, 1.0f / m->Height); const CVector3D cameraForward = g_Renderer.GetSceneRenderer().GetCullCamera().GetOrientation().GetIn(); - shader->Uniform(str_cameraForward, cameraForward.X, cameraForward.Y, cameraForward.Z, + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_cameraForward), cameraForward.X, cameraForward.Y, cameraForward.Z, cameraForward.Dot(g_Renderer.GetSceneRenderer().GetCullCamera().GetOrientation().GetTranslation())); + if (GetCascadeCount() == 1) { - shader->Uniform(str_shadowTransform, m->Cascades[0].TextureMatrix); - shader->Uniform(str_shadowDistance, m->Cascades[0].Distance); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowTransform), + m->Cascades[0].TextureMatrix.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowDistance), m->Cascades[0].Distance); } else { @@ -655,8 +664,12 @@ shadowDistances.emplace_back(cascade.Distance); shadowTransforms.emplace_back(cascade.TextureMatrix); } - shader->Uniform(str_shadowTransforms, GetCascadeCount(), shadowTransforms.data()); - shader->Uniform(str_shadowDistances, GetCascadeCount(), shadowDistances.data()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowTransform), + PS::span(shadowTransforms[0]._data, 16 * GetCascadeCount())); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_shadowDistance), + PS::span(shadowDistances.data(), shadowDistances.size())); } } @@ -711,64 +724,6 @@ ogl_WarnIfError(); } -void ShadowMap::RenderDebugTexture( - Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext) -{ - if (!m->Texture) - return; - -#if !CONFIG2_GLES - deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, m->Texture->GetHandle()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); -#endif - - CShaderTechniquePtr texTech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d); - deviceCommandContext->SetGraphicsPipelineState( - texTech->GetGraphicsPipelineStateDesc()); - deviceCommandContext->BeginPass(); - - Renderer::Backend::GL::CShaderProgram* texShader = texTech->GetShader(); - - texShader->Uniform(str_transform, GetDefaultGuiMatrix()); - texShader->BindTexture(str_tex, m->Texture.get()); - texShader->Uniform(str_colorAdd, CColor(0.0f, 0.0f, 0.0f, 1.0f)); - texShader->Uniform(str_colorMul, CColor(1.0f, 1.0f, 1.0f, 0.0f)); - texShader->Uniform(str_grayscaleFactor, 0.0f); - - float s = 256.f; - float boxVerts[] = - { - 0,0, 0,s, s,0, - s,0, 0,s, s,s - }; - float boxUV[] = - { - 0,0, 0,1, 1,0, - 1,0, 0,1, 1,1 - }; - - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::POSITION, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 0); - deviceCommandContext->SetVertexAttributeFormat( - Renderer::Backend::VertexAttributeStream::UV0, - Renderer::Backend::Format::R32G32_SFLOAT, 0, 0, 1); - - deviceCommandContext->SetVertexBufferData(0, boxVerts); - deviceCommandContext->SetVertexBufferData(1, boxUV); - - deviceCommandContext->Draw(0, 6); - - deviceCommandContext->EndPass(); - -#if !CONFIG2_GLES - deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, m->Texture->GetHandle()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_COMPARE_R_TO_TEXTURE); -#endif - - ogl_WarnIfError(); -} - int ShadowMap::GetCascadeCount() const { #if CONFIG2_GLES Index: source/renderer/SilhouetteRenderer.cpp =================================================================== --- source/renderer/SilhouetteRenderer.cpp +++ source/renderer/SilhouetteRenderer.cpp @@ -477,13 +477,16 @@ pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); - Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); - shader->Uniform(str_transform, proj); + Renderer::Backend::IShaderProgram* shader = shaderTech->GetShader(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), proj.AsFloatArray()); + const int32_t colorBindingSlot = shader->GetBindingSlot(str_color); for (size_t i = 0; i < m_DebugRects.size(); ++i) { const DebugRect& r = m_DebugRects[i]; - shader->Uniform(str_color, r.color); + deviceCommandContext->SetUniform( + colorBindingSlot, r.color.AsFloatArray()); u16 verts[] = { r.x0, r.y0, Index: source/renderer/SkyManager.cpp =================================================================== --- source/renderer/SkyManager.cpp +++ source/renderer/SkyManager.cpp @@ -224,8 +224,9 @@ deviceCommandContext->SetGraphicsPipelineState( skytech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = skytech->GetShader(); - shader->BindTexture(str_baseTex, m_SkyTextureCube->GetBackendTexture()); + Renderer::Backend::IShaderProgram* shader = skytech->GetShader(); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), m_SkyTextureCube->GetBackendTexture()); // Translate so the sky center is at the camera space origin. CMatrix3D translate; @@ -238,12 +239,12 @@ // Rotate so that the "left" face, which contains the brightest part of // each skymap, is in the direction of the sun from our light // environment. - CMatrix3D rotate; - rotate.SetYRotation(M_PI + g_Renderer.GetSceneRenderer().GetLightEnv().GetRotation()); + CMatrix3D transform; + transform.SetYRotation(M_PI + g_Renderer.GetSceneRenderer().GetLightEnv().GetRotation()); - shader->Uniform( - str_transform, - camera.GetViewProjection() * translate * rotate * scale); + transform = camera.GetViewProjection() * translate * transform * scale; + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); m_VertexArray.PrepareForRendering(); m_VertexArray.UploadIfNeeded(deviceCommandContext); Index: source/renderer/TerrainOverlay.cpp =================================================================== --- source/renderer/TerrainOverlay.cpp +++ source/renderer/TerrainOverlay.cpp @@ -210,10 +210,14 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* overlayShader = overlayTech->GetShader(); + Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); - overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - overlayShader->Uniform(str_color, color); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, @@ -271,10 +275,14 @@ deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* overlayShader = overlayTech->GetShader(); + Renderer::Backend::IShaderProgram* overlayShader = overlayTech->GetShader(); - overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - overlayShader->Uniform(str_color, color); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + overlayShader->GetBindingSlot(str_color), color.AsFloatArray()); deviceCommandContext->SetVertexAttributeFormat( Renderer::Backend::VertexAttributeStream::POSITION, Index: source/renderer/TerrainRenderer.h =================================================================== --- source/renderer/TerrainRenderer.h +++ source/renderer/TerrainRenderer.h @@ -26,8 +26,8 @@ #include "graphics/Color.h" #include "maths/BoundingBoxAligned.h" #include "renderer/backend/gl/DeviceCommandContext.h" -#include "renderer/backend/gl/ShaderProgram.h" #include "renderer/backend/gl/Texture.h" +#include "renderer/backend/IShaderProgram.h" class CCamera; class CCanvas2D; @@ -187,7 +187,9 @@ Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int cullGroup); - static void PrepareShader(Renderer::Backend::GL::CShaderProgram* shader, ShadowMap* shadow); + static void PrepareShader( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow); }; #endif // INCLUDED_TERRAINRENDERER Index: source/renderer/TerrainRenderer.cpp =================================================================== --- source/renderer/TerrainRenderer.cpp +++ source/renderer/TerrainRenderer.cpp @@ -174,12 +174,17 @@ deviceCommandContext->SetGraphicsPipelineState( debugOverlayTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* debugOverlayShader = debugOverlayTech->GetShader(); + Renderer::Backend::IShaderProgram* debugOverlayShader = debugOverlayTech->GetShader(); - debugOverlayShader->BindTexture(str_baseTex, texture); - debugOverlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - debugOverlayShader->Uniform(str_textureTransform, textureMatrix); - CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, debugOverlayShader, true); + deviceCommandContext->SetTexture( + debugOverlayShader->GetBindingSlot(str_baseTex), texture); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + debugOverlayShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + debugOverlayShader->GetBindingSlot(str_textureTransform), textureMatrix.AsFloatArray()); + CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, true); // To make the overlay visible over water, render an additional map-sized // water-height patch. @@ -221,28 +226,47 @@ /** * Set up all the uniforms for a shader pass. */ -void TerrainRenderer::PrepareShader(Renderer::Backend::GL::CShaderProgram* shader, ShadowMap* shadow) +void TerrainRenderer::PrepareShader( + Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, + Renderer::Backend::IShaderProgram* shader, ShadowMap* shadow) { CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); - shader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); - shader->Uniform(str_cameraPos, sceneRenderer.GetViewCamera().GetOrientation().GetTranslation()); + const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_cameraPos), + sceneRenderer.GetViewCamera().GetOrientation().GetTranslation().AsFloatArray()); const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); if (shadow) - shadow->BindTo(shader); + shadow->BindTo(deviceCommandContext, shader); CLOSTexture& los = sceneRenderer.GetScene().GetLOSTexture(); - shader->BindTexture(str_losTex, los.GetTextureSmooth()); - shader->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); - - shader->Uniform(str_ambient, lightEnv.m_AmbientColor); - shader->Uniform(str_sunColor, lightEnv.m_SunColor); - shader->Uniform(str_sunDir, lightEnv.GetSunDir()); - - shader->Uniform(str_fogColor, lightEnv.m_FogColor); - shader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_losTex), los.GetTextureSmooth()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_losTransform), + los.GetTextureMatrix()[0], los.GetTextureMatrix()[12]); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_ambient), + lightEnv.m_AmbientColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunColor), + lightEnv.m_SunColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_sunDir), + lightEnv.GetSunDir().AsFloatArray()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogColor), + lightEnv.m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_fogParams), + lightEnv.m_FogFactor, lightEnv.m_FogMax); } void TerrainRenderer::RenderTerrainShader( @@ -264,11 +288,15 @@ deviceCommandContext->SetGraphicsPipelineState(solidPipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shaderSolid = techSolid->GetShader(); - shaderSolid->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - shaderSolid->Uniform(str_color, 0.0f, 0.0f, 0.0f, 1.0f); + Renderer::Backend::IShaderProgram* shaderSolid = techSolid->GetShader(); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shaderSolid->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + shaderSolid->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 1.0f); - CPatchRData::RenderSides(deviceCommandContext, visiblePatches, shaderSolid); + CPatchRData::RenderSides(deviceCommandContext, visiblePatches); deviceCommandContext->EndPass(); @@ -278,14 +306,8 @@ CPatchRData::RenderBlends(deviceCommandContext, visiblePatches, context, shadow); CDecalRData::RenderDecals(deviceCommandContext, visibleDecals, context, shadow); - - // restore OpenGL state - deviceCommandContext->BindTexture(3, GL_TEXTURE_2D, 0); - deviceCommandContext->BindTexture(2, GL_TEXTURE_2D, 0); - deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); } - /////////////////////////////////////////////////////////////////// // Render un-textured patches as polygons void TerrainRenderer::RenderPatches( @@ -305,11 +327,16 @@ solidTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* solidShader = solidTech->GetShader(); - solidShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - solidShader->Uniform(str_color, color); + Renderer::Backend::IShaderProgram* solidShader = solidTech->GetShader(); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + solidShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + solidShader->GetBindingSlot(str_color), color.AsFloatArray()); - CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, solidShader, false); + CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, false); deviceCommandContext->EndPass(); } @@ -405,7 +432,7 @@ deviceCommandContext->SetGraphicsPipelineState( m->fancyWaterTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader(); + Renderer::Backend::IShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader(); const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -413,87 +440,157 @@ // TODO: move uploading to a prepare function during loading. const CTexturePtr& currentNormalTexture = waterManager.m_NormalMap[waterManager.GetCurrentTextureIndex(period)]; const CTexturePtr& nextNormalTexture = waterManager.m_NormalMap[waterManager.GetNextTextureIndex(period)]; + currentNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext); nextNormalTexture->UploadBackendTextureIfNeeded(deviceCommandContext); - fancyWaterShader->BindTexture(str_normalMap, currentNormalTexture->GetBackendTexture()); - fancyWaterShader->BindTexture(str_normalMap2, nextNormalTexture->GetBackendTexture()); + + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_normalMap), + currentNormalTexture->GetBackendTexture()); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_normalMap2), + nextNormalTexture->GetBackendTexture()); if (waterManager.m_WaterFancyEffects) { - fancyWaterShader->BindTexture(str_waterEffectsTex, waterManager.m_FancyTexture.get()); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_waterEffectsTex), + waterManager.m_FancyTexture.get()); } if (waterManager.m_WaterRefraction && waterManager.m_WaterRealDepth) { - fancyWaterShader->BindTexture(str_depthTex, waterManager.m_RefrFboDepthTexture.get()); - fancyWaterShader->Uniform(str_projInvTransform, waterManager.m_RefractionProjInvMatrix); - fancyWaterShader->Uniform(str_viewInvTransform, waterManager.m_RefractionViewInvMatrix); + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_depthTex), + waterManager.m_RefrFboDepthTexture.get()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_projInvTransform), + waterManager.m_RefractionProjInvMatrix.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_viewInvTransform), + waterManager.m_RefractionViewInvMatrix.AsFloatArray()); } if (waterManager.m_WaterRefraction) - fancyWaterShader->BindTexture(str_refractionMap, waterManager.m_RefractionTexture.get()); + { + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_refractionMap), + waterManager.m_RefractionTexture.get()); + } if (waterManager.m_WaterReflection) - fancyWaterShader->BindTexture(str_reflectionMap, waterManager.m_ReflectionTexture.get()); - fancyWaterShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); + { + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_reflectionMap), + waterManager.m_ReflectionTexture.get()); + } + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth()); const CLightEnv& lightEnv = sceneRenderer.GetLightEnv(); - fancyWaterShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); - - fancyWaterShader->BindTexture(str_skyCube, sceneRenderer.GetSkyManager().GetSkyCube()); + const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + + deviceCommandContext->SetTexture( + fancyWaterShader->GetBindingSlot(str_skyCube), + sceneRenderer.GetSkyManager().GetSkyCube()); // TODO: check that this rotates in the right direction. CMatrix3D skyBoxRotation; skyBoxRotation.SetIdentity(); skyBoxRotation.RotateY(M_PI + lightEnv.GetRotation()); - fancyWaterShader->Uniform(str_skyBoxRot, skyBoxRotation); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_skyBoxRot), + skyBoxRotation.AsFloatArray()); if (waterManager.m_WaterRefraction) - fancyWaterShader->Uniform(str_refractionMatrix, waterManager.m_RefractionMatrix); + { + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_refractionMatrix), + waterManager.m_RefractionMatrix.AsFloatArray()); + } if (waterManager.m_WaterReflection) - fancyWaterShader->Uniform(str_reflectionMatrix, waterManager.m_ReflectionMatrix); - - fancyWaterShader->Uniform(str_ambient, lightEnv.m_AmbientColor); - fancyWaterShader->Uniform(str_sunDir, lightEnv.GetSunDir()); - fancyWaterShader->Uniform(str_sunColor, lightEnv.m_SunColor); - fancyWaterShader->Uniform(str_color, waterManager.m_WaterColor); - fancyWaterShader->Uniform(str_tint, waterManager.m_WaterTint); - fancyWaterShader->Uniform(str_waviness, waterManager.m_Waviness); - fancyWaterShader->Uniform(str_murkiness, waterManager.m_Murkiness); - fancyWaterShader->Uniform(str_windAngle, waterManager.m_WindAngle); - fancyWaterShader->Uniform(str_repeatScale, 1.0f / repeatPeriod); - fancyWaterShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); - - fancyWaterShader->Uniform(str_cameraPos, camera.GetOrientation().GetTranslation()); - - fancyWaterShader->Uniform(str_fogColor, lightEnv.m_FogColor); - fancyWaterShader->Uniform(str_fogParams, lightEnv.m_FogFactor, lightEnv.m_FogMax, 0.f, 0.f); - fancyWaterShader->Uniform(str_time, (float)time); - fancyWaterShader->Uniform(str_screenSize, (float)g_Renderer.GetWidth(), (float)g_Renderer.GetHeight(), 0.0f, 0.0f); + { + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_reflectionMatrix), + waterManager.m_ReflectionMatrix.AsFloatArray()); + } + + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_ambient), lightEnv.m_AmbientColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_sunDir), lightEnv.GetSunDir().AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_sunColor), lightEnv.m_SunColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_tint), waterManager.m_WaterTint.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waviness), waterManager.m_Waviness); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_murkiness), waterManager.m_Murkiness); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_windAngle), waterManager.m_WindAngle); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_repeatScale), 1.0f / repeatPeriod); + + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_losTransform), + losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_cameraPos), + camera.GetOrientation().GetTranslation().AsFloatArray()); + + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_fogColor), + lightEnv.m_FogColor.AsFloatArray()); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_fogParams), + lightEnv.m_FogFactor, lightEnv.m_FogMax); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_time), static_cast(time)); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_screenSize), + static_cast(g_Renderer.GetWidth()), + static_cast(g_Renderer.GetHeight())); if (waterManager.m_WaterType == L"clap") { - fancyWaterShader->Uniform(str_waveParams1, 30.0f,1.5f,20.0f,0.03f); - fancyWaterShader->Uniform(str_waveParams2, 0.5f,0.0f,0.0f,0.0f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams1), + 30.0f, 1.5f, 20.0f, 0.03f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams2), + 0.5f, 0.0f, 0.0f, 0.0f); } else if (waterManager.m_WaterType == L"lake") { - fancyWaterShader->Uniform(str_waveParams1, 8.5f,1.5f,15.0f,0.03f); - fancyWaterShader->Uniform(str_waveParams2, 0.2f,0.0f,0.0f,0.07f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams1), + 8.5f, 1.5f, 15.0f, 0.03f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams2), + 0.2f, 0.0f, 0.0f, 0.07f); } else { - fancyWaterShader->Uniform(str_waveParams1, 15.0f,0.8f,10.0f,0.1f); - fancyWaterShader->Uniform(str_waveParams2, 0.3f,0.0f,0.1f,0.3f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams1), + 15.0f, 0.8f, 10.0f, 0.1f); + deviceCommandContext->SetUniform( + fancyWaterShader->GetBindingSlot(str_waveParams2), + 0.3f, 0.0f, 0.1f, 0.3f); } if (shadow) - shadow->BindTo(fancyWaterShader); + shadow->BindTo(deviceCommandContext, fancyWaterShader); for (CPatchRData* data : m->visiblePatches[cullGroup]) { - data->RenderWaterSurface(deviceCommandContext, fancyWaterShader, true); + data->RenderWaterSurface(deviceCommandContext, true); if (waterManager.m_WaterFancyEffects) - data->RenderWaterShore(deviceCommandContext, fancyWaterShader); + data->RenderWaterShore(deviceCommandContext); } deviceCommandContext->EndPass(); @@ -521,26 +618,36 @@ deviceCommandContext->SetGraphicsPipelineState( waterSimpleTech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* waterSimpleShader = waterSimpleTech->GetShader(); + Renderer::Backend::IShaderProgram* waterSimpleShader = waterSimpleTech->GetShader(); const CTexturePtr& waterTexture = waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)]; waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext); - waterSimpleShader->BindTexture(str_baseTex, waterTexture->GetBackendTexture()); - waterSimpleShader->BindTexture(str_losTex, losTexture.GetTextureSmooth()); - waterSimpleShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); - waterSimpleShader->Uniform(str_losTransform, losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12], 0.f, 0.f); - waterSimpleShader->Uniform(str_time, static_cast(time)); - waterSimpleShader->Uniform(str_color, waterManager.m_WaterColor); + + deviceCommandContext->SetTexture( + waterSimpleShader->GetBindingSlot(str_baseTex), waterTexture->GetBackendTexture()); + deviceCommandContext->SetTexture( + waterSimpleShader->GetBindingSlot(str_losTex), losTexture.GetTextureSmooth()); + + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_losTransform), + losTexture.GetTextureMatrix()[0], losTexture.GetTextureMatrix()[12]); + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_time), static_cast(time)); + deviceCommandContext->SetUniform( + waterSimpleShader->GetBindingSlot(str_color), waterManager.m_WaterColor.AsFloatArray()); std::vector& visiblePatches = m->visiblePatches[cullGroup]; for (size_t i = 0; i < visiblePatches.size(); ++i) { CPatchRData* data = visiblePatches[i]; - data->RenderWaterSurface(deviceCommandContext, waterSimpleShader, false); + data->RenderWaterSurface(deviceCommandContext, false); } - deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); - deviceCommandContext->EndPass(); } @@ -580,12 +687,18 @@ pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* dummyShader = dummyTech->GetShader(); - dummyShader->Uniform(str_transform, sceneRenderer.GetViewCamera().GetViewProjection()); - dummyShader->Uniform(str_color, 0.0f, 0.0f, 0.0f, 0.0f); + Renderer::Backend::IShaderProgram* dummyShader = dummyTech->GetShader(); + + const CMatrix3D transform = sceneRenderer.GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + dummyShader->GetBindingSlot(str_transform), transform.AsFloatArray()); + deviceCommandContext->SetUniform( + dummyShader->GetBindingSlot(str_color), 0.0f, 0.0f, 0.0f, 0.0f); + for (CPatchRData* data : m->visiblePatches[cullGroup]) - data->RenderWaterShore(deviceCommandContext, dummyShader); + data->RenderWaterShore(deviceCommandContext); + deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( Index: source/renderer/TexturedLineRData.h =================================================================== --- source/renderer/TexturedLineRData.h +++ source/renderer/TexturedLineRData.h @@ -53,7 +53,7 @@ void Update(const SOverlayTexturedLine& line); void Render(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const SOverlayTexturedLine& line, Renderer::Backend::GL::CShaderProgram* shader); + const SOverlayTexturedLine& line, Renderer::Backend::IShaderProgram* shader); bool IsVisibleInFrustum(const CFrustum& frustum) const; Index: source/renderer/TexturedLineRData.cpp =================================================================== --- source/renderer/TexturedLineRData.cpp +++ source/renderer/TexturedLineRData.cpp @@ -37,7 +37,7 @@ void CTexturedLineRData::Render( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const SOverlayTexturedLine& line, Renderer::Backend::GL::CShaderProgram* shader) + const SOverlayTexturedLine& line, Renderer::Backend::IShaderProgram* shader) { if (!m_VB || !m_VBIndices) return; // might have failed to allocate @@ -50,9 +50,12 @@ m_VB->m_Owner->UploadIfNeeded(deviceCommandContext); m_VBIndices->m_Owner->UploadIfNeeded(deviceCommandContext); - shader->BindTexture(str_baseTex, line.m_TextureBase->GetBackendTexture()); - shader->BindTexture(str_maskTex, line.m_TextureMask->GetBackendTexture()); - shader->Uniform(str_objectColor, line.m_Color); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_baseTex), line.m_TextureBase->GetBackendTexture()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_maskTex), line.m_TextureMask->GetBackendTexture()); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_objectColor), line.m_Color.AsFloatArray()); const uint32_t stride = sizeof(CTexturedLineRData::SVertex); Index: source/renderer/VertexBufferManager.h =================================================================== --- source/renderer/VertexBufferManager.h +++ source/renderer/VertexBufferManager.h @@ -80,10 +80,10 @@ * Try to allocate a vertex buffer of the given size and type. * * @param vertexSize size of each vertex in the buffer - * @param numVertices number of vertices in the buffer - * @param usage GL_STATIC_DRAW, GL_DYNAMIC_DRAW, GL_STREAM_DRAW - * @param target typically GL_ARRAY_BUFFER or GL_ELEMENT_ARRAY_BUFFER - * @param backingStore if usage is STATIC, this is NULL; else for DYNAMIC/STREAM, + * @param numberOfVertices number of vertices in the buffer + * @param type buffer type + * @param dynamic will be buffer updated frequently or not + * @param backingStore if not dynamic, this is nullptr; else for dynamic, * this must be a copy of the vertex data that remains valid for the * lifetime of the VBChunk * @return chunk, or empty handle if no free chunks available Index: source/renderer/WaterManager.cpp =================================================================== --- source/renderer/WaterManager.cpp +++ source/renderer/WaterManager.cpp @@ -802,15 +802,22 @@ deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); deviceCommandContext->BeginPass(); - Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); + Renderer::Backend::IShaderProgram* shader = tech->GetShader(); m_WaveTex->UploadBackendTextureIfNeeded(deviceCommandContext); m_FoamTex->UploadBackendTextureIfNeeded(deviceCommandContext); - shader->BindTexture(str_waveTex, m_WaveTex->GetBackendTexture()); - shader->BindTexture(str_foamTex, m_FoamTex->GetBackendTexture()); - shader->Uniform(str_time, (float)m_WaterTexTimer); - shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_waveTex), m_WaveTex->GetBackendTexture()); + deviceCommandContext->SetTexture( + shader->GetBindingSlot(str_foamTex), m_FoamTex->GetBackendTexture()); + + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_time), static_cast(m_WaterTexTimer)); + const CMatrix3D transform = + g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection(); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_transform), transform.AsFloatArray()); for (size_t a = 0; a < m_ShoreWaves.size(); ++a) { @@ -850,19 +857,19 @@ Renderer::Backend::Format::R32G32B32_SFLOAT, firstVertexOffset + offsetof(SWavesVertex, m_RetreatPosition), stride, 0); - shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff); - shader->Uniform(str_width, (int)m_ShoreWaves[a]->m_Width); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_translation), m_ShoreWaves[a]->m_TimeDiff); + deviceCommandContext->SetUniform( + shader->GetBindingSlot(str_width), static_cast(m_ShoreWaves[a]->m_Width)); deviceCommandContext->SetVertexBuffer(0, VBchunk->m_Owner->GetBuffer()); deviceCommandContext->SetIndexBuffer(m_ShoreWavesVBIndices->m_Owner->GetBuffer()); - deviceCommandContext->DrawIndexed(m_ShoreWavesVBIndices->m_Index, (m_ShoreWaves[a]->m_Width - 1) * (7 * 6), 0); + const uint32_t indexCount = (m_ShoreWaves[a]->m_Width - 1) * (7 * 6); + deviceCommandContext->DrawIndexed(m_ShoreWavesVBIndices->m_Index, indexCount, 0); - shader->Uniform(str_translation, m_ShoreWaves[a]->m_TimeDiff + 6.0f); - - // TODO: figure out why this doesn't work. - //g_Renderer.m_Stats.m_DrawCalls++; - //g_Renderer.m_Stats.m_WaterTris += m_ShoreWaves_VBIndices->m_Count / 3; + g_Renderer.GetStats().m_DrawCalls++; + g_Renderer.GetStats().m_WaterTris += indexCount / 3; } deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( Index: source/renderer/backend/IShaderProgram.h =================================================================== --- source/renderer/backend/IShaderProgram.h +++ source/renderer/backend/IShaderProgram.h @@ -18,6 +18,9 @@ #ifndef INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM #define INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM +#include "lib/file/vfs/vfs_path.h" +#include "ps/CStrIntern.h" + namespace Renderer { @@ -46,6 +49,10 @@ { public: virtual ~IShaderProgram() {} + + virtual int32_t GetBindingSlot(const CStrIntern name) const = 0; + + virtual std::vector GetFileDependencies() const = 0; }; } // namespace Backend Index: source/renderer/backend/gl/Device.h =================================================================== --- source/renderer/backend/gl/Device.h +++ source/renderer/backend/gl/Device.h @@ -100,7 +100,7 @@ std::unique_ptr CreateBuffer( const char* name, const CBuffer::Type type, const uint32_t size, const bool dynamic); - std::unique_ptr CreateShaderProgram( + std::unique_ptr CreateShaderProgram( const CStr& name, const CShaderDefines& defines); void Present(); Index: source/renderer/backend/gl/Device.cpp =================================================================== --- source/renderer/backend/gl/Device.cpp +++ source/renderer/backend/gl/Device.cpp @@ -821,7 +821,7 @@ return CBuffer::Create(this, name, type, size, dynamic); } -std::unique_ptr CDevice::CreateShaderProgram( +std::unique_ptr CDevice::CreateShaderProgram( const CStr& name, const CShaderDefines& defines) { return CShaderProgram::Create(this, name, defines); Index: source/renderer/backend/gl/DeviceCommandContext.h =================================================================== --- source/renderer/backend/gl/DeviceCommandContext.h +++ source/renderer/backend/gl/DeviceCommandContext.h @@ -19,6 +19,7 @@ #define INCLUDED_RENDERER_GL_DEVICECOMMANDCONTEXT #include "lib/ogl.h" +#include "ps/containers/Span.h" #include "renderer/backend/Format.h" #include "renderer/backend/gl/Buffer.h" #include "renderer/backend/PipelineState.h" @@ -41,6 +42,7 @@ class CDevice; class CFramebuffer; +class CShaderProgram; class CTexture; class CDeviceCommandContext @@ -111,12 +113,28 @@ const uint32_t firstIndex, const uint32_t indexCount, const uint32_t start, const uint32_t end); + void SetTexture(const int32_t bindingSlot, CTexture* texture); + + void SetUniform( + const int32_t bindingSlot, + const float value); + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY); + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ); + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW); + void SetUniform( + const int32_t bindingSlot, PS::span values); + void BeginScopedLabel(const char* name); void EndScopedLabel(); - // TODO: remove direct binding after moving shaders. - void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle); - // We need to know when to invalidate our texture bind cache. void OnTextureDestroy(CTexture* texture); @@ -124,6 +142,7 @@ private: friend class CDevice; + friend class CTexture; static std::unique_ptr Create(CDevice* device); @@ -134,12 +153,14 @@ void SetGraphicsPipelineStateImpl( const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force); + void BindTexture(const uint32_t unit, const GLenum target, const GLuint handle); void BindBuffer(const CBuffer::Type type, CBuffer* buffer); CDevice* m_Device = nullptr; GraphicsPipelineStateDesc m_GraphicsPipelineStateDesc{}; CFramebuffer* m_Framebuffer = nullptr; + CShaderProgram* m_ShaderProgram = nullptr; uint32_t m_ScissorCount = 0; // GL2.1 doesn't support more than 1 scissor. std::array m_Scissors; @@ -153,7 +174,11 @@ bool m_InsidePass = false; uint32_t m_ActiveTextureUnit = 0; - using BindUnit = std::pair; + struct BindUnit + { + GLenum target; + GLuint handle; + }; std::array m_BoundTextures; class ScopedBind { @@ -165,6 +190,7 @@ private: CDeviceCommandContext* m_DeviceCommandContext = nullptr; BindUnit m_OldBindUnit; + uint32_t m_ActiveTextureUnit = 0; }; using BoundBuffer = std::pair; Index: source/renderer/backend/gl/DeviceCommandContext.cpp =================================================================== --- source/renderer/backend/gl/DeviceCommandContext.cpp +++ source/renderer/backend/gl/DeviceCommandContext.cpp @@ -106,6 +106,13 @@ return target; } +bool IsDepthTexture(const Format format) +{ + return + format == Format::D16 || format == Format::D24 || + format == Format::D32 || format == Format::D24_S8; +} + void UploadBufferRegionImpl( const GLenum target, const uint32_t dataOffset, const uint32_t dataSize, const CDeviceCommandContext::UploadBufferFunction& uploadFunction) @@ -148,10 +155,10 @@ { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, 0); - for (std::pair& unit : m_BoundTextures) + for (BindUnit& unit : m_BoundTextures) { - unit.first = GL_TEXTURE_2D; - unit.second = 0; + unit.target = GL_TEXTURE_2D; + unit.handle = 0; } for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) { @@ -372,7 +379,8 @@ glPopDebugGroup(); } -void CDeviceCommandContext::BindTexture(const uint32_t unit, const GLenum target, const GLuint handle) +void CDeviceCommandContext::BindTexture( + const uint32_t unit, const GLenum target, const GLuint handle) { ENSURE(unit < m_BoundTextures.size()); #if CONFIG2_GLES @@ -380,16 +388,16 @@ #else ENSURE(target == GL_TEXTURE_2D || target == GL_TEXTURE_CUBE_MAP || target == GL_TEXTURE_2D_MULTISAMPLE); #endif - if (m_BoundTextures[unit].first == target && m_BoundTextures[unit].second == handle) - return; if (m_ActiveTextureUnit != unit) { glActiveTexture(GL_TEXTURE0 + unit); m_ActiveTextureUnit = unit; } - if (m_BoundTextures[unit].first != target && m_BoundTextures[unit].first && m_BoundTextures[unit].second) - glBindTexture(m_BoundTextures[unit].first, 0); - if (m_BoundTextures[unit].second != handle) + if (m_BoundTextures[unit].target == target && m_BoundTextures[unit].handle == handle) + return; + if (m_BoundTextures[unit].target != target && m_BoundTextures[unit].target && m_BoundTextures[unit].handle) + glBindTexture(m_BoundTextures[unit].target, 0); + if (m_BoundTextures[unit].handle != handle) glBindTexture(target, handle); m_BoundTextures[unit] = {target, handle}; } @@ -421,7 +429,7 @@ { ENSURE(texture); for (size_t index = 0; index < m_BoundTextures.size(); ++index) - if (m_BoundTextures[index].second == texture->GetHandle()) + if (m_BoundTextures[index].handle == texture->GetHandle()) BindTexture(index, GL_TEXTURE_2D, 0); } @@ -476,6 +484,8 @@ nextShaderProgram->Bind(currentShaderProgram); else if (currentShaderProgram) currentShaderProgram->Unbind(); + + m_ShaderProgram = nextShaderProgram; } const DepthStencilStateDesc& currentDepthStencilStateDesc = m_GraphicsPipelineStateDesc.depthStencilState; @@ -822,17 +832,15 @@ { ENSURE(buffer); ENSURE(buffer->GetType() == CBuffer::Type::VERTEX); - ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_ShaderProgram); BindBuffer(buffer->GetType(), buffer); - CShaderProgram* shaderProgram = - static_cast(m_GraphicsPipelineStateDesc.shaderProgram); for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) { if (!m_VertexAttributeFormat[index].active || m_VertexAttributeFormat[index].bindingSlot != bindingSlot) continue; ENSURE(m_VertexAttributeFormat[index].initialized); const VertexAttributeStream stream = static_cast(index); - shaderProgram->VertexAttribPointer(stream, + m_ShaderProgram->VertexAttribPointer(stream, m_VertexAttributeFormat[index].format, m_VertexAttributeFormat[index].offset, m_VertexAttributeFormat[index].stride, @@ -844,17 +852,15 @@ const uint32_t bindingSlot, const void* data) { ENSURE(data); - ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_ShaderProgram); BindBuffer(CBuffer::Type::VERTEX, nullptr); - CShaderProgram* shaderProgram = - static_cast(m_GraphicsPipelineStateDesc.shaderProgram); for (size_t index = 0; index < m_VertexAttributeFormat.size(); ++index) { if (!m_VertexAttributeFormat[index].active || m_VertexAttributeFormat[index].bindingSlot != bindingSlot) continue; ENSURE(m_VertexAttributeFormat[index].initialized); const VertexAttributeStream stream = static_cast(index); - shaderProgram->VertexAttribPointer(stream, + m_ShaderProgram->VertexAttribPointer(stream, m_VertexAttributeFormat[index].format, m_VertexAttributeFormat[index].offset, m_VertexAttributeFormat[index].stride, @@ -895,14 +901,13 @@ void CDeviceCommandContext::Draw( const uint32_t firstVertex, const uint32_t vertexCount) { - ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_ShaderProgram); ENSURE(m_InsidePass); // Some drivers apparently don't like count = 0 in glDrawArrays here, so skip // all drawing in that case. if (vertexCount == 0) return; - static_cast(m_GraphicsPipelineStateDesc.shaderProgram) - ->AssertPointersBound(); + m_ShaderProgram->AssertPointersBound(); glDrawArrays(GL_TRIANGLES, firstVertex, vertexCount); ogl_WarnIfError(); } @@ -910,7 +915,7 @@ void CDeviceCommandContext::DrawIndexed( const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) { - ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_ShaderProgram); ENSURE(m_InsidePass); if (indexCount == 0) return; @@ -920,8 +925,7 @@ { ENSURE(sizeof(uint16_t) * (firstIndex + indexCount) <= m_IndexBuffer->GetSize()); } - static_cast(m_GraphicsPipelineStateDesc.shaderProgram) - ->AssertPointersBound(); + m_ShaderProgram->AssertPointersBound(); // Don't use glMultiDrawElements here since it doesn't have a significant // performance impact and it suffers from various driver bugs (e.g. it breaks // in Mesa 7.10 swrast with index VBOs). @@ -934,15 +938,14 @@ const uint32_t firstIndex, const uint32_t indexCount, const uint32_t start, const uint32_t end) { - ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_ShaderProgram); ENSURE(m_InsidePass); if (indexCount == 0) return; ENSURE(m_IndexBuffer || m_IndexBufferData); const void* indices = static_cast((static_cast(m_IndexBufferData) + sizeof(uint16_t) * firstIndex)); - static_cast(m_GraphicsPipelineStateDesc.shaderProgram) - ->AssertPointersBound(); + m_ShaderProgram->AssertPointersBound(); // Draw with DrawRangeElements where available, since it might be more // efficient for slow hardware. #if CONFIG2_GLES @@ -955,20 +958,92 @@ ogl_WarnIfError(); } +void CDeviceCommandContext::SetTexture(const int32_t bindingSlot, CTexture* texture) +{ + ENSURE(m_ShaderProgram); + ENSURE(texture); + const CShaderProgram::TextureUnit textureUnit = + m_ShaderProgram->GetTextureUnit(bindingSlot); + if (!textureUnit.type) + return; + + if (textureUnit.type != GL_SAMPLER_2D && + textureUnit.type != GL_SAMPLER_2D_SHADOW && + textureUnit.type != GL_SAMPLER_CUBE) + { + LOGERROR("CDeviceCommandContext::SetTexture: expected sampler at binding slot"); + return; + } + + if (textureUnit.type == GL_SAMPLER_2D_SHADOW) + { + if (!IsDepthTexture(texture->GetFormat())) + { + LOGERROR("CDeviceCommandContext::SetTexture: Invalid texture type (expected depth texture)"); + return; + } + } + ENSURE(textureUnit.unit >= 0); + m_Device->GetActiveCommandContext()->BindTexture( + textureUnit.unit, textureUnit.target, texture->GetHandle()); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float value) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, value); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, valueX, valueY, valueZ, valueW); +} + +void CDeviceCommandContext::SetUniform( + const int32_t bindingSlot, PS::span values) +{ + ENSURE(m_ShaderProgram); + m_ShaderProgram->SetUniform(bindingSlot, values); +} + CDeviceCommandContext::ScopedBind::ScopedBind( CDeviceCommandContext* deviceCommandContext, const GLenum target, const GLuint handle) : m_DeviceCommandContext(deviceCommandContext), - m_OldBindUnit(deviceCommandContext->m_BoundTextures[deviceCommandContext->m_ActiveTextureUnit]) + m_OldBindUnit(deviceCommandContext->m_BoundTextures[deviceCommandContext->m_ActiveTextureUnit]), + m_ActiveTextureUnit(deviceCommandContext->m_ActiveTextureUnit) { - m_DeviceCommandContext->BindTexture( - m_DeviceCommandContext->m_ActiveTextureUnit, target, handle); + const uint32_t unit = m_DeviceCommandContext->m_BoundTextures.size() - 1; + m_DeviceCommandContext->BindTexture(unit, target, handle); } CDeviceCommandContext::ScopedBind::~ScopedBind() { m_DeviceCommandContext->BindTexture( - m_DeviceCommandContext->m_ActiveTextureUnit, m_OldBindUnit.first, m_OldBindUnit.second); + m_ActiveTextureUnit, m_OldBindUnit.target, m_OldBindUnit.handle); } CDeviceCommandContext::ScopedBufferBind::ScopedBufferBind( Index: source/renderer/backend/gl/ShaderProgram.h =================================================================== --- source/renderer/backend/gl/ShaderProgram.h +++ source/renderer/backend/gl/ShaderProgram.h @@ -53,7 +53,7 @@ * * Texture/uniform IDs are typically strings, corresponding to the names defined in * the shader .xml file. Alternatively (and more efficiently, if used very frequently), - * call GetTextureBinding/GetUniformBinding and pass its return value as the ID. + * call GetBindingSlot and pass its return value as the ID. * Setting uniforms that the shader .xml doesn't support is harmless. * * For a high-level overview of shaders and materials, see @@ -65,35 +65,9 @@ public: typedef CStrIntern attrib_id_t; - typedef CStrIntern texture_id_t; - typedef CStrIntern uniform_id_t; - typedef std::pair frag_index_pair_t; - static std::unique_ptr Create(CDevice* device, const CStr& name, const CShaderDefines& baseDefines); - - /** - * Represents a uniform attribute or texture binding. - * For uniforms: - * - ARB shaders store vertex location in 'first', fragment location in 'second'. - * - GLSL shaders store uniform location in 'first', data type in 'second'. - * For textures, all store texture target (e.g. GL_TEXTURE_2D) in 'first', texture unit in 'second'. - * Non-existent bindings must store -1 in both. - */ - struct Binding - { - Binding(int a, int b) : first(a), second(b) { } - - Binding() : first(-1), second(-1) { } - - /** - * Returns whether this uniform attribute is active in the shader. - * If not then there's no point calling Uniform() to set its value. - */ - bool Active() const { return first != -1 || second != -1; } - - int first; - int second; - }; + static std::unique_ptr Create( + CDevice* device, const CStr& name, const CShaderDefines& baseDefines); ~CShaderProgram() override; @@ -108,41 +82,32 @@ */ virtual void Unbind() = 0; + struct TextureUnit + { + GLenum type; + GLenum target; + GLint unit; + }; + virtual TextureUnit GetTextureUnit(const int32_t bindingSlot) = 0; - virtual Binding GetTextureBinding(texture_id_t id) = 0; - - // Variants of texture binding: - void BindTexture(texture_id_t id, const Renderer::Backend::GL::CTexture* tex); - void BindTexture(Binding id, const Renderer::Backend::GL::CTexture* tex); - - virtual Binding GetUniformBinding(uniform_id_t id) = 0; - - // Uniform-setting methods that subclasses must define: - virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) = 0; - virtual void Uniform(Binding id, const CMatrix3D& v) = 0; - virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) = 0; - virtual void Uniform(Binding id, size_t count, const float* v) = 0; - - // Convenient uniform-setting wrappers: - - void Uniform(Binding id, int v); - void Uniform(Binding id, float v); - void Uniform(Binding id, float v0, float v1); - void Uniform(Binding id, const CVector3D& v); - void Uniform(Binding id, const CColor& v); - - void Uniform(uniform_id_t id, int v); - void Uniform(uniform_id_t id, float v); - void Uniform(uniform_id_t id, float v0, float v1); - void Uniform(uniform_id_t id, const CVector3D& v); - void Uniform(uniform_id_t id, const CColor& v); - void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3); - void Uniform(uniform_id_t id, const CMatrix3D& v); - void Uniform(uniform_id_t id, size_t count, const CMatrix3D* v); - void Uniform(uniform_id_t id, size_t count, const float* v); - - // Vertex attribute pointers (equivalent to glVertexPointer etc): + virtual void SetUniform( + const int32_t bindingSlot, + const float value) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ) = 0; + virtual void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) = 0; + virtual void SetUniform( + const int32_t bindingSlot, PS::span values) = 0; + // Vertex attribute pointers (equivalent to glVertexPointer etc). virtual void VertexAttribPointer( const VertexAttributeStream stream, const Format format, const uint32_t offset, const uint32_t stride, const void* data); @@ -155,39 +120,15 @@ */ void AssertPointersBound(); - virtual std::vector GetFileDependencies() const = 0; - protected: CShaderProgram(int streamflags); - /** - * Construct based on ARB vertex/fragment program files. - */ - static std::unique_ptr ConstructARB( - CDevice* device, const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags); - - /** - * Construct based on GLSL vertex/fragment shader files. - */ - static std::unique_ptr ConstructGLSL( - CDevice* device, const CStr& name, - const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags); - void VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer); void VertexAttribPointer(attrib_id_t id, const Renderer::Backend::Format format, GLboolean normalized, GLsizei stride, const void* pointer); - virtual void BindTexture(texture_id_t id, GLuint tex) = 0; - virtual void BindTexture(Binding id, GLuint tex) = 0; - int m_StreamFlags; // Non-GLSL client state handling: Index: source/renderer/backend/gl/ShaderProgram.cpp =================================================================== --- source/renderer/backend/gl/ShaderProgram.cpp +++ source/renderer/backend/gl/ShaderProgram.cpp @@ -23,8 +23,6 @@ #include "graphics/PreprocessorWrapper.h" #include "graphics/ShaderManager.h" #include "graphics/TextureManager.h" -#include "maths/Matrix3D.h" -#include "maths/Vector3D.h" #include "ps/CLogger.h" #include "ps/Filesystem.h" #include "ps/Profile.h" @@ -40,6 +38,8 @@ #endif #include +#include +#include namespace Renderer { @@ -53,6 +53,22 @@ namespace { +struct Binding +{ + Binding(int a, int b) : first(a), second(b) { } + + Binding() : first(-1), second(-1) { } + + /** + * Returns whether this uniform attribute is active in the shader. + * If not then there's no point calling Uniform() to set its value. + */ + bool Active() const { return first != -1 || second != -1; } + + int first; + int second; +}; + int GetStreamMask(const VertexAttributeStream stream) { return 1 << static_cast(stream); @@ -201,6 +217,46 @@ return true; } +std::tuple GetElementTypeAndCountFromString(const CStr& str) +{ +#define CASE(MATCH_STRING, TYPE, ELEMENT_TYPE, ELEMENT_COUNT) \ + if (str == MATCH_STRING) return {GL_ ## TYPE, GL_ ## ELEMENT_TYPE, ELEMENT_COUNT} + + CASE("float", FLOAT, FLOAT, 1); + CASE("vec2", FLOAT_VEC2, FLOAT, 2); + CASE("vec3", FLOAT_VEC3, FLOAT, 3); + CASE("vec4", FLOAT_VEC4, FLOAT, 4); + CASE("mat2", FLOAT_MAT2, FLOAT, 4); + CASE("mat3", FLOAT_MAT3, FLOAT, 9); + CASE("mat4", FLOAT_MAT4, FLOAT, 16); + CASE("mat2x3", FLOAT_MAT2x3, FLOAT, 6); + CASE("mat2x4", FLOAT_MAT2x4, FLOAT, 8); + CASE("mat3x2", FLOAT_MAT3x2, FLOAT, 6); + CASE("mat3x4", FLOAT_MAT3x4, FLOAT, 12); + CASE("mat4x2", FLOAT_MAT4x2, FLOAT, 8); + CASE("mat4x3", FLOAT_MAT4x3, FLOAT, 12); + + // A somewhat incomplete listing, missing "shadow" and "rect" versions + // which are interpreted as 2D (NB: our shadowmaps may change + // type based on user config). +#if CONFIG2_GLES + if (str == "sampler1D") debug_warn(L"sampler1D not implemented on GLES"); +#else + CASE("sampler1D", SAMPLER_1D, TEXTURE_1D, 1); +#endif + CASE("sampler2D", SAMPLER_2D, TEXTURE_2D, 1); + CASE("sampler2DShadow", SAMPLER_2D_SHADOW, TEXTURE_2D, 1); +#if CONFIG2_GLES + if (str == "sampler3D") debug_warn(L"sampler3D not implemented on GLES"); +#else + CASE("sampler3D", SAMPLER_3D, TEXTURE_3D, 1); +#endif + CASE("samplerCube", SAMPLER_CUBE, TEXTURE_CUBE_MAP, 1); + +#undef CASE + return {0, 0, 0}; +} + } // anonymous namespace #if !CONFIG2_GLES @@ -212,11 +268,10 @@ CDevice* device, const VfsPath& vertexFilePath, const VfsPath& fragmentFilePath, const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags) : - CShaderProgram(streamflags), - m_Device(device), - m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes) + const std::map>& vertexIndices, + const std::map>& fragmentIndices, + int streamflags) + : CShaderProgram(streamflags), m_Device(device) { glGenProgramsARB(1, &m_VertexProgram); glGenProgramsARB(1, &m_FragmentProgram); @@ -241,6 +296,30 @@ if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, fragmentFilePath, fragmentCode)) return; + + for (const auto& index : vertexIndices) + { + BindingSlot& bindingSlot = GetOrCreateBindingSlot(index.first); + bindingSlot.vertexProgramLocation = index.second.second; + const auto [type, elementType, elementCount] = GetElementTypeAndCountFromString(index.second.first); + bindingSlot.type = type; + bindingSlot.elementType = elementType; + bindingSlot.elementCount = elementCount; + } + + for (const auto& index : fragmentIndices) + { + BindingSlot& bindingSlot = GetOrCreateBindingSlot(index.first); + bindingSlot.fragmentProgramLocation = index.second.second; + const auto [type, elementType, elementCount] = GetElementTypeAndCountFromString(index.second.first); + if (bindingSlot.type && type != bindingSlot.type) + { + LOGERROR("CShaderProgramARB: vertex and fragment program uniforms with the same name should have the same type."); + } + bindingSlot.type = type; + bindingSlot.elementType = elementType; + bindingSlot.elementCount = elementCount; + } } ~CShaderProgramARB() override @@ -302,106 +381,201 @@ glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); UnbindClientStates(); - - // TODO: should unbind textures, probably } - int GetUniformVertexIndex(CStrIntern id) + int32_t GetBindingSlot(const CStrIntern name) const override { - std::map::iterator it = m_VertexIndexes.find(id); - if (it == m_VertexIndexes.end()) - return -1; - return it->second; + auto it = m_BindingSlotsMapping.find(name); + return it == m_BindingSlotsMapping.end() ? -1 : it->second; } - frag_index_pair_t GetUniformFragmentIndex(CStrIntern id) + TextureUnit GetTextureUnit(const int32_t bindingSlot) override { - std::map::iterator it = m_FragmentIndexes.find(id); - if (it == m_FragmentIndexes.end()) - return std::make_pair(-1, 0); - return it->second; + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return { 0, 0, 0 }; + TextureUnit textureUnit; + textureUnit.type = m_BindingSlots[bindingSlot].type; + textureUnit.target = m_BindingSlots[bindingSlot].elementType; + textureUnit.unit = m_BindingSlots[bindingSlot].fragmentProgramLocation; + return textureUnit; } - Binding GetTextureBinding(texture_id_t id) override + void SetUniform( + const int32_t bindingSlot, + const float value) override { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index == -1) - return Binding(); - else - return Binding((int)fPair.second, index); + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float)"); + return; + } + SetUniform(m_BindingSlots[bindingSlot], value, 0.0f, 0.0f, 0.0f); } - void BindTexture(texture_id_t id, GLuint tex) override + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) override { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index != -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC2) { - m_Device->GetActiveCommandContext()->BindTexture(index, fPair.second, tex); + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float)"); + return; } + SetUniform(m_BindingSlots[bindingSlot], valueX, valueY, 0.0f, 0.0f); } - void BindTexture(Binding id, GLuint tex) override + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, const float valueZ) override { - int index = id.second; - if (index != -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC3) { - m_Device->GetActiveCommandContext()->BindTexture(index, id.first, tex); + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float)"); + return; } + SetUniform(m_BindingSlots[bindingSlot], valueX, valueY, valueZ, 0.0f); } - Binding GetUniformBinding(uniform_id_t id) override + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) override { - return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id).first); + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC4) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float)"); + return; + } + SetUniform(m_BindingSlots[bindingSlot], valueX, valueY, valueZ, valueW); } - void Uniform(Binding id, float v0, float v1, float v2, float v3) override + void SetUniform( + const int32_t bindingSlot, PS::span values) override { - if (id.first != -1) - glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3); + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].elementType != GL_FLOAT) + { + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform element type (expected float)"); + return; + } + if (m_BindingSlots[bindingSlot].elementCount > static_cast(values.size())) + { + LOGERROR( + "CShaderProgramARB::SetUniform(): Invalid uniform element count (expected: %zu passed: %zu)", + m_BindingSlots[bindingSlot].elementCount, values.size()); + return; + } + const GLenum type = m_BindingSlots[bindingSlot].type; - if (id.second != -1) - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3); + if (type == GL_FLOAT) + SetUniform(m_BindingSlots[bindingSlot], values[0], 0.0f, 0.0f, 0.0f); + else if (type == GL_FLOAT_VEC2) + SetUniform(m_BindingSlots[bindingSlot], values[0], values[1], 0.0f, 0.0f); + else if (type == GL_FLOAT_VEC3) + SetUniform(m_BindingSlots[bindingSlot], values[0], values[1], values[2], 0.0f); + else if (type == GL_FLOAT_VEC4) + SetUniform(m_BindingSlots[bindingSlot], values[0], values[1], values[2], values[3]); + else if (type == GL_FLOAT_MAT4) + SetUniformMatrix(m_BindingSlots[bindingSlot], values); + else + LOGERROR("CShaderProgramARB::SetUniform(): Invalid uniform type (expected float, vec2, vec3, vec4, mat4)"); + ogl_WarnIfError(); } - void Uniform(Binding id, const CMatrix3D& v) override + std::vector GetFileDependencies() const override { - if (id.first != -1) - { - glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+0, v._11, v._12, v._13, v._14); - glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+1, v._21, v._22, v._23, v._24); - glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+2, v._31, v._32, v._33, v._34); - glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first+3, v._41, v._42, v._43, v._44); - } + return m_FileDependencies; + } - if (id.second != -1) +private: + struct BindingSlot + { + CStrIntern name; + int vertexProgramLocation; + int fragmentProgramLocation; + GLenum type; + GLenum elementType; + GLint elementCount; + }; + + BindingSlot& GetOrCreateBindingSlot(const CStrIntern name) + { + auto it = m_BindingSlotsMapping.find(name); + if (it == m_BindingSlotsMapping.end()) { - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+0, v._11, v._12, v._13, v._14); - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+1, v._21, v._22, v._23, v._24); - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+2, v._31, v._32, v._33, v._34); - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second+3, v._41, v._42, v._43, v._44); + m_BindingSlotsMapping[name] = m_BindingSlots.size(); + BindingSlot bindingSlot{}; + bindingSlot.name = name; + bindingSlot.vertexProgramLocation = -1; + bindingSlot.fragmentProgramLocation = -1; + bindingSlot.elementType = 0; + bindingSlot.elementCount = 0; + m_BindingSlots.emplace_back(std::move(bindingSlot)); + return m_BindingSlots.back(); } + else + return m_BindingSlots[it->second]; } - void Uniform(Binding id, size_t count, const CMatrix3D* v) override + void SetUniform( + const BindingSlot& bindingSlot, + const float v0, const float v1, const float v2, const float v3) { - ENSURE(count == 1); - Uniform(id, v[0]); - } + if (bindingSlot.vertexProgramLocation >= 0) + { + glProgramLocalParameter4fARB( + GL_VERTEX_PROGRAM_ARB, + static_cast(bindingSlot.vertexProgramLocation), v0, v1, v2, v3); + } - void Uniform(Binding id, size_t count, const float* v) override - { - ENSURE(count == 4); - Uniform(id, v[0], v[1], v[2], v[3]); + if (bindingSlot.fragmentProgramLocation >= 0) + { + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, + static_cast(bindingSlot.fragmentProgramLocation), v0, v1, v2, v3); + } } - std::vector GetFileDependencies() const override + void SetUniformMatrix( + const BindingSlot& bindingSlot, PS::span values) { - return m_FileDependencies; + ENSURE(values.size() == 16); + if (bindingSlot.vertexProgramLocation >= 0) + { + const GLuint location = static_cast(bindingSlot.vertexProgramLocation); + glProgramLocalParameter4fARB( + GL_VERTEX_PROGRAM_ARB, location + 0, values[0], values[4], values[8], values[12]); + glProgramLocalParameter4fARB( + GL_VERTEX_PROGRAM_ARB, location + 1, values[1], values[5], values[9], values[13]); + glProgramLocalParameter4fARB( + GL_VERTEX_PROGRAM_ARB, location + 2, values[2], values[6], values[10], values[14]); + glProgramLocalParameter4fARB( + GL_VERTEX_PROGRAM_ARB, location + 3, values[3], values[7], values[11], values[15]); + } + + if (bindingSlot.fragmentProgramLocation >= 0) + { + const GLuint location = static_cast(bindingSlot.fragmentProgramLocation); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, location + 0, values[0], values[4], values[8], values[12]); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, location + 1, values[1], values[5], values[9], values[13]); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, location + 2, values[2], values[6], values[10], values[14]); + glProgramLocalParameter4fARB( + GL_FRAGMENT_PROGRAM_ARB, location + 3, values[3], values[7], values[11], values[15]); + } } -private: CDevice* m_Device = nullptr; std::vector m_FileDependencies; @@ -409,10 +583,8 @@ GLuint m_VertexProgram; GLuint m_FragmentProgram; - std::map m_VertexIndexes; - - // pair contains - std::map m_FragmentIndexes; + std::vector m_BindingSlots; + std::unordered_map m_BindingSlotsMapping; }; #endif // !CONFIG2_GLES @@ -596,13 +768,24 @@ if (!ok) return false; - m_Uniforms.clear(); - m_Samplers.clear(); - Bind(nullptr); ogl_WarnIfError(); + // Reorder sampler units to decrease redundant texture unit changes when + // samplers bound in a different order. + const std::unordered_map requiredUnits = + { + {CStrIntern("baseTex"), 0}, + {CStrIntern("normTex"), 1}, + {CStrIntern("specTex"), 2}, + {CStrIntern("aoTex"), 3}, + {CStrIntern("shadowTex"), 4}, + {CStrIntern("losTex"), 5}, + }; + + std::vector occupiedUnits; + GLint numUniforms = 0; glGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); ogl_WarnIfError(); @@ -629,10 +812,43 @@ } name[nameLength] = 0; - CStrIntern nameIntern(name); - m_Uniforms[nameIntern] = std::make_pair(location, type); + const CStrIntern nameIntern(name); + + m_BindingSlotsMapping[nameIntern] = m_BindingSlots.size(); + BindingSlot bindingSlot{}; + bindingSlot.name = nameIntern; + bindingSlot.location = location; + bindingSlot.size = size; + bindingSlot.type = type; + bindingSlot.isTexture = false; + +#define CASE(TYPE, ELEMENT_TYPE, ELEMENT_COUNT) \ + case GL_ ## TYPE: \ + bindingSlot.elementType = GL_ ## ELEMENT_TYPE; \ + bindingSlot.elementCount = ELEMENT_COUNT; \ + break; - // Assign sampler uniforms to sequential texture units + switch (type) + { + CASE(FLOAT, FLOAT, 1); + CASE(FLOAT_VEC2, FLOAT, 2); + CASE(FLOAT_VEC3, FLOAT, 3); + CASE(FLOAT_VEC4, FLOAT, 4); + CASE(INT, INT, 1); + CASE(UNSIGNED_INT, UNSIGNED_INT, 1); + CASE(FLOAT_MAT2, FLOAT, 4); + CASE(FLOAT_MAT3, FLOAT, 9); + CASE(FLOAT_MAT4, FLOAT, 16); + CASE(FLOAT_MAT2x3, FLOAT, 6); + CASE(FLOAT_MAT2x4, FLOAT, 8); + CASE(FLOAT_MAT3x2, FLOAT, 6); + CASE(FLOAT_MAT3x4, FLOAT, 12); + CASE(FLOAT_MAT4x2, FLOAT, 8); + CASE(FLOAT_MAT4x3, FLOAT, 12); + } +#undef CASE + + // Assign sampler uniforms to sequential texture units. if (type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE #if !CONFIG2_GLES @@ -640,20 +856,51 @@ #endif ) { - const int unit = static_cast(m_Samplers.size()); - m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); - m_Samplers[nameIntern].second = unit; - glUniform1i(location, unit); // link uniform to unit - ogl_WarnIfError(); + const auto it = requiredUnits.find(nameIntern); + const int unit = it == requiredUnits.end() ? -1 : it->second; + bindingSlot.elementType = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); + bindingSlot.elementCount = unit; + bindingSlot.isTexture = true; + if (unit != -1) + { + if (unit >= static_cast(occupiedUnits.size())) + occupiedUnits.resize(unit + 1); + occupiedUnits[unit] = true; + } } + + if (bindingSlot.elementType == 0) + { + LOGERROR("CShaderProgramGLSL::Link: unsupported uniform type: 0x%04x", static_cast(type)); + } + + m_BindingSlots.emplace_back(std::move(bindingSlot)); + } + + for (BindingSlot& bindingSlot : m_BindingSlots) + { + if (!bindingSlot.isTexture) + continue; + if (bindingSlot.elementCount == -1) + { + // We need to find a minimal available unit. + int unit = 0; + while (unit < static_cast(occupiedUnits.size()) && occupiedUnits[unit]) + ++unit; + if (unit >= static_cast(occupiedUnits.size())) + occupiedUnits.resize(unit + 1); + occupiedUnits[unit] = true; + bindingSlot.elementCount = unit; + } + // Link uniform to unit. + glUniform1i(bindingSlot.location, bindingSlot.elementCount); + ogl_WarnIfError(); } // TODO: verify that we're not using more samplers than is supported Unbind(); - ogl_WarnIfError(); - return true; } @@ -720,93 +967,128 @@ for (const int index : m_ActiveVertexAttributes) glDisableVertexAttribArray(index); - - // TODO: should unbind textures, probably } - Binding GetTextureBinding(texture_id_t id) override + int32_t GetBindingSlot(const CStrIntern name) const override { - std::map>::iterator it = m_Samplers.find(CStrIntern(id)); - if (it == m_Samplers.end()) - return Binding(); - else - return Binding((int)it->second.first, it->second.second); + auto it = m_BindingSlotsMapping.find(name); + return it == m_BindingSlotsMapping.end() ? -1 : it->second; } - void BindTexture(texture_id_t id, GLuint tex) override + TextureUnit GetTextureUnit(const int32_t bindingSlot) override { - std::map>::iterator it = m_Samplers.find(CStrIntern(id)); - if (it == m_Samplers.end()) - return; - - m_Device->GetActiveCommandContext()->BindTexture(it->second.second, it->second.first, tex); + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return { 0, 0, 0 }; + TextureUnit textureUnit; + textureUnit.type = m_BindingSlots[bindingSlot].type; + textureUnit.target = m_BindingSlots[bindingSlot].elementType; + textureUnit.unit = m_BindingSlots[bindingSlot].elementCount; + return textureUnit; } - void BindTexture(Binding id, GLuint tex) override + void SetUniform( + const int32_t bindingSlot, + const float value) override { - if (id.second == -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) return; - - m_Device->GetActiveCommandContext()->BindTexture(id.second, id.first, tex); - } - - Binding GetUniformBinding(uniform_id_t id) override - { - std::map>::iterator it = m_Uniforms.find(id); - if (it == m_Uniforms.end()) - return Binding(); - else - return Binding(it->second.first, (int)it->second.second); + if (m_BindingSlots[bindingSlot].type != GL_FLOAT || + m_BindingSlots[bindingSlot].size != 1) + { + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected float)"); + return; + } + glUniform1f(m_BindingSlots[bindingSlot].location, value); + ogl_WarnIfError(); } - void Uniform(Binding id, float v0, float v1, float v2, float v3) override + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY) override { - if (id.first != -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC2 || + m_BindingSlots[bindingSlot].size != 1) { - if (id.second == GL_FLOAT) - glUniform1f(id.first, v0); - else if (id.second == GL_FLOAT_VEC2) - glUniform2f(id.first, v0, v1); - else if (id.second == GL_FLOAT_VEC3) - glUniform3f(id.first, v0, v1, v2); - else if (id.second == GL_FLOAT_VEC4) - glUniform4f(id.first, v0, v1, v2, v3); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float, vec2, vec3, vec4)"); + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected vec2)"); + return; } + glUniform2f(m_BindingSlots[bindingSlot].location, valueX, valueY); + ogl_WarnIfError(); } - void Uniform(Binding id, const CMatrix3D& v) override + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, const float valueZ) { - if (id.first != -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC3 || + m_BindingSlots[bindingSlot].size != 1) { - if (id.second == GL_FLOAT_MAT4) - glUniformMatrix4fv(id.first, 1, GL_FALSE, v.AsFloatArray()); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected vec3)"); + return; } + glUniform3f(m_BindingSlots[bindingSlot].location, valueX, valueY, valueZ); + ogl_WarnIfError(); } - void Uniform(Binding id, size_t count, const CMatrix3D* v) override + void SetUniform( + const int32_t bindingSlot, + const float valueX, const float valueY, + const float valueZ, const float valueW) { - if (id.first != -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].type != GL_FLOAT_VEC4 || + m_BindingSlots[bindingSlot].size != 1) { - if (id.second == GL_FLOAT_MAT4) - glUniformMatrix4fv(id.first, count, GL_FALSE, &v->_11); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected vec4)"); + return; } + glUniform4f(m_BindingSlots[bindingSlot].location, valueX, valueY, valueZ, valueW); + ogl_WarnIfError(); } - void Uniform(Binding id, size_t count, const float* v) override + void SetUniform( + const int32_t bindingSlot, PS::span values) override { - if (id.first != -1) + if (bindingSlot < 0 || bindingSlot >= static_cast(m_BindingSlots.size())) + return; + if (m_BindingSlots[bindingSlot].elementType != GL_FLOAT) { - if (id.second == GL_FLOAT) - glUniform1fv(id.first, count, v); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float)"); + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform element type (expected float)"); + return; + } + if (m_BindingSlots[bindingSlot].size == 1 && m_BindingSlots[bindingSlot].elementCount > static_cast(values.size())) + { + LOGERROR( + "CShaderProgramGLSL::SetUniform(): Invalid uniform element count (expected: %zu passed: %zu)", + m_BindingSlots[bindingSlot].elementCount, values.size()); + return; + } + const GLint location = m_BindingSlots[bindingSlot].location; + const GLenum type = m_BindingSlots[bindingSlot].type; + + if (type == GL_FLOAT) + glUniform1fv(location, 1, values.data()); + else if (type == GL_FLOAT_VEC2) + glUniform2fv(location, 1, values.data()); + else if (type == GL_FLOAT_VEC3) + glUniform3fv(location, 1, values.data()); + else if (type == GL_FLOAT_VEC4) + glUniform4fv(location, 1, values.data()); + else if (type == GL_FLOAT_MAT4) + { + // For case of array of matrices we might pass less number of matrices. + const GLint size = std::min( + m_BindingSlots[bindingSlot].size, static_cast(values.size() / 16)); + glUniformMatrix4fv(location, size, GL_FALSE, values.data()); } + else + LOGERROR("CShaderProgramGLSL::SetUniform(): Invalid uniform type (expected float, vec2, vec3, vec4, mat4)"); + ogl_WarnIfError(); } void VertexAttribPointer( @@ -844,8 +1126,18 @@ GLuint m_Program; GLuint m_VertexShader, m_FragmentShader; - std::map> m_Uniforms; - std::map> m_Samplers; // texture target & unit chosen for each uniform sampler + struct BindingSlot + { + CStrIntern name; + GLint location; + GLint size; + GLenum type; + GLenum elementType; + GLint elementCount; + bool isTexture; + }; + std::vector m_BindingSlots; + std::unordered_map m_BindingSlotsMapping; }; CShaderProgram::CShaderProgram(int streamflags) @@ -908,8 +1200,8 @@ VfsPath vertexFile; VfsPath fragmentFile; CShaderDefines defines = baseDefines; - std::map vertexUniforms; - std::map fragmentUniforms; + std::map> vertexUniforms; + std::map> fragmentUniforms; std::map vertexAttribs; int streamFlags = 0; @@ -933,7 +1225,8 @@ if (param.GetNodeName() == el_uniform) { - vertexUniforms[CStrIntern(attributes.GetNamedItem(at_name))] = attributes.GetNamedItem(at_loc).ToInt(); + vertexUniforms[CStrIntern(attributes.GetNamedItem(at_name))] = + std::make_pair(attributes.GetNamedItem(at_type), attributes.GetNamedItem(at_loc).ToInt()); } else if (param.GetNodeName() == el_stream) { @@ -992,158 +1285,32 @@ if (param.GetNodeName() == el_uniform) { - // A somewhat incomplete listing, missing "shadow" and "rect" versions - // which are interpreted as 2D (NB: our shadowmaps may change - // type based on user config). - GLenum type = GL_TEXTURE_2D; - const CStr t = attributes.GetNamedItem(at_type); - if (t == "sampler1D") -#if CONFIG2_GLES - debug_warn(L"sampler1D not implemented on GLES"); -#else - type = GL_TEXTURE_1D; -#endif - else if (t == "sampler2D") - type = GL_TEXTURE_2D; - else if (t == "sampler3D") -#if CONFIG2_GLES - debug_warn(L"sampler3D not implemented on GLES"); -#else - type = GL_TEXTURE_3D; -#endif - else if (t == "samplerCube") - type = GL_TEXTURE_CUBE_MAP; - fragmentUniforms[CStrIntern(attributes.GetNamedItem(at_name))] = - std::make_pair(attributes.GetNamedItem(at_loc).ToInt(), type); + std::make_pair(attributes.GetNamedItem(at_type), attributes.GetNamedItem(at_loc).ToInt()); } } } } if (isGLSL) - return CShaderProgram::ConstructGLSL(device, name, vertexFile, fragmentFile, defines, vertexAttribs, streamFlags); + { + return std::make_unique( + device, name, vertexFile, fragmentFile, defines, vertexAttribs, streamFlags); + } else - return CShaderProgram::ConstructARB(device, vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags); -} - + { #if CONFIG2_GLES -// static -std::unique_ptr CShaderProgram::ConstructARB(CDevice* UNUSED(device), const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& UNUSED(defines), - const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes), - int UNUSED(streamflags)) -{ - LOGERROR("CShaderProgram::ConstructARB: '%s'+'%s': ARB shaders not supported on this device", - vertexFile.string8(), fragmentFile.string8()); - return nullptr; -} + LOGERROR("CShaderProgram::Create: '%s'+'%s': ARB shaders not supported on this device", + vertexFile.string8(), fragmentFile.string8()); + return nullptr; #else -// static -std::unique_ptr CShaderProgram::ConstructARB( - CDevice* device, const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, - const std::map& fragmentIndexes, - int streamflags) -{ - return std::make_unique( - device, vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags); -} + return std::make_unique( + device, vertexFile, fragmentFile, defines, + vertexUniforms, fragmentUniforms, streamFlags); #endif - -// static -std::unique_ptr CShaderProgram::ConstructGLSL( - CDevice* device, const CStr& name, - const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, int streamflags) -{ - return std::make_unique( - device, name, vertexFile, fragmentFile, defines, vertexAttribs, streamflags); -} - -void CShaderProgram::BindTexture(texture_id_t id, const Renderer::Backend::GL::CTexture* tex) -{ - BindTexture(id, tex->GetHandle()); -} - -void CShaderProgram::BindTexture(Binding id, const Renderer::Backend::GL::CTexture* tex) -{ - BindTexture(id, tex->GetHandle()); -} - -void CShaderProgram::Uniform(Binding id, int v) -{ - Uniform(id, (float)v, (float)v, (float)v, (float)v); -} - -void CShaderProgram::Uniform(Binding id, float v) -{ - Uniform(id, v, v, v, v); -} - -void CShaderProgram::Uniform(Binding id, float v0, float v1) -{ - Uniform(id, v0, v1, 0.0f, 0.0f); -} - -void CShaderProgram::Uniform(Binding id, const CVector3D& v) -{ - Uniform(id, v.X, v.Y, v.Z, 0.0f); -} - -void CShaderProgram::Uniform(Binding id, const CColor& v) -{ - Uniform(id, v.r, v.g, v.b, v.a); -} - -void CShaderProgram::Uniform(uniform_id_t id, int v) -{ - Uniform(GetUniformBinding(id), (float)v, (float)v, (float)v, (float)v); -} - -void CShaderProgram::Uniform(uniform_id_t id, float v) -{ - Uniform(GetUniformBinding(id), v, v, v, v); -} - -void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1) -{ - Uniform(GetUniformBinding(id), v0, v1, 0.0f, 0.0f); -} - -void CShaderProgram::Uniform(uniform_id_t id, const CVector3D& v) -{ - Uniform(GetUniformBinding(id), v.X, v.Y, v.Z, 0.0f); -} - -void CShaderProgram::Uniform(uniform_id_t id, const CColor& v) -{ - Uniform(GetUniformBinding(id), v.r, v.g, v.b, v.a); -} - -void CShaderProgram::Uniform(uniform_id_t id, float v0, float v1, float v2, float v3) -{ - Uniform(GetUniformBinding(id), v0, v1, v2, v3); -} - -void CShaderProgram::Uniform(uniform_id_t id, const CMatrix3D& v) -{ - Uniform(GetUniformBinding(id), v); -} - -void CShaderProgram::Uniform(uniform_id_t id, size_t count, const CMatrix3D* v) -{ - Uniform(GetUniformBinding(id), count, v); -} - -void CShaderProgram::Uniform(uniform_id_t id, size_t count, const float* v) -{ - Uniform(GetUniformBinding(id), count, v); + } } - // These should all be overridden by CShaderProgramGLSL, and not used // if a non-GLSL shader was loaded instead: Index: source/renderer/backend/gl/Texture.cpp =================================================================== --- source/renderer/backend/gl/Texture.cpp +++ source/renderer/backend/gl/Texture.cpp @@ -110,7 +110,10 @@ const GLenum target = TypeToGLEnum(type); - texture->m_Device->GetActiveCommandContext()->BindTexture(0, target, texture->m_Handle); + // TODO: maybe we need to switch the active texture to some big value to + // not rebind textures used by pipeline. + CDeviceCommandContext::ScopedBind scopedBind( + texture->m_Device->GetActiveCommandContext(), target, texture->m_Handle); // It's forbidden to set sampler state for multisample textures. if (type != Type::TEXTURE_2D_MULTISAMPLE) @@ -151,7 +154,7 @@ defaultSamplerDesc.addressModeV == Sampler::AddressMode::CLAMP_TO_BORDER || defaultSamplerDesc.addressModeW == Sampler::AddressMode::CLAMP_TO_BORDER) { - glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, defaultSamplerDesc.borderColor.AsFloatArray()); + glTexParameterfv(target, GL_TEXTURE_BORDER_COLOR, defaultSamplerDesc.borderColor.AsFloatArray().data()); } ogl_WarnIfError(); @@ -284,8 +287,6 @@ glObjectLabel(GL_TEXTURE, texture->m_Handle, -1, name); } - texture->m_Device->GetActiveCommandContext()->BindTexture(0, target, 0); - return texture; } Index: source/soundmanager/items/CSoundBase.cpp =================================================================== --- source/soundmanager/items/CSoundBase.cpp +++ source/soundmanager/items/CSoundBase.cpp @@ -177,7 +177,7 @@ if ( m_ALSource ) { std::lock_guard lock(m_ItemMutex); - alSourcefv(m_ALSource, AL_DIRECTION, direction.AsFloatArray()); + alSourcefv(m_ALSource, AL_DIRECTION, direction.AsFloatArray().data()); AL_CHECK; } } @@ -212,7 +212,7 @@ if ( m_ALSource != 0 ) { std::lock_guard lock(m_ItemMutex); - alSourcefv(m_ALSource,AL_POSITION, position.AsFloatArray()); + alSourcefv(m_ALSource,AL_POSITION, position.AsFloatArray().data()); AL_CHECK; } }