diff --git a/source/graphics/Canvas2D.cpp b/source/graphics/Canvas2D.cpp index 859f3ae5c8..0ef7cab3dc 100644 --- a/source/graphics/Canvas2D.cpp +++ b/source/graphics/Canvas2D.cpp @@ -39,7 +39,7 @@ using PlaneArray2D = std::array; inline void DrawTextureImpl( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, const CTexturePtr& texture, + Renderer::Backend::GL::CShaderProgram* shader, const CTexturePtr& texture, const PlaneArray2D& vertices, PlaneArray2D uvs, const CColor& multiply, const CColor& add, const float grayscaleFactor) { @@ -83,10 +83,10 @@ public: CShaderDefines defines; Tech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d, defines); ENSURE(Tech); - Tech->BeginPass(); DeviceCommandContext->SetGraphicsPipelineState( Tech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& shader = Tech->GetShader(); + DeviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* shader = Tech->GetShader(); shader->Uniform(str_transform, GetDefaultGuiMatrix()); } @@ -95,7 +95,7 @@ public: if (!Tech) return; - Tech->EndPass(); + DeviceCommandContext->EndPass(); Tech.reset(); } @@ -246,7 +246,7 @@ void CCanvas2D::DrawLine(const std::vector& points, const float width m->BindTechIfNeeded(); - const CShaderProgramPtr& shader = m->Tech->GetShader(); + 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); @@ -324,7 +324,7 @@ void CCanvas2D::DrawText(CTextRenderer& textRenderer) { m->BindTechIfNeeded(); - const CShaderProgramPtr& shader = m->Tech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = m->Tech->GetShader(); shader->Uniform(str_grayscaleFactor, 0.0f); textRenderer.Render(m->DeviceCommandContext, shader, GetDefaultGuiMatrix()); diff --git a/source/graphics/LOSTexture.cpp b/source/graphics/LOSTexture.cpp index 851f3fda2c..010cadc9f1 100644 --- a/source/graphics/LOSTexture.cpp +++ b/source/graphics/LOSTexture.cpp @@ -80,7 +80,7 @@ CLOSTexture::~CLOSTexture() bool CLOSTexture::CreateShader() { m_SmoothTech = g_Renderer.GetShaderManager().LoadEffect(str_los_interp); - CShaderProgramPtr shader = m_SmoothTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = m_SmoothTech->GetShader(); m_ShaderInitialized = m_SmoothTech && shader; @@ -141,11 +141,11 @@ void CLOSTexture::InterpolateLOS(Renderer::Backend::GL::CDeviceCommandContext* d GPU_SCOPED_LABEL(deviceCommandContext, "Render LOS texture"); deviceCommandContext->SetFramebuffer(m_SmoothFramebuffers[m_WhichTexture].get()); - m_SmoothTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( m_SmoothTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = m_SmoothTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = m_SmoothTech->GetShader(); shader->BindTexture(str_losTex1, m_Texture.get()); shader->BindTexture(str_losTex2, m_SmoothTextures[m_WhichTexture].get()); @@ -188,7 +188,7 @@ void CLOSTexture::InterpolateLOS(Renderer::Backend::GL::CDeviceCommandContext* d g_Renderer.SetViewport(oldVp); - m_SmoothTech->EndPass(); + deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); diff --git a/source/graphics/MiniMapTexture.cpp b/source/graphics/MiniMapTexture.cpp index 9d03d6f31e..f87549b995 100644 --- a/source/graphics/MiniMapTexture.cpp +++ b/source/graphics/MiniMapTexture.cpp @@ -72,7 +72,7 @@ unsigned int ScaleColor(unsigned int color, float x) void DrawTexture( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader) + Renderer::Backend::GL::CShaderProgram* shader) { const float quadUVs[] = { @@ -363,7 +363,7 @@ void CMiniMapTexture::RenderFinalTexture( 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; - CShaderProgramPtr shader; + Renderer::Backend::GL::CShaderProgram* shader; CShaderTechniquePtr tech; CShaderDefines baseDefines; @@ -372,8 +372,8 @@ void CMiniMapTexture::RenderFinalTexture( tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, baseDefines); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = tech->GetGraphicsPipelineStateDesc(); - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); shader = tech->GetShader(); if (m_TerrainTexture) @@ -392,6 +392,7 @@ void CMiniMapTexture::RenderFinalTexture( if (m_TerrainTexture) DrawTexture(deviceCommandContext, shader); + deviceCommandContext->EndPass(); pipelineStateDesc.blendState.enabled = true; pipelineStateDesc.blendState.srcColorBlendFactor = pipelineStateDesc.blendState.srcAlphaBlendFactor = @@ -405,6 +406,7 @@ void CMiniMapTexture::RenderFinalTexture( Renderer::Backend::ColorWriteMask::GREEN | Renderer::Backend::ColorWriteMask::BLUE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); // Draw territory boundaries CTerritoryTexture& territoryTexture = g_Game->GetView()->GetTerritoryTexture(); @@ -414,11 +416,13 @@ void CMiniMapTexture::RenderFinalTexture( shader->Uniform(str_textureTransform, territoryTexture.GetMinimapTextureMatrix()); DrawTexture(deviceCommandContext, shader); + deviceCommandContext->EndPass(); pipelineStateDesc.blendState.enabled = false; pipelineStateDesc.blendState.colorWriteMask = Renderer::Backend::ColorWriteMask::ALPHA; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); shader->BindTexture(str_baseTex, losTexture.GetTexture()); shader->Uniform(str_transform, baseTransform); @@ -426,14 +430,14 @@ void CMiniMapTexture::RenderFinalTexture( DrawTexture(deviceCommandContext, shader); - tech->EndPass(); + deviceCommandContext->EndPass(); CShaderDefines pointDefines; pointDefines.Add(str_MINIMAP_POINT, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_minimap, pointDefines); - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); shader = tech->GetShader(); shader->Uniform(str_transform, baseTransform); @@ -581,7 +585,7 @@ void CMiniMapTexture::RenderFinalTexture( deviceCommandContext->SetScissors(0, nullptr); } - tech->EndPass(); + deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); g_Renderer.SetViewport(oldViewPort); diff --git a/source/graphics/ParticleEmitter.cpp b/source/graphics/ParticleEmitter.cpp index 4da1e1d8de..35aa685644 100644 --- a/source/graphics/ParticleEmitter.cpp +++ b/source/graphics/ParticleEmitter.cpp @@ -176,7 +176,7 @@ void CParticleEmitter::PrepareForRendering() void CParticleEmitter::Bind( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader) + Renderer::Backend::GL::CShaderProgram* shader) { m_Type->m_Texture->UploadBackendTextureIfNeeded(deviceCommandContext); @@ -194,7 +194,7 @@ void CParticleEmitter::Bind( void CParticleEmitter::RenderArray( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader) + Renderer::Backend::GL::CShaderProgram* shader) { if (m_Particles.empty()) return; diff --git a/source/graphics/ParticleEmitter.h b/source/graphics/ParticleEmitter.h index 7e130276a1..e7025b0f7d 100644 --- a/source/graphics/ParticleEmitter.h +++ b/source/graphics/ParticleEmitter.h @@ -22,6 +22,7 @@ #include "graphics/ParticleEmitterType.h" #include "maths/Quaternion.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/ShaderProgram.h" #include "renderer/VertexArray.h" #include @@ -123,14 +124,14 @@ public: */ void Bind( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader); + Renderer::Backend::GL::CShaderProgram* shader); /** * Draw the vertex array. */ void RenderArray( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader); + Renderer::Backend::GL::CShaderProgram* shader); /** * Stop this emitter emitting new particles, and pass responsibility for rendering diff --git a/source/graphics/ShaderDefines.cpp b/source/graphics/ShaderDefines.cpp index 5c5cc88d26..9a668f055f 100644 --- a/source/graphics/ShaderDefines.cpp +++ b/source/graphics/ShaderDefines.cpp @@ -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 @@ -225,7 +225,7 @@ CVector4D CShaderUniforms::GetVector(const char* name) const return CVector4D(); } -void CShaderUniforms::BindUniforms(const CShaderProgramPtr& shader) const +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) diff --git a/source/graphics/ShaderDefines.h b/source/graphics/ShaderDefines.h index b37c53bd5c..bb8f123ca2 100644 --- a/source/graphics/ShaderDefines.h +++ b/source/graphics/ShaderDefines.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 @@ -18,9 +18,9 @@ #ifndef INCLUDED_SHADERDEFINES #define INCLUDED_SHADERDEFINES -#include "graphics/ShaderProgramPtr.h" #include "ps/CStr.h" #include "ps/CStrIntern.h" +#include "renderer/backend/gl/ShaderProgram.h" #include #include @@ -178,7 +178,7 @@ public: /** * Bind the collection of uniforms onto the given shader. */ - void BindUniforms(const CShaderProgramPtr& shader) const; + void BindUniforms(Renderer::Backend::GL::CShaderProgram* shader) const; }; // Add here the types of queries we can make in the renderer diff --git a/source/graphics/ShaderManager.cpp b/source/graphics/ShaderManager.cpp index 77c99cda71..a241188d9b 100644 --- a/source/graphics/ShaderManager.cpp +++ b/source/graphics/ShaderManager.cpp @@ -66,7 +66,7 @@ CShaderManager::~CShaderManager() UnregisterFileReloadFunc(ReloadChangedFileCB, this); } -CShaderProgramPtr CShaderManager::LoadProgram(const char* name, const CShaderDefines& defines) +CShaderProgramPtr CShaderManager::LoadProgram(const CStr& name, const CShaderDefines& defines) { CacheKey key = { name, defines }; std::map::iterator it = m_ProgramCache.find(key); @@ -129,10 +129,10 @@ CShaderTechniquePtr CShaderManager::LoadEffect(CStrIntern name, const CShaderDef return tech; } -bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefines, CShaderTechniquePtr& tech) +bool CShaderManager::NewEffect(const CStr& name, const CShaderDefines& baseDefines, CShaderTechniquePtr& tech) { PROFILE2("loading effect"); - PROFILE2_ATTR("name: %s", name); + PROFILE2_ATTR("name: %s", name.c_str()); VfsPath xmlFilename = L"shaders/effects/" + wstring_from_utf8(name) + L".xml"; @@ -256,7 +256,6 @@ bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefin { CShaderDefines passDefines = techDefines; - CShaderPass pass; Renderer::Backend::GraphicsPipelineStateDesc passPipelineStateDesc = Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc(); @@ -393,12 +392,10 @@ bool CShaderManager::NewEffect(const char* name, const CShaderDefines& baseDefin } } - pass.SetPipelineStateDesc(passPipelineStateDesc); - - // Load the shader program after we've read all the possibly-relevant s - pass.SetShader(LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines)); - - techPasses.emplace_back(std::move(pass)); + techPasses.emplace_back( + passPipelineStateDesc, + // Load the shader program after we've read all the possibly-relevant s. + LoadProgram(Child.GetAttributes().GetNamedItem(at_shader).c_str(), passDefines)); } } diff --git a/source/graphics/ShaderManager.h b/source/graphics/ShaderManager.h index 1c7fd2fe6b..5861a2faa1 100644 --- a/source/graphics/ShaderManager.h +++ b/source/graphics/ShaderManager.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 @@ -110,9 +110,9 @@ private: * @param defines key/value set of preprocessor definitions * @return loaded program, or null pointer on error */ - CShaderProgramPtr LoadProgram(const char* name, const CShaderDefines& defines); + CShaderProgramPtr LoadProgram(const CStr& name, const CShaderDefines& defines); - bool NewEffect(const char* name, const CShaderDefines& defines, CShaderTechniquePtr& tech); + bool NewEffect(const CStr& name, const CShaderDefines& defines, CShaderTechniquePtr& tech); static Status ReloadChangedFileCB(void* param, const VfsPath& path); Status ReloadChangedFile(const VfsPath& path); diff --git a/source/graphics/ShaderProgram.cpp b/source/graphics/ShaderProgram.cpp index 6a3bfea79e..e8dcd83c53 100644 --- a/source/graphics/ShaderProgram.cpp +++ b/source/graphics/ShaderProgram.cpp @@ -19,1132 +19,31 @@ #include "ShaderProgram.h" -#include "graphics/Color.h" -#include "graphics/PreprocessorWrapper.h" -#include "graphics/ShaderManager.h" -#include "graphics/TextureManager.h" -#include "lib/timer.h" -#include "maths/Matrix3D.h" -#include "maths/Vector3D.h" -#include "ps/CLogger.h" -#include "ps/Filesystem.h" -#include "ps/Profile.h" -#include "ps/XML/Xeromyces.h" -#include "renderer/backend/gl/DeviceCommandContext.h" -#include "renderer/Renderer.h" +#include "ps/VideoMode.h" +#include "renderer/backend/gl/Device.h" -#define USE_SHADER_XML_VALIDATION 1 - -#if USE_SHADER_XML_VALIDATION -#include "ps/XML/RelaxNG.h" -#include "ps/XML/XMLWriter.h" -#endif - -#include - -TIMER_ADD_CLIENT(tc_ShaderProgramValidation); - -namespace -{ - -GLint GLSizeFromFormat(const Renderer::Backend::Format format) -{ - GLint size = 1; - if (format == Renderer::Backend::Format::R32_SFLOAT || - format == Renderer::Backend::Format::R16_SINT) - size = 1; - else if ( - format == Renderer::Backend::Format::R8G8_UNORM || - format == Renderer::Backend::Format::R8G8_UINT || - format == Renderer::Backend::Format::R16G16_SINT || - format == Renderer::Backend::Format::R32G32_SFLOAT) - size = 2; - else if (format == Renderer::Backend::Format::R32G32B32_SFLOAT) - size = 3; - else if ( - format == Renderer::Backend::Format::R32G32B32A32_SFLOAT || - format == Renderer::Backend::Format::R8G8B8A8_UNORM || - format == Renderer::Backend::Format::R8G8B8A8_UINT) - size = 4; - else - debug_warn("Unsupported format."); - return size; -} - -GLenum GLTypeFromFormat(const Renderer::Backend::Format format) -{ - GLenum type = GL_FLOAT; - if (format == Renderer::Backend::Format::R32_SFLOAT || - format == Renderer::Backend::Format::R32G32_SFLOAT || - format == Renderer::Backend::Format::R32G32B32_SFLOAT || - format == Renderer::Backend::Format::R32G32B32A32_SFLOAT) - type = GL_FLOAT; - else if ( - format == Renderer::Backend::Format::R16_SINT || - format == Renderer::Backend::Format::R16G16_SINT) - type = GL_SHORT; - else if ( - format == Renderer::Backend::Format::R8G8_UNORM || - format == Renderer::Backend::Format::R8G8_UINT || - format == Renderer::Backend::Format::R8G8B8A8_UNORM || - format == Renderer::Backend::Format::R8G8B8A8_UINT) - type = GL_UNSIGNED_BYTE; - else - debug_warn("Unsupported format."); - return type; -} - -GLenum ParseAttribSemantics(const CStr& str) -{ - // Map known semantics onto the attribute locations documented by NVIDIA - if (str == "gl_Vertex") return 0; - if (str == "gl_Normal") return 2; - if (str == "gl_Color") return 3; - if (str == "gl_SecondaryColor") return 4; - if (str == "gl_FogCoord") return 5; - if (str == "gl_MultiTexCoord0") return 8; - if (str == "gl_MultiTexCoord1") return 9; - if (str == "gl_MultiTexCoord2") return 10; - if (str == "gl_MultiTexCoord3") return 11; - if (str == "gl_MultiTexCoord4") return 12; - if (str == "gl_MultiTexCoord5") return 13; - if (str == "gl_MultiTexCoord6") return 14; - if (str == "gl_MultiTexCoord7") return 15; - - debug_warn("Invalid attribute semantics"); - return 0; -} - -} // anonymous namespace - -#if !CONFIG2_GLES - -class CShaderProgramARB : public CShaderProgram -{ -public: - CShaderProgramARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags) : - CShaderProgram(streamflags), - m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), - m_Defines(defines), - m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes) - { - glGenProgramsARB(1, &m_VertexProgram); - glGenProgramsARB(1, &m_FragmentProgram); - } - - ~CShaderProgramARB() - { - Unload(); - - glDeleteProgramsARB(1, &m_VertexProgram); - glDeleteProgramsARB(1, &m_FragmentProgram); - } - - bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code) - { - ogl_WarnIfError(); - - glBindProgramARB(target, program); - - ogl_WarnIfError(); - - glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str()); - - if (ogl_SquelchError(GL_INVALID_OPERATION)) - { - GLint errPos = 0; - glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); - int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1; - char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); - LOGERROR("Failed to compile %s program '%s' (line %d):\n%s", targetName, file.string8(), errLine, errStr); - return false; - } - - glBindProgramARB(target, 0); - - ogl_WarnIfError(); - - return true; - } - - void Reload() override - { - Unload(); - - CVFSFile vertexFile; - if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) - return; - - CVFSFile fragmentFile; - if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) - return; - - CPreprocessorWrapper preprocessor; - preprocessor.AddDefines(m_Defines); - - CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); - CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); - - if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode)) - return; - - if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode)) - return; - } - - void Unload() - { - } - - void Bind() override - { - glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram); - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram); - - BindClientStates(); - } - - void Unbind() override - { - glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); - glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); - - UnbindClientStates(); - - // TODO: should unbind textures, probably - } - - int GetUniformVertexIndex(CStrIntern id) - { - std::map::iterator it = m_VertexIndexes.find(id); - if (it == m_VertexIndexes.end()) - return -1; - return it->second; - } - - frag_index_pair_t GetUniformFragmentIndex(CStrIntern id) - { - std::map::iterator it = m_FragmentIndexes.find(id); - if (it == m_FragmentIndexes.end()) - return std::make_pair(-1, 0); - return it->second; - } - - Binding GetTextureBinding(texture_id_t id) override - { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index == -1) - return Binding(); - else - return Binding((int)fPair.second, index); - } - - void BindTexture(texture_id_t id, GLuint tex) override - { - frag_index_pair_t fPair = GetUniformFragmentIndex(id); - int index = fPair.first; - if (index != -1) - { - g_Renderer.GetDeviceCommandContext()->BindTexture(index, fPair.second, tex); - } - } - - void BindTexture(Binding id, GLuint tex) override - { - int index = id.second; - if (index != -1) - { - g_Renderer.GetDeviceCommandContext()->BindTexture(index, id.first, tex); - } - } - - Binding GetUniformBinding(uniform_id_t id) override - { - return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id).first); - } - - void Uniform(Binding id, float v0, float v1, float v2, float v3) override - { - if (id.first != -1) - glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3); - - if (id.second != -1) - glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3); - } - - void Uniform(Binding id, const CMatrix3D& v) 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); - } - - if (id.second != -1) - { - 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); - } - } - - void Uniform(Binding id, size_t count, const CMatrix3D* v) override - { - ENSURE(count == 1); - Uniform(id, v[0]); - } - - void Uniform(Binding id, size_t count, const float* v) override - { - ENSURE(count == 4); - Uniform(id, v[0], v[1], v[2], v[3]); - } - - std::vector GetFileDependencies() const override - { - return {m_VertexFile, m_FragmentFile}; - } - -private: - VfsPath m_VertexFile; - VfsPath m_FragmentFile; - CShaderDefines m_Defines; - - GLuint m_VertexProgram; - GLuint m_FragmentProgram; - - std::map m_VertexIndexes; - - // pair contains - std::map m_FragmentIndexes; -}; - -#endif // #if !CONFIG2_GLES - -////////////////////////////////////////////////////////////////////////// - -TIMER_ADD_CLIENT(tc_ShaderGLSLCompile); -TIMER_ADD_CLIENT(tc_ShaderGLSLLink); - -class CShaderProgramGLSL : public CShaderProgram -{ -public: - CShaderProgramGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags) : - CShaderProgram(streamflags), - m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), - m_Defines(defines), - m_VertexAttribs(vertexAttribs) - { - m_Program = 0; - m_VertexShader = glCreateShader(GL_VERTEX_SHADER); - m_FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); - m_FileDependencies = {m_VertexFile, m_FragmentFile}; - } - - ~CShaderProgramGLSL() - { - Unload(); - - glDeleteShader(m_VertexShader); - glDeleteShader(m_FragmentShader); - } - - bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code) - { - TIMER_ACCRUE(tc_ShaderGLSLCompile); - - ogl_WarnIfError(); - - const char* code_string = code.c_str(); - GLint code_length = code.length(); - glShaderSource(shader, 1, &code_string, &code_length); - - glCompileShader(shader); - - GLint ok = 0; - glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); - - GLint length = 0; - glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); - - // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0 - // (http://code.google.com/p/android/issues/detail?id=9953) - if (!ok && length == 0) - length = 4096; - - if (length > 1) - { - char* infolog = new char[length]; - glGetShaderInfoLog(shader, length, NULL, infolog); - - if (ok) - LOGMESSAGE("Info when compiling shader '%s':\n%s", file.string8(), infolog); - else - LOGERROR("Failed to compile shader '%s':\n%s", file.string8(), infolog); - - delete[] infolog; - } - - ogl_WarnIfError(); - - return (ok ? true : false); - } - - bool Link() - { - TIMER_ACCRUE(tc_ShaderGLSLLink); - - ENSURE(!m_Program); - m_Program = glCreateProgram(); - - glAttachShader(m_Program, m_VertexShader); - ogl_WarnIfError(); - glAttachShader(m_Program, m_FragmentShader); - ogl_WarnIfError(); - - // Set up the attribute bindings explicitly, since apparently drivers - // don't always pick the most efficient bindings automatically, - // and also this lets us hardcode indexes into VertexPointer etc - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) - glBindAttribLocation(m_Program, it->second, it->first.c_str()); - - glLinkProgram(m_Program); - - GLint ok = 0; - glGetProgramiv(m_Program, GL_LINK_STATUS, &ok); - - GLint length = 0; - glGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length); - - if (!ok && length == 0) - length = 4096; - - if (length > 1) - { - char* infolog = new char[length]; - glGetProgramInfoLog(m_Program, length, NULL, infolog); - - if (ok) - LOGMESSAGE("Info when linking program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); - else - LOGERROR("Failed to link program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); - - delete[] infolog; - } - - ogl_WarnIfError(); - - if (!ok) - return false; - - m_Uniforms.clear(); - m_Samplers.clear(); - - Bind(); - - ogl_WarnIfError(); - - GLint numUniforms = 0; - glGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); - ogl_WarnIfError(); - for (GLint i = 0; i < numUniforms; ++i) - { - char name[256] = {0}; - GLsizei nameLength = 0; - GLint size = 0; - GLenum type = 0; - glGetActiveUniform(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name); - ogl_WarnIfError(); - - GLint loc = glGetUniformLocation(m_Program, name); - - CStrIntern nameIntern(name); - m_Uniforms[nameIntern] = std::make_pair(loc, type); - - // Assign sampler uniforms to sequential texture units - if (type == GL_SAMPLER_2D - || type == GL_SAMPLER_CUBE -#if !CONFIG2_GLES - || type == GL_SAMPLER_2D_SHADOW -#endif - ) - { - int unit = (int)m_Samplers.size(); - m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); - m_Samplers[nameIntern].second = unit; - glUniform1i(loc, unit); // link uniform to unit - ogl_WarnIfError(); - } - } - - // TODO: verify that we're not using more samplers than is supported - - Unbind(); - - ogl_WarnIfError(); - - return true; - } - - void Reload() override - { - Unload(); - - CVFSFile vertexFile; - if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) - return; - - CVFSFile fragmentFile; - if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) - return; - - std::vector newFileDependencies = {m_VertexFile, m_FragmentFile}; - - CPreprocessorWrapper preprocessor([&newFileDependencies](const CStr& includePath, CStr& out) -> bool { - const VfsPath includeFilePath(L"shaders/glsl/" + wstring_from_utf8(includePath)); - // Add dependencies anyway to reload the shader when the file is - // appeared. - newFileDependencies.push_back(includeFilePath); - CVFSFile includeFile; - if (includeFile.Load(g_VFS, includeFilePath) != PSRETURN_OK) - return false; - out = includeFile.GetAsString(); - return true; - }); - preprocessor.AddDefines(m_Defines); - -#if CONFIG2_GLES - // GLES defines the macro "GL_ES" in its GLSL preprocessor, - // but since we run our own preprocessor first, we need to explicitly - // define it here - preprocessor.AddDefine("GL_ES", "1"); -#endif - - CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); - CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); - - m_FileDependencies = std::move(newFileDependencies); - - if (vertexCode.empty()) - LOGERROR("Failed to preprocess vertex shader: '%s'", m_VertexFile.string8()); - if (fragmentCode.empty()) - LOGERROR("Failed to preprocess fragment shader: '%s'", m_FragmentFile.string8()); - -#if CONFIG2_GLES - // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00, - // and also to set default float precision for fragment shaders - vertexCode.Replace("#version 110\n", "#version 100\n"); - vertexCode.Replace("#version 110\r\n", "#version 100\n"); - vertexCode.Replace("#version 120\n", "#version 100\n"); - vertexCode.Replace("#version 120\r\n", "#version 100\n"); - fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n"); - fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n"); - fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n"); - fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n"); -#endif - - if (!Compile(m_VertexShader, m_VertexFile, vertexCode)) - return; - - if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode)) - return; - - if (!Link()) - return; - } - - void Unload() - { - if (m_Program) - glDeleteProgram(m_Program); - m_Program = 0; - - // The shader objects can be reused and don't need to be deleted here - } - - void Bind() override - { - glUseProgram(m_Program); - - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) - glEnableVertexAttribArray(it->second); - } - - void Unbind() override - { - glUseProgram(0); - - for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) - glDisableVertexAttribArray(it->second); - - // TODO: should unbind textures, probably - } - - Binding GetTextureBinding(texture_id_t id) 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); - } - - void BindTexture(texture_id_t id, GLuint tex) override - { - std::map>::iterator it = m_Samplers.find(CStrIntern(id)); - if (it == m_Samplers.end()) - return; - - g_Renderer.GetDeviceCommandContext()->BindTexture(it->second.second, it->second.first, tex); - } - - void BindTexture(Binding id, GLuint tex) override - { - if (id.second == -1) - return; - - g_Renderer.GetDeviceCommandContext()->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); - } - - void Uniform(Binding id, float v0, float v1, float v2, float v3) override - { - if (id.first != -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)"); - } - } - - void Uniform(Binding id, const CMatrix3D& v) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT_MAT4) - glUniformMatrix4fv(id.first, 1, GL_FALSE, &v._11); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); - } - } - - void Uniform(Binding id, size_t count, const CMatrix3D* v) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT_MAT4) - glUniformMatrix4fv(id.first, count, GL_FALSE, &v->_11); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); - } - } - - void Uniform(Binding id, size_t count, const float* v) override - { - if (id.first != -1) - { - if (id.second == GL_FLOAT) - glUniform1fv(id.first, count, v); - else - LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float)"); - } - } - - // Map the various fixed-function Pointer functions onto generic vertex attributes - // (matching the attribute indexes from ShaderManager's ParseAttribSemantics): - - void VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override - { - const GLint size = GLSizeFromFormat(format); - const GLenum type = GLTypeFromFormat(format); - glVertexAttribPointer(0, size, type, GL_FALSE, stride, pointer); - m_ValidStreams |= STREAM_POS; - } - - void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override - { - const GLint size = GLSizeFromFormat(format); - const GLenum type = GLTypeFromFormat(format); - glVertexAttribPointer(2, size, type, (type == GL_FLOAT ? GL_FALSE : GL_TRUE), stride, pointer); - m_ValidStreams |= STREAM_NORMAL; - } - - void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override - { - const GLint size = GLSizeFromFormat(format); - const GLenum type = GLTypeFromFormat(format); - glVertexAttribPointer(3, size, type, (type == GL_FLOAT ? GL_FALSE : GL_TRUE), stride, pointer); - m_ValidStreams |= STREAM_COLOR; - } - - void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override - { - const GLint size = GLSizeFromFormat(format); - const GLenum type = GLTypeFromFormat(format); - glVertexAttribPointer(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer); - m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); - } - - void VertexAttribPointer(attrib_id_t id, const Renderer::Backend::Format format, GLboolean normalized, GLsizei stride, const void* pointer) override - { - std::map::iterator it = m_VertexAttribs.find(id); - if (it != m_VertexAttribs.end()) - { - const GLint size = GLSizeFromFormat(format); - const GLenum type = GLTypeFromFormat(format); - glVertexAttribPointer(it->second, size, type, normalized, stride, pointer); - } - } - - std::vector GetFileDependencies() const override - { - return m_FileDependencies; - } - -private: - VfsPath m_VertexFile; - VfsPath m_FragmentFile; - std::vector m_FileDependencies; - CShaderDefines m_Defines; - std::map m_VertexAttribs; - - GLhandleARB m_Program; - GLhandleARB m_VertexShader; - GLhandleARB m_FragmentShader; - - std::map> m_Uniforms; - std::map> m_Samplers; // texture target & unit chosen for each uniform sampler -}; - -////////////////////////////////////////////////////////////////////////// - -CShaderProgram::CShaderProgram(int streamflags) - : m_StreamFlags(streamflags), m_ValidStreams(0) +CShaderProgram::CShaderProgram(const CStr& name, const CShaderDefines& defines) + : m_Name(name), m_Defines(defines) { } // static -CShaderProgramPtr CShaderProgram::Create(const char* name, const CShaderDefines& baseDefines) +CShaderProgramPtr CShaderProgram::Create(const CStr& name, const CShaderDefines& defines) { - PROFILE2("loading shader"); - PROFILE2_ATTR("name: %s", name); - - VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml"; - - CXeromyces XeroFile; - PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); - if (ret != PSRETURN_OK) - return nullptr; - -#if USE_SHADER_XML_VALIDATION - { - TIMER_ACCRUE(tc_ShaderProgramValidation); - - // Serialize the XMB data and pass it to the validator - XMLWriter_File shaderFile; - shaderFile.SetPrettyPrint(false); - shaderFile.XMB(XeroFile); - bool ok = CXeromyces::ValidateEncoded("shader", name, shaderFile.GetOutput()); - if (!ok) - return nullptr; - } -#endif - - // Define all the elements and attributes used in the XML file -#define EL(x) int el_##x = XeroFile.GetElementID(#x) -#define AT(x) int at_##x = XeroFile.GetAttributeID(#x) - EL(attrib); - EL(define); - EL(fragment); - EL(stream); - EL(uniform); - EL(vertex); - AT(file); - AT(if); - AT(loc); - AT(name); - AT(semantics); - AT(type); - AT(value); -#undef AT -#undef EL - - CPreprocessorWrapper preprocessor; - preprocessor.AddDefines(baseDefines); - - XMBElement root = XeroFile.GetRoot(); - - VfsPath vertexFile; - VfsPath fragmentFile; - CShaderDefines defines = baseDefines; - std::map vertexUniforms; - std::map fragmentUniforms; - std::map vertexAttribs; - int streamFlags = 0; - - XERO_ITER_EL(root, Child) - { - if (Child.GetNodeName() == el_define) - { - defines.Add(CStrIntern(Child.GetAttributes().GetNamedItem(at_name)), CStrIntern(Child.GetAttributes().GetNamedItem(at_value))); - } - else if (Child.GetNodeName() == el_vertex) - { - vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); - - XERO_ITER_EL(Child, Param) - { - XMBAttributeList Attrs = Param.GetAttributes(); - - CStr cond = Attrs.GetNamedItem(at_if); - if (!cond.empty() && !preprocessor.TestConditional(cond)) - continue; - - if (Param.GetNodeName() == el_uniform) - { - vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt(); - } - else if (Param.GetNodeName() == el_stream) - { - CStr StreamName = Attrs.GetNamedItem(at_name); - if (StreamName == "pos") - streamFlags |= STREAM_POS; - else if (StreamName == "normal") - streamFlags |= STREAM_NORMAL; - else if (StreamName == "color") - streamFlags |= STREAM_COLOR; - else if (StreamName == "uv0") - streamFlags |= STREAM_UV0; - else if (StreamName == "uv1") - streamFlags |= STREAM_UV1; - else if (StreamName == "uv2") - streamFlags |= STREAM_UV2; - else if (StreamName == "uv3") - streamFlags |= STREAM_UV3; - } - else if (Param.GetNodeName() == el_attrib) - { - int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics)); - vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc; - } - } - } - else if (Child.GetNodeName() == el_fragment) - { - fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); - - XERO_ITER_EL(Child, Param) - { - XMBAttributeList Attrs = Param.GetAttributes(); - - CStr cond = Attrs.GetNamedItem(at_if); - if (!cond.empty() && !preprocessor.TestConditional(cond)) - continue; - - 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; - CStr t = Attrs.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(Attrs.GetNamedItem(at_name))] = - std::make_pair(Attrs.GetNamedItem(at_loc).ToInt(), type); - } - } - } - } - - if (root.GetAttributes().GetNamedItem(at_type) == "glsl") - return CShaderProgram::ConstructGLSL(vertexFile, fragmentFile, defines, vertexAttribs, streamFlags); - else - return CShaderProgram::ConstructARB(vertexFile, fragmentFile, defines, vertexUniforms, fragmentUniforms, streamFlags); + return CShaderProgramPtr(new CShaderProgram(name, defines)); } -#if CONFIG2_GLES -// static -CShaderProgramPtr CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& UNUSED(defines), - const std::map& UNUSED(vertexIndexes), const std::map& UNUSED(fragmentIndexes), - int UNUSED(streamflags)) +void CShaderProgram::Reload() { - LOGERROR("CShaderProgram::ConstructARB: '%s'+'%s': ARB shaders not supported on this device", - vertexFile.string8(), fragmentFile.string8()); - return nullptr; -} -#else -// static -CShaderProgramPtr CShaderProgram::ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexIndexes, const std::map& fragmentIndexes, - int streamflags) -{ - return std::make_shared(vertexFile, fragmentFile, defines, vertexIndexes, fragmentIndexes, streamflags); -} -#endif - -// static -CShaderProgramPtr CShaderProgram::ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags) -{ - return std::make_shared(vertexFile, fragmentFile, defines, vertexAttribs, streamflags); + std::unique_ptr backendShaderProgram = + g_VideoMode.GetBackendDevice()->CreateShaderProgram(m_Name, m_Defines); + if (backendShaderProgram) + m_BackendShaderProgram = std::move(backendShaderProgram); } -int CShaderProgram::GetStreamFlags() const +std::vector CShaderProgram::GetFileDependencies() const { - return m_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: - -void CShaderProgram::VertexAttribPointer(attrib_id_t UNUSED(id), const Renderer::Backend::Format UNUSED(format), - GLboolean UNUSED(normalized), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("Shader type doesn't support VertexAttribPointer"); -} - -#if CONFIG2_GLES - -// These should all be overridden by CShaderProgramGLSL -// (GLES doesn't support any other types of shader program): - -void CShaderProgram::VertexPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::VertexPointer should be overridden"); -} -void CShaderProgram::NormalPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::NormalPointer should be overridden"); -} -void CShaderProgram::ColorPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::ColorPointer should be overridden"); -} -void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) -{ - debug_warn("CShaderProgram::TexCoordPointer should be overridden"); -} - -#else - -// These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders -// both use the fixed-function vertex attribute pointers so we'll share their -// definitions here: - -void CShaderProgram::VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) -{ - const GLint size = GLSizeFromFormat(format); - ENSURE(2 <= size && size <= 4); - const GLenum type = GLTypeFromFormat(format); - glVertexPointer(size, type, stride, pointer); - m_ValidStreams |= STREAM_POS; -} - -void CShaderProgram::NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) -{ - ENSURE(format == Renderer::Backend::Format::R32G32B32_SFLOAT); - glNormalPointer(GL_FLOAT, stride, pointer); - m_ValidStreams |= STREAM_NORMAL; -} - -void CShaderProgram::ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) -{ - const GLint size = GLSizeFromFormat(format); - ENSURE(3 <= size && size <= 4); - const GLenum type = GLTypeFromFormat(format); - glColorPointer(size, type, stride, pointer); - m_ValidStreams |= STREAM_COLOR; -} - -void CShaderProgram::TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer) -{ - glClientActiveTextureARB(texture); - const GLint size = GLSizeFromFormat(format); - ENSURE(1 <= size && size <= 4); - const GLenum type = GLTypeFromFormat(format); - glTexCoordPointer(size, type, stride, pointer); - glClientActiveTextureARB(GL_TEXTURE0); - m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); -} - -void CShaderProgram::BindClientStates() -{ - ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1))); - - // Enable all the desired client states for non-GLSL rendering - - if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY); - if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY); - if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); - - if (m_StreamFlags & STREAM_UV0) - { - glClientActiveTextureARB(GL_TEXTURE0); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (m_StreamFlags & STREAM_UV1) - { - glClientActiveTextureARB(GL_TEXTURE1); - glEnableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0); - } - - // Rendering code must subsequently call VertexPointer etc for all of the streams - // that were activated in this function, else AssertPointersBound will complain - // that some arrays were unspecified - m_ValidStreams = 0; -} - -void CShaderProgram::UnbindClientStates() -{ - if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY); - if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY); - if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); - - if (m_StreamFlags & STREAM_UV0) - { - glClientActiveTextureARB(GL_TEXTURE0); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - } - - if (m_StreamFlags & STREAM_UV1) - { - glClientActiveTextureARB(GL_TEXTURE1); - glDisableClientState(GL_TEXTURE_COORD_ARRAY); - glClientActiveTextureARB(GL_TEXTURE0); - } -} - -#endif // !CONFIG2_GLES - -void CShaderProgram::AssertPointersBound() -{ - ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); + if (m_BackendShaderProgram) + return m_BackendShaderProgram->GetFileDependencies(); + return {}; } diff --git a/source/graphics/ShaderProgram.h b/source/graphics/ShaderProgram.h index 39ad8c8d0f..5db1938f30 100644 --- a/source/graphics/ShaderProgram.h +++ b/source/graphics/ShaderProgram.h @@ -18,181 +18,38 @@ #ifndef INCLUDED_SHADERPROGRAM #define INCLUDED_SHADERPROGRAM +#include "graphics/ShaderDefines.h" #include "graphics/ShaderProgramPtr.h" -#include "lib/ogl.h" #include "lib/file/vfs/vfs_path.h" -#include "renderer/backend/Format.h" -#include "renderer/backend/gl/Texture.h" +#include "ps/CStr.h" +#include "renderer/backend/gl/ShaderProgram.h" +#include "renderer/backend/IShaderProgram.h" -#include #include -struct CColor; -class CMatrix3D; -class CVector3D; -class CShaderDefines; -class CStrIntern; - -// Vertex data stream flags -enum -{ - STREAM_POS = (1 << 0), - STREAM_NORMAL = (1 << 1), - STREAM_COLOR = (1 << 2), - STREAM_UV0 = (1 << 3), - STREAM_UV1 = (1 << 4), - STREAM_UV2 = (1 << 5), - STREAM_UV3 = (1 << 6) -}; - /** - * A compiled vertex+fragment shader program. - * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax) - * or GL_ARB_{vertex,fragment}_shader (GLSL), or may use hard-coded fixed-function - * multitexturing setup code; the difference is hidden from the caller. - * - * 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. - * Setting uniforms that the shader .xml doesn't support is harmless. - * - * For a high-level overview of shaders and materials, see - * http://trac.wildfiregames.com/wiki/MaterialSystem + * A wrapper for backend shader program to handle high-level operations like + * file reloading and handling errors on reload. */ class CShaderProgram { NONCOPYABLE(CShaderProgram); public: - typedef CStrIntern attrib_id_t; - typedef CStrIntern texture_id_t; - typedef CStrIntern uniform_id_t; - typedef std::pair frag_index_pair_t; + static CShaderProgramPtr Create(const CStr& name, const CShaderDefines& defines); - static CShaderProgramPtr Create(const char* name, const CShaderDefines& baseDefines); + void Reload(); - /** - * 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) { } + std::vector GetFileDependencies() const; - 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; - }; - - virtual ~CShaderProgram() { } - - virtual void Reload() = 0; - - /** - * Binds the shader into the GL context. Call this before calling Uniform() - * or trying to render with it. - */ - virtual void Bind() = 0; - - /** - * Unbinds the shader from the GL context. Call this after rendering with it. - */ - virtual void Unbind() = 0; - - /** - * Returns bitset of STREAM_* value, indicating what vertex data streams the - * vertex shader needs (e.g. position, color, UV, ...). - */ - int GetStreamFlags() const; - - - 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 VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); - virtual void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); - virtual void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); - virtual void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer); - virtual void VertexAttribPointer(attrib_id_t id, const Renderer::Backend::Format format, GLboolean normalized, GLsizei stride, const void* pointer); - - /** - * Checks that all the required vertex attributes have been set. - * Call this before calling Draw/DrawIndexed etc to avoid potential crashes. - */ - void AssertPointersBound(); - - virtual std::vector GetFileDependencies() const = 0; + Renderer::Backend::GL::CShaderProgram* GetBackendShaderProgram() { return m_BackendShaderProgram.get(); } protected: - CShaderProgram(int streamflags); + CShaderProgram(const CStr& name, const CShaderDefines& defines); - /** - * Construct based on ARB vertex/fragment program files. - */ - static CShaderProgramPtr ConstructARB(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 CShaderProgramPtr ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile, - const CShaderDefines& defines, - const std::map& vertexAttribs, - int streamflags); - - 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: - void BindClientStates(); - void UnbindClientStates(); - int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind + CStr m_Name; + CShaderDefines m_Defines; + std::unique_ptr m_BackendShaderProgram; }; #endif // INCLUDED_SHADERPROGRAM diff --git a/source/graphics/ShaderTechnique.cpp b/source/graphics/ShaderTechnique.cpp index 9cfa7a9229..00ec16002d 100644 --- a/source/graphics/ShaderTechnique.cpp +++ b/source/graphics/ShaderTechnique.cpp @@ -21,22 +21,12 @@ #include "graphics/ShaderProgram.h" -CShaderPass::CShaderPass() = default; - -void CShaderPass::Bind() +CShaderPass::CShaderPass( + const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, + const CShaderProgramPtr& shader) + : m_PipelineStateDesc(pipelineStateDesc), m_Shader(shader) { - m_Shader->Bind(); -} - -void CShaderPass::Unbind() -{ - m_Shader->Unbind(); -} - -void CShaderPass::SetPipelineStateDesc( - const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc) -{ - m_PipelineStateDesc = pipelineStateDesc; + m_PipelineStateDesc.shaderProgram = m_Shader->GetBackendShaderProgram(); } CShaderTechnique::CShaderTechnique() = default; @@ -51,19 +41,7 @@ int CShaderTechnique::GetNumPasses() const return m_Passes.size(); } -void CShaderTechnique::BeginPass(int pass) -{ - ENSURE(0 <= pass && pass < (int)m_Passes.size()); - m_Passes[pass].Bind(); -} - -void CShaderTechnique::EndPass(int pass) -{ - ENSURE(0 <= pass && pass < (int)m_Passes.size()); - m_Passes[pass].Unbind(); -} - -const CShaderProgramPtr& CShaderTechnique::GetShader(int pass) const +Renderer::Backend::GL::CShaderProgram* CShaderTechnique::GetShader(int pass) const { ENSURE(0 <= pass && pass < (int)m_Passes.size()); return m_Passes[pass].GetShader(); diff --git a/source/graphics/ShaderTechnique.h b/source/graphics/ShaderTechnique.h index 7bffdda2a6..81ffb68254 100644 --- a/source/graphics/ShaderTechnique.h +++ b/source/graphics/ShaderTechnique.h @@ -18,9 +18,8 @@ #ifndef INCLUDED_SHADERTECHNIQUE #define INCLUDED_SHADERTECHNIQUE -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" #include "graphics/ShaderTechniquePtr.h" -#include "lib/ogl.h" #include "renderer/backend/PipelineState.h" #include @@ -32,27 +31,9 @@ class CShaderPass { public: - CShaderPass(); + CShaderPass(const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc, const CShaderProgramPtr& shader); - /** - * Set the shader program used for rendering with this pass. - */ - void SetShader(const CShaderProgramPtr& shader) { m_Shader = shader; } - - void SetPipelineStateDesc( - const Renderer::Backend::GraphicsPipelineStateDesc& pipelineStateDesc); - - /** - * Set up all the GL state that was previously specified on this pass. - */ - void Bind(); - - /** - * Reset the GL state to the default. - */ - void Unbind(); - - const CShaderProgramPtr& GetShader() const { return m_Shader; } + Renderer::Backend::GL::CShaderProgram* GetShader() const { return m_Shader->GetBackendShaderProgram(); } const Renderer::Backend::GraphicsPipelineStateDesc& GetPipelineStateDesc() const { return m_PipelineStateDesc; } @@ -75,9 +56,7 @@ public: int GetNumPasses() const; - void BeginPass(int pass = 0); - void EndPass(int pass = 0); - const CShaderProgramPtr& GetShader(int pass = 0) const; + Renderer::Backend::GL::CShaderProgram* GetShader(int pass = 0) const; const Renderer::Backend::GraphicsPipelineStateDesc& GetGraphicsPipelineStateDesc(int pass = 0) const; diff --git a/source/graphics/TextRenderer.cpp b/source/graphics/TextRenderer.cpp index dfe27d794d..04a6c9832a 100644 --- a/source/graphics/TextRenderer.cpp +++ b/source/graphics/TextRenderer.cpp @@ -204,7 +204,7 @@ struct SBatchCompare void CTextRenderer::Render( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, const CMatrix3D& transform) + Renderer::Backend::GL::CShaderProgram* shader, const CMatrix3D& transform) { std::vector indexes; std::vector vertexes; diff --git a/source/graphics/TextRenderer.h b/source/graphics/TextRenderer.h index dabadc5f8d..8290702e78 100644 --- a/source/graphics/TextRenderer.h +++ b/source/graphics/TextRenderer.h @@ -19,7 +19,7 @@ #define INCLUDED_TEXTRENDERER #include "graphics/Color.h" -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" #include "maths/Rect.h" #include "maths/Vector2D.h" #include "ps/CStrIntern.h" @@ -105,7 +105,7 @@ public: */ void Render( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, const CMatrix3D& transform); + Renderer::Backend::GL::CShaderProgram* shader, const CMatrix3D& transform); private: friend struct SBatchCompare; diff --git a/source/gui/ObjectTypes/CMiniMap.cpp b/source/gui/ObjectTypes/CMiniMap.cpp index 91b583bb77..390b45f269 100644 --- a/source/gui/ObjectTypes/CMiniMap.cpp +++ b/source/gui/ObjectTypes/CMiniMap.cpp @@ -97,7 +97,7 @@ void CropPointsByCircle(const std::array& points, const CVector3D& void DrawTexture( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, float angle, float x, float y, float x2, float y2, float mapScale) + Renderer::Backend::GL::CShaderProgram* shader, float angle, float x, float y, float x2, float y2, float mapScale) { // Rotate the texture coordinates (0,0)-(coordMax,coordMax) around their center point (m,m) // Scale square maps to fit in circular minimap area @@ -409,7 +409,7 @@ void CMiniMap::Draw(CCanvas2D& canvas) CMiniMapTexture& miniMapTexture = g_Game->GetView()->GetMiniMapTexture(); if (miniMapTexture.GetTexture()) { - CShaderProgramPtr shader; + Renderer::Backend::GL::CShaderProgram* shader; CShaderTechniquePtr tech; CShaderDefines baseDefines; @@ -425,10 +425,10 @@ void CMiniMap::Draw(CCanvas2D& canvas) Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; - tech->BeginPass(); Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); shader = tech->GetShader(); shader->BindTexture(str_baseTex, miniMapTexture.GetTexture()); @@ -443,7 +443,7 @@ void CMiniMap::Draw(CCanvas2D& canvas) const float angle = GetAngle(); DrawTexture(deviceCommandContext, shader, angle, x, y, x2, y2, m_MapScale); - tech->EndPass(); + deviceCommandContext->EndPass(); } for (const CMiniMapTexture::Icon& icon : miniMapTexture.GetIcons()) diff --git a/source/renderer/DebugRenderer.cpp b/source/renderer/DebugRenderer.cpp index 558d88bcd2..2c3ee0a621 100644 --- a/source/renderer/DebugRenderer.cpp +++ b/source/renderer/DebugRenderer.cpp @@ -85,15 +85,15 @@ void CDebugRenderer::DrawLine( #else CShaderTechniquePtr debugLineTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - debugLineTech->BeginPass(); Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( deviceCommandContext, debugLineTech, color, depthTestEnabled); + deviceCommandContext->BeginPass(); const CCamera& viewCamera = g_Renderer.GetSceneRenderer().GetViewCamera(); - CShaderProgramPtr debugLineShader = debugLineTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* debugLineShader = debugLineTech->GetShader(); debugLineShader->Uniform(str_transform, viewCamera.GetViewProjection()); debugLineShader->Uniform(str_color, color); @@ -131,7 +131,7 @@ void CDebugRenderer::DrawLine( debugLineShader->AssertPointersBound(); deviceCommandContext->Draw(0, vertices.size() / 3); - debugLineTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -143,15 +143,15 @@ void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, con #else CShaderTechniquePtr debugCircleTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - debugCircleTech->BeginPass(); Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( deviceCommandContext, debugCircleTech, color); + deviceCommandContext->BeginPass(); const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); - CShaderProgramPtr debugCircleShader = debugCircleTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* debugCircleShader = debugCircleTech->GetShader(); debugCircleShader->Uniform(str_transform, camera.GetViewProjection()); debugCircleShader->Uniform(str_color, color); @@ -183,7 +183,7 @@ void CDebugRenderer::DrawCircle(const CVector3D& origin, const float radius, con debugCircleShader->AssertPointersBound(); deviceCommandContext->Draw(0, vertices.size() / 3); - debugCircleTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -206,13 +206,13 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo CShaderTechniquePtr overlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_line); - overlayTech->BeginPass(); Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( deviceCommandContext, overlayTech, color, true, wireframe); + deviceCommandContext->BeginPass(); - CShaderProgramPtr overlayShader = overlayTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* overlayShader = overlayTech->GetShader(); overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); overlayShader->Uniform(str_color, color); @@ -280,7 +280,7 @@ void CDebugRenderer::DrawCameraFrustum(const CCamera& camera, const CColor& colo deviceCommandContext->Draw(0, vertices.size() / 3); #undef ADD - overlayTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -298,13 +298,13 @@ void CDebugRenderer::DrawBoundingBox( const CMatrix3D& transform, bool wireframe) { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( deviceCommandContext, shaderTech, color, true, wireframe); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = shaderTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); shader->Uniform(str_color, color); shader->Uniform(str_transform, transform); @@ -335,19 +335,19 @@ void CDebugRenderer::DrawBoundingBox( shader->AssertPointersBound(); deviceCommandContext->Draw(0, 6*6); - shaderTech->EndPass(); + deviceCommandContext->EndPass(); } void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wireframe) { CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); SetGraphicsPipelineStateFromTechAndColor( deviceCommandContext, shaderTech, color, true, wireframe); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = shaderTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); shader->Uniform(str_color, color); shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); @@ -382,6 +382,6 @@ void CDebugRenderer::DrawBrush(const CBrush& brush, const CColor& color, bool wi shader->AssertPointersBound(); deviceCommandContext->Draw(0, data.size() / 5); - shaderTech->EndPass(); + deviceCommandContext->EndPass(); } diff --git a/source/renderer/DecalRData.cpp b/source/renderer/DecalRData.cpp index 516ed30b26..7dd31479ff 100644 --- a/source/renderer/DecalRData.cpp +++ b/source/renderer/DecalRData.cpp @@ -163,10 +163,10 @@ void CDecalRData::RenderDecals( Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; - techBase->BeginPass(pass); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = techBase->GetShader(pass); + Renderer::Backend::GL::CShaderProgram* shader = techBase->GetShader(pass); TerrainRenderer::PrepareShader(shader, shadow); CVertexBuffer* lastVB = nullptr; @@ -225,7 +225,7 @@ void CDecalRData::RenderDecals( g_Renderer.m_Stats.m_TerrainTris += batch.indices->m_Count / 3; } - techBase->EndPass(); + deviceCommandContext->EndPass(); } } diff --git a/source/renderer/HWLightingModelRenderer.cpp b/source/renderer/HWLightingModelRenderer.cpp index bd6da4c072..5a15b366a5 100644 --- a/source/renderer/HWLightingModelRenderer.cpp +++ b/source/renderer/HWLightingModelRenderer.cpp @@ -190,7 +190,7 @@ void ShaderModelVertexRenderer::EndPass( // Prepare UV coordinates for this modeldef void ShaderModelVertexRenderer::PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, const CModelDef& def) { m->shadermodeldef = (ShaderModelDef*)def.GetRenderData(m); @@ -218,7 +218,7 @@ void ShaderModelVertexRenderer::PrepareModelDef( // Render one model void ShaderModelVertexRenderer::RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, CModel* model, CModelRData* data) { const CModelDefPtr& mdldef = model->GetModelDef(); ShaderModel* shadermodel = static_cast(data); diff --git a/source/renderer/HWLightingModelRenderer.h b/source/renderer/HWLightingModelRenderer.h index df3fe8d818..c33663b2c5 100644 --- a/source/renderer/HWLightingModelRenderer.h +++ b/source/renderer/HWLightingModelRenderer.h @@ -44,10 +44,10 @@ public: Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int streamflags) override; void PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) override; + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, const CModelDef& def) override; void RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) override; + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, CModel* model, CModelRData* data) override; protected: struct ShaderModelRendererInternals; diff --git a/source/renderer/InstancingModelRenderer.cpp b/source/renderer/InstancingModelRenderer.cpp index 9e50a0be1a..4778dca059 100644 --- a/source/renderer/InstancingModelRenderer.cpp +++ b/source/renderer/InstancingModelRenderer.cpp @@ -312,7 +312,7 @@ void InstancingModelRenderer::EndPass( // Prepare UV coordinates for this modeldef void InstancingModelRenderer::PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, const CModelDef& def) { m->imodeldef = (IModelDef*)def.GetRenderData(m); @@ -377,7 +377,7 @@ void InstancingModelRenderer::PrepareModelDef( // Render one model void InstancingModelRenderer::RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data)) + Renderer::Backend::GL::CShaderProgram* shader, int UNUSED(streamflags), CModel* model, CModelRData* UNUSED(data)) { const CModelDefPtr& mdldef = model->GetModelDef(); diff --git a/source/renderer/InstancingModelRenderer.h b/source/renderer/InstancingModelRenderer.h index 8358741b49..29bec6e0cf 100644 --- a/source/renderer/InstancingModelRenderer.h +++ b/source/renderer/InstancingModelRenderer.h @@ -48,9 +48,9 @@ public: int streamflags); void PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, const CModelDef& def); + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, const CModelDef& def); void RenderModel(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data); + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, CModel* model, CModelRData* data); protected: InstancingModelRendererInternals* m; diff --git a/source/renderer/ModelRenderer.cpp b/source/renderer/ModelRenderer.cpp index 8890f92b30..7276d97a91 100644 --- a/source/renderer/ModelRenderer.cpp +++ b/source/renderer/ModelRenderer.cpp @@ -606,8 +606,8 @@ void ShaderModelRenderer::Render( // 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; @@ -629,11 +629,11 @@ void ShaderModelRenderer::Render( // For each of the technique's passes, render all the models in this run for (int pass = 0; pass < currentTech->GetNumPasses(); ++pass) { - currentTech->BeginPass(pass); deviceCommandContext->SetGraphicsPipelineState( currentTech->GetGraphicsPipelineStateDesc(pass)); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = currentTech->GetShader(pass); + Renderer::Backend::GL::CShaderProgram* shader = currentTech->GetShader(pass); int streamflags = shader->GetStreamFlags(); modifier->BeginPass(shader); @@ -669,11 +669,11 @@ void ShaderModelRenderer::Render( if (currentTexs.size() != samplersNum) { currentTexs.resize(samplersNum, NULL); - texBindings.resize(samplersNum, CShaderProgram::Binding()); + texBindings.resize(samplersNum, Renderer::Backend::GL::CShaderProgram::Binding()); texBindingNames.resize(samplersNum, CStrIntern()); // ensure they are definitely empty - std::fill(texBindings.begin(), texBindings.end(), CShaderProgram::Binding()); + std::fill(texBindings.begin(), texBindings.end(), Renderer::Backend::GL::CShaderProgram::Binding()); std::fill(currentTexs.begin(), currentTexs.end(), (CTexture*)NULL); std::fill(texBindingNames.begin(), texBindingNames.end(), CStrIntern()); } @@ -756,7 +756,7 @@ void ShaderModelRenderer::Render( m->vertexRenderer->EndPass(deviceCommandContext, streamflags); - currentTech->EndPass(pass); + deviceCommandContext->EndPass(); } idxTechStart = idxTechEnd; diff --git a/source/renderer/ModelVertexRenderer.h b/source/renderer/ModelVertexRenderer.h index 6333c06377..f16940085e 100644 --- a/source/renderer/ModelVertexRenderer.h +++ b/source/renderer/ModelVertexRenderer.h @@ -26,6 +26,7 @@ #include "graphics/MeshManager.h" #include "graphics/ShaderProgramPtr.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/ShaderProgram.h" class CModel; class CModelRData; @@ -134,7 +135,7 @@ public: */ virtual void PrepareModelDef( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, const CModelDef& def) = 0; + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, const CModelDef& def) = 0; /** @@ -158,7 +159,7 @@ public: */ virtual void RenderModel( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, int streamflags, CModel* model, CModelRData* data) = 0; + Renderer::Backend::GL::CShaderProgram* shader, int streamflags, CModel* model, CModelRData* data) = 0; }; diff --git a/source/renderer/OverlayRenderer.cpp b/source/renderer/OverlayRenderer.cpp index d5289d29f3..99150623f9 100644 --- a/source/renderer/OverlayRenderer.cpp +++ b/source/renderer/OverlayRenderer.cpp @@ -427,10 +427,10 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC Renderer::Backend::BlendOp::ADD; if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - shaderTechTexLineNormal->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - CShaderProgramPtr shaderTexLineNormal = shaderTechTexLineNormal->GetShader(); + Renderer::Backend::GL::CShaderProgram* shaderTexLineNormal = shaderTechTexLineNormal->GetShader(); shaderTexLineNormal->BindTexture(str_losTex, los.GetTexture()); shaderTexLineNormal->Uniform(str_losTransform, los.GetTextureMatrix()[0], los.GetTextureMatrix()[12], 0.f, 0.f); @@ -440,7 +440,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC // batch render only the non-always-visible overlay lines using the normal shader RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineNormal, false); - shaderTechTexLineNormal->EndPass(); + deviceCommandContext->EndPass(); } // ---------------------------------------------------------------------------------------- @@ -460,10 +460,10 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC Renderer::Backend::BlendOp::ADD; if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - shaderTechTexLineAlwaysVisible->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - CShaderProgramPtr shaderTexLineAlwaysVisible = shaderTechTexLineAlwaysVisible->GetShader(); + Renderer::Backend::GL::CShaderProgram* 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()); @@ -474,7 +474,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC // batch render only the always-visible overlay lines using the LoS-ignored shader RenderTexturedOverlayLines(deviceCommandContext, shaderTexLineAlwaysVisible, true); - shaderTechTexLineAlwaysVisible->EndPass(); + deviceCommandContext->EndPass(); } // ---------------------------------------------------------------------------------------- @@ -488,7 +488,7 @@ void OverlayRenderer::RenderTexturedOverlayLines(Renderer::Backend::GL::CDeviceC void OverlayRenderer::RenderTexturedOverlayLines( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, bool alwaysVisible) + Renderer::Backend::GL::CShaderProgram* shader, bool alwaysVisible) { for (size_t i = 0; i < m->texlines.size(); ++i) { @@ -530,10 +530,10 @@ void OverlayRenderer::RenderQuadOverlays( Renderer::Backend::BlendOp::ADD; if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - shaderTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = shaderTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); CLOSTexture& los = g_Renderer.GetSceneRenderer().GetScene().GetLOSTexture(); @@ -586,7 +586,7 @@ void OverlayRenderer::RenderQuadOverlays( g_Renderer.GetStats().m_OverlayTris += batchNumQuads*2; } - shaderTech->EndPass(); + deviceCommandContext->EndPass(); // TODO: the shader should probably be responsible for unbinding its textures deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); @@ -622,10 +622,10 @@ void OverlayRenderer::RenderForegroundOverlays( Renderer::Backend::BlendOp::ADD; if (g_Renderer.GetSceneRenderer().GetOverlayRenderMode() == WIREFRAME) pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = tech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); shader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); @@ -672,7 +672,7 @@ void OverlayRenderer::RenderForegroundOverlays( g_Renderer.GetStats().m_OverlayTris += 2; } - tech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -749,7 +749,7 @@ void OverlayRenderer::RenderSphereOverlays( if (m->spheres.empty()) return; - CShaderProgramPtr shader; + Renderer::Backend::GL::CShaderProgram* shader; CShaderTechniquePtr tech; tech = g_Renderer.GetShaderManager().LoadEffect(str_overlay_solid); @@ -763,8 +763,8 @@ void OverlayRenderer::RenderSphereOverlays( Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); shader = tech->GetShader(); @@ -794,6 +794,6 @@ void OverlayRenderer::RenderSphereOverlays( g_Renderer.GetStats().m_OverlayTris = m->sphereIndexes.size()/3; } - tech->EndPass(); + deviceCommandContext->EndPass(); #endif } diff --git a/source/renderer/OverlayRenderer.h b/source/renderer/OverlayRenderer.h index c0ecc6e836..4c4f68dc8e 100644 --- a/source/renderer/OverlayRenderer.h +++ b/source/renderer/OverlayRenderer.h @@ -18,7 +18,7 @@ #ifndef INCLUDED_OVERLAYRENDERER #define INCLUDED_OVERLAYRENDERER -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" #include "renderer/backend/gl/DeviceCommandContext.h" struct SOverlayLine; @@ -140,7 +140,7 @@ private: */ void RenderTexturedOverlayLines( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, bool alwaysVisible); + Renderer::Backend::GL::CShaderProgram* shader, bool alwaysVisible); /** * Helper method; batch-renders all registered quad overlays, batched by their texture for effiency. diff --git a/source/renderer/ParticleRenderer.cpp b/source/renderer/ParticleRenderer.cpp index 33fe2d3ca8..647143e2d4 100644 --- a/source/renderer/ParticleRenderer.cpp +++ b/source/renderer/ParticleRenderer.cpp @@ -151,11 +151,13 @@ void ParticleRenderer::RenderParticles( ENSURE(currentTech); if (lastTech != currentTech) { + if (lastTech) + deviceCommandContext->EndPass(); lastTech = currentTech; - lastTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(lastTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = lastTech->GetShader(); + 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()); } @@ -164,7 +166,7 @@ void ParticleRenderer::RenderParticles( } if (lastTech) - lastTech->EndPass(); + deviceCommandContext->EndPass(); CVertexBuffer::Unbind(deviceCommandContext); } diff --git a/source/renderer/PatchRData.cpp b/source/renderer/PatchRData.cpp index 17ab75bc52..7827eccf43 100644 --- a/source/renderer/PatchRData.cpp +++ b/source/renderer/PatchRData.cpp @@ -771,10 +771,10 @@ void CPatchRData::RenderBases( const int numPasses = techBase->GetNumPasses(); for (int pass = 0; pass < numPasses; ++pass) { - techBase->BeginPass(pass); deviceCommandContext->SetGraphicsPipelineState( techBase->GetGraphicsPipelineStateDesc(pass)); - const CShaderProgramPtr& shader = techBase->GetShader(pass); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* shader = techBase->GetShader(pass); TerrainRenderer::PrepareShader(shader, shadow); TextureBatches& textureBatches = itTech->second; @@ -827,7 +827,7 @@ void CPatchRData::RenderBases( } } } - techBase->EndPass(); + deviceCommandContext->EndPass(); } } @@ -964,7 +964,7 @@ void CPatchRData::RenderBlends( PROFILE_END("compute batches"); CVertexBuffer* lastVB = nullptr; - CShaderProgramPtr previousShader; + Renderer::Backend::GL::CShaderProgram* 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) @@ -983,10 +983,10 @@ void CPatchRData::RenderBlends( Renderer::Backend::BlendFactor::ONE_MINUS_SRC_ALPHA; pipelineStateDesc.blendState.colorBlendOp = pipelineStateDesc.blendState.alphaBlendOp = Renderer::Backend::BlendOp::ADD; - techBase->BeginPass(pass); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shader = techBase->GetShader(pass); + Renderer::Backend::GL::CShaderProgram* shader = techBase->GetShader(pass); TerrainRenderer::PrepareShader(shader, shadow); Renderer::Backend::GL::CTexture* lastBlendTex = nullptr; @@ -1060,7 +1060,7 @@ void CPatchRData::RenderBlends( } } } - techBase->EndPass(); + deviceCommandContext->EndPass(); } } @@ -1069,7 +1069,7 @@ void CPatchRData::RenderBlends( void CPatchRData::RenderStreams( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, const CShaderProgramPtr& shader, + const std::vector& patches, Renderer::Backend::GL::CShaderProgram* shader, const bool bindPositionAsTexCoord) { PROFILE3("render terrain streams"); @@ -1167,7 +1167,7 @@ void CPatchRData::RenderOutline() void CPatchRData::RenderSides( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, const CShaderProgramPtr& shader) + const std::vector& patches, Renderer::Backend::GL::CShaderProgram* shader) { PROFILE3("render terrain sides"); GPU_SCOPED_LABEL(deviceCommandContext, "Render terrain sides"); @@ -1430,7 +1430,7 @@ void CPatchRData::BuildWater() void CPatchRData::RenderWaterSurface( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, const bool bindWaterData) + Renderer::Backend::GL::CShaderProgram* shader, const bool bindWaterData) { ASSERT(m_UpdateFlags == 0); @@ -1465,7 +1465,7 @@ void CPatchRData::RenderWaterSurface( void CPatchRData::RenderWaterShore( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader) + Renderer::Backend::GL::CShaderProgram* shader) { ASSERT(m_UpdateFlags == 0); diff --git a/source/renderer/PatchRData.h b/source/renderer/PatchRData.h index bbb4ef542d..2f141781b9 100644 --- a/source/renderer/PatchRData.h +++ b/source/renderer/PatchRData.h @@ -20,10 +20,10 @@ #include "graphics/Patch.h" #include "graphics/RenderableObject.h" -#include "graphics/ShaderProgramPtr.h" #include "maths/Vector2D.h" #include "maths/Vector3D.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/ShaderProgram.h" #include "renderer/VertexBufferManager.h" #include @@ -50,10 +50,10 @@ public: void RenderWaterSurface( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader, const bool bindWaterData); + Renderer::Backend::GL::CShaderProgram* shader, const bool bindWaterData); void RenderWaterShore( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const CShaderProgramPtr& shader); + Renderer::Backend::GL::CShaderProgram* shader); CPatch* GetPatch() { return m_Patch; } @@ -67,13 +67,13 @@ public: const std::vector& patches, const CShaderDefines& context, ShadowMap* shadow); static void RenderStreams( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, const CShaderProgramPtr& shader, + const std::vector& patches, Renderer::Backend::GL::CShaderProgram* shader, const bool bindPositionAsTexCoord); static void RenderSides( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const std::vector& patches, const CShaderProgramPtr& shader); + const std::vector& patches, Renderer::Backend::GL::CShaderProgram* shader); - static void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow); + static void PrepareShader(Renderer::Backend::GL::CShaderProgram* shader, ShadowMap* shadow); private: friend struct SBlendStackItem; diff --git a/source/renderer/PostprocManager.cpp b/source/renderer/PostprocManager.cpp index 62ba4723d2..9e1ced4e09 100644 --- a/source/renderer/PostprocManager.cpp +++ b/source/renderer/PostprocManager.cpp @@ -197,10 +197,10 @@ void CPostprocManager::ApplyBlurDownscale2x( defines.Add(str_BLOOM_NOP, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines); - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& shader = tech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); shader->BindTexture(str_renderedTex, inTex); @@ -237,7 +237,7 @@ void CPostprocManager::ApplyBlurDownscale2x( g_Renderer.SetViewport(oldVp); - tech->EndPass(); + deviceCommandContext->EndPass(); } void CPostprocManager::ApplyBlurGauss( @@ -255,10 +255,10 @@ void CPostprocManager::ApplyBlurGauss( defines2.Add(str_BLOOM_PASS_H, str_1); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines2); - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); - CShaderProgramPtr shader = tech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); shader->BindTexture(str_renderedTex, inTex); shader->Uniform(str_texSize, inWidth, inHeight, 0.0f, 0.0f); @@ -295,7 +295,7 @@ void CPostprocManager::ApplyBlurGauss( g_Renderer.SetViewport(oldVp); - tech->EndPass(); + deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer(outFramebuffer); @@ -303,8 +303,10 @@ void CPostprocManager::ApplyBlurGauss( CShaderDefines defines3; defines3.Add(str_BLOOM_PASS_V, str_1); tech = g_Renderer.GetShaderManager().LoadEffect(str_bloom, defines3); + deviceCommandContext->SetGraphicsPipelineState( + tech->GetGraphicsPipelineStateDesc()); - tech->BeginPass(); + deviceCommandContext->BeginPass(); shader = tech->GetShader(); // Our input texture to the shader is the output of the horizontal pass. @@ -322,7 +324,7 @@ void CPostprocManager::ApplyBlurGauss( g_Renderer.SetViewport(oldVp); - tech->EndPass(); + deviceCommandContext->EndPass(); } void CPostprocManager::ApplyBlur( @@ -384,10 +386,10 @@ void CPostprocManager::ApplyEffect( deviceCommandContext->SetFramebuffer( (m_WhichBuffer ? m_PongFramebuffer : m_PingFramebuffer).get()); - shaderTech->BeginPass(pass); deviceCommandContext->SetGraphicsPipelineState( shaderTech->GetGraphicsPipelineStateDesc(pass)); - const CShaderProgramPtr& shader = shaderTech->GetShader(pass); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* 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 @@ -442,7 +444,7 @@ void CPostprocManager::ApplyEffect( shader->AssertPointersBound(); deviceCommandContext->Draw(0, 6); - shaderTech->EndPass(pass); + deviceCommandContext->EndPass(); m_WhichBuffer = !m_WhichBuffer; } diff --git a/source/renderer/RenderModifiers.cpp b/source/renderer/RenderModifiers.cpp index c00aeee409..4257405216 100644 --- a/source/renderer/RenderModifiers.cpp +++ b/source/renderer/RenderModifiers.cpp @@ -67,7 +67,7 @@ ShaderRenderModifier::ShaderRenderModifier() { } -void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader) +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()); @@ -98,7 +98,7 @@ void ShaderRenderModifier::BeginPass(const CShaderProgramPtr& shader) m_BindingPlayerColor = shader->GetUniformBinding(str_playerColor); } -void ShaderRenderModifier::PrepareModel(const CShaderProgramPtr& shader, CModel* model) +void ShaderRenderModifier::PrepareModel(Renderer::Backend::GL::CShaderProgram* shader, CModel* model) { if (m_BindingInstancingTransform.Active()) shader->Uniform(m_BindingInstancingTransform, model->GetTransform()); diff --git a/source/renderer/RenderModifiers.h b/source/renderer/RenderModifiers.h index efeade4f49..287d8ecf26 100644 --- a/source/renderer/RenderModifiers.h +++ b/source/renderer/RenderModifiers.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 @@ -60,7 +60,7 @@ public: * @return The streamflags that indicate which vertex components * are required by the fragment stages (see STREAM_XYZ constants). */ - virtual void BeginPass(const CShaderProgramPtr& shader) = 0; + virtual void BeginPass(Renderer::Backend::GL::CShaderProgram* shader) = 0; /** * PrepareModel: Called before rendering the given model. @@ -70,7 +70,7 @@ public: * @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(const CShaderProgramPtr& shader, CModel* model) = 0; + virtual void PrepareModel(Renderer::Backend::GL::CShaderProgram* shader, CModel* model) = 0; }; @@ -121,13 +121,13 @@ public: ShaderRenderModifier(); // Implementation - void BeginPass(const CShaderProgramPtr& shader); - void PrepareModel(const CShaderProgramPtr& shader, CModel* model); + void BeginPass(Renderer::Backend::GL::CShaderProgram* shader); + void PrepareModel(Renderer::Backend::GL::CShaderProgram* shader, CModel* model); private: - CShaderProgram::Binding m_BindingInstancingTransform; - CShaderProgram::Binding m_BindingShadingColor; - CShaderProgram::Binding m_BindingPlayerColor; + Renderer::Backend::GL::CShaderProgram::Binding m_BindingInstancingTransform; + Renderer::Backend::GL::CShaderProgram::Binding m_BindingShadingColor; + Renderer::Backend::GL::CShaderProgram::Binding m_BindingPlayerColor; }; #endif // INCLUDED_RENDERMODIFIERS diff --git a/source/renderer/SceneRenderer.cpp b/source/renderer/SceneRenderer.cpp index 80d9331fd7..8836ab9343 100644 --- a/source/renderer/SceneRenderer.cpp +++ b/source/renderer/SceneRenderer.cpp @@ -577,6 +577,8 @@ void CSceneRenderer::RenderReflections( scissorRect.height = screenScissor.y2 - screenScissor.y1; deviceCommandContext->SetScissors(1, &scissorRect); + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->SetFramebuffer(wm.m_ReflectionFramebuffer.get()); deviceCommandContext->ClearFramebuffer(); @@ -603,9 +605,6 @@ void CSceneRenderer::RenderReflections( // Reset old camera m_ViewCamera = normalCamera; g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); - - deviceCommandContext->SetFramebuffer( - deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } // RenderRefractions: render the water refractions to the refraction texture @@ -651,6 +650,8 @@ void CSceneRenderer::RenderRefractions( scissorRect.height = screenScissor.y2 - screenScissor.y1; deviceCommandContext->SetScissors(1, &scissorRect); + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->SetFramebuffer(wm.m_RefractionFramebuffer.get()); deviceCommandContext->ClearFramebuffer(); @@ -670,9 +671,6 @@ void CSceneRenderer::RenderRefractions( // Reset old camera m_ViewCamera = normalCamera; g_Renderer.SetViewport(m_ViewCamera.GetViewPort()); - - deviceCommandContext->SetFramebuffer( - deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); } void CSceneRenderer::RenderSilhouettes( @@ -810,6 +808,9 @@ void CSceneRenderer::RenderSubmissions( } } + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); + CPostprocManager& postprocManager = g_Renderer.GetPostprocManager(); if (postprocManager.IsEnabled()) { diff --git a/source/renderer/ShadowMap.cpp b/source/renderer/ShadowMap.cpp index b0df337cd1..269c76e6a7 100644 --- a/source/renderer/ShadowMap.cpp +++ b/source/renderer/ShadowMap.cpp @@ -572,6 +572,8 @@ void ShadowMap::BeginRender() { Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext = g_Renderer.GetDeviceCommandContext(); + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); { PROFILE("bind framebuffer"); @@ -629,7 +631,7 @@ void ShadowMap::EndRender() g_Renderer.SetViewport(vp); } -void ShadowMap::BindTo(const CShaderProgramPtr& shader) const +void ShadowMap::BindTo(Renderer::Backend::GL::CShaderProgram* shader) const { if (!shader->GetTextureBinding(str_shadowTex).Active() || !m->Texture) return; @@ -723,11 +725,11 @@ void ShadowMap::RenderDebugTexture( #endif CShaderTechniquePtr texTech = g_Renderer.GetShaderManager().LoadEffect(str_canvas2d); - texTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( texTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& texShader = texTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* texShader = texTech->GetShader(); texShader->Uniform(str_transform, GetDefaultGuiMatrix()); texShader->BindTexture(str_tex, m->Texture.get()); @@ -754,7 +756,7 @@ void ShadowMap::RenderDebugTexture( texShader->AssertPointersBound(); deviceCommandContext->Draw(0, 6); - texTech->EndPass(); + deviceCommandContext->EndPass(); #if !CONFIG2_GLES deviceCommandContext->BindTexture(0, GL_TEXTURE_2D, m->Texture->GetHandle()); diff --git a/source/renderer/ShadowMap.h b/source/renderer/ShadowMap.h index 4d4a1e655a..200ae58b8f 100644 --- a/source/renderer/ShadowMap.h +++ b/source/renderer/ShadowMap.h @@ -18,9 +18,8 @@ #ifndef INCLUDED_SHADOWMAP #define INCLUDED_SHADOWMAP -#include "graphics/ShaderProgramPtr.h" -#include "lib/ogl.h" #include "renderer/backend/gl/DeviceCommandContext.h" +#include "renderer/backend/gl/ShaderProgram.h" class CBoundingBoxAligned; class CCamera; @@ -127,7 +126,7 @@ public: /** * Binds all needed resources and uniforms to draw shadows using the shader. */ - void BindTo(const CShaderProgramPtr& shader) const; + void BindTo(Renderer::Backend::GL::CShaderProgram* shader) const; /** * Visualize shadow mapping calculations to help in diff --git a/source/renderer/SilhouetteRenderer.cpp b/source/renderer/SilhouetteRenderer.cpp index 6e1450c375..2de8042a52 100644 --- a/source/renderer/SilhouetteRenderer.cpp +++ b/source/renderer/SilhouetteRenderer.cpp @@ -470,14 +470,14 @@ void SilhouetteRenderer::RenderDebugOverlays( m = proj * m; CShaderTechniquePtr shaderTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - shaderTech->BeginPass(); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = shaderTech->GetGraphicsPipelineStateDesc(); + deviceCommandContext->BeginPass(); pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); - const CShaderProgramPtr& shader = shaderTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* shader = shaderTech->GetShader(); shader->Uniform(str_transform, proj); for (size_t i = 0; i < m_DebugRects.size(); ++i) @@ -498,7 +498,7 @@ void SilhouetteRenderer::RenderDebugOverlays( deviceCommandContext->Draw(0, 6); } - shaderTech->EndPass(); + deviceCommandContext->EndPass(); } void SilhouetteRenderer::EndFrame() diff --git a/source/renderer/SkyManager.cpp b/source/renderer/SkyManager.cpp index 6652d92df2..bddb6e1899 100644 --- a/source/renderer/SkyManager.cpp +++ b/source/renderer/SkyManager.cpp @@ -207,10 +207,10 @@ void SkyManager::RenderSky( CShaderTechniquePtr skytech = g_Renderer.GetShaderManager().LoadEffect(str_sky_simple); - skytech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( skytech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& shader = skytech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* shader = skytech->GetShader(); shader->BindTexture(str_baseTex, m_SkyCubeMap.get()); // Translate so the sky center is at the camera space origin. @@ -244,7 +244,7 @@ void SkyManager::RenderSky( deviceCommandContext->Draw(0, m_VertexArray.GetNumberOfVertices()); - skytech->EndPass(); + deviceCommandContext->EndPass(); } void SkyManager::CreateSkyCube() diff --git a/source/renderer/TerrainOverlay.cpp b/source/renderer/TerrainOverlay.cpp index 0576f7c5c8..66708a574a 100644 --- a/source/renderer/TerrainOverlay.cpp +++ b/source/renderer/TerrainOverlay.cpp @@ -221,10 +221,10 @@ void TerrainOverlay::RenderTile( pipelineStateDesc.rasterizationState.depthBiasEnabled = true; pipelineStateDesc.rasterizationState.depthBiasConstantFactor = -1.0f; pipelineStateDesc.rasterizationState.depthBiasSlopeFactor = -1.0f; - overlayTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - CShaderProgramPtr overlayShader = overlayTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* overlayShader = overlayTech->GetShader(); overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); overlayShader->Uniform(str_color, color); @@ -235,7 +235,7 @@ void TerrainOverlay::RenderTile( deviceCommandContext->Draw(0, vertices.size() / 3); - overlayTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -290,10 +290,10 @@ void TerrainOverlay::RenderTileOutline( pipelineStateDesc.rasterizationState.cullMode = drawHidden ? Renderer::Backend::CullMode::NONE : Renderer::Backend::CullMode::BACK; pipelineStateDesc.rasterizationState.polygonMode = Renderer::Backend::PolygonMode::LINE; - overlayTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& overlayShader = overlayTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* overlayShader = overlayTech->GetShader(); overlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); overlayShader->Uniform(str_color, color); @@ -304,7 +304,7 @@ void TerrainOverlay::RenderTileOutline( deviceCommandContext->Draw(0, vertices.size() / 3); - overlayTech->EndPass(); + deviceCommandContext->EndPass(); #endif } diff --git a/source/renderer/TerrainRenderer.cpp b/source/renderer/TerrainRenderer.cpp index eb1f9eb5c6..7a9ae89388 100644 --- a/source/renderer/TerrainRenderer.cpp +++ b/source/renderer/TerrainRenderer.cpp @@ -178,10 +178,10 @@ void TerrainRenderer::RenderTerrainOverlayTexture( CShaderTechniquePtr debugOverlayTech = g_Renderer.GetShaderManager().LoadEffect(str_debug_overlay); - debugOverlayTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( debugOverlayTech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& debugOverlayShader = debugOverlayTech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* debugOverlayShader = debugOverlayTech->GetShader(); debugOverlayShader->BindTexture(str_baseTex, texture); debugOverlayShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); @@ -217,7 +217,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture( deviceCommandContext->Draw(0, 6); } - debugOverlayTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -227,7 +227,7 @@ void TerrainRenderer::RenderTerrainOverlayTexture( /** * Set up all the uniforms for a shader pass. */ -void TerrainRenderer::PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow) +void TerrainRenderer::PrepareShader(Renderer::Backend::GL::CShaderProgram* shader, ShadowMap* shadow) { CSceneRenderer& sceneRenderer = g_Renderer.GetSceneRenderer(); @@ -264,19 +264,19 @@ void TerrainRenderer::RenderTerrainShader( // render the solid black sides of the map first CShaderTechniquePtr techSolid = g_Renderer.GetShaderManager().LoadEffect(str_solid); - techSolid->BeginPass(); Renderer::Backend::GraphicsPipelineStateDesc solidPipelineStateDesc = techSolid->GetGraphicsPipelineStateDesc(); solidPipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(solidPipelineStateDesc); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& shaderSolid = techSolid->GetShader(); + 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); CPatchRData::RenderSides(deviceCommandContext, visiblePatches, shaderSolid); - techSolid->EndPass(); + deviceCommandContext->EndPass(); CPatchRData::RenderBases(deviceCommandContext, visiblePatches, context, shadow); @@ -314,16 +314,16 @@ void TerrainRenderer::RenderPatches( #else CShaderTechniquePtr solidTech = g_Renderer.GetShaderManager().LoadEffect(str_terrain_solid, defines); - solidTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( solidTech->GetGraphicsPipelineStateDesc()); + deviceCommandContext->BeginPass(); - const CShaderProgramPtr& solidShader = solidTech->GetShader(); + Renderer::Backend::GL::CShaderProgram* solidShader = solidTech->GetShader(); solidShader->Uniform(str_transform, g_Renderer.GetSceneRenderer().GetViewCamera().GetViewProjection()); solidShader->Uniform(str_color, color); CPatchRData::RenderStreams(deviceCommandContext, visiblePatches, solidShader, false); - solidTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -416,10 +416,10 @@ bool TerrainRenderer::RenderFancyWater( const double time = waterManager.m_WaterTexTimer; const float repeatPeriod = waterManager.m_RepeatPeriod; - m->fancyWaterTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( m->fancyWaterTech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& fancyWaterShader = m->fancyWaterTech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* fancyWaterShader = m->fancyWaterTech->GetShader(); const CCamera& camera = g_Renderer.GetSceneRenderer().GetViewCamera(); @@ -509,7 +509,7 @@ bool TerrainRenderer::RenderFancyWater( if (waterManager.m_WaterFancyEffects) data->RenderWaterShore(deviceCommandContext, fancyWaterShader); } - m->fancyWaterTech->EndPass(); + deviceCommandContext->EndPass(); return true; } @@ -536,10 +536,10 @@ void TerrainRenderer::RenderSimpleWater( CShaderTechniquePtr waterSimpleTech = g_Renderer.GetShaderManager().LoadEffect(str_water_simple, context); - waterSimpleTech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( waterSimpleTech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& waterSimpleShader = waterSimpleTech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* waterSimpleShader = waterSimpleTech->GetShader(); const CTexturePtr& waterTexture = waterManager.m_WaterTexture[waterManager.GetCurrentTextureIndex(1.6)]; waterTexture->UploadBackendTextureIfNeeded(deviceCommandContext); @@ -559,7 +559,7 @@ void TerrainRenderer::RenderSimpleWater( deviceCommandContext->BindTexture(1, GL_TEXTURE_2D, 0); - waterSimpleTech->EndPass(); + deviceCommandContext->EndPass(); #endif } @@ -593,19 +593,19 @@ void TerrainRenderer::RenderWaterFoamOccluders( // Overwrite waves that would be behind the ground. CShaderTechniquePtr dummyTech = g_Renderer.GetShaderManager().LoadEffect(str_solid); - dummyTech->BeginPass(); Renderer::Backend::GraphicsPipelineStateDesc pipelineStateDesc = dummyTech->GetGraphicsPipelineStateDesc(); pipelineStateDesc.depthStencilState.depthTestEnabled = true; pipelineStateDesc.rasterizationState.cullMode = Renderer::Backend::CullMode::NONE; deviceCommandContext->SetGraphicsPipelineState(pipelineStateDesc); - const CShaderProgramPtr& dummyShader = dummyTech->GetShader(); + 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); for (CPatchRData* data : m->visiblePatches[cullGroup]) data->RenderWaterShore(deviceCommandContext, dummyShader); - dummyTech->EndPass(); + deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); diff --git a/source/renderer/TerrainRenderer.h b/source/renderer/TerrainRenderer.h index 8757a85b96..d0f1d015bc 100644 --- a/source/renderer/TerrainRenderer.h +++ b/source/renderer/TerrainRenderer.h @@ -26,6 +26,7 @@ #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" class CCamera; @@ -186,7 +187,7 @@ private: Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, int cullGroup); - static void PrepareShader(const CShaderProgramPtr& shader, ShadowMap* shadow); + static void PrepareShader(Renderer::Backend::GL::CShaderProgram* shader, ShadowMap* shadow); }; #endif // INCLUDED_TERRAINRENDERER diff --git a/source/renderer/TexturedLineRData.cpp b/source/renderer/TexturedLineRData.cpp index c1c3676431..ec98802054 100644 --- a/source/renderer/TexturedLineRData.cpp +++ b/source/renderer/TexturedLineRData.cpp @@ -37,7 +37,7 @@ void CTexturedLineRData::Render( Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const SOverlayTexturedLine& line, const CShaderProgramPtr& shader) + const SOverlayTexturedLine& line, Renderer::Backend::GL::CShaderProgram* shader) { if (!m_VB || !m_VBIndices) return; // might have failed to allocate diff --git a/source/renderer/TexturedLineRData.h b/source/renderer/TexturedLineRData.h index ee6f962ed6..e23d925c5c 100644 --- a/source/renderer/TexturedLineRData.h +++ b/source/renderer/TexturedLineRData.h @@ -20,7 +20,7 @@ #include "graphics/Overlay.h" #include "graphics/RenderableObject.h" -#include "graphics/ShaderProgramPtr.h" +#include "graphics/ShaderProgram.h" #include "graphics/TextureManager.h" #include "maths/BoundingBoxAligned.h" #include "renderer/backend/gl/DeviceCommandContext.h" @@ -53,7 +53,7 @@ public: void Update(const SOverlayTexturedLine& line); void Render(Renderer::Backend::GL::CDeviceCommandContext* deviceCommandContext, - const SOverlayTexturedLine& line, const CShaderProgramPtr& shader); + const SOverlayTexturedLine& line, Renderer::Backend::GL::CShaderProgram* shader); bool IsVisibleInFrustum(const CFrustum& frustum) const; diff --git a/source/renderer/WaterManager.cpp b/source/renderer/WaterManager.cpp index c14deaeed9..0687cc86ff 100644 --- a/source/renderer/WaterManager.cpp +++ b/source/renderer/WaterManager.cpp @@ -798,14 +798,16 @@ void WaterManager::RenderWaves( if (!m_WaterFancyEffects) return; + deviceCommandContext->SetGraphicsPipelineState( + Renderer::Backend::MakeDefaultGraphicsPipelineStateDesc()); deviceCommandContext->SetFramebuffer(m_FancyEffectsFramebuffer.get()); deviceCommandContext->ClearFramebuffer(); CShaderTechniquePtr tech = g_Renderer.GetShaderManager().LoadEffect(str_water_waves); - tech->BeginPass(); deviceCommandContext->SetGraphicsPipelineState( tech->GetGraphicsPipelineStateDesc()); - const CShaderProgramPtr& shader = tech->GetShader(); + deviceCommandContext->BeginPass(); + Renderer::Backend::GL::CShaderProgram* shader = tech->GetShader(); m_WaveTex->UploadBackendTextureIfNeeded(deviceCommandContext); m_FoamTex->UploadBackendTextureIfNeeded(deviceCommandContext); @@ -855,7 +857,7 @@ void WaterManager::RenderWaves( CVertexBuffer::Unbind(deviceCommandContext); } - tech->EndPass(); + deviceCommandContext->EndPass(); deviceCommandContext->SetFramebuffer( deviceCommandContext->GetDevice()->GetCurrentBackbuffer()); #endif diff --git a/source/renderer/backend/IShaderProgram.h b/source/renderer/backend/IShaderProgram.h new file mode 100644 index 0000000000..cbfb1dc7d4 --- /dev/null +++ b/source/renderer/backend/IShaderProgram.h @@ -0,0 +1,40 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM +#define INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM + +namespace Renderer +{ + +namespace Backend +{ + +/** + * IShaderProgram is a container for multiple shaders of different types. + */ +class IShaderProgram +{ +public: + virtual ~IShaderProgram() {} +}; + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_ISHADERPROGRAM diff --git a/source/renderer/backend/PipelineState.cpp b/source/renderer/backend/PipelineState.cpp index 162dc357b2..7b815649bc 100644 --- a/source/renderer/backend/PipelineState.cpp +++ b/source/renderer/backend/PipelineState.cpp @@ -31,6 +31,8 @@ GraphicsPipelineStateDesc MakeDefaultGraphicsPipelineStateDesc() { GraphicsPipelineStateDesc desc{}; + desc.shaderProgram = nullptr; + desc.depthStencilState.depthTestEnabled = true; desc.depthStencilState.depthCompareOp = CompareOp::LESS_OR_EQUAL; desc.depthStencilState.depthWriteEnabled = true; diff --git a/source/renderer/backend/PipelineState.h b/source/renderer/backend/PipelineState.h index 6a4e08cb1a..67229165dd 100644 --- a/source/renderer/backend/PipelineState.h +++ b/source/renderer/backend/PipelineState.h @@ -20,6 +20,7 @@ #include "graphics/Color.h" #include "renderer/backend/CompareOp.h" +#include "renderer/backend/IShaderProgram.h" class CStr; @@ -159,9 +160,11 @@ struct RasterizationStateDesc float depthBiasSlopeFactor; }; -// TODO: Add a shader program to the graphics pipeline state. struct GraphicsPipelineStateDesc { + // It's a backend client reponsibility to keep the shader program alive + // while it's bound. + IShaderProgram* shaderProgram; DepthStencilStateDesc depthStencilState; BlendStateDesc blendState; RasterizationStateDesc rasterizationState; diff --git a/source/renderer/backend/gl/Device.cpp b/source/renderer/backend/gl/Device.cpp index 2036c9f2cb..56c687d7fa 100644 --- a/source/renderer/backend/gl/Device.cpp +++ b/source/renderer/backend/gl/Device.cpp @@ -820,6 +820,12 @@ std::unique_ptr CDevice::CreateBuffer( return CBuffer::Create(this, name, type, size, dynamic); } +std::unique_ptr CDevice::CreateShaderProgram( + const CStr& name, const CShaderDefines& defines) +{ + return CShaderProgram::Create(this, name, defines); +} + void CDevice::Present() { if (m_Window) diff --git a/source/renderer/backend/gl/Device.h b/source/renderer/backend/gl/Device.h index 5229374af1..c0adb4b623 100644 --- a/source/renderer/backend/gl/Device.h +++ b/source/renderer/backend/gl/Device.h @@ -21,6 +21,7 @@ #include "renderer/backend/Format.h" #include "renderer/backend/gl/Buffer.h" #include "renderer/backend/gl/Framebuffer.h" +#include "renderer/backend/gl/ShaderProgram.h" #include "renderer/backend/gl/Texture.h" #include "scriptinterface/ScriptForward.h" @@ -98,6 +99,9 @@ public: std::unique_ptr CreateBuffer( const char* name, const CBuffer::Type type, const uint32_t size, const bool dynamic); + std::unique_ptr CreateShaderProgram( + const CStr& name, const CShaderDefines& defines); + void Present(); bool IsTextureFormatSupported(const Format format) const; diff --git a/source/renderer/backend/gl/DeviceCommandContext.cpp b/source/renderer/backend/gl/DeviceCommandContext.cpp index 1d41be4345..949aaced70 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.cpp +++ b/source/renderer/backend/gl/DeviceCommandContext.cpp @@ -24,6 +24,7 @@ #include "renderer/backend/gl/Device.h" #include "renderer/backend/gl/Framebuffer.h" #include "renderer/backend/gl/Mapping.h" +#include "renderer/backend/gl/ShaderProgram.h" #include "renderer/backend/gl/Texture.h" #include @@ -413,6 +414,28 @@ void CDeviceCommandContext::ResetStates() void CDeviceCommandContext::SetGraphicsPipelineStateImpl( const GraphicsPipelineStateDesc& pipelineStateDesc, const bool force) { + ENSURE(!m_InsidePass); + + if (m_GraphicsPipelineStateDesc.shaderProgram != pipelineStateDesc.shaderProgram) + { + CShaderProgram* currentShaderProgram = nullptr; + if (m_GraphicsPipelineStateDesc.shaderProgram) + { + currentShaderProgram = + static_cast(m_GraphicsPipelineStateDesc.shaderProgram); + } + CShaderProgram* nextShaderProgram = nullptr; + if (pipelineStateDesc.shaderProgram) + { + nextShaderProgram = + static_cast(pipelineStateDesc.shaderProgram); + } + if (nextShaderProgram) + nextShaderProgram->Bind(currentShaderProgram); + else if (currentShaderProgram) + currentShaderProgram->Unbind(); + } + const DepthStencilStateDesc& currentDepthStencilStateDesc = m_GraphicsPipelineStateDesc.depthStencilState; const DepthStencilStateDesc& nextDepthStencilStateDesc = pipelineStateDesc.depthStencilState; if (force || currentDepthStencilStateDesc.depthTestEnabled != nextDepthStencilStateDesc.depthTestEnabled) @@ -740,9 +763,23 @@ void CDeviceCommandContext::SetIndexBufferData(const void* data) m_IndexBufferData = data; } +void CDeviceCommandContext::BeginPass() +{ + ENSURE(!m_InsidePass); + m_InsidePass = true; +} + +void CDeviceCommandContext::EndPass() +{ + ENSURE(m_InsidePass); + m_InsidePass = false; +} + void CDeviceCommandContext::Draw( const uint32_t firstVertex, const uint32_t vertexCount) { + ENSURE(m_GraphicsPipelineStateDesc.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) @@ -753,6 +790,8 @@ void CDeviceCommandContext::Draw( void CDeviceCommandContext::DrawIndexed( const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset) { + ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_InsidePass); if (indexCount == 0) return; ENSURE(m_IndexBuffer || m_IndexBufferData); @@ -772,6 +811,8 @@ void CDeviceCommandContext::DrawIndexedInRange( const uint32_t firstIndex, const uint32_t indexCount, const uint32_t start, const uint32_t end) { + ENSURE(m_GraphicsPipelineStateDesc.shaderProgram); + ENSURE(m_InsidePass); if (indexCount == 0) return; ENSURE(m_IndexBuffer || m_IndexBufferData); diff --git a/source/renderer/backend/gl/DeviceCommandContext.h b/source/renderer/backend/gl/DeviceCommandContext.h index e47c545511..44062fc95b 100644 --- a/source/renderer/backend/gl/DeviceCommandContext.h +++ b/source/renderer/backend/gl/DeviceCommandContext.h @@ -88,6 +88,9 @@ public: void SetIndexBuffer(CBuffer* buffer); void SetIndexBufferData(const void* data); + void BeginPass(); + void EndPass(); + void Draw(const uint32_t firstVertex, const uint32_t vertexCount); void DrawIndexed( const uint32_t firstIndex, const uint32_t indexCount, const int32_t vertexOffset); @@ -130,6 +133,8 @@ private: CBuffer* m_IndexBuffer = nullptr; const void* m_IndexBufferData = nullptr; + bool m_InsidePass = false; + uint32_t m_ActiveTextureUnit = 0; using BindUnit = std::pair; std::array m_BoundTextures; diff --git a/source/renderer/backend/gl/ShaderProgram.cpp b/source/renderer/backend/gl/ShaderProgram.cpp new file mode 100644 index 0000000000..f5dba1f364 --- /dev/null +++ b/source/renderer/backend/gl/ShaderProgram.cpp @@ -0,0 +1,1243 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#include "precompiled.h" + +#include "ShaderProgram.h" + +#include "graphics/Color.h" +#include "graphics/PreprocessorWrapper.h" +#include "graphics/ShaderManager.h" +#include "graphics/TextureManager.h" +#include "lib/timer.h" +#include "maths/Matrix3D.h" +#include "maths/Vector3D.h" +#include "ps/CLogger.h" +#include "ps/Filesystem.h" +#include "ps/Profile.h" +#include "ps/XML/Xeromyces.h" +#include "renderer/backend/gl/Device.h" +#include "renderer/backend/gl/DeviceCommandContext.h" + +#define USE_SHADER_XML_VALIDATION 1 + +#if USE_SHADER_XML_VALIDATION +#include "ps/XML/RelaxNG.h" +#include "ps/XML/XMLWriter.h" +#endif + +#include + +TIMER_ADD_CLIENT(tc_ShaderProgramValidation); + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +namespace +{ + +GLint GLSizeFromFormat(const Renderer::Backend::Format format) +{ + GLint size = 1; + if (format == Renderer::Backend::Format::R32_SFLOAT || + format == Renderer::Backend::Format::R16_SINT) + size = 1; + else if ( + format == Renderer::Backend::Format::R8G8_UNORM || + format == Renderer::Backend::Format::R8G8_UINT || + format == Renderer::Backend::Format::R16G16_SINT || + format == Renderer::Backend::Format::R32G32_SFLOAT) + size = 2; + else if (format == Renderer::Backend::Format::R32G32B32_SFLOAT) + size = 3; + else if ( + format == Renderer::Backend::Format::R32G32B32A32_SFLOAT || + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UINT) + size = 4; + else + debug_warn("Unsupported format."); + return size; +} + +GLenum GLTypeFromFormat(const Renderer::Backend::Format format) +{ + GLenum type = GL_FLOAT; + if (format == Renderer::Backend::Format::R32_SFLOAT || + format == Renderer::Backend::Format::R32G32_SFLOAT || + format == Renderer::Backend::Format::R32G32B32_SFLOAT || + format == Renderer::Backend::Format::R32G32B32A32_SFLOAT) + type = GL_FLOAT; + else if ( + format == Renderer::Backend::Format::R16_SINT || + format == Renderer::Backend::Format::R16G16_SINT) + type = GL_SHORT; + else if ( + format == Renderer::Backend::Format::R8G8_UNORM || + format == Renderer::Backend::Format::R8G8_UINT || + format == Renderer::Backend::Format::R8G8B8A8_UNORM || + format == Renderer::Backend::Format::R8G8B8A8_UINT) + type = GL_UNSIGNED_BYTE; + else + debug_warn("Unsupported format."); + return type; +} + +GLenum ParseAttribSemantics(const CStr& str) +{ + // Map known semantics onto the attribute locations documented by NVIDIA + if (str == "gl_Vertex") return 0; + if (str == "gl_Normal") return 2; + if (str == "gl_Color") return 3; + if (str == "gl_SecondaryColor") return 4; + if (str == "gl_FogCoord") return 5; + if (str == "gl_MultiTexCoord0") return 8; + if (str == "gl_MultiTexCoord1") return 9; + if (str == "gl_MultiTexCoord2") return 10; + if (str == "gl_MultiTexCoord3") return 11; + if (str == "gl_MultiTexCoord4") return 12; + if (str == "gl_MultiTexCoord5") return 13; + if (str == "gl_MultiTexCoord6") return 14; + if (str == "gl_MultiTexCoord7") return 15; + + debug_warn("Invalid attribute semantics"); + return 0; +} + +} // anonymous namespace + +#if !CONFIG2_GLES + +class CShaderProgramARB : public CShaderProgram +{ +public: + CShaderProgramARB( + CDevice* device, + const VfsPath& vertexFile, const VfsPath& fragmentFile, + const CShaderDefines& defines, + const std::map& vertexIndexes, const std::map& fragmentIndexes, + int streamflags) : + CShaderProgram(streamflags), + m_Device(device), + m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), + m_Defines(defines), + m_VertexIndexes(vertexIndexes), m_FragmentIndexes(fragmentIndexes) + { + glGenProgramsARB(1, &m_VertexProgram); + glGenProgramsARB(1, &m_FragmentProgram); + + Load(); + } + + ~CShaderProgramARB() override + { + Unload(); + + glDeleteProgramsARB(1, &m_VertexProgram); + glDeleteProgramsARB(1, &m_FragmentProgram); + } + + bool Compile(GLuint target, const char* targetName, GLuint program, const VfsPath& file, const CStr& code) + { + ogl_WarnIfError(); + + glBindProgramARB(target, program); + + ogl_WarnIfError(); + + glProgramStringARB(target, GL_PROGRAM_FORMAT_ASCII_ARB, (GLsizei)code.length(), code.c_str()); + + if (ogl_SquelchError(GL_INVALID_OPERATION)) + { + GLint errPos = 0; + glGetIntegerv(GL_PROGRAM_ERROR_POSITION_ARB, &errPos); + int errLine = std::count(code.begin(), code.begin() + std::min((int)code.length(), errPos + 1), '\n') + 1; + char* errStr = (char*)glGetString(GL_PROGRAM_ERROR_STRING_ARB); + LOGERROR("Failed to compile %s program '%s' (line %d):\n%s", targetName, file.string8(), errLine, errStr); + return false; + } + + glBindProgramARB(target, 0); + + ogl_WarnIfError(); + + return true; + } + + void Load() + { + CVFSFile vertexFile; + if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) + return; + + CVFSFile fragmentFile; + if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) + return; + + CPreprocessorWrapper preprocessor; + preprocessor.AddDefines(m_Defines); + + CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); + CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); + + // TODO: replace by scoped bind. + m_Device->GetActiveCommandContext()->SetGraphicsPipelineState( + MakeDefaultGraphicsPipelineStateDesc()); + + if (!Compile(GL_VERTEX_PROGRAM_ARB, "vertex", m_VertexProgram, m_VertexFile, vertexCode)) + return; + + if (!Compile(GL_FRAGMENT_PROGRAM_ARB, "fragment", m_FragmentProgram, m_FragmentFile, fragmentCode)) + return; + } + + void Unload() + { + } + + void Bind(CShaderProgram* previousShaderProgram) override + { + if (previousShaderProgram) + previousShaderProgram->Unbind(); + + glBindProgramARB(GL_VERTEX_PROGRAM_ARB, m_VertexProgram); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, m_FragmentProgram); + + BindClientStates(); + } + + void Unbind() override + { + glBindProgramARB(GL_VERTEX_PROGRAM_ARB, 0); + glBindProgramARB(GL_FRAGMENT_PROGRAM_ARB, 0); + + UnbindClientStates(); + + // TODO: should unbind textures, probably + } + + int GetUniformVertexIndex(CStrIntern id) + { + std::map::iterator it = m_VertexIndexes.find(id); + if (it == m_VertexIndexes.end()) + return -1; + return it->second; + } + + frag_index_pair_t GetUniformFragmentIndex(CStrIntern id) + { + std::map::iterator it = m_FragmentIndexes.find(id); + if (it == m_FragmentIndexes.end()) + return std::make_pair(-1, 0); + return it->second; + } + + Binding GetTextureBinding(texture_id_t id) override + { + frag_index_pair_t fPair = GetUniformFragmentIndex(id); + int index = fPair.first; + if (index == -1) + return Binding(); + else + return Binding((int)fPair.second, index); + } + + void BindTexture(texture_id_t id, GLuint tex) override + { + frag_index_pair_t fPair = GetUniformFragmentIndex(id); + int index = fPair.first; + if (index != -1) + { + m_Device->GetActiveCommandContext()->BindTexture(index, fPair.second, tex); + } + } + + void BindTexture(Binding id, GLuint tex) override + { + int index = id.second; + if (index != -1) + { + m_Device->GetActiveCommandContext()->BindTexture(index, id.first, tex); + } + } + + Binding GetUniformBinding(uniform_id_t id) override + { + return Binding(GetUniformVertexIndex(id), GetUniformFragmentIndex(id).first); + } + + void Uniform(Binding id, float v0, float v1, float v2, float v3) override + { + if (id.first != -1) + glProgramLocalParameter4fARB(GL_VERTEX_PROGRAM_ARB, (GLuint)id.first, v0, v1, v2, v3); + + if (id.second != -1) + glProgramLocalParameter4fARB(GL_FRAGMENT_PROGRAM_ARB, (GLuint)id.second, v0, v1, v2, v3); + } + + void Uniform(Binding id, const CMatrix3D& v) 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); + } + + if (id.second != -1) + { + 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); + } + } + + void Uniform(Binding id, size_t count, const CMatrix3D* v) override + { + ENSURE(count == 1); + Uniform(id, v[0]); + } + + void Uniform(Binding id, size_t count, const float* v) override + { + ENSURE(count == 4); + Uniform(id, v[0], v[1], v[2], v[3]); + } + + std::vector GetFileDependencies() const override + { + return {m_VertexFile, m_FragmentFile}; + } + +private: + CDevice* m_Device = nullptr; + + VfsPath m_VertexFile; + VfsPath m_FragmentFile; + CShaderDefines m_Defines; + + GLuint m_VertexProgram; + GLuint m_FragmentProgram; + + std::map m_VertexIndexes; + + // pair contains + std::map m_FragmentIndexes; +}; + +#endif // #if !CONFIG2_GLES + +////////////////////////////////////////////////////////////////////////// + +TIMER_ADD_CLIENT(tc_ShaderGLSLCompile); +TIMER_ADD_CLIENT(tc_ShaderGLSLLink); + +class CShaderProgramGLSL : public CShaderProgram +{ +public: + CShaderProgramGLSL( + CDevice* device, + const VfsPath& vertexFile, const VfsPath& fragmentFile, + const CShaderDefines& defines, + const std::map& vertexAttribs, + int streamflags) : + CShaderProgram(streamflags), + m_Device(device), + m_VertexFile(vertexFile), m_FragmentFile(fragmentFile), + m_Defines(defines), m_VertexAttribs(vertexAttribs) + { + for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + m_ActiveVertexAttributes.emplace_back(it->second); + std::sort(m_ActiveVertexAttributes.begin(), m_ActiveVertexAttributes.end()); + m_Program = 0; + m_VertexShader = glCreateShader(GL_VERTEX_SHADER); + m_FragmentShader = glCreateShader(GL_FRAGMENT_SHADER); + m_FileDependencies = {m_VertexFile, m_FragmentFile}; + + Load(); + } + + ~CShaderProgramGLSL() override + { + Unload(); + + glDeleteShader(m_VertexShader); + glDeleteShader(m_FragmentShader); + } + + bool Compile(GLhandleARB shader, const VfsPath& file, const CStr& code) + { + TIMER_ACCRUE(tc_ShaderGLSLCompile); + + ogl_WarnIfError(); + + const char* code_string = code.c_str(); + GLint code_length = code.length(); + glShaderSource(shader, 1, &code_string, &code_length); + + glCompileShader(shader); + + GLint ok = 0; + glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); + + GLint length = 0; + glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length); + + // Apparently sometimes GL_INFO_LOG_LENGTH is incorrectly reported as 0 + // (http://code.google.com/p/android/issues/detail?id=9953) + if (!ok && length == 0) + length = 4096; + + if (length > 1) + { + char* infolog = new char[length]; + glGetShaderInfoLog(shader, length, NULL, infolog); + + if (ok) + LOGMESSAGE("Info when compiling shader '%s':\n%s", file.string8(), infolog); + else + LOGERROR("Failed to compile shader '%s':\n%s", file.string8(), infolog); + + delete[] infolog; + } + + ogl_WarnIfError(); + + return (ok ? true : false); + } + + bool Link() + { + TIMER_ACCRUE(tc_ShaderGLSLLink); + + ENSURE(!m_Program); + m_Program = glCreateProgram(); + + glAttachShader(m_Program, m_VertexShader); + ogl_WarnIfError(); + glAttachShader(m_Program, m_FragmentShader); + ogl_WarnIfError(); + + // Set up the attribute bindings explicitly, since apparently drivers + // don't always pick the most efficient bindings automatically, + // and also this lets us hardcode indexes into VertexPointer etc + for (std::map::iterator it = m_VertexAttribs.begin(); it != m_VertexAttribs.end(); ++it) + glBindAttribLocation(m_Program, it->second, it->first.c_str()); + + glLinkProgram(m_Program); + + GLint ok = 0; + glGetProgramiv(m_Program, GL_LINK_STATUS, &ok); + + GLint length = 0; + glGetProgramiv(m_Program, GL_INFO_LOG_LENGTH, &length); + + if (!ok && length == 0) + length = 4096; + + if (length > 1) + { + char* infolog = new char[length]; + glGetProgramInfoLog(m_Program, length, NULL, infolog); + + if (ok) + LOGMESSAGE("Info when linking program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); + else + LOGERROR("Failed to link program '%s'+'%s':\n%s", m_VertexFile.string8(), m_FragmentFile.string8(), infolog); + + delete[] infolog; + } + + ogl_WarnIfError(); + + if (!ok) + return false; + + m_Uniforms.clear(); + m_Samplers.clear(); + + Bind(nullptr); + + ogl_WarnIfError(); + + GLint numUniforms = 0; + glGetProgramiv(m_Program, GL_ACTIVE_UNIFORMS, &numUniforms); + ogl_WarnIfError(); + for (GLint i = 0; i < numUniforms; ++i) + { + char name[256] = {0}; + GLsizei nameLength = 0; + GLint size = 0; + GLenum type = 0; + glGetActiveUniform(m_Program, i, ARRAY_SIZE(name), &nameLength, &size, &type, name); + ogl_WarnIfError(); + + GLint loc = glGetUniformLocation(m_Program, name); + + CStrIntern nameIntern(name); + m_Uniforms[nameIntern] = std::make_pair(loc, type); + + // Assign sampler uniforms to sequential texture units + if (type == GL_SAMPLER_2D + || type == GL_SAMPLER_CUBE +#if !CONFIG2_GLES + || type == GL_SAMPLER_2D_SHADOW +#endif + ) + { + int unit = (int)m_Samplers.size(); + m_Samplers[nameIntern].first = (type == GL_SAMPLER_CUBE ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D); + m_Samplers[nameIntern].second = unit; + glUniform1i(loc, unit); // link uniform to unit + ogl_WarnIfError(); + } + } + + // TODO: verify that we're not using more samplers than is supported + + Unbind(); + + ogl_WarnIfError(); + + return true; + } + + void Load() + { + CVFSFile vertexFile; + if (vertexFile.Load(g_VFS, m_VertexFile) != PSRETURN_OK) + return; + + CVFSFile fragmentFile; + if (fragmentFile.Load(g_VFS, m_FragmentFile) != PSRETURN_OK) + return; + + std::vector newFileDependencies = {m_VertexFile, m_FragmentFile}; + + CPreprocessorWrapper preprocessor([&newFileDependencies](const CStr& includePath, CStr& out) -> bool { + const VfsPath includeFilePath(L"shaders/glsl/" + wstring_from_utf8(includePath)); + // Add dependencies anyway to reload the shader when the file is + // appeared. + newFileDependencies.push_back(includeFilePath); + CVFSFile includeFile; + if (includeFile.Load(g_VFS, includeFilePath) != PSRETURN_OK) + return false; + out = includeFile.GetAsString(); + return true; + }); + preprocessor.AddDefines(m_Defines); + +#if CONFIG2_GLES + // GLES defines the macro "GL_ES" in its GLSL preprocessor, + // but since we run our own preprocessor first, we need to explicitly + // define it here + preprocessor.AddDefine("GL_ES", "1"); +#endif + + CStr vertexCode = preprocessor.Preprocess(vertexFile.GetAsString()); + CStr fragmentCode = preprocessor.Preprocess(fragmentFile.GetAsString()); + + m_FileDependencies = std::move(newFileDependencies); + + if (vertexCode.empty()) + LOGERROR("Failed to preprocess vertex shader: '%s'", m_VertexFile.string8()); + if (fragmentCode.empty()) + LOGERROR("Failed to preprocess fragment shader: '%s'", m_FragmentFile.string8()); + +#if CONFIG2_GLES + // Ugly hack to replace desktop GLSL 1.10/1.20 with GLSL ES 1.00, + // and also to set default float precision for fragment shaders + vertexCode.Replace("#version 110\n", "#version 100\n"); + vertexCode.Replace("#version 110\r\n", "#version 100\n"); + vertexCode.Replace("#version 120\n", "#version 100\n"); + vertexCode.Replace("#version 120\r\n", "#version 100\n"); + fragmentCode.Replace("#version 110\n", "#version 100\nprecision mediump float;\n"); + fragmentCode.Replace("#version 110\r\n", "#version 100\nprecision mediump float;\n"); + fragmentCode.Replace("#version 120\n", "#version 100\nprecision mediump float;\n"); + fragmentCode.Replace("#version 120\r\n", "#version 100\nprecision mediump float;\n"); +#endif + + // TODO: replace by scoped bind. + m_Device->GetActiveCommandContext()->SetGraphicsPipelineState( + MakeDefaultGraphicsPipelineStateDesc()); + + if (!Compile(m_VertexShader, m_VertexFile, vertexCode)) + return; + + if (!Compile(m_FragmentShader, m_FragmentFile, fragmentCode)) + return; + + if (!Link()) + return; + } + + void Unload() + { + if (m_Program) + glDeleteProgram(m_Program); + m_Program = 0; + + // The shader objects can be reused and don't need to be deleted here + } + + void Bind(CShaderProgram* previousShaderProgram) override + { + CShaderProgramGLSL* previousShaderProgramGLSL = nullptr; + if (previousShaderProgram) + previousShaderProgramGLSL = static_cast(previousShaderProgram); + ENSURE(this != previousShaderProgramGLSL); + + glUseProgram(m_Program); + + if (previousShaderProgramGLSL) + { + std::vector::iterator itPrevious = previousShaderProgramGLSL->m_ActiveVertexAttributes.begin(); + std::vector::iterator itNext = m_ActiveVertexAttributes.begin(); + while ( + itPrevious != previousShaderProgramGLSL->m_ActiveVertexAttributes.end() || + itNext != m_ActiveVertexAttributes.end()) + { + if (itPrevious != previousShaderProgramGLSL->m_ActiveVertexAttributes.end() && + itNext != m_ActiveVertexAttributes.end()) + { + if (*itPrevious == *itNext) + { + ++itPrevious; + ++itNext; + } + else if (*itPrevious < *itNext) + { + glDisableVertexAttribArray(*itPrevious); + ++itPrevious; + } + else if (*itPrevious > *itNext) + { + glEnableVertexAttribArray(*itNext); + ++itNext; + } + } + else if (itPrevious != previousShaderProgramGLSL->m_ActiveVertexAttributes.end()) + { + glDisableVertexAttribArray(*itPrevious); + ++itPrevious; + } + else if (itNext != m_ActiveVertexAttributes.end()) + { + glEnableVertexAttribArray(*itNext); + ++itNext; + } + } + } + else + { + for (const int index : m_ActiveVertexAttributes) + glEnableVertexAttribArray(index); + } + } + + void Unbind() override + { + glUseProgram(0); + + for (const int index : m_ActiveVertexAttributes) + glDisableVertexAttribArray(index); + + // TODO: should unbind textures, probably + } + + Binding GetTextureBinding(texture_id_t id) 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); + } + + void BindTexture(texture_id_t id, GLuint tex) 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); + } + + void BindTexture(Binding id, GLuint tex) override + { + if (id.second == -1) + 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); + } + + void Uniform(Binding id, float v0, float v1, float v2, float v3) override + { + if (id.first != -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)"); + } + } + + void Uniform(Binding id, const CMatrix3D& v) override + { + if (id.first != -1) + { + if (id.second == GL_FLOAT_MAT4) + glUniformMatrix4fv(id.first, 1, GL_FALSE, &v._11); + else + LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); + } + } + + void Uniform(Binding id, size_t count, const CMatrix3D* v) override + { + if (id.first != -1) + { + if (id.second == GL_FLOAT_MAT4) + glUniformMatrix4fv(id.first, count, GL_FALSE, &v->_11); + else + LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected mat4)"); + } + } + + void Uniform(Binding id, size_t count, const float* v) override + { + if (id.first != -1) + { + if (id.second == GL_FLOAT) + glUniform1fv(id.first, count, v); + else + LOGERROR("CShaderProgramGLSL::Uniform(): Invalid uniform type (expected float)"); + } + } + + // Map the various fixed-function Pointer functions onto generic vertex attributes + // (matching the attribute indexes from ShaderManager's ParseAttribSemantics): + + void VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override + { + const GLint size = GLSizeFromFormat(format); + const GLenum type = GLTypeFromFormat(format); + glVertexAttribPointer(0, size, type, GL_FALSE, stride, pointer); + m_ValidStreams |= STREAM_POS; + } + + void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override + { + const GLint size = GLSizeFromFormat(format); + const GLenum type = GLTypeFromFormat(format); + glVertexAttribPointer(2, size, type, (type == GL_FLOAT ? GL_FALSE : GL_TRUE), stride, pointer); + m_ValidStreams |= STREAM_NORMAL; + } + + void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override + { + const GLint size = GLSizeFromFormat(format); + const GLenum type = GLTypeFromFormat(format); + glVertexAttribPointer(3, size, type, (type == GL_FLOAT ? GL_FALSE : GL_TRUE), stride, pointer); + m_ValidStreams |= STREAM_COLOR; + } + + void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer) override + { + const GLint size = GLSizeFromFormat(format); + const GLenum type = GLTypeFromFormat(format); + glVertexAttribPointer(8 + texture - GL_TEXTURE0, size, type, GL_FALSE, stride, pointer); + m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); + } + + void VertexAttribPointer(attrib_id_t id, const Renderer::Backend::Format format, GLboolean normalized, GLsizei stride, const void* pointer) override + { + std::map::iterator it = m_VertexAttribs.find(id); + if (it != m_VertexAttribs.end()) + { + const GLint size = GLSizeFromFormat(format); + const GLenum type = GLTypeFromFormat(format); + glVertexAttribPointer(it->second, size, type, normalized, stride, pointer); + } + } + + std::vector GetFileDependencies() const override + { + return m_FileDependencies; + } + +private: + CDevice* m_Device = nullptr; + + VfsPath m_VertexFile; + VfsPath m_FragmentFile; + std::vector m_FileDependencies; + CShaderDefines m_Defines; + std::map m_VertexAttribs; + // Sorted list of active vertex attributes. + std::vector m_ActiveVertexAttributes; + + GLhandleARB m_Program; + GLhandleARB m_VertexShader; + GLhandleARB m_FragmentShader; + + std::map> m_Uniforms; + std::map> m_Samplers; // texture target & unit chosen for each uniform sampler +}; + +////////////////////////////////////////////////////////////////////////// + +CShaderProgram::CShaderProgram(int streamflags) + : m_StreamFlags(streamflags), m_ValidStreams(0) +{ +} + +CShaderProgram::~CShaderProgram() = default; + +// static +std::unique_ptr CShaderProgram::Create(CDevice* device, const CStr& name, const CShaderDefines& baseDefines) +{ + PROFILE2("loading shader"); + PROFILE2_ATTR("name: %s", name.c_str()); + + VfsPath xmlFilename = L"shaders/" + wstring_from_utf8(name) + L".xml"; + + CXeromyces XeroFile; + PSRETURN ret = XeroFile.Load(g_VFS, xmlFilename); + if (ret != PSRETURN_OK) + return nullptr; + +#if USE_SHADER_XML_VALIDATION + { + TIMER_ACCRUE(tc_ShaderProgramValidation); + + // Serialize the XMB data and pass it to the validator + XMLWriter_File shaderFile; + shaderFile.SetPrettyPrint(false); + shaderFile.XMB(XeroFile); + bool ok = CXeromyces::ValidateEncoded("shader", name, shaderFile.GetOutput()); + if (!ok) + return nullptr; + } +#endif + + // Define all the elements and attributes used in the XML file +#define EL(x) int el_##x = XeroFile.GetElementID(#x) +#define AT(x) int at_##x = XeroFile.GetAttributeID(#x) + EL(attrib); + EL(define); + EL(fragment); + EL(stream); + EL(uniform); + EL(vertex); + AT(file); + AT(if); + AT(loc); + AT(name); + AT(semantics); + AT(type); + AT(value); +#undef AT +#undef EL + + CPreprocessorWrapper preprocessor; + preprocessor.AddDefines(baseDefines); + + XMBElement root = XeroFile.GetRoot(); + + VfsPath vertexFile; + VfsPath fragmentFile; + CShaderDefines defines = baseDefines; + std::map vertexUniforms; + std::map fragmentUniforms; + std::map vertexAttribs; + int streamFlags = 0; + + XERO_ITER_EL(root, Child) + { + if (Child.GetNodeName() == el_define) + { + defines.Add(CStrIntern(Child.GetAttributes().GetNamedItem(at_name)), CStrIntern(Child.GetAttributes().GetNamedItem(at_value))); + } + else if (Child.GetNodeName() == el_vertex) + { + vertexFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); + + XERO_ITER_EL(Child, Param) + { + XMBAttributeList Attrs = Param.GetAttributes(); + + CStr cond = Attrs.GetNamedItem(at_if); + if (!cond.empty() && !preprocessor.TestConditional(cond)) + continue; + + if (Param.GetNodeName() == el_uniform) + { + vertexUniforms[CStrIntern(Attrs.GetNamedItem(at_name))] = Attrs.GetNamedItem(at_loc).ToInt(); + } + else if (Param.GetNodeName() == el_stream) + { + CStr StreamName = Attrs.GetNamedItem(at_name); + if (StreamName == "pos") + streamFlags |= STREAM_POS; + else if (StreamName == "normal") + streamFlags |= STREAM_NORMAL; + else if (StreamName == "color") + streamFlags |= STREAM_COLOR; + else if (StreamName == "uv0") + streamFlags |= STREAM_UV0; + else if (StreamName == "uv1") + streamFlags |= STREAM_UV1; + else if (StreamName == "uv2") + streamFlags |= STREAM_UV2; + else if (StreamName == "uv3") + streamFlags |= STREAM_UV3; + } + else if (Param.GetNodeName() == el_attrib) + { + int attribLoc = ParseAttribSemantics(Attrs.GetNamedItem(at_semantics)); + vertexAttribs[CStrIntern(Attrs.GetNamedItem(at_name))] = attribLoc; + } + } + } + else if (Child.GetNodeName() == el_fragment) + { + fragmentFile = L"shaders/" + Child.GetAttributes().GetNamedItem(at_file).FromUTF8(); + + XERO_ITER_EL(Child, Param) + { + XMBAttributeList Attrs = Param.GetAttributes(); + + CStr cond = Attrs.GetNamedItem(at_if); + if (!cond.empty() && !preprocessor.TestConditional(cond)) + continue; + + 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; + CStr t = Attrs.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(Attrs.GetNamedItem(at_name))] = + std::make_pair(Attrs.GetNamedItem(at_loc).ToInt(), type); + } + } + } + } + + if (root.GetAttributes().GetNamedItem(at_type) == "glsl") + return CShaderProgram::ConstructGLSL(device, 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; +} +#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); +} +#endif + +// static +std::unique_ptr CShaderProgram::ConstructGLSL( + CDevice* device, const VfsPath& vertexFile, const VfsPath& fragmentFile, + const CShaderDefines& defines, + const std::map& vertexAttribs, int streamflags) +{ + return std::make_unique( + device, vertexFile, fragmentFile, defines, vertexAttribs, streamflags); +} + +int CShaderProgram::GetStreamFlags() const +{ + return m_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: + +void CShaderProgram::VertexAttribPointer(attrib_id_t UNUSED(id), const Renderer::Backend::Format UNUSED(format), + GLboolean UNUSED(normalized), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("Shader type doesn't support VertexAttribPointer"); +} + +#if CONFIG2_GLES + +// These should all be overridden by CShaderProgramGLSL +// (GLES doesn't support any other types of shader program): + +void CShaderProgram::VertexPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::VertexPointer should be overridden"); +} +void CShaderProgram::NormalPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::NormalPointer should be overridden"); +} +void CShaderProgram::ColorPointer(const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::ColorPointer should be overridden"); +} +void CShaderProgram::TexCoordPointer(GLenum UNUSED(texture), const Renderer::Backend::Format UNUSED(format), GLsizei UNUSED(stride), const void* UNUSED(pointer)) +{ + debug_warn("CShaderProgram::TexCoordPointer should be overridden"); +} + +#else + +// These are overridden by CShaderProgramGLSL, but fixed-function and ARB shaders +// both use the fixed-function vertex attribute pointers so we'll share their +// definitions here: + +void CShaderProgram::VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + const GLint size = GLSizeFromFormat(format); + ENSURE(2 <= size && size <= 4); + const GLenum type = GLTypeFromFormat(format); + glVertexPointer(size, type, stride, pointer); + m_ValidStreams |= STREAM_POS; +} + +void CShaderProgram::NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + ENSURE(format == Renderer::Backend::Format::R32G32B32_SFLOAT); + glNormalPointer(GL_FLOAT, stride, pointer); + m_ValidStreams |= STREAM_NORMAL; +} + +void CShaderProgram::ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + const GLint size = GLSizeFromFormat(format); + ENSURE(3 <= size && size <= 4); + const GLenum type = GLTypeFromFormat(format); + glColorPointer(size, type, stride, pointer); + m_ValidStreams |= STREAM_COLOR; +} + +void CShaderProgram::TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer) +{ + glClientActiveTextureARB(texture); + const GLint size = GLSizeFromFormat(format); + ENSURE(1 <= size && size <= 4); + const GLenum type = GLTypeFromFormat(format); + glTexCoordPointer(size, type, stride, pointer); + glClientActiveTextureARB(GL_TEXTURE0); + m_ValidStreams |= STREAM_UV0 << (texture - GL_TEXTURE0); +} + +void CShaderProgram::BindClientStates() +{ + ENSURE(m_StreamFlags == (m_StreamFlags & (STREAM_POS|STREAM_NORMAL|STREAM_COLOR|STREAM_UV0|STREAM_UV1))); + + // Enable all the desired client states for non-GLSL rendering + + if (m_StreamFlags & STREAM_POS) glEnableClientState(GL_VERTEX_ARRAY); + if (m_StreamFlags & STREAM_NORMAL) glEnableClientState(GL_NORMAL_ARRAY); + if (m_StreamFlags & STREAM_COLOR) glEnableClientState(GL_COLOR_ARRAY); + + if (m_StreamFlags & STREAM_UV0) + { + glClientActiveTextureARB(GL_TEXTURE0); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (m_StreamFlags & STREAM_UV1) + { + glClientActiveTextureARB(GL_TEXTURE1); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0); + } + + // Rendering code must subsequently call VertexPointer etc for all of the streams + // that were activated in this function, else AssertPointersBound will complain + // that some arrays were unspecified + m_ValidStreams = 0; +} + +void CShaderProgram::UnbindClientStates() +{ + if (m_StreamFlags & STREAM_POS) glDisableClientState(GL_VERTEX_ARRAY); + if (m_StreamFlags & STREAM_NORMAL) glDisableClientState(GL_NORMAL_ARRAY); + if (m_StreamFlags & STREAM_COLOR) glDisableClientState(GL_COLOR_ARRAY); + + if (m_StreamFlags & STREAM_UV0) + { + glClientActiveTextureARB(GL_TEXTURE0); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + } + + if (m_StreamFlags & STREAM_UV1) + { + glClientActiveTextureARB(GL_TEXTURE1); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + glClientActiveTextureARB(GL_TEXTURE0); + } +} + +#endif // !CONFIG2_GLES + +void CShaderProgram::AssertPointersBound() +{ + ENSURE((m_StreamFlags & ~m_ValidStreams) == 0); +} + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer diff --git a/source/renderer/backend/gl/ShaderProgram.h b/source/renderer/backend/gl/ShaderProgram.h new file mode 100644 index 0000000000..7642a30808 --- /dev/null +++ b/source/renderer/backend/gl/ShaderProgram.h @@ -0,0 +1,216 @@ +/* Copyright (C) 2022 Wildfire Games. + * This file is part of 0 A.D. + * + * 0 A.D. is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 of the License, or + * (at your option) any later version. + * + * 0 A.D. is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with 0 A.D. If not, see . + */ + +#ifndef INCLUDED_RENDERER_BACKEND_GL_SHADERPROGRAM +#define INCLUDED_RENDERER_BACKEND_GL_SHADERPROGRAM + +#include "lib/ogl.h" +#include "lib/file/vfs/vfs_path.h" +#include "ps/CStrForward.h" +#include "renderer/backend/Format.h" +#include "renderer/backend/gl/Texture.h" +#include "renderer/backend/IShaderProgram.h" + +#include +#include + +struct CColor; +class CMatrix3D; +class CVector3D; +class CShaderDefines; +class CStrIntern; + +// Vertex data stream flags +enum +{ + STREAM_POS = (1 << 0), + STREAM_NORMAL = (1 << 1), + STREAM_COLOR = (1 << 2), + STREAM_UV0 = (1 << 3), + STREAM_UV1 = (1 << 4), + STREAM_UV2 = (1 << 5), + STREAM_UV3 = (1 << 6) +}; + +namespace Renderer +{ + +namespace Backend +{ + +namespace GL +{ + +class CDevice; + +/** + * A compiled vertex+fragment shader program. + * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax) + * or GL_ARB_{vertex,fragment}_shader (GLSL), or may use hard-coded fixed-function + * multitexturing setup code; the difference is hidden from the caller. + * + * 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. + * Setting uniforms that the shader .xml doesn't support is harmless. + * + * For a high-level overview of shaders and materials, see + * http://trac.wildfiregames.com/wiki/MaterialSystem + */ +class CShaderProgram : public IShaderProgram +{ + NONCOPYABLE(CShaderProgram); + +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; + }; + + ~CShaderProgram() override; + + /** + * Binds the shader into the GL context. Call this before calling Uniform() + * or trying to render with it. + */ + virtual void Bind(CShaderProgram* previousShaderProgram) = 0; + + /** + * Unbinds the shader from the GL context. Call this after rendering with it. + */ + virtual void Unbind() = 0; + + /** + * Returns bitset of STREAM_* value, indicating what vertex data streams the + * vertex shader needs (e.g. position, color, UV, ...). + */ + int GetStreamFlags() const; + + + 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 VertexPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + virtual void NormalPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + virtual void ColorPointer(const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + virtual void TexCoordPointer(GLenum texture, const Renderer::Backend::Format format, GLsizei stride, const void* pointer); + virtual void VertexAttribPointer(attrib_id_t id, const Renderer::Backend::Format format, GLboolean normalized, GLsizei stride, const void* pointer); + + /** + * Checks that all the required vertex attributes have been set. + * Call this before calling Draw/DrawIndexed etc to avoid potential crashes. + */ + 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 VfsPath& vertexFile, const VfsPath& fragmentFile, + const CShaderDefines& defines, + const std::map& vertexAttribs, + int streamflags); + + 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: + void BindClientStates(); + void UnbindClientStates(); + int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind +}; + +} // namespace GL + +} // namespace Backend + +} // namespace Renderer + +#endif // INCLUDED_RENDERER_BACKEND_GL_SHADERPROGRAM