Branch data Line data Source code
1 : : /*
2 : : * This file is part of libplacebo.
3 : : *
4 : : * libplacebo is free software; you can redistribute it and/or
5 : : * modify it under the terms of the GNU Lesser General Public
6 : : * License as published by the Free Software Foundation; either
7 : : * version 2.1 of the License, or (at your option) any later version.
8 : : *
9 : : * libplacebo is distributed in the hope that it will be useful,
10 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 : : * GNU Lesser General Public License for more details.
13 : : *
14 : : * You should have received a copy of the GNU Lesser General Public
15 : : * License along with libplacebo. If not, see <http://www.gnu.org/licenses/>.
16 : : */
17 : :
18 : : #include "gpu.h"
19 : : #include "cache.h"
20 : : #include "formats.h"
21 : : #include "utils.h"
22 : :
23 : 3608 : int gl_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
24 : : {
25 : 3608 : return (int) type;
26 : : }
27 : :
28 : : struct gl_cache_header {
29 : : GLenum format;
30 : : };
31 : :
32 : 332 : static GLuint load_cached_program(pl_gpu gpu, pl_cache cache, pl_cache_obj *obj)
33 : : {
34 : : const gl_funcs *gl = gl_funcs_get(gpu);
35 [ - + ]: 332 : if (!gl_test_ext(gpu, "GL_ARB_get_program_binary", 41, 30))
36 : : return 0;
37 : :
38 [ + + ]: 332 : if (!pl_cache_get(cache, obj))
39 : : return 0;
40 : :
41 [ - + ]: 1 : if (obj->size < sizeof(struct gl_cache_header))
42 : : return 0;
43 : :
44 : 1 : GLuint prog = gl->CreateProgram();
45 [ - + ]: 1 : if (!gl_check_err(gpu, "load_cached_program: glCreateProgram"))
46 : : return 0;
47 : :
48 : 1 : struct gl_cache_header *header = (struct gl_cache_header *) obj->data;
49 [ + - ]: 1 : pl_str rest = (pl_str) { obj->data, obj->size };
50 : : rest = pl_str_drop(rest, sizeof(*header));
51 : 1 : gl->ProgramBinary(prog, header->format, rest.buf, rest.len);
52 : 1 : gl->GetError(); // discard potential useless error
53 : :
54 : 1 : GLint status = 0;
55 : 1 : gl->GetProgramiv(prog, GL_LINK_STATUS, &status);
56 [ - + ]: 1 : if (status)
57 : : return prog;
58 : :
59 : 0 : gl->DeleteProgram(prog);
60 : 0 : gl_check_err(gpu, "load_cached_program: glProgramBinary");
61 : 0 : return 0;
62 : : }
63 : :
64 : : static enum pl_log_level gl_log_level(GLint status, GLint log_length)
65 : : {
66 : 959 : if (!status) {
67 : : return PL_LOG_ERR;
68 [ + - + - ]: 959 : } else if (log_length > 0) {
69 : : return PL_LOG_INFO;
70 : : } else {
71 : 959 : return PL_LOG_DEBUG;
72 : : }
73 : : }
74 : :
75 : 628 : static bool gl_attach_shader(pl_gpu gpu, GLuint program, GLenum type, const char *src)
76 : : {
77 : : const gl_funcs *gl = gl_funcs_get(gpu);
78 : 628 : GLuint shader = gl->CreateShader(type);
79 : 628 : gl->ShaderSource(shader, 1, &src, NULL);
80 : 628 : gl->CompileShader(shader);
81 : :
82 : 628 : GLint status = 0;
83 : 628 : gl->GetShaderiv(shader, GL_COMPILE_STATUS, &status);
84 : 628 : GLint log_length = 0;
85 : 628 : gl->GetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
86 : :
87 [ + - ]: 628 : enum pl_log_level level = gl_log_level(status, log_length);
88 [ + - ]: 628 : if (pl_msg_test(gpu->log, level)) {
89 : 250 : GLchar *logstr = pl_zalloc(NULL, log_length + 1);
90 : 250 : gl->GetShaderInfoLog(shader, log_length, NULL, logstr);
91 : 250 : PL_MSG(gpu, level, "shader compile log (status=%d): %s", status, logstr);
92 : 250 : pl_free(logstr);
93 : : }
94 : :
95 [ + - - + ]: 628 : if (!status || !gl_check_err(gpu, "gl_attach_shader"))
96 : 0 : goto error;
97 : :
98 : 628 : gl->AttachShader(program, shader);
99 : 628 : gl->DeleteShader(shader);
100 : 628 : return true;
101 : :
102 : : error:
103 : 0 : gl->DeleteShader(shader);
104 : 0 : return false;
105 : : }
106 : :
107 : 331 : static GLuint gl_compile_program(pl_gpu gpu, const struct pl_pass_params *params)
108 : : {
109 : : const gl_funcs *gl = gl_funcs_get(gpu);
110 : 331 : GLuint prog = gl->CreateProgram();
111 : : bool ok = true;
112 : :
113 [ + + - - ]: 331 : switch (params->type) {
114 : 34 : case PL_PASS_COMPUTE:
115 : 34 : ok &= gl_attach_shader(gpu, prog, GL_COMPUTE_SHADER, params->glsl_shader);
116 : 34 : break;
117 : 297 : case PL_PASS_RASTER:
118 : 297 : ok &= gl_attach_shader(gpu, prog, GL_VERTEX_SHADER, params->vertex_shader);
119 : 297 : ok &= gl_attach_shader(gpu, prog, GL_FRAGMENT_SHADER, params->glsl_shader);
120 [ + + ]: 913 : for (int i = 0; i < params->num_vertex_attribs; i++)
121 : 616 : gl->BindAttribLocation(prog, i, params->vertex_attribs[i].name);
122 : : break;
123 : : case PL_PASS_INVALID:
124 : : case PL_PASS_TYPE_COUNT:
125 : 0 : pl_unreachable();
126 : : }
127 : :
128 [ + - - + ]: 331 : if (!ok || !gl_check_err(gpu, "gl_compile_program: attach shader"))
129 : 0 : goto error;
130 : :
131 : 331 : gl->LinkProgram(prog);
132 : 331 : GLint status = 0;
133 : 331 : gl->GetProgramiv(prog, GL_LINK_STATUS, &status);
134 : 331 : GLint log_length = 0;
135 : 331 : gl->GetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length);
136 : :
137 [ + - ]: 331 : enum pl_log_level level = gl_log_level(status, log_length);
138 [ + - ]: 331 : if (pl_msg_test(gpu->log, level)) {
139 : 142 : GLchar *logstr = pl_zalloc(NULL, log_length + 1);
140 : 142 : gl->GetProgramInfoLog(prog, log_length, NULL, logstr);
141 : 142 : PL_MSG(gpu, level, "shader link log (status=%d): %s", status, logstr);
142 : 142 : pl_free(logstr);
143 : : }
144 : :
145 [ - + ]: 331 : if (!gl_check_err(gpu, "gl_compile_program: link program"))
146 : 0 : goto error;
147 : :
148 : : return prog;
149 : :
150 : 0 : error:
151 : 0 : gl->DeleteProgram(prog);
152 : 0 : PL_ERR(gpu, "Failed compiling/linking GLSL program");
153 : 0 : return 0;
154 : : }
155 : :
156 : : // For pl_pass.priv
157 : : struct pl_pass_gl {
158 : : GLuint program;
159 : : GLuint vao; // the VAO object
160 : : uint64_t vao_id; // buf_gl.id of VAO
161 : : size_t vao_offset; // VBO offset of VAO
162 : : GLuint buffer; // VBO for raw vertex pointers
163 : : GLuint index_buffer;
164 : : GLint *var_locs;
165 : : };
166 : :
167 : 332 : void gl_pass_destroy(pl_gpu gpu, pl_pass pass)
168 : : {
169 : : const gl_funcs *gl = gl_funcs_get(gpu);
170 : : if (!MAKE_CURRENT()) {
171 : 0 : PL_ERR(gpu, "Failed uninitializing pass, leaking resources!");
172 : 0 : return;
173 : : }
174 : :
175 : 332 : struct pl_pass_gl *pass_gl = PL_PRIV(pass);
176 [ + - ]: 332 : if (pass_gl->vao)
177 : 332 : gl->DeleteVertexArrays(1, &pass_gl->vao);
178 : 332 : gl->DeleteBuffers(1, &pass_gl->index_buffer);
179 : 332 : gl->DeleteBuffers(1, &pass_gl->buffer);
180 : 332 : gl->DeleteProgram(pass_gl->program);
181 : :
182 : 332 : gl_check_err(gpu, "gl_pass_destroy");
183 : : RELEASE_CURRENT();
184 : 332 : pl_free((void *) pass);
185 : : }
186 : :
187 : 334 : static void gl_update_va(pl_gpu gpu, pl_pass pass, size_t vbo_offset)
188 : : {
189 : : const gl_funcs *gl = gl_funcs_get(gpu);
190 [ + + ]: 954 : for (int i = 0; i < pass->params.num_vertex_attribs; i++) {
191 : 620 : const struct pl_vertex_attrib *va = &pass->params.vertex_attribs[i];
192 : 620 : const struct gl_format **glfmtp = PL_PRIV(va->fmt);
193 : 620 : const struct gl_format *glfmt = *glfmtp;
194 : :
195 : : bool norm = false;
196 [ - - + ]: 620 : switch (va->fmt->type) {
197 : 0 : case PL_FMT_UNORM:
198 : : case PL_FMT_SNORM:
199 : : norm = true;
200 : 0 : break;
201 : :
202 : : case PL_FMT_UNKNOWN:
203 : : case PL_FMT_FLOAT:
204 : : case PL_FMT_UINT:
205 : : case PL_FMT_SINT:
206 : : break;
207 : : case PL_FMT_TYPE_COUNT:
208 : 0 : pl_unreachable();
209 : : }
210 : :
211 : 620 : gl->EnableVertexAttribArray(i);
212 : 620 : gl->VertexAttribPointer(i, va->fmt->num_components, glfmt->type, norm,
213 : 620 : pass->params.vertex_stride,
214 : 620 : (void *) (va->offset + vbo_offset));
215 : : }
216 : 334 : }
217 : :
218 : 332 : pl_pass gl_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
219 : : {
220 : : const gl_funcs *gl = gl_funcs_get(gpu);
221 : : if (!MAKE_CURRENT())
222 : 0 : return NULL;
223 : :
224 : : struct pl_gl *p = PL_PRIV(gpu);
225 : 332 : struct pl_pass_t *pass = pl_zalloc_obj(NULL, pass, struct pl_pass_gl);
226 : 332 : struct pl_pass_gl *pass_gl = PL_PRIV(pass);
227 : 332 : pl_cache cache = pl_gpu_cache(gpu);
228 : 332 : pass->params = pl_pass_params_copy(pass, params);
229 : :
230 : 332 : pl_cache_obj obj = { .key = CACHE_KEY_GL_PROG };
231 [ + + ]: 332 : if (cache) {
232 [ - + ]: 2 : pl_hash_merge(&obj.key, pl_str0_hash(params->glsl_shader));
233 [ - + ]: 2 : if (params->type == PL_PASS_RASTER)
234 : 0 : pl_hash_merge(&obj.key, pl_str0_hash(params->vertex_shader));
235 : : }
236 : :
237 : : // Load/Compile program
238 [ + + ]: 332 : if ((pass_gl->program = load_cached_program(gpu, cache, &obj))) {
239 : 1 : PL_DEBUG(gpu, "Using cached GL program");
240 : : } else {
241 : : pl_clock_t start = pl_clock_now();
242 : 331 : pass_gl->program = gl_compile_program(gpu, params);
243 : 331 : pl_log_cpu_time(gpu->log, start, pl_clock_now(), "compiling shader");
244 : : }
245 : :
246 [ - + ]: 332 : if (!pass_gl->program)
247 : 0 : goto error;
248 : :
249 : : // Update program cache if possible
250 [ + + + - ]: 332 : if (cache && gl_test_ext(gpu, "GL_ARB_get_program_binary", 41, 30)) {
251 : 2 : GLint buf_size = 0;
252 : 2 : gl->GetProgramiv(pass_gl->program, GL_PROGRAM_BINARY_LENGTH, &buf_size);
253 [ + - ]: 2 : if (buf_size > 0) {
254 : 2 : buf_size += sizeof(struct gl_cache_header);
255 : 2 : pl_cache_obj_resize(NULL, &obj, buf_size);
256 : 2 : struct gl_cache_header *header = obj.data;
257 : 2 : void *buffer = &header[1];
258 : 2 : GLsizei binary_size = 0;
259 : 2 : gl->GetProgramBinary(pass_gl->program, buf_size, &binary_size,
260 : : &header->format, buffer);
261 : 2 : bool ok = gl_check_err(gpu, "gl_pass_create: get program binary");
262 [ + - ]: 2 : if (ok) {
263 : 2 : obj.size = sizeof(*header) + binary_size;
264 [ - + ]: 2 : pl_assert(obj.size <= buf_size);
265 : 2 : pl_cache_set(cache, &obj);
266 : : }
267 : : }
268 : : }
269 : :
270 : 332 : gl->UseProgram(pass_gl->program);
271 : 332 : pass_gl->var_locs = pl_calloc(pass, params->num_variables, sizeof(GLint));
272 : :
273 [ + + ]: 858 : for (int i = 0; i < params->num_variables; i++) {
274 : 1052 : pass_gl->var_locs[i] = gl->GetUniformLocation(pass_gl->program,
275 : 526 : params->variables[i].name);
276 : :
277 : : // Due to OpenGL API restrictions, we need to ensure that this is a
278 : : // variable type we can actually *update*. Fortunately, this is easily
279 : : // checked by virtue of the fact that all legal combinations of
280 : : // parameters will have a valid GLSL type name
281 [ - + ]: 526 : if (!pl_var_glsl_type_name(params->variables[i])) {
282 : 0 : gl->UseProgram(0);
283 : 0 : PL_ERR(gpu, "Input variable '%s' does not match any known type!",
284 : : params->variables[i].name);
285 : 0 : goto error;
286 : : }
287 : : }
288 : :
289 [ + + ]: 1071 : for (int i = 0; i < params->num_descriptors; i++) {
290 : 739 : const struct pl_desc *desc = ¶ms->descriptors[i];
291 [ + + + - : 739 : switch (desc->type) {
- - ]
292 : 631 : case PL_DESC_SAMPLED_TEX:
293 : : case PL_DESC_STORAGE_IMG: {
294 : : // For compatibility with older OpenGL, we need to explicitly
295 : : // update the texture/image unit bindings after creating the shader
296 : : // program, since specifying it directly requires GLSL 4.20+
297 : 631 : GLint loc = gl->GetUniformLocation(pass_gl->program, desc->name);
298 : 631 : gl->Uniform1i(loc, desc->binding);
299 : 631 : break;
300 : : }
301 : 101 : case PL_DESC_BUF_UNIFORM: {
302 : 101 : GLuint idx = gl->GetUniformBlockIndex(pass_gl->program, desc->name);
303 : 101 : gl->UniformBlockBinding(pass_gl->program, idx, desc->binding);
304 : 101 : break;
305 : : }
306 : 7 : case PL_DESC_BUF_STORAGE: {
307 : 7 : GLuint idx = gl->GetProgramResourceIndex(pass_gl->program,
308 : : GL_SHADER_STORAGE_BLOCK,
309 : 7 : desc->name);
310 : 7 : gl->ShaderStorageBlockBinding(pass_gl->program, idx, desc->binding);
311 : 7 : break;
312 : : }
313 : : case PL_DESC_BUF_TEXEL_UNIFORM:
314 : : case PL_DESC_BUF_TEXEL_STORAGE:
315 : 0 : assert(!"unimplemented"); // TODO
316 : : case PL_DESC_INVALID:
317 : : case PL_DESC_TYPE_COUNT:
318 : 0 : pl_unreachable();
319 : : }
320 : : }
321 : :
322 : 332 : gl->UseProgram(0);
323 : :
324 : : // Initialize the VAO and single vertex buffer
325 : 332 : gl->GenBuffers(1, &pass_gl->buffer);
326 [ + - ]: 332 : if (p->has_vao) {
327 : 332 : gl->GenVertexArrays(1, &pass_gl->vao);
328 : 332 : gl->BindBuffer(GL_ARRAY_BUFFER, pass_gl->buffer);
329 : 332 : gl->BindVertexArray(pass_gl->vao);
330 : 332 : gl_update_va(gpu, pass, 0);
331 : 332 : gl->BindVertexArray(0);
332 : 332 : gl->BindBuffer(GL_ARRAY_BUFFER, 0);
333 : : }
334 : :
335 [ - + ]: 332 : if (!gl_check_err(gpu, "gl_pass_create"))
336 : 0 : goto error;
337 : :
338 : : pl_cache_obj_free(&obj);
339 : : RELEASE_CURRENT();
340 : 332 : return pass;
341 : :
342 : 0 : error:
343 : 0 : PL_ERR(gpu, "Failed creating pass");
344 : : pl_cache_obj_free(&obj);
345 : 0 : gl_pass_destroy(gpu, pass);
346 : : RELEASE_CURRENT();
347 : 0 : return NULL;
348 : : }
349 : :
350 [ + + + - ]: 1110 : static void update_var(pl_gpu gpu, pl_pass pass,
351 : : const struct pl_var_update *vu)
352 : : {
353 : : const gl_funcs *gl = gl_funcs_get(gpu);
354 : 1110 : struct pl_pass_gl *pass_gl = PL_PRIV(pass);
355 : 1110 : const struct pl_var *var = &pass->params.variables[vu->index];
356 : 1110 : GLint loc = pass_gl->var_locs[vu->index];
357 : :
358 [ + + + - ]: 1110 : switch (var->type) {
359 : 33 : case PL_VAR_SINT: {
360 : 33 : const int *i = vu->data;
361 [ - + ]: 33 : pl_assert(var->dim_m == 1);
362 [ + + - - : 33 : switch (var->dim_v) {
- ]
363 : 13 : case 1: gl->Uniform1iv(loc, var->dim_a, i); break;
364 : 20 : case 2: gl->Uniform2iv(loc, var->dim_a, i); break;
365 : 0 : case 3: gl->Uniform3iv(loc, var->dim_a, i); break;
366 : 0 : case 4: gl->Uniform4iv(loc, var->dim_a, i); break;
367 : 0 : default: pl_unreachable();
368 : : }
369 : : return;
370 : : }
371 : 16 : case PL_VAR_UINT: {
372 : 16 : const unsigned int *u = vu->data;
373 [ - + ]: 16 : pl_assert(var->dim_m == 1);
374 [ + - - - : 16 : switch (var->dim_v) {
- ]
375 : 16 : case 1: gl->Uniform1uiv(loc, var->dim_a, u); break;
376 : 0 : case 2: gl->Uniform2uiv(loc, var->dim_a, u); break;
377 : 0 : case 3: gl->Uniform3uiv(loc, var->dim_a, u); break;
378 : 0 : case 4: gl->Uniform4uiv(loc, var->dim_a, u); break;
379 : 0 : default: pl_unreachable();
380 : : }
381 : : return;
382 : : }
383 : 1061 : case PL_VAR_FLOAT: {
384 : 1061 : const float *f = vu->data;
385 [ + + ]: 1061 : if (var->dim_m == 1) {
386 [ + + + - : 908 : switch (var->dim_v) {
- ]
387 : 683 : case 1: gl->Uniform1fv(loc, var->dim_a, f); break;
388 : 157 : case 2: gl->Uniform2fv(loc, var->dim_a, f); break;
389 : 68 : case 3: gl->Uniform3fv(loc, var->dim_a, f); break;
390 : 0 : case 4: gl->Uniform4fv(loc, var->dim_a, f); break;
391 : 0 : default: pl_unreachable();
392 : : }
393 [ + + + - ]: 153 : } else if (var->dim_m == 2 && var->dim_v == 2) {
394 : 17 : gl->UniformMatrix2fv(loc, var->dim_a, GL_FALSE, f);
395 [ + - + - ]: 136 : } else if (var->dim_m == 3 && var->dim_v == 3) {
396 : 136 : gl->UniformMatrix3fv(loc, var->dim_a, GL_FALSE, f);
397 [ # # # # ]: 0 : } else if (var->dim_m == 4 && var->dim_v == 4) {
398 : 0 : gl->UniformMatrix4fv(loc, var->dim_a, GL_FALSE, f);
399 [ # # # # ]: 0 : } else if (var->dim_m == 2 && var->dim_v == 3) {
400 : 0 : gl->UniformMatrix2x3fv(loc, var->dim_a, GL_FALSE, f);
401 [ # # # # ]: 0 : } else if (var->dim_m == 3 && var->dim_v == 2) {
402 : 0 : gl->UniformMatrix3x2fv(loc, var->dim_a, GL_FALSE, f);
403 [ # # # # ]: 0 : } else if (var->dim_m == 2 && var->dim_v == 4) {
404 : 0 : gl->UniformMatrix2x4fv(loc, var->dim_a, GL_FALSE, f);
405 [ # # # # ]: 0 : } else if (var->dim_m == 4 && var->dim_v == 2) {
406 : 0 : gl->UniformMatrix4x2fv(loc, var->dim_a, GL_FALSE, f);
407 [ # # # # ]: 0 : } else if (var->dim_m == 3 && var->dim_v == 4) {
408 : 0 : gl->UniformMatrix3x4fv(loc, var->dim_a, GL_FALSE, f);
409 [ # # # # ]: 0 : } else if (var->dim_m == 4 && var->dim_v == 3) {
410 : 0 : gl->UniformMatrix4x3fv(loc, var->dim_a, GL_FALSE, f);
411 : : } else {
412 : 0 : pl_unreachable();
413 : : }
414 : : return;
415 : : }
416 : :
417 : : case PL_VAR_INVALID:
418 : : case PL_VAR_TYPE_COUNT:
419 : : break;
420 : : }
421 : :
422 : 0 : pl_unreachable();
423 : : }
424 : :
425 [ + + + + : 2711 : static void update_desc(pl_gpu gpu, pl_pass pass, int index,
- - ]
426 : : const struct pl_desc_binding *db)
427 : : {
428 : : const gl_funcs *gl = gl_funcs_get(gpu);
429 : 2711 : const struct pl_desc *desc = &pass->params.descriptors[index];
430 : :
431 : : static const GLenum access[] = {
432 : : [PL_DESC_ACCESS_READWRITE] = GL_READ_WRITE,
433 : : [PL_DESC_ACCESS_READONLY] = GL_READ_ONLY,
434 : : [PL_DESC_ACCESS_WRITEONLY] = GL_WRITE_ONLY,
435 : : };
436 : :
437 : : static const GLint wraps[PL_TEX_ADDRESS_MODE_COUNT] = {
438 : : [PL_TEX_ADDRESS_CLAMP] = GL_CLAMP_TO_EDGE,
439 : : [PL_TEX_ADDRESS_REPEAT] = GL_REPEAT,
440 : : [PL_TEX_ADDRESS_MIRROR] = GL_MIRRORED_REPEAT,
441 : : };
442 : :
443 : : static const GLint filters[PL_TEX_SAMPLE_MODE_COUNT] = {
444 : : [PL_TEX_SAMPLE_NEAREST] = GL_NEAREST,
445 : : [PL_TEX_SAMPLE_LINEAR] = GL_LINEAR,
446 : : };
447 : :
448 [ + + + + : 2711 : switch (desc->type) {
- - ]
449 : 2181 : case PL_DESC_SAMPLED_TEX: {
450 : 2181 : pl_tex tex = db->object;
451 : 2181 : struct pl_tex_gl *tex_gl = PL_PRIV(tex);
452 : 2181 : gl->ActiveTexture(GL_TEXTURE0 + desc->binding);
453 : 2181 : gl->BindTexture(tex_gl->target, tex_gl->texture);
454 : :
455 : 2181 : GLint filter = filters[db->sample_mode];
456 : 2181 : GLint wrap = wraps[db->address_mode];
457 : 2181 : gl->TexParameteri(tex_gl->target, GL_TEXTURE_MIN_FILTER, filter);
458 : 2181 : gl->TexParameteri(tex_gl->target, GL_TEXTURE_MAG_FILTER, filter);
459 : : switch (pl_tex_params_dimension(tex->params)) {
460 : 70 : case 3: gl->TexParameteri(tex_gl->target, GL_TEXTURE_WRAP_R, wrap); // fall through
461 : 2063 : case 2: gl->TexParameteri(tex_gl->target, GL_TEXTURE_WRAP_T, wrap); // fall through
462 : 2181 : case 1: gl->TexParameteri(tex_gl->target, GL_TEXTURE_WRAP_S, wrap); break;
463 : : }
464 : : return;
465 : : }
466 : 48 : case PL_DESC_STORAGE_IMG: {
467 : 48 : pl_tex tex = db->object;
468 : 48 : struct pl_tex_gl *tex_gl = PL_PRIV(tex);
469 : 48 : gl->BindImageTexture(desc->binding, tex_gl->texture, 0, GL_FALSE, 0,
470 : 48 : access[desc->access], tex_gl->iformat);
471 : 48 : return;
472 : : }
473 : 471 : case PL_DESC_BUF_UNIFORM: {
474 : 471 : pl_buf buf = db->object;
475 : 471 : struct pl_buf_gl *buf_gl = PL_PRIV(buf);
476 : 471 : gl->BindBufferRange(GL_UNIFORM_BUFFER, desc->binding, buf_gl->buffer,
477 : 471 : buf_gl->offset, buf->params.size);
478 : 471 : return;
479 : : }
480 : 11 : case PL_DESC_BUF_STORAGE: {
481 : 11 : pl_buf buf = db->object;
482 : 11 : struct pl_buf_gl *buf_gl = PL_PRIV(buf);
483 : 11 : gl->BindBufferRange(GL_SHADER_STORAGE_BUFFER, desc->binding, buf_gl->buffer,
484 : 11 : buf_gl->offset, buf->params.size);
485 : 11 : return;
486 : : }
487 : : case PL_DESC_BUF_TEXEL_UNIFORM:
488 : : case PL_DESC_BUF_TEXEL_STORAGE:
489 : 0 : assert(!"unimplemented"); // TODO
490 : :
491 : : case PL_DESC_INVALID:
492 : : case PL_DESC_TYPE_COUNT:
493 : : break;
494 : : }
495 : :
496 : 0 : pl_unreachable();
497 : : }
498 : :
499 [ + + + + : 2711 : static void unbind_desc(pl_gpu gpu, pl_pass pass, int index,
- - ]
500 : : const struct pl_desc_binding *db)
501 : : {
502 : : const gl_funcs *gl = gl_funcs_get(gpu);
503 : 2711 : const struct pl_desc *desc = &pass->params.descriptors[index];
504 : :
505 [ + + + + : 2711 : switch (desc->type) {
- - ]
506 : 2181 : case PL_DESC_SAMPLED_TEX: {
507 : 2181 : pl_tex tex = db->object;
508 : 2181 : struct pl_tex_gl *tex_gl = PL_PRIV(tex);
509 : 2181 : gl->ActiveTexture(GL_TEXTURE0 + desc->binding);
510 : 2181 : gl->BindTexture(tex_gl->target, 0);
511 : 2181 : return;
512 : : }
513 : 48 : case PL_DESC_STORAGE_IMG: {
514 : 48 : pl_tex tex = db->object;
515 : 48 : struct pl_tex_gl *tex_gl = PL_PRIV(tex);
516 : 48 : gl->BindImageTexture(desc->binding, 0, 0, GL_FALSE, 0,
517 : : GL_WRITE_ONLY, GL_R32F);
518 [ + + ]: 48 : if (desc->access != PL_DESC_ACCESS_READONLY)
519 : 46 : gl->MemoryBarrier(tex_gl->barrier);
520 : : return;
521 : : }
522 : 471 : case PL_DESC_BUF_UNIFORM:
523 : 471 : gl->BindBufferBase(GL_UNIFORM_BUFFER, desc->binding, 0);
524 : 471 : return;
525 : 11 : case PL_DESC_BUF_STORAGE: {
526 : 11 : pl_buf buf = db->object;
527 : 11 : struct pl_buf_gl *buf_gl = PL_PRIV(buf);
528 : 11 : gl->BindBufferBase(GL_SHADER_STORAGE_BUFFER, desc->binding, 0);
529 [ + + ]: 11 : if (desc->access != PL_DESC_ACCESS_READONLY)
530 : 10 : gl->MemoryBarrier(buf_gl->barrier);
531 : : return;
532 : : }
533 : : case PL_DESC_BUF_TEXEL_UNIFORM:
534 : : case PL_DESC_BUF_TEXEL_STORAGE:
535 : 0 : assert(!"unimplemented"); // TODO
536 : : case PL_DESC_INVALID:
537 : : case PL_DESC_TYPE_COUNT:
538 : : break;
539 : : }
540 : :
541 : 0 : pl_unreachable();
542 : : }
543 : :
544 : 1415 : void gl_pass_run(pl_gpu gpu, const struct pl_pass_run_params *params)
545 : : {
546 : : const gl_funcs *gl = gl_funcs_get(gpu);
547 : : if (!MAKE_CURRENT())
548 : 0 : return;
549 : :
550 : 1415 : pl_pass pass = params->pass;
551 : 1415 : struct pl_pass_gl *pass_gl = PL_PRIV(pass);
552 : : struct pl_gl *p = PL_PRIV(gpu);
553 : :
554 : 1415 : gl->UseProgram(pass_gl->program);
555 : :
556 [ + + ]: 2525 : for (int i = 0; i < params->num_var_updates; i++)
557 : 1110 : update_var(gpu, pass, ¶ms->var_updates[i]);
558 [ + + ]: 4126 : for (int i = 0; i < pass->params.num_descriptors; i++)
559 : 2711 : update_desc(gpu, pass, i, ¶ms->desc_bindings[i]);
560 : 1415 : gl->ActiveTexture(GL_TEXTURE0);
561 : :
562 [ - + ]: 1415 : if (!gl_check_err(gpu, "gl_pass_run: updating uniforms")) {
563 : : RELEASE_CURRENT();
564 : 0 : return;
565 : : }
566 : :
567 [ + + - - ]: 1415 : switch (pass->params.type) {
568 : 1367 : case PL_PASS_RASTER: {
569 : 1367 : struct pl_tex_gl *target_gl = PL_PRIV(params->target);
570 : 1367 : gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, target_gl->fbo);
571 [ + + + - ]: 1367 : if (!pass->params.load_target && p->has_invalidate_fb) {
572 [ - + ]: 1275 : GLenum fb = target_gl->fbo ? GL_COLOR_ATTACHMENT0 : GL_COLOR;
573 : 1275 : gl->InvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &fb);
574 : : }
575 : :
576 : 1367 : gl->Viewport(params->viewport.x0, params->viewport.y0,
577 : 1367 : pl_rect_w(params->viewport), pl_rect_h(params->viewport));
578 : 1367 : gl->Scissor(params->scissors.x0, params->scissors.y0,
579 : 1367 : pl_rect_w(params->scissors), pl_rect_h(params->scissors));
580 : 1367 : gl->Enable(GL_SCISSOR_TEST);
581 : 1367 : gl->Disable(GL_DEPTH_TEST);
582 : 1367 : gl->Disable(GL_CULL_FACE);
583 : 1367 : gl_check_err(gpu, "gl_pass_run: enabling viewport/scissor");
584 : :
585 : 1367 : const struct pl_blend_params *blend = pass->params.blend_params;
586 [ + + ]: 1367 : if (blend) {
587 : : static const GLenum map_blend[] = {
588 : : [PL_BLEND_ZERO] = GL_ZERO,
589 : : [PL_BLEND_ONE] = GL_ONE,
590 : : [PL_BLEND_SRC_ALPHA] = GL_SRC_ALPHA,
591 : : [PL_BLEND_ONE_MINUS_SRC_ALPHA] = GL_ONE_MINUS_SRC_ALPHA,
592 : : };
593 : :
594 : 12 : gl->BlendFuncSeparate(map_blend[blend->src_rgb],
595 : 12 : map_blend[blend->dst_rgb],
596 : 12 : map_blend[blend->src_alpha],
597 : 12 : map_blend[blend->dst_alpha]);
598 : 12 : gl->Enable(GL_BLEND);
599 : 12 : gl_check_err(gpu, "gl_pass_run: enabling blend");
600 : : }
601 : :
602 : : // Update VBO and VAO
603 : 1367 : pl_buf vert = params->vertex_buf;
604 [ + + ]: 1367 : struct pl_buf_gl *vert_gl = vert ? PL_PRIV(vert) : NULL;
605 [ + + ]: 1367 : gl->BindBuffer(GL_ARRAY_BUFFER, vert ? vert_gl->buffer : pass_gl->buffer);
606 : :
607 [ + + ]: 1367 : if (!vert) {
608 : : // Update the buffer directly. In theory we could also do a memcmp
609 : : // cache here to avoid unnecessary updates.
610 : 1366 : gl->BufferData(GL_ARRAY_BUFFER, pl_vertex_buf_size(params),
611 : 1366 : params->vertex_data, GL_STREAM_DRAW);
612 : : }
613 : :
614 [ + - ]: 1367 : if (pass_gl->vao)
615 : 1367 : gl->BindVertexArray(pass_gl->vao);
616 : :
617 [ + + ]: 1367 : uint64_t vert_id = vert ? vert_gl->id : 0;
618 : 1 : size_t vert_offset = vert ? params->buf_offset : 0;
619 [ + - + + ]: 1367 : if (!pass_gl->vao || pass_gl->vao_id != vert_id ||
620 [ - + ]: 1365 : pass_gl->vao_offset != vert_offset)
621 : : {
622 : : // We need to update the VAO when the buffer ID or offset changes
623 : 2 : gl_update_va(gpu, pass, vert_offset);
624 : 2 : pass_gl->vao_id = vert_id;
625 : 2 : pass_gl->vao_offset = vert_offset;
626 : : }
627 : :
628 : 1367 : gl_check_err(gpu, "gl_pass_run: update/bind vertex buffer");
629 : :
630 : : static const GLenum map_prim[PL_PRIM_TYPE_COUNT] = {
631 : : [PL_PRIM_TRIANGLE_LIST] = GL_TRIANGLES,
632 : : [PL_PRIM_TRIANGLE_STRIP] = GL_TRIANGLE_STRIP,
633 : : };
634 : 1367 : GLenum mode = map_prim[pass->params.vertex_type];
635 : :
636 : 1367 : gl_timer_begin(gpu, params->timer);
637 : :
638 [ + + ]: 1367 : if (params->index_data) {
639 : :
640 : : static const GLenum index_fmts[PL_INDEX_FORMAT_COUNT] = {
641 : : [PL_INDEX_UINT16] = GL_UNSIGNED_SHORT,
642 : : [PL_INDEX_UINT32] = GL_UNSIGNED_INT,
643 : : };
644 : :
645 : : // Upload indices to temporary buffer object
646 [ + + ]: 13 : if (!pass_gl->index_buffer)
647 : 7 : gl->GenBuffers(1, &pass_gl->index_buffer); // lazily allocated
648 : 13 : gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, pass_gl->index_buffer);
649 : 13 : gl->BufferData(GL_ELEMENT_ARRAY_BUFFER, pl_index_buf_size(params),
650 : 13 : params->index_data, GL_STREAM_DRAW);
651 : 13 : gl->DrawElements(mode, params->vertex_count,
652 : 13 : index_fmts[params->index_fmt], 0);
653 : 13 : gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
654 : :
655 [ - + ]: 1354 : } else if (params->index_buf) {
656 : :
657 : : // The pointer argument becomes the index buffer offset
658 : 0 : struct pl_buf_gl *index_gl = PL_PRIV(params->index_buf);
659 : 0 : gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_gl->buffer);
660 : 0 : gl->DrawElements(mode, params->vertex_count, GL_UNSIGNED_SHORT,
661 : 0 : (void *) params->index_offset);
662 : 0 : gl->BindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
663 : :
664 : : } else {
665 : :
666 : : // Note: the VBO offset is handled in the VAO
667 : 1354 : gl->DrawArrays(mode, 0, params->vertex_count);
668 : : }
669 : :
670 : 1367 : gl_timer_end(gpu, params->timer);
671 : 1367 : gl_check_err(gpu, "gl_pass_run: drawing");
672 : :
673 [ + - ]: 1367 : if (pass_gl->vao) {
674 : 1367 : gl->BindVertexArray(0);
675 : : } else {
676 [ # # ]: 0 : for (int i = 0; i < pass->params.num_vertex_attribs; i++)
677 : 0 : gl->DisableVertexAttribArray(i);
678 : : }
679 : :
680 : 1367 : gl->BindBuffer(GL_ARRAY_BUFFER, 0);
681 : 1367 : gl->Disable(GL_SCISSOR_TEST);
682 : 1367 : gl->Disable(GL_BLEND);
683 : 1367 : gl->BindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
684 : 1367 : break;
685 : : }
686 : :
687 : 48 : case PL_PASS_COMPUTE:
688 : 48 : gl_timer_begin(gpu, params->timer);
689 : 48 : gl->DispatchCompute(params->compute_groups[0],
690 : 48 : params->compute_groups[1],
691 : 48 : params->compute_groups[2]);
692 : 48 : gl_timer_end(gpu, params->timer);
693 : 48 : break;
694 : :
695 : : case PL_PASS_INVALID:
696 : : case PL_PASS_TYPE_COUNT:
697 : 0 : pl_unreachable();
698 : : }
699 : :
700 [ + + ]: 4126 : for (int i = 0; i < pass->params.num_descriptors; i++)
701 : 2711 : unbind_desc(gpu, pass, i, ¶ms->desc_bindings[i]);
702 : 1415 : gl->ActiveTexture(GL_TEXTURE0);
703 : :
704 : 1415 : gl->UseProgram(0);
705 : 1415 : gl_check_err(gpu, "gl_pass_run");
706 : : RELEASE_CURRENT();
707 : : }
|