1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
|
/*
* Copyright (c) 2022, Stephan Unverwerth <s.unverwerth@serenityos.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include <AK/StringBuilder.h>
#include <LibGL/GLContext.h>
namespace GL {
GLuint GLContext::gl_create_shader(GLenum shader_type)
{
// 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;
}
void GLContext::gl_delete_shader(GLuint shader)
{
// "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);
}
void GLContext::gl_shader_source(GLuint shader, GLsizei count, GLchar const** string, GLint const* length)
{
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);
}
}
}
void GLContext::gl_compile_shader(GLuint shader)
{
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();
}
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;
m_program_name_allocator.allocate(1, &program_name);
auto program = Program::create();
m_allocated_programs.set(program_name, program);
return program_name;
}
void GLContext::gl_delete_program(GLuint program)
{
// "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);
}
void GLContext::gl_attach_shader(GLuint program, GLuint shader)
{
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);
}
void GLContext::gl_link_program(GLuint program)
{
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
(void)program_it->value->link(*m_rasterizer);
}
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;
}
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();
}
}
}
|