16#include "OpenGLPipeline.hpp"
17#include "OpenGLFunctions.hpp"
18#include "aeongames/CRC.hpp"
27 mOpenGLRenderer{aOpenGLPipeline.mOpenGLRenderer}
29 std::swap ( mPipeline, aOpenGLPipeline.mPipeline );
30 std::swap ( mProgramId, aOpenGLPipeline.mProgramId );
31 mAttributes.swap ( aOpenGLPipeline.mAttributes );
32 mUniformBlocks.swap ( aOpenGLPipeline.mUniformBlocks );
33 mSamplerLocations.swap ( aOpenGLPipeline.mSamplerLocations );
36 static const std::unordered_map<ShaderType, const GLenum> ShaderTypeToGLShaderType
38 {
VERT, GL_VERTEX_SHADER },
39 {
FRAG, GL_FRAGMENT_SHADER },
40 {
COMP, GL_COMPUTE_SHADER },
41 {
TESC, GL_TESS_CONTROL_SHADER },
42 {
TESE, GL_TESS_EVALUATION_SHADER },
43 {
GEOM, GL_GEOMETRY_SHADER }
47 mOpenGLRenderer{aOpenGLRenderer}, mPipeline{&aPipeline}
49 mProgramId = glCreateProgram();
50 OPENGL_CHECK_ERROR_THROW;
54 std::array<std::string_view, ShaderType::COUNT> shader_codes =
64 std::array<uint32_t, ShaderType::COUNT> shader_ids =
66 shader_codes.at (
VERT ).empty() ? 0 : glCreateShader ( ShaderTypeToGLShaderType.at (
VERT ) ),
67 shader_codes.at (
FRAG ).empty() ? 0 : glCreateShader ( ShaderTypeToGLShaderType.at (
FRAG ) ),
68 shader_codes.at (
COMP ).empty() ? 0 : glCreateShader ( ShaderTypeToGLShaderType.at (
COMP ) ),
69 shader_codes.at (
TESC ).empty() ? 0 : glCreateShader ( ShaderTypeToGLShaderType.at (
TESC ) ),
70 shader_codes.at (
TESE ).empty() ? 0 : glCreateShader ( ShaderTypeToGLShaderType.at (
TESE ) ),
71 shader_codes.at (
GEOM ).empty() ? 0 : glCreateShader ( ShaderTypeToGLShaderType.at (
GEOM ) )
73 OPENGL_CHECK_ERROR_THROW;
76 for (
size_t i = 0; i < shader_codes.size(); ++i )
78 if ( shader_ids.at ( i ) == 0 )
82 const auto* source_ptr =
reinterpret_cast<const GLchar *
> ( shader_codes.at ( i ).data() );
83 auto source_len =
static_cast<GLint
> ( shader_codes.at ( i ).length() );
90 OPENGL_CHECK_ERROR_THROW;
92 glCompileShader ( shader_ids.at ( i ) );
93 OPENGL_CHECK_ERROR_THROW;
94 glGetShaderiv ( shader_ids.at ( i ), GL_COMPILE_STATUS, &compile_status );
95 OPENGL_CHECK_ERROR_THROW;
96 if ( compile_status != GL_TRUE )
99 glGetShaderiv ( shader_ids.at ( i ), GL_INFO_LOG_LENGTH, &info_log_len );
100 OPENGL_CHECK_ERROR_THROW;
101 std::string log_string;
102 log_string.resize ( info_log_len );
103 if ( info_log_len > 1 )
105 glGetShaderInfoLog ( shader_ids.at ( i ), info_log_len,
nullptr,
const_cast<GLchar*
> ( log_string.data() ) );
106 OPENGL_CHECK_ERROR_THROW;
107 std::cout << shader_codes.at ( i ) << std::endl;
108 std::cout << log_string << std::endl;
110 throw std::runtime_error ( log_string.c_str() );
113 std::cout <<
LogLevel::Error <<
"Error Compiling Shaders." << std::endl;
114 throw std::runtime_error (
"Error Compiling Shaders." );
116 glAttachShader ( mProgramId, shader_ids.at ( i ) );
117 OPENGL_CHECK_ERROR_THROW;
121 glLinkProgram ( mProgramId );
122 OPENGL_CHECK_ERROR_THROW;
123 glGetProgramiv ( mProgramId, GL_LINK_STATUS, &link_status );
124 OPENGL_CHECK_ERROR_THROW;
125 if ( link_status != GL_TRUE )
128 glGetProgramiv ( mProgramId, GL_INFO_LOG_LENGTH, &info_log_len );
129 OPENGL_CHECK_ERROR_THROW;
130 std::string log_string;
131 log_string.resize ( info_log_len );
132 if ( info_log_len > 1 )
134 glGetProgramInfoLog ( mProgramId, info_log_len,
nullptr,
const_cast<GLchar*
> ( log_string.data() ) );
135 for (
const auto& shader_code : shader_codes )
137 if ( shader_code.empty() )
141 std::cout << shader_code << std::endl;
143 std::cout << log_string << std::endl;
144 OPENGL_CHECK_ERROR_THROW;
147 for (
const auto& shader_id : shader_ids )
149 if ( shader_id == 0 )
153 glDetachShader ( mProgramId, shader_id );
154 OPENGL_CHECK_ERROR_THROW;
155 glDeleteShader ( shader_id );
156 OPENGL_CHECK_ERROR_THROW;
162 void OpenGLPipeline::ReflectAttributes()
165 GLint active_attribute_count{};
171 glGetProgramiv ( mProgramId, GL_ACTIVE_ATTRIBUTES, &active_attribute_count );
172 OPENGL_CHECK_ERROR_THROW;
173 mAttributes.reserve ( active_attribute_count );
174 for ( GLint i = 0; i < active_attribute_count; ++i )
176 glGetActiveAttrib ( mProgramId, i,
sizeof ( name ), &length, &size, &type, name );
177 OPENGL_CHECK_ERROR_THROW;
178 location = glGetAttribLocation ( mProgramId, name );
179 OPENGL_CHECK_ERROR_THROW;
185 const uint32_t name_crc{
crc32i ( name, length ) };
186 auto it = std::lower_bound ( mAttributes.begin(), mAttributes.end(), name_crc,
187 [] (
const OpenGLVariable & a,
const uint32_t b )
191 mAttributes.insert ( it, { name_crc, {location}, size, type } );
193 for (
const auto& attribute : mAttributes )
195 std::cout <<
LogLevel::Debug <<
"Attribute: " << attribute.name <<
" (crc: " << std::hex << attribute.name << std::dec <<
", location: " << attribute.location <<
", size: " << attribute.size <<
", type: " << attribute.type <<
")" << std::endl;
199 void OpenGLPipeline::ReflectUniforms()
201 mSamplerLocations.clear();
202 mUniformBlocks.clear();
203 GLint block_uniform_count{};
204 GLint uniform_block_count = 0;
205 glGetProgramiv ( mProgramId, GL_ACTIVE_UNIFORM_BLOCKS, &uniform_block_count );
206 OPENGL_CHECK_ERROR_THROW;
213 GLint binding_offset_or_location{};
215 mUniformBlocks.reserve ( uniform_block_count );
216 for ( GLint i = 0; i < uniform_block_count; ++i )
218 glGetActiveUniformBlockName ( mProgramId, i,
sizeof ( name ), &length, name );
219 OPENGL_CHECK_ERROR_THROW;
220 glGetActiveUniformBlockiv ( mProgramId, i, GL_UNIFORM_BLOCK_DATA_SIZE, &size );
221 OPENGL_CHECK_ERROR_THROW;
222 glGetActiveUniformBlockiv ( mProgramId, i, GL_UNIFORM_BLOCK_BINDING, &binding_offset_or_location );
223 OPENGL_CHECK_ERROR_THROW;
224 glGetActiveUniformBlockiv ( mProgramId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORMS, &block_uniform_count );
225 OPENGL_CHECK_ERROR_THROW;
226 assert ( block_uniform_count <= 64 );
228 const uint32_t name_crc{
crc32i ( name, length ) };
229 auto it = std::lower_bound ( mUniformBlocks.begin(), mUniformBlocks.end(), name_crc,
230 [] (
const OpenGLUniformBlock & a,
const uint32_t b )
234 mUniformBlocks.insert ( it, { name_crc, size, binding_offset_or_location } );
236 it->uniforms.reserve ( block_uniform_count );
237 if ( block_uniform_count > 0 )
239 glGetActiveUniformBlockiv ( mProgramId, i, GL_UNIFORM_BLOCK_ACTIVE_UNIFORM_INDICES, indices );
240 OPENGL_CHECK_ERROR_THROW;
241 for ( GLint j = 0; j < block_uniform_count; ++j )
243 GLuint uniform_index =
static_cast<GLuint
> ( indices[
static_cast<size_t> ( j ) ] );
244 glGetActiveUniform ( mProgramId, uniform_index,
sizeof ( name ), &length, &size, &type, name );
245 OPENGL_CHECK_ERROR_THROW;
247 glGetActiveUniformsiv ( mProgramId, 1, &uniform_index, GL_UNIFORM_OFFSET, &binding_offset_or_location );
248 OPENGL_CHECK_ERROR_THROW;
250 uint32_t name_crc{
crc32i ( name, length ) };
251 auto il = std::lower_bound ( it->uniforms.begin(), it->uniforms.end(), name_crc,
252 [] (
const OpenGLVariable & a,
const uint32_t b )
256 it->uniforms.insert ( il, { name_crc, {binding_offset_or_location}, size, type } );
262 GLint sampler_count{0};
263 glGetProgramiv ( mProgramId, GL_ACTIVE_UNIFORMS, &uniform_count );
264 OPENGL_CHECK_ERROR_THROW;
265 for ( GLint i = 0; i < uniform_count; ++i )
267 glGetActiveUniform ( mProgramId, i,
sizeof ( name ), &length, &size, &type, name );
268 OPENGL_CHECK_ERROR_THROW;
269 sampler_count += ( type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_3D ||
270 type == GL_SAMPLER_2D_ARRAY || type == GL_SAMPLER_2D_SHADOW || type == GL_SAMPLER_CUBE_SHADOW ) ? 1 : 0;
272 mSamplerLocations.reserve ( sampler_count );
273 for ( GLint i = 0; i < uniform_count; ++i )
275 glGetActiveUniform ( mProgramId, i,
sizeof ( name ), &length, &size, &type, name );
276 OPENGL_CHECK_ERROR_THROW;
277 if ( type == GL_SAMPLER_2D || type == GL_SAMPLER_CUBE || type == GL_SAMPLER_3D ||
278 type == GL_SAMPLER_2D_ARRAY || type == GL_SAMPLER_2D_SHADOW || type == GL_SAMPLER_CUBE_SHADOW )
280 binding_offset_or_location = glGetUniformLocation ( mProgramId, name );
281 OPENGL_CHECK_ERROR_THROW;
282 uint32_t name_crc{
crc32i ( name, length ) };
283 auto il = std::lower_bound ( mSamplerLocations.begin(), mSamplerLocations.end(), name_crc,
284 [] (
const OpenGLSamplerLocation & a,
const uint32_t b )
288 mSamplerLocations.insert ( il, { name_crc, binding_offset_or_location } );
292 for (
const auto& sampler : mSamplerLocations )
294 std::cout <<
LogLevel::Debug <<
"Sampler: " << sampler.name <<
" (crc: " << std::hex << sampler.name << std::dec <<
", location: " << sampler.location <<
")" << std::endl;
296 for (
const auto& block : mUniformBlocks )
298 std::cout <<
LogLevel::Debug <<
"Uniform Block: " << block.name <<
" (crc: " << std::hex << block.name << std::dec <<
", size: " << block.size <<
", binding: " << block.binding <<
", active uniforms: " << block.uniforms.size() <<
")" << std::endl;
299 for (
const auto& uniform : block.uniforms )
301 std::cout <<
LogLevel::Debug <<
"\tUniform: " << uniform.name <<
" (crc: " << std::hex << uniform.name << std::dec <<
", offset: " << uniform.offset <<
", size: " << uniform.size <<
", type: " << uniform.type <<
")" << std::endl;
306 OpenGLPipeline::~OpenGLPipeline()
308 if ( glIsProgram ( mProgramId ) )
310 OPENGL_CHECK_ERROR_NO_THROW;
311 glDeleteProgram ( mProgramId );
312 OPENGL_CHECK_ERROR_NO_THROW;
315 OPENGL_CHECK_ERROR_NO_THROW;
330 auto it = std::lower_bound ( mSamplerLocations.begin(), mSamplerLocations.end(), name_hash,
335 if ( it == mSamplerLocations.end() || it->location < 0 )
344 auto it = std::lower_bound ( mUniformBlocks.begin(), mUniformBlocks.end(), name,
349 if ( it == mUniformBlocks.end() )
OpenGLPipeline(const OpenGLRenderer &aOpenGLRenderer, const Pipeline &aPipeline)
Construct from a renderer and pipeline resource.
GLint GetProgramId() const
Get the linked shader program identifier.
const OpenGLUniformBlock * GetUniformBlock(uint32_t name) const
Get a uniform block by its name hash, or nullptr if not found.
const std::vector< OpenGLVariable > & GetVertexAttributes() const
Get the reflected vertex attribute descriptions.
const GLuint GetSamplerLocation(uint32_t name_hash) const
Get the uniform location of a sampler by its name hash.
OpenGL rendering backend implementing the Renderer interface.
Rendering pipeline resource.
DLL const std::string_view GetShaderCode(ShaderType aType) const
Get the shader source code for the given shader stage.
<- This is here just for the literals
uint32_t crc32i(const char *message, size_t size, uint32_t previous_crc)
Compute the CRC32 of a given message, continuing from a previous CRC value.
const std::unordered_map< ShaderType, const char * > ShaderTypeToString
Map from ShaderType enum values to human-readable string names.
ShaderType
Shader stage types.
@ TESC
Tessellation control shader.
@ TESE
Tessellation evaluation shader.
@ Debug
Detailed diagnostic information.
Maps a sampler name hash to its OpenGL uniform location.