diff --git a/Tests/LibGL/TestShaders.cpp b/Tests/LibGL/TestShaders.cpp index 94454cb36e..6bbffc033d 100644 --- a/Tests/LibGL/TestShaders.cpp +++ b/Tests/LibGL/TestShaders.cpp @@ -44,10 +44,16 @@ TEST_CASE(0001_program_creation) vertex_shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vertex_shader, 1, &vertex_shader_source, nullptr); glCompileShader(vertex_shader); + GLint vertex_shader_compile_status; + glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &vertex_shader_compile_status); + EXPECT_EQ(vertex_shader_compile_status, GL_TRUE); fragment_shader = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fragment_shader, 1, &fragment_shader_source, nullptr); glCompileShader(fragment_shader); + GLint fragment_shader_compile_status; + glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &fragment_shader_compile_status); + EXPECT_EQ(fragment_shader_compile_status, GL_TRUE); program = glCreateProgram(); glAttachShader(program, vertex_shader); diff --git a/Userland/Libraries/LibGL/GL/gl.h b/Userland/Libraries/LibGL/GL/gl.h index b5c1039bd5..ad34de16b9 100644 --- a/Userland/Libraries/LibGL/GL/gl.h +++ b/Userland/Libraries/LibGL/GL/gl.h @@ -603,6 +603,11 @@ extern "C" { // Programmable pipeline #define GL_FRAGMENT_SHADER 0x8B30 #define GL_VERTEX_SHADER 0x8B31 +#define GL_SHADER_TYPE 0x8B4F +#define GL_DELETE_STATUS 0x8B80 +#define GL_COMPILE_STATUS 0x8B81 +#define GL_INFO_LOG_LENGTH 0x8B84 +#define GL_SHADER_SOURCE_LENGTH 0x8B88 GLAPI void glBegin(GLenum mode); GLAPI void glClear(GLbitfield mask); @@ -820,6 +825,7 @@ GLAPI GLuint glCreateShader(GLenum shader_type); GLAPI void glDeleteShader(GLuint shader); GLAPI void glShaderSource(GLuint shader, GLsizei count, GLchar const** string, GLint const* length); GLAPI void glCompileShader(GLuint shader); +GLAPI void glGetShaderiv(GLuint shader, GLenum pname, GLint* params); GLAPI GLuint glCreateProgram(); GLAPI void glDeleteProgram(GLuint program); diff --git a/Userland/Libraries/LibGL/GLAPI.cpp b/Userland/Libraries/LibGL/GLAPI.cpp index 8d41f1f8fc..ab6e464a0a 100644 --- a/Userland/Libraries/LibGL/GLAPI.cpp +++ b/Userland/Libraries/LibGL/GLAPI.cpp @@ -504,6 +504,11 @@ GLubyte const* glGetString(GLenum name) return g_gl_context->gl_get_string(name); } +void glGetShaderiv(GLuint shader, GLenum pname, GLint* params) +{ + g_gl_context->gl_get_shader(shader, pname, params); +} + void glGetTexImage(GLenum target, GLint level, GLenum format, GLenum type, void* pixels) { g_gl_context->gl_get_tex_image(target, level, format, type, pixels); diff --git a/Userland/Libraries/LibGL/GLContext.h b/Userland/Libraries/LibGL/GLContext.h index b773078a34..3d5431609e 100644 --- a/Userland/Libraries/LibGL/GLContext.h +++ b/Userland/Libraries/LibGL/GLContext.h @@ -234,6 +234,7 @@ public: void gl_delete_shader(GLuint shader); void gl_shader_source(GLuint shader, GLsizei count, GLchar const** string, GLint const* length); void gl_compile_shader(GLuint shader); + void gl_get_shader(GLuint shader, GLenum pname, GLint* params); GLuint gl_create_program(); void gl_delete_program(GLuint program); diff --git a/Userland/Libraries/LibGL/Shader.cpp b/Userland/Libraries/LibGL/Shader.cpp index 014c558ce0..611191be2d 100644 --- a/Userland/Libraries/LibGL/Shader.cpp +++ b/Userland/Libraries/LibGL/Shader.cpp @@ -70,6 +70,48 @@ void GLContext::gl_compile_shader(GLuint shader) (void)it->value->compile(); } +void GLContext::gl_get_shader(GLuint shader, GLenum pname, GLint* params) +{ + RETURN_WITH_ERROR_IF(pname != GL_SHADER_TYPE + && pname != GL_DELETE_STATUS + && pname != GL_COMPILE_STATUS + && pname != GL_INFO_LOG_LENGTH + && pname != GL_SHADER_SOURCE_LENGTH, + GL_INVALID_ENUM); + + // FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL." + // FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPILE_STATUS, GL_INFO_LOG_LENGTH, or GL_SHADER_SOURCE_LENGTH but a shader compiler is not supported." + + auto it = m_allocated_shaders.find(shader); + RETURN_WITH_ERROR_IF(it == m_allocated_shaders.end(), GL_INVALID_OPERATION); + + switch (pname) { + case GL_SHADER_TYPE: + *params = it->value->type(); + break; + + case GL_DELETE_STATUS: + // FIXME: Return the actual delete status once we implement this missing feature + *params = GL_FALSE; + break; + + case GL_COMPILE_STATUS: + *params = it->value->compile_status() ? GL_TRUE : GL_FALSE; + break; + + case GL_INFO_LOG_LENGTH: + *params = it->value->info_log_length(); + break; + + case GL_SHADER_SOURCE_LENGTH: + *params = it->value->combined_source_length(); + break; + + default: + VERIFY_NOT_REACHED(); + } +} + GLuint GLContext::gl_create_program() { GLuint program_name; diff --git a/Userland/Libraries/LibGL/Shaders/Shader.cpp b/Userland/Libraries/LibGL/Shaders/Shader.cpp index 7a78e94ba3..8de48e6e07 100644 --- a/Userland/Libraries/LibGL/Shaders/Shader.cpp +++ b/Userland/Libraries/LibGL/Shaders/Shader.cpp @@ -28,4 +28,26 @@ ErrorOr Shader::compile() return {}; } +size_t Shader::info_log_length() const +{ + if (!m_info_log.has_value()) + return 0; + + // Per the spec we return the size including the null terminator + return m_info_log.value().bytes().size() + 1; +} + +size_t Shader::combined_source_length() const +{ + if (m_sources.is_empty()) + return 0; + + size_t combined_size = 0; + for (auto source : m_sources) + combined_size += source.bytes().size(); + + // Per the spec we return the size including the null terminator + return combined_size + 1; +} + } diff --git a/Userland/Libraries/LibGL/Shaders/Shader.h b/Userland/Libraries/LibGL/Shaders/Shader.h index af1575b6e8..108298c33a 100644 --- a/Userland/Libraries/LibGL/Shaders/Shader.h +++ b/Userland/Libraries/LibGL/Shaders/Shader.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include @@ -27,6 +28,9 @@ public: GLenum type() const { return m_type; } bool compile_status() const { return m_compile_status; } + size_t info_log_length() const; + size_t combined_source_length() const; + private: explicit Shader(GLenum shader_type) : m_type { shader_type } @@ -36,6 +40,7 @@ private: Vector m_sources; GLenum m_type; bool m_compile_status { false }; + Optional m_info_log; }; }