2022-08-27 18:07:07 +02:00
/*
* Copyright ( c ) 2022 , Stephan Unverwerth < s . unverwerth @ serenityos . org >
*
* SPDX - License - Identifier : BSD - 2 - Clause
*/
2022-08-28 11:12:31 +02:00
# include <AK/StringBuilder.h>
2022-08-27 18:07:07 +02:00
# include <LibGL/GLContext.h>
namespace GL {
GLuint GLContext : : gl_create_shader ( GLenum shader_type )
{
2022-08-28 10:51:37 +02:00
// FIXME: Add support for GL_COMPUTE_SHADER, GL_TESS_CONTROL_SHADER, GL_TESS_EVALUATION_SHADER and GL_GEOMETRY_SHADER.
RETURN_VALUE_WITH_ERROR_IF ( shader_type ! = GL_VERTEX_SHADER
& & shader_type ! = GL_FRAGMENT_SHADER ,
GL_INVALID_ENUM ,
0 ) ;
GLuint shader_name ;
m_shader_name_allocator . allocate ( 1 , & shader_name ) ;
auto shader = Shader : : create ( shader_type ) ;
m_allocated_shaders . set ( shader_name , shader ) ;
return shader_name ;
2022-08-27 18:07:07 +02:00
}
void GLContext : : gl_delete_shader ( GLuint shader )
{
2022-08-28 10:51:37 +02:00
// "A value of 0 for shader will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteShader.xhtml)
if ( shader = = 0 )
return ;
auto it = m_allocated_shaders . find ( shader ) ;
RETURN_WITH_ERROR_IF ( it = = m_allocated_shaders . end ( ) , GL_INVALID_VALUE ) ;
// FIXME: According to the spec, we should only flag the shader for deletion here and delete it once it is detached from all programs.
m_allocated_shaders . remove ( it ) ;
m_shader_name_allocator . free ( shader ) ;
2022-08-27 18:07:07 +02:00
}
void GLContext : : gl_shader_source ( GLuint shader , GLsizei count , GLchar const * * string , GLint const * length )
{
2022-08-28 11:12:31 +02:00
auto it = m_allocated_shaders . find ( shader ) ;
// FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL."
RETURN_WITH_ERROR_IF ( it = = m_allocated_shaders . end ( ) , GL_INVALID_OPERATION ) ;
RETURN_WITH_ERROR_IF ( count < 0 , GL_INVALID_VALUE ) ;
it - > value - > clear_sources ( ) ;
for ( int i = 0 ; i < count ; i + + ) {
if ( length = = nullptr | | length [ i ] < 0 ) {
auto result = it - > value - > add_source ( StringView ( string [ i ] , strlen ( string [ i ] ) ) ) ;
RETURN_WITH_ERROR_IF ( result . is_error ( ) & & result . error ( ) . is_errno ( ) & & result . error ( ) . code ( ) = = ENOMEM , GL_OUT_OF_MEMORY ) ;
RETURN_WITH_ERROR_IF ( result . is_error ( ) , GL_INVALID_OPERATION ) ;
} else {
auto result = it - > value - > add_source ( StringView ( string [ i ] , length [ i ] ) ) ;
RETURN_WITH_ERROR_IF ( result . is_error ( ) & & result . error ( ) . is_errno ( ) & & result . error ( ) . code ( ) = = ENOMEM , GL_OUT_OF_MEMORY ) ;
RETURN_WITH_ERROR_IF ( result . is_error ( ) , GL_INVALID_OPERATION ) ;
}
}
2022-08-27 18:07:07 +02:00
}
void GLContext : : gl_compile_shader ( GLuint shader )
{
2022-08-28 11:19:36 +02:00
auto it = m_allocated_shaders . find ( shader ) ;
// FIXME: implement check "GL_INVALID_VALUE is generated if shader is not a value generated by OpenGL."
RETURN_WITH_ERROR_IF ( it = = m_allocated_shaders . end ( ) , GL_INVALID_OPERATION ) ;
// NOTE: We are ignoring the compilation result here since it is tracked inside the shader object
( void ) it - > value - > compile ( ) ;
2022-08-27 18:07:07 +02:00
}
2022-08-28 16:19:42 +02:00
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 ( ) ;
}
}
2022-08-27 18:07:07 +02:00
GLuint GLContext : : gl_create_program ( )
{
2022-08-28 10:57:07 +02:00
GLuint program_name ;
m_program_name_allocator . allocate ( 1 , & program_name ) ;
auto program = Program : : create ( ) ;
m_allocated_programs . set ( program_name , program ) ;
return program_name ;
2022-08-27 18:07:07 +02:00
}
void GLContext : : gl_delete_program ( GLuint program )
{
2022-08-28 10:57:07 +02:00
// "A value of 0 for program will be silently ignored." (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glDeleteProgram.xhtml)
if ( program = = 0 )
return ;
auto it = m_allocated_programs . find ( program ) ;
RETURN_WITH_ERROR_IF ( it = = m_allocated_programs . end ( ) , GL_INVALID_VALUE ) ;
// FIXME: According to the spec, we should only flag the program for deletion here and delete it once it is not used anymore.
m_allocated_programs . remove ( it ) ;
m_program_name_allocator . free ( program ) ;
2022-08-27 18:07:07 +02:00
}
void GLContext : : gl_attach_shader ( GLuint program , GLuint shader )
{
2022-08-28 11:47:58 +02:00
auto program_it = m_allocated_programs . find ( program ) ;
auto shader_it = m_allocated_shaders . find ( shader ) ;
// FIXME: implement check "GL_INVALID_VALUE is generated if either program or shader is not a value generated by OpenGL."
RETURN_WITH_ERROR_IF ( program_it = = m_allocated_programs . end ( ) , GL_INVALID_OPERATION ) ;
RETURN_WITH_ERROR_IF ( shader_it = = m_allocated_shaders . end ( ) , GL_INVALID_OPERATION ) ;
// NOTE: attach_result is Error if the shader is already attached to this program
auto attach_result = program_it - > value - > attach_shader ( * shader_it - > value ) ;
RETURN_WITH_ERROR_IF ( attach_result . is_error ( ) & & attach_result . error ( ) . is_errno ( ) & & attach_result . error ( ) . code ( ) = = ENOMEM , GL_OUT_OF_MEMORY ) ;
RETURN_WITH_ERROR_IF ( attach_result . is_error ( ) , GL_INVALID_OPERATION ) ;
2022-08-27 18:07:07 +02:00
}
void GLContext : : gl_link_program ( GLuint program )
{
2022-08-28 12:04:18 +02:00
auto program_it = m_allocated_programs . find ( program ) ;
// FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL."
RETURN_WITH_ERROR_IF ( program_it = = m_allocated_programs . end ( ) , GL_INVALID_OPERATION ) ;
// FIXME: implement check "GL_INVALID_OPERATION is generated if program is the currently active program object and transform feedback mode is active."
// NOTE: We are ignoring the link result since this is tracked inside the program object
2022-09-14 23:48:10 +02:00
( void ) program_it - > value - > link ( * m_rasterizer ) ;
2022-08-27 18:07:07 +02:00
}
2022-08-28 15:39:44 +02:00
void GLContext : : gl_use_program ( GLuint program )
{
if ( program = = 0 ) {
m_current_program = nullptr ;
return ;
}
auto it = m_allocated_programs . find ( program ) ;
// FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL."
RETURN_WITH_ERROR_IF ( it = = m_allocated_programs . end ( ) , GL_INVALID_OPERATION ) ;
// FIXME: implement check "GL_INVALID_OPERATION is generated if transform feedback mode is active."
RETURN_WITH_ERROR_IF ( it - > value - > link_status ( ) ! = true , GL_INVALID_OPERATION ) ;
m_current_program = it - > value ;
}
2022-08-28 16:34:17 +02:00
void GLContext : : gl_get_program ( GLuint program , GLenum pname , GLint * params )
{
auto it = m_allocated_programs . find ( program ) ;
// FIXME: implement check "GL_INVALID_VALUE is generated if program is not a value generated by OpenGL."
RETURN_WITH_ERROR_IF ( it = = m_allocated_programs . end ( ) , GL_INVALID_OPERATION ) ;
// FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_GEOMETRY_VERTICES_OUT, GL_GEOMETRY_INPUT_TYPE, or GL_GEOMETRY_OUTPUT_TYPE, and program does not contain a geometry shader."
// FIXME: implement all the other allowed pname values (https://registry.khronos.org/OpenGL-Refpages/gl4/html/glGetProgram.xhtml)
RETURN_WITH_ERROR_IF ( pname ! = GL_DELETE_STATUS
& & pname ! = GL_LINK_STATUS
& & pname ! = GL_INFO_LOG_LENGTH ,
GL_INVALID_ENUM ) ;
// FIXME: implement check "GL_INVALID_OPERATION is generated if pname is GL_COMPUTE_WORK_GROUP_SIZE and program does not contain a binary for the compute shader stage."
switch ( pname ) {
case GL_DELETE_STATUS :
// FIXME: Return the actual delete status once we implement this missing feature
* params = GL_FALSE ;
break ;
case GL_LINK_STATUS :
* params = it - > value - > link_status ( ) ? GL_TRUE : GL_FALSE ;
break ;
case GL_INFO_LOG_LENGTH :
* params = it - > value - > info_log_length ( ) ;
break ;
default :
VERIFY_NOT_REACHED ( ) ;
}
}
2022-08-27 18:07:07 +02:00
}