Skip to content

Commit

Permalink
Added shader permutations to GL backend to better emulate clip space …
Browse files Browse the repository at this point in the history
…control (in case of missing GL_ARB_clip_control).
  • Loading branch information
LukasBanana committed Jul 29, 2023
1 parent 9439578 commit b6e99d6
Show file tree
Hide file tree
Showing 18 changed files with 413 additions and 169 deletions.
48 changes: 38 additions & 10 deletions sources/Renderer/OpenGL/RenderState/GLPipelineState.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,23 @@ GLPipelineState::GLPipelineState(
:
isGraphicsPSO_ { isGraphicsPSO }
{
/* Create shader pipeline */
shaderPipeline_ = GLStatePool::Get().CreateShaderPipeline(shaders.size(), shaders.data());
shaderPipeline_->QueryInfoLogs(report_);
for_range(permutationIndex, GLShader::PermutationCount)
{
const GLShader::Permutation permutation = static_cast<GLShader::Permutation>(permutationIndex);
if (GLShader::HasAnyShaderPermutation(permutation, shaders))
{
/* Create shader pipeline for current permutation */
shaderPipelines_[permutation] = GLStatePool::Get().CreateShaderPipeline(shaders.size(), shaders.data(), permutation);

/* Query information log and stop linking shader pipelines if the default permutation has errors */
if (permutation == GLShader::PermutationDefault)
{
shaderPipelines_[GLShader::PermutationDefault]->QueryInfoLogs(report_);
if (report_.HasErrors())
break;
}
}
}

/* Create shader binding layout by binding descriptor */
if (pipelineLayout != nullptr)
Expand All @@ -43,13 +57,18 @@ GLPipelineState::GLPipelineState(
}

/* Build uniform table */
BuildUniformMap(pipelineLayout_->GetUniforms());
for_range(permutationIndex, GLShader::PermutationCount)
{
const GLShader::Permutation permutation = static_cast<GLShader::Permutation>(permutationIndex);
BuildUniformMap(permutation, pipelineLayout_->GetUniforms());
}
}
}

GLPipelineState::~GLPipelineState()
{
GLStatePool::Get().ReleaseShaderPipeline(std::move(shaderPipeline_));
for (auto& shaderPipeline : shaderPipelines_)
GLStatePool::Get().ReleaseShaderPipeline(std::move(shaderPipeline));
GLStatePool::Get().ReleaseShaderBindingLayout(std::move(shaderBindingLayout_));
}

Expand All @@ -60,12 +79,21 @@ const Report* GLPipelineState::GetReport() const

void GLPipelineState::Bind(GLStateManager& stateMngr)
{
/* Select shader pipeline permutation depending on what is needed for the current framebuffer */
const GLShader::Permutation shaderPipelinePermutation =
(
stateMngr.GetBoundRenderTarget() != nullptr && shaderPipelines_[GLShader::PermutationFlippedYPosition].get() != nullptr
? GLShader::PermutationFlippedYPosition
: GLShader::PermutationDefault
);
GLShaderPipeline* shaderPipeline = shaderPipelines_[shaderPipelinePermutation].get();

/* Bind shader program and discard rasterizer if there is no fragment shader */
shaderPipeline_->Bind(stateMngr);
shaderPipeline->Bind(stateMngr);

/* Update resource slots in shader program (if necessary) */
if (shaderBindingLayout_)
shaderPipeline_->BindResourceSlots(*shaderBindingLayout_);
shaderPipeline->BindResourceSlots(*shaderBindingLayout_);

/* Bind static samplers */
if (pipelineLayout_ != nullptr)
Expand All @@ -78,11 +106,11 @@ void GLPipelineState::Bind(GLStateManager& stateMngr)
*/

//TODO: support separate shaders; each separable shader needs its own set of uniform locations
void GLPipelineState::BuildUniformMap(const std::vector<UniformDescriptor>& uniforms)
void GLPipelineState::BuildUniformMap(GLShader::Permutation permutation, const std::vector<UniformDescriptor>& uniforms)
{
if (!uniforms.empty())
if (shaderPipelines_[permutation].get() != nullptr && !uniforms.empty())
{
const GLuint program = shaderPipeline_->GetID();
const GLuint program = shaderPipelines_[permutation]->GetID();

/* Build uniform locations from input descriptors */
uniformMap_.resize(uniforms.size());
Expand Down
11 changes: 6 additions & 5 deletions sources/Renderer/OpenGL/RenderState/GLPipelineState.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "../OpenGL.h"
#include "../Shader/GLShaderBindingLayout.h"
#include "../Shader/GLShaderPipeline.h"
#include "../Shader/GLShader.h"
#include <LLGL/Report.h>
#include <LLGL/PipelineState.h>
#include <LLGL/RenderSystemFlags.h>
Expand Down Expand Up @@ -69,7 +70,7 @@ class GLPipelineState : public PipelineState
// Returns the shader pipeline used for this PSO.
inline const GLShaderPipeline* GetShaderPipeline() const
{
return shaderPipeline_.get();
return shaderPipelines_[GLShader::PermutationDefault].get();
}

// Returns the list of uniforms that maps from index of 'PipelineLayoutDescriptor::uniforms[]' to GL uniform location.
Expand All @@ -89,16 +90,16 @@ class GLPipelineState : public PipelineState
private:

// Builds the index-to-uniform map.
void BuildUniformMap(const std::vector<UniformDescriptor>& uniforms);
void BuildUniformMap(GLShader::Permutation permutation, const std::vector<UniformDescriptor>& uniforms);

// Builds the specified uniform location.
void BuildUniformLocation(GLuint program, GLUniformLocation& outUniform, const UniformDescriptor& inUniform);

private:

const bool isGraphicsPSO_ = false;
const GLPipelineLayout* pipelineLayout_ = nullptr;
GLShaderPipelineSPtr shaderPipeline_ = nullptr;
const bool isGraphicsPSO_ = false;
const GLPipelineLayout* pipelineLayout_ = nullptr;
GLShaderPipelineSPtr shaderPipelines_[GLShader::PermutationCount];
GLShaderBindingLayoutSPtr shaderBindingLayout_;
std::vector<GLUniformLocation> uniformMap_;
Report report_;
Expand Down
18 changes: 9 additions & 9 deletions sources/Renderer/OpenGL/RenderState/GLStatePool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ std::shared_ptr<T> FindCompatibleStateObject(
const TCompare& compareObject,
std::size_t& index)
{
auto* entry = FindInSortedArray<std::shared_ptr<TBase>>(
std::shared_ptr<TBase>* entry = FindInSortedArray<std::shared_ptr<TBase>>(
container.data(),
container.size(),
[&compareObject](const std::shared_ptr<TBase>& entry) -> int
Expand All @@ -55,11 +55,11 @@ std::shared_ptr<T> CreateRenderStateObjectExt(std::vector<std::shared_ptr<TBase>
const TCompare stateToCompare{ std::forward<Args>(args)... };

std::size_t insertionIndex = 0;
if (auto sharedState = FindCompatibleStateObject<T, TCompare, TBase>(container, stateToCompare, insertionIndex))
if (std::shared_ptr<T> sharedState = FindCompatibleStateObject<T, TCompare, TBase>(container, stateToCompare, insertionIndex))
return sharedState;

/* Allocate new render state object with insertion sort */
auto newState = std::make_shared<T>(std::forward<Args>(args)...);
std::shared_ptr<T> newState = std::make_shared<T>(std::forward<Args>(args)...);
container.insert(container.begin() + insertionIndex, newState);

return newState;
Expand All @@ -72,11 +72,11 @@ std::shared_ptr<T> CreateRenderStateObject(std::vector<std::shared_ptr<T>>& cont
T stateToCompare{ std::forward<Args>(args)... };

std::size_t insertionIndex = 0;
if (auto sharedState = FindCompatibleStateObject<T, T, T>(container, stateToCompare, insertionIndex))
if (std::shared_ptr<T> sharedState = FindCompatibleStateObject<T, T, T>(container, stateToCompare, insertionIndex))
return sharedState;

/* Allocate new render state object with insertion sort */
auto newState = std::make_shared<T>(stateToCompare);
std::shared_ptr<T> newState = std::make_shared<T>(stateToCompare);
container.insert(container.begin() + insertionIndex, newState);

return newState;
Expand All @@ -91,7 +91,7 @@ void ReleaseRenderStateObject(
if (renderState && renderState.use_count() == 2)
{
/* Reset render state */
auto objectRef = renderState.get();
T* objectRef = renderState.get();
renderState.reset();

/* Retrieve entry index in container to remove entry */
Expand Down Expand Up @@ -208,20 +208,20 @@ static bool HasGLSeparableShaders(std::size_t numShaders, Shader* const* shaders
return (numShaders > 0 && IsGLSeparableShader(shaders[0]));
}

GLShaderPipelineSPtr GLStatePool::CreateShaderPipeline(std::size_t numShaders, Shader* const* shaders)
GLShaderPipelineSPtr GLStatePool::CreateShaderPipeline(std::size_t numShaders, Shader* const* shaders, GLShader::Permutation permutation)
{
#ifdef LLGL_OPENGL
if (HasExtension(GLExt::ARB_separate_shader_objects) && HasGLSeparableShaders(numShaders, shaders))
{
return std::static_pointer_cast<GLShaderPipeline>(
CreateRenderStateObjectExt<GLProgramPipeline, GLPipelineSignature>(shaderPipelines_, numShaders, shaders)
CreateRenderStateObjectExt<GLProgramPipeline, GLPipelineSignature>(shaderPipelines_, numShaders, shaders, permutation)
);
}
else
#endif
{
return std::static_pointer_cast<GLShaderPipeline>(
CreateRenderStateObjectExt<GLShaderProgram, GLPipelineSignature>(shaderPipelines_, numShaders, shaders)
CreateRenderStateObjectExt<GLShaderProgram, GLPipelineSignature>(shaderPipelines_, numShaders, shaders, permutation)
);
}
}
Expand Down
3 changes: 2 additions & 1 deletion sources/Renderer/OpenGL/RenderState/GLStatePool.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "GLPipelineLayout.h"
#include "../Shader/GLShaderBindingLayout.h"
#include "../Shader/GLShaderPipeline.h"
#include "../Shader/GLShader.h"
#include <vector>


Expand Down Expand Up @@ -66,7 +67,7 @@ class GLStatePool

/* ----- Shader pipelines ----- */

GLShaderPipelineSPtr CreateShaderPipeline(std::size_t numShaders, Shader* const* shaders);
GLShaderPipelineSPtr CreateShaderPipeline(std::size_t numShaders, Shader* const* shaders, GLShader::Permutation permutation = GLShader::PermutationDefault);
void ReleaseShaderPipeline(GLShaderPipelineSPtr&& shaderPipeline);

private:
Expand Down
60 changes: 43 additions & 17 deletions sources/Renderer/OpenGL/Shader/GLLegacyShader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,7 @@ namespace LLGL
GLLegacyShader::GLLegacyShader(const ShaderDescriptor& desc) :
GLShader { /*isSeparable:*/ false, desc }
{
GLuint id = glCreateShader(GLTypes::Map(desc.type));
SetID(id);
BuildShader(desc);

/* Query compile status and log */
ReportStatusAndLog(
GLLegacyShader::GetCompileStatus(GetID()),
GLLegacyShader::GetGLShaderLog(GetID())
);
}

GLLegacyShader::~GLLegacyShader()
Expand Down Expand Up @@ -92,6 +84,21 @@ std::string GLLegacyShader::GetGLShaderLog(GLuint shader)
* ======= Private: =======
*/

GLuint GLLegacyShader::CreateShaderPermutation(Permutation permutation)
{
GLuint id = glCreateShader(GLTypes::Map(GetType()));
SetID(id, permutation);
return id;
}

bool GLLegacyShader::FinalizeShaderPermutation(Permutation permutation)
{
/* Query compile status and log */
const bool status = GLLegacyShader::GetCompileStatus(GetID());
ReportStatusAndLog(status, GLLegacyShader::GetGLShaderLog(GetID()));
return status;
}

void GLLegacyShader::BuildShader(const ShaderDescriptor& shaderDesc)
{
if (IsShaderSourceCode(shaderDesc.sourceType))
Expand All @@ -102,17 +109,35 @@ void GLLegacyShader::BuildShader(const ShaderDescriptor& shaderDesc)

void GLLegacyShader::CompileSource(const ShaderDescriptor& shaderDesc)
{
GLShader::PatchShaderSource(
[this](const char* source)
auto CompileShaderPermutation = [this, &shaderDesc](Permutation permutation, long enabledFlags) -> bool
{
const GLuint shader = CreateShaderPermutation(permutation);
auto sourceCallback = std::bind(GLLegacyShader::CompileShaderSource, shader, std::placeholders::_1);

if (shaderDesc.sourceType == ShaderSourceType::CodeFile)
{
GLLegacyShader::CompileShaderSource(GetID(), source);
},
shaderDesc
);
const std::string fileContent = ReadFileString(shaderDesc.source);
GLShader::PatchShaderSource(sourceCallback, fileContent.c_str(), shaderDesc, enabledFlags);
}
else
GLShader::PatchShaderSource(sourceCallback, shaderDesc.source, shaderDesc, enabledFlags);

return FinalizeShaderPermutation(permutation);
};

/* Compile and patch default shader permutation */
if (CompileShaderPermutation(PermutationDefault, ShaderCompileFlags::NoOptimization))
{
/* Compile and patch shader permutation for flipped Y-position */
if (GLShader::NeedsPermutationFlippedYPosition(shaderDesc.type, shaderDesc.flags))
CompileShaderPermutation(PermutationFlippedYPosition, ShaderCompileFlags::NoOptimization | ShaderCompileFlags::PatchClippingOrigin);
}
}

void GLLegacyShader::LoadBinary(const ShaderDescriptor& shaderDesc)
{
const GLuint shader = CreateShaderPermutation(PermutationDefault);

#if defined GL_ARB_gl_spirv && defined GL_ARB_ES2_compatibility
if (HasExtension(GLExt::ARB_gl_spirv) && HasExtension(GLExt::ARB_ES2_compatibility))
{
Expand All @@ -136,18 +161,19 @@ void GLLegacyShader::LoadBinary(const ShaderDescriptor& shaderDesc)
}

/* Load shader binary */
const GLuint shaders[] = { GetID() };
glShaderBinary(1, shaders, GL_SHADER_BINARY_FORMAT_SPIR_V, binaryBuffer, binaryLength);
glShaderBinary(1, &shader, GL_SHADER_BINARY_FORMAT_SPIR_V, binaryBuffer, binaryLength);

/* Specialize for the default "main" function in a SPIR-V module */
const char* entryPoint = (shaderDesc.entryPoint == nullptr || *shaderDesc.entryPoint == '\0' ? "main" : shaderDesc.entryPoint);
glSpecializeShader(GetID(), entryPoint, 0, nullptr, nullptr);
glSpecializeShader(shader, entryPoint, 0, nullptr, nullptr);
}
else
#endif
{
LLGL_TRAP_FEATURE_NOT_SUPPORTED("loading binary shader");
}

FinalizeShaderPermutation(PermutationDefault);
}


Expand Down
3 changes: 3 additions & 0 deletions sources/Renderer/OpenGL/Shader/GLLegacyShader.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ class GLLegacyShader final : public GLShader

private:

GLuint CreateShaderPermutation(Permutation permutation);
bool FinalizeShaderPermutation(Permutation permutation);

void BuildShader(const ShaderDescriptor& shaderDesc);
void CompileSource(const ShaderDescriptor& shaderDesc);
void LoadBinary(const ShaderDescriptor& shaderDesc);
Expand Down
Loading

0 comments on commit b6e99d6

Please sign in to comment.