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 "formats.h"
20 #include "utils.h"
21
gl_desc_namespace(pl_gpu gpu,enum pl_desc_type type)22 int gl_desc_namespace(pl_gpu gpu, enum pl_desc_type type)
23 {
24 return (int) type;
25 }
26
27 #define CACHE_MAGIC {'P','L','G','L'}
28 #define CACHE_VERSION 1
29 static const char gl_cache_magic[4] = CACHE_MAGIC;
30
31 struct gl_cache_header {
32 char magic[sizeof(gl_cache_magic)];
33 int cache_version;
34 GLenum format;
35 };
36
load_cached_program(pl_gpu gpu,const struct pl_pass_params * params)37 static GLuint load_cached_program(pl_gpu gpu, const struct pl_pass_params *params)
38 {
39 if (!gl_test_ext(gpu, "GL_ARB_get_program_binary", 41, 30))
40 return 0;
41
42 pl_str cache = {
43 .buf = (void *) params->cached_program,
44 .len = params->cached_program_len,
45 };
46
47 if (cache.len < sizeof(struct gl_cache_header))
48 return false;
49
50 struct gl_cache_header *header = (struct gl_cache_header *) cache.buf;
51 cache = pl_str_drop(cache, sizeof(*header));
52
53 if (strncmp(header->magic, gl_cache_magic, sizeof(gl_cache_magic)) != 0)
54 return 0;
55 if (header->cache_version != CACHE_VERSION)
56 return 0;
57
58 GLuint prog = glCreateProgram();
59 if (!gl_check_err(gpu, "load_cached_program: glCreateProgram"))
60 return 0;
61
62 glProgramBinary(prog, header->format, cache.buf, cache.len);
63 glGetError(); // discard potential useless error
64
65 GLint status = 0;
66 glGetProgramiv(prog, GL_LINK_STATUS, &status);
67 if (status)
68 return prog;
69
70 glDeleteProgram(prog);
71 gl_check_err(gpu, "load_cached_program: glProgramBinary");
72 return 0;
73 }
74
gl_log_level(GLint status,GLint log_length)75 static enum pl_log_level gl_log_level(GLint status, GLint log_length)
76 {
77 if (!status) {
78 return PL_LOG_ERR;
79 } else if (log_length > 0) {
80 return PL_LOG_INFO;
81 } else {
82 return PL_LOG_DEBUG;
83 }
84 }
85
gl_attach_shader(pl_gpu gpu,GLuint program,GLenum type,const char * src)86 static bool gl_attach_shader(pl_gpu gpu, GLuint program, GLenum type, const char *src)
87 {
88 GLuint shader = glCreateShader(type);
89 glShaderSource(shader, 1, &src, NULL);
90 glCompileShader(shader);
91
92 GLint status = 0;
93 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
94 GLint log_length = 0;
95 glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &log_length);
96
97 enum pl_log_level level = gl_log_level(status, log_length);
98 if (pl_msg_test(gpu->log, level)) {
99 static const char *shader_name;
100 switch (type) {
101 case GL_VERTEX_SHADER: shader_name = "vertex"; break;
102 case GL_FRAGMENT_SHADER: shader_name = "fragment"; break;
103 case GL_COMPUTE_SHADER: shader_name = "compute"; break;
104 default: pl_unreachable();
105 };
106
107 PL_MSG(gpu, level, "%s shader source:", shader_name);
108 pl_msg_source(gpu->log, level, src);
109
110 GLchar *logstr = pl_zalloc(NULL, log_length + 1);
111 glGetShaderInfoLog(shader, log_length, NULL, logstr);
112 PL_MSG(gpu, level, "shader compile log (status=%d): %s", status, logstr);
113 pl_free(logstr);
114 }
115
116 if (!status || !gl_check_err(gpu, "gl_attach_shader"))
117 goto error;
118
119 glAttachShader(program, shader);
120 glDeleteShader(shader);
121 return true;
122
123 error:
124 glDeleteShader(shader);
125 return false;
126 }
127
gl_compile_program(pl_gpu gpu,const struct pl_pass_params * params)128 static GLuint gl_compile_program(pl_gpu gpu, const struct pl_pass_params *params)
129 {
130 GLuint prog = glCreateProgram();
131 bool ok = true;
132
133 switch (params->type) {
134 case PL_PASS_COMPUTE:
135 ok &= gl_attach_shader(gpu, prog, GL_COMPUTE_SHADER, params->glsl_shader);
136 break;
137 case PL_PASS_RASTER:
138 ok &= gl_attach_shader(gpu, prog, GL_VERTEX_SHADER, params->vertex_shader);
139 ok &= gl_attach_shader(gpu, prog, GL_FRAGMENT_SHADER, params->glsl_shader);
140 for (int i = 0; i < params->num_vertex_attribs; i++)
141 glBindAttribLocation(prog, i, params->vertex_attribs[i].name);
142 break;
143 case PL_PASS_INVALID:
144 case PL_PASS_TYPE_COUNT:
145 pl_unreachable();
146 }
147
148 if (!ok || !gl_check_err(gpu, "gl_compile_program: attach shader"))
149 goto error;
150
151 glLinkProgram(prog);
152 GLint status = 0;
153 glGetProgramiv(prog, GL_LINK_STATUS, &status);
154 GLint log_length = 0;
155 glGetProgramiv(prog, GL_INFO_LOG_LENGTH, &log_length);
156
157 enum pl_log_level level = gl_log_level(status, log_length);
158 if (pl_msg_test(gpu->log, level)) {
159 GLchar *logstr = pl_zalloc(NULL, log_length + 1);
160 glGetProgramInfoLog(prog, log_length, NULL, logstr);
161 PL_MSG(gpu, level, "shader link log (status=%d): %s", status, logstr);
162 pl_free(logstr);
163 }
164
165 if (!gl_check_err(gpu, "gl_compile_program: link program"))
166 goto error;
167
168 return prog;
169
170 error:
171 glDeleteProgram(prog);
172 PL_ERR(gpu, "Failed compiling/linking GLSL program");
173 return 0;
174 }
175
176 // For pl_pass.priv
177 struct pl_pass_gl {
178 GLuint program;
179 GLuint vao; // the VAO object
180 uint64_t vao_id; // buf_gl.id of VAO
181 size_t vao_offset; // VBO offset of VAO
182 GLuint buffer; // VBO for raw vertex pointers
183 GLint *var_locs;
184 };
185
gl_pass_destroy(pl_gpu gpu,pl_pass pass)186 void gl_pass_destroy(pl_gpu gpu, pl_pass pass)
187 {
188 if (!MAKE_CURRENT()) {
189 PL_ERR(gpu, "Failed uninitializing pass, leaking resources!");
190 return;
191 }
192
193 struct pl_pass_gl *pass_gl = PL_PRIV(pass);
194 if (pass_gl->vao)
195 glDeleteVertexArrays(1, &pass_gl->vao);
196 glDeleteBuffers(1, &pass_gl->buffer);
197 glDeleteProgram(pass_gl->program);
198
199 gl_check_err(gpu, "gl_pass_destroy");
200 RELEASE_CURRENT();
201 pl_free((void *) pass);
202 }
203
gl_update_va(pl_pass pass,size_t vbo_offset)204 static void gl_update_va(pl_pass pass, size_t vbo_offset)
205 {
206 for (int i = 0; i < pass->params.num_vertex_attribs; i++) {
207 const struct pl_vertex_attrib *va = &pass->params.vertex_attribs[i];
208 const struct gl_format **glfmtp = PL_PRIV(va->fmt);
209 const struct gl_format *glfmt = *glfmtp;
210
211 bool norm = false;
212 switch (va->fmt->type) {
213 case PL_FMT_UNORM:
214 case PL_FMT_SNORM:
215 norm = true;
216 break;
217
218 case PL_FMT_UNKNOWN:
219 case PL_FMT_FLOAT:
220 case PL_FMT_UINT:
221 case PL_FMT_SINT:
222 break;
223 case PL_FMT_TYPE_COUNT:
224 pl_unreachable();
225 }
226
227 glEnableVertexAttribArray(i);
228 glVertexAttribPointer(i, va->fmt->num_components, glfmt->type, norm,
229 pass->params.vertex_stride,
230 (void *) (va->offset + vbo_offset));
231 }
232 }
233
gl_pass_create(pl_gpu gpu,const struct pl_pass_params * params)234 pl_pass gl_pass_create(pl_gpu gpu, const struct pl_pass_params *params)
235 {
236 if (!MAKE_CURRENT())
237 return NULL;
238
239 struct pl_gl *p = PL_PRIV(gpu);
240 struct pl_pass *pass = pl_zalloc_obj(NULL, pass, struct pl_pass_gl);
241 struct pl_pass_gl *pass_gl = PL_PRIV(pass);
242 pass->params = pl_pass_params_copy(pass, params);
243
244 // Load/Compile program
245 if ((pass_gl->program = load_cached_program(gpu, params))) {
246 PL_DEBUG(gpu, "Using cached GL program");
247 } else {
248 clock_t start = clock();
249 pass_gl->program = gl_compile_program(gpu, params);
250 pl_log_cpu_time(gpu->log, start, clock(), "compiling shader");
251 }
252
253 if (!pass_gl->program)
254 goto error;
255
256 // Update program cache if possible
257 if (gl_test_ext(gpu, "GL_ARB_get_program_binary", 41, 30)) {
258 GLint size = 0;
259 glGetProgramiv(pass_gl->program, GL_PROGRAM_BINARY_LENGTH, &size);
260
261 if (size > 0) {
262 uint8_t *buffer = pl_alloc(NULL, size);
263 GLsizei actual_size = 0;
264 struct gl_cache_header header = {
265 .magic = CACHE_MAGIC,
266 .cache_version = CACHE_VERSION,
267 };
268
269 glGetProgramBinary(pass_gl->program, size, &actual_size,
270 &header.format, buffer);
271 if (actual_size > 0) {
272 pl_str cache = {0};
273 pl_str_append(pass, &cache, (pl_str) { (void *) &header, sizeof(header) });
274 pl_str_append(pass, &cache, (pl_str) { buffer, actual_size });
275 pass->params.cached_program = cache.buf;
276 pass->params.cached_program_len = cache.len;
277 }
278
279 pl_free(buffer);
280 }
281
282 if (!gl_check_err(gpu, "gl_pass_create: get program binary")) {
283 PL_WARN(gpu, "Failed generating program binary.. ignoring");
284 pl_free((void *) pass->params.cached_program);
285 pass->params.cached_program = NULL;
286 pass->params.cached_program_len = 0;
287 }
288 }
289
290 glUseProgram(pass_gl->program);
291 pass_gl->var_locs = pl_calloc(pass, params->num_variables, sizeof(GLint));
292
293 for (int i = 0; i < params->num_variables; i++) {
294 pass_gl->var_locs[i] = glGetUniformLocation(pass_gl->program,
295 params->variables[i].name);
296
297 // Due to OpenGL API restrictions, we need to ensure that this is a
298 // variable type we can actually *update*. Fortunately, this is easily
299 // checked by virtue of the fact that all legal combinations of
300 // parameters will have a valid GLSL type name
301 if (!pl_var_glsl_type_name(params->variables[i])) {
302 glUseProgram(0);
303 PL_ERR(gpu, "Input variable '%s' does not match any known type!",
304 params->variables[i].name);
305 goto error;
306 }
307 }
308
309 for (int i = 0; i < params->num_descriptors; i++) {
310 // For compatibility with older OpenGL, we need to explicitly update
311 // the texture/image unit bindings after creating the shader program,
312 // since specifying it directly requires GLSL 4.20+
313 GLint loc = glGetUniformLocation(pass_gl->program, params->descriptors[i].name);
314 glUniform1i(loc, params->descriptors[i].binding);
315 }
316
317 glUseProgram(0);
318
319 // Initialize the VAO and single vertex buffer
320 glGenBuffers(1, &pass_gl->buffer);
321 if (p->has_vao) {
322 glGenVertexArrays(1, &pass_gl->vao);
323 glBindBuffer(GL_ARRAY_BUFFER, pass_gl->buffer);
324 glBindVertexArray(pass_gl->vao);
325 gl_update_va(pass, 0);
326 glBindVertexArray(0);
327 glBindBuffer(GL_ARRAY_BUFFER, 0);
328 }
329
330 if (!gl_check_err(gpu, "gl_pass_create"))
331 goto error;
332
333 RELEASE_CURRENT();
334 return pass;
335
336 error:
337 PL_ERR(gpu, "Failed creating pass");
338 gl_pass_destroy(gpu, pass);
339 RELEASE_CURRENT();
340 return NULL;
341 }
342
update_var(pl_pass pass,const struct pl_var_update * vu)343 static void update_var(pl_pass pass, const struct pl_var_update *vu)
344 {
345 struct pl_pass_gl *pass_gl = PL_PRIV(pass);
346 const struct pl_var *var = &pass->params.variables[vu->index];
347 GLint loc = pass_gl->var_locs[vu->index];
348
349 switch (var->type) {
350 case PL_VAR_SINT: {
351 const int *i = vu->data;
352 pl_assert(var->dim_m == 1);
353 switch (var->dim_v) {
354 case 1: glUniform1iv(loc, var->dim_a, i); break;
355 case 2: glUniform2iv(loc, var->dim_a, i); break;
356 case 3: glUniform3iv(loc, var->dim_a, i); break;
357 case 4: glUniform4iv(loc, var->dim_a, i); break;
358 default: pl_unreachable();
359 }
360 return;
361 }
362 case PL_VAR_UINT: {
363 const unsigned int *u = vu->data;
364 pl_assert(var->dim_m == 1);
365 switch (var->dim_v) {
366 case 1: glUniform1uiv(loc, var->dim_a, u); break;
367 case 2: glUniform2uiv(loc, var->dim_a, u); break;
368 case 3: glUniform3uiv(loc, var->dim_a, u); break;
369 case 4: glUniform4uiv(loc, var->dim_a, u); break;
370 default: pl_unreachable();
371 }
372 return;
373 }
374 case PL_VAR_FLOAT: {
375 const float *f = vu->data;
376 if (var->dim_m == 1) {
377 switch (var->dim_v) {
378 case 1: glUniform1fv(loc, var->dim_a, f); break;
379 case 2: glUniform2fv(loc, var->dim_a, f); break;
380 case 3: glUniform3fv(loc, var->dim_a, f); break;
381 case 4: glUniform4fv(loc, var->dim_a, f); break;
382 default: pl_unreachable();
383 }
384 } else if (var->dim_m == 2 && var->dim_v == 2) {
385 glUniformMatrix2fv(loc, var->dim_a, GL_FALSE, f);
386 } else if (var->dim_m == 3 && var->dim_v == 3) {
387 glUniformMatrix3fv(loc, var->dim_a, GL_FALSE, f);
388 } else if (var->dim_m == 4 && var->dim_v == 4) {
389 glUniformMatrix4fv(loc, var->dim_a, GL_FALSE, f);
390 } else if (var->dim_m == 2 && var->dim_v == 3) {
391 glUniformMatrix2x3fv(loc, var->dim_a, GL_FALSE, f);
392 } else if (var->dim_m == 3 && var->dim_v == 2) {
393 glUniformMatrix3x2fv(loc, var->dim_a, GL_FALSE, f);
394 } else if (var->dim_m == 2 && var->dim_v == 4) {
395 glUniformMatrix2x4fv(loc, var->dim_a, GL_FALSE, f);
396 } else if (var->dim_m == 4 && var->dim_v == 2) {
397 glUniformMatrix4x2fv(loc, var->dim_a, GL_FALSE, f);
398 } else if (var->dim_m == 3 && var->dim_v == 4) {
399 glUniformMatrix3x4fv(loc, var->dim_a, GL_FALSE, f);
400 } else if (var->dim_m == 4 && var->dim_v == 3) {
401 glUniformMatrix4x3fv(loc, var->dim_a, GL_FALSE, f);
402 } else {
403 pl_unreachable();
404 }
405 return;
406 }
407
408 case PL_VAR_INVALID:
409 case PL_VAR_TYPE_COUNT:
410 break;
411 }
412
413 pl_unreachable();
414 }
415
update_desc(pl_pass pass,int index,const struct pl_desc_binding * db)416 static void update_desc(pl_pass pass, int index, const struct pl_desc_binding *db)
417 {
418 const struct pl_desc *desc = &pass->params.descriptors[index];
419
420 static const GLenum access[] = {
421 [PL_DESC_ACCESS_READWRITE] = GL_READ_WRITE,
422 [PL_DESC_ACCESS_READONLY] = GL_READ_ONLY,
423 [PL_DESC_ACCESS_WRITEONLY] = GL_WRITE_ONLY,
424 };
425
426 static const GLint wraps[PL_TEX_ADDRESS_MODE_COUNT] = {
427 [PL_TEX_ADDRESS_CLAMP] = GL_CLAMP_TO_EDGE,
428 [PL_TEX_ADDRESS_REPEAT] = GL_REPEAT,
429 [PL_TEX_ADDRESS_MIRROR] = GL_MIRRORED_REPEAT,
430 };
431
432 static const GLint filters[PL_TEX_SAMPLE_MODE_COUNT] = {
433 [PL_TEX_SAMPLE_NEAREST] = GL_NEAREST,
434 [PL_TEX_SAMPLE_LINEAR] = GL_LINEAR,
435 };
436
437 switch (desc->type) {
438 case PL_DESC_SAMPLED_TEX: {
439 pl_tex tex = db->object;
440 struct pl_tex_gl *tex_gl = PL_PRIV(tex);
441 glActiveTexture(GL_TEXTURE0 + desc->binding);
442 glBindTexture(tex_gl->target, tex_gl->texture);
443
444 GLint filter = filters[db->sample_mode];
445 GLint wrap = wraps[db->address_mode];
446 glTexParameteri(tex_gl->target, GL_TEXTURE_MIN_FILTER, filter);
447 glTexParameteri(tex_gl->target, GL_TEXTURE_MAG_FILTER, filter);
448 switch (pl_tex_params_dimension(tex->params)) {
449 case 3: glTexParameteri(tex_gl->target, GL_TEXTURE_WRAP_R, wrap);
450 // fall through
451 case 2:
452 glTexParameteri(tex_gl->target, GL_TEXTURE_WRAP_T, wrap);
453 // fall through
454 case 1:
455 glTexParameteri(tex_gl->target, GL_TEXTURE_WRAP_S, wrap);
456 break;
457 }
458 return;
459 }
460 case PL_DESC_STORAGE_IMG: {
461 pl_tex tex = db->object;
462 struct pl_tex_gl *tex_gl = PL_PRIV(tex);
463 glBindImageTexture(desc->binding, tex_gl->texture, 0, GL_FALSE, 0,
464 access[desc->access], tex_gl->iformat);
465 return;
466 }
467 case PL_DESC_BUF_UNIFORM: {
468 pl_buf buf = db->object;
469 struct pl_buf_gl *buf_gl = PL_PRIV(buf);
470 glBindBufferRange(GL_UNIFORM_BUFFER, desc->binding, buf_gl->buffer,
471 buf_gl->offset, buf->params.size);
472 return;
473 }
474 case PL_DESC_BUF_STORAGE: {
475 pl_buf buf = db->object;
476 struct pl_buf_gl *buf_gl = PL_PRIV(buf);
477 glBindBufferRange(GL_SHADER_STORAGE_BUFFER, desc->binding, buf_gl->buffer,
478 buf_gl->offset, buf->params.size);
479 return;
480 }
481 case PL_DESC_BUF_TEXEL_UNIFORM:
482 case PL_DESC_BUF_TEXEL_STORAGE:
483 assert(!"unimplemented"); // TODO
484
485 case PL_DESC_INVALID:
486 case PL_DESC_TYPE_COUNT:
487 break;
488 }
489
490 pl_unreachable();
491 }
492
unbind_desc(pl_pass pass,int index,const struct pl_desc_binding * db)493 static void unbind_desc(pl_pass pass, int index, const struct pl_desc_binding *db)
494 {
495 const struct pl_desc *desc = &pass->params.descriptors[index];
496
497 switch (desc->type) {
498 case PL_DESC_SAMPLED_TEX: {
499 pl_tex tex = db->object;
500 struct pl_tex_gl *tex_gl = PL_PRIV(tex);
501 glActiveTexture(GL_TEXTURE0 + desc->binding);
502 glBindTexture(tex_gl->target, 0);
503 return;
504 }
505 case PL_DESC_STORAGE_IMG: {
506 pl_tex tex = db->object;
507 struct pl_tex_gl *tex_gl = PL_PRIV(tex);
508 glBindImageTexture(desc->binding, 0, 0, GL_FALSE, 0,
509 GL_WRITE_ONLY, GL_R32F);
510 if (desc->access != PL_DESC_ACCESS_READONLY)
511 glMemoryBarrier(tex_gl->barrier);
512 return;
513 }
514 case PL_DESC_BUF_UNIFORM:
515 glBindBufferBase(GL_UNIFORM_BUFFER, desc->binding, 0);
516 return;
517 case PL_DESC_BUF_STORAGE: {
518 pl_buf buf = db->object;
519 struct pl_buf_gl *buf_gl = PL_PRIV(buf);
520 glBindBufferBase(GL_SHADER_STORAGE_BUFFER, desc->binding, 0);
521 if (desc->access != PL_DESC_ACCESS_READONLY)
522 glMemoryBarrier(buf_gl->barrier);
523 return;
524 }
525 case PL_DESC_BUF_TEXEL_UNIFORM:
526 case PL_DESC_BUF_TEXEL_STORAGE:
527 assert(!"unimplemented"); // TODO
528 case PL_DESC_INVALID:
529 case PL_DESC_TYPE_COUNT:
530 break;
531 }
532
533 pl_unreachable();
534 }
535
gl_pass_run(pl_gpu gpu,const struct pl_pass_run_params * params)536 void gl_pass_run(pl_gpu gpu, const struct pl_pass_run_params *params)
537 {
538 if (!MAKE_CURRENT())
539 return;
540
541 pl_pass pass = params->pass;
542 struct pl_pass_gl *pass_gl = PL_PRIV(pass);
543 struct pl_gl *p = PL_PRIV(gpu);
544
545 glUseProgram(pass_gl->program);
546
547 for (int i = 0; i < params->num_var_updates; i++)
548 update_var(pass, ¶ms->var_updates[i]);
549 for (int i = 0; i < pass->params.num_descriptors; i++)
550 update_desc(pass, i, ¶ms->desc_bindings[i]);
551 glActiveTexture(GL_TEXTURE0);
552
553 if (!gl_check_err(gpu, "gl_pass_run: updating uniforms")) {
554 RELEASE_CURRENT();
555 return;
556 }
557
558 switch (pass->params.type) {
559 case PL_PASS_RASTER: {
560 struct pl_tex_gl *target_gl = PL_PRIV(params->target);
561 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, target_gl->fbo);
562 if (!pass->params.load_target && p->has_invalidate_fb) {
563 GLenum fb = target_gl->fbo ? GL_COLOR_ATTACHMENT0 : GL_COLOR;
564 glInvalidateFramebuffer(GL_DRAW_FRAMEBUFFER, 1, &fb);
565 }
566
567 glViewport(params->viewport.x0, params->viewport.y0,
568 pl_rect_w(params->viewport), pl_rect_h(params->viewport));
569 glScissor(params->scissors.x0, params->scissors.y0,
570 pl_rect_w(params->scissors), pl_rect_h(params->scissors));
571 glEnable(GL_SCISSOR_TEST);
572 gl_check_err(gpu, "gl_pass_run: enabling viewport/scissor");
573
574 const struct pl_blend_params *blend = pass->params.blend_params;
575 if (blend) {
576 static const GLenum map_blend[] = {
577 [PL_BLEND_ZERO] = GL_ZERO,
578 [PL_BLEND_ONE] = GL_ONE,
579 [PL_BLEND_SRC_ALPHA] = GL_SRC_ALPHA,
580 [PL_BLEND_ONE_MINUS_SRC_ALPHA] = GL_ONE_MINUS_SRC_ALPHA,
581 };
582
583 glBlendFuncSeparate(map_blend[blend->src_rgb],
584 map_blend[blend->dst_rgb],
585 map_blend[blend->src_alpha],
586 map_blend[blend->dst_alpha]);
587 glEnable(GL_BLEND);
588 }
589 gl_check_err(gpu, "gl_pass_run: enabling blend");
590
591 // Update VBO and VAO
592 pl_buf vert = params->vertex_buf;
593 struct pl_buf_gl *vert_gl = vert ? PL_PRIV(vert) : NULL;
594 glBindBuffer(GL_ARRAY_BUFFER, vert ? vert_gl->buffer : pass_gl->buffer);
595
596 if (!vert) {
597 // Update the buffer directly. In theory we could also do a memcmp
598 // cache here to avoid unnecessary updates.
599 int num_vertices = 0;
600 if (params->index_data) {
601 // Indexed draw, so we need to store all indexed vertices
602 for (int i = 0; i < params->vertex_count; i++)
603 num_vertices = PL_MAX(num_vertices, params->index_data[i]);
604 num_vertices += 1;
605 } else {
606 num_vertices = params->vertex_count;
607 }
608 size_t vert_size = num_vertices * pass->params.vertex_stride;
609 glBufferData(GL_ARRAY_BUFFER, vert_size, params->vertex_data, GL_STREAM_DRAW);
610 }
611
612 if (pass_gl->vao)
613 glBindVertexArray(pass_gl->vao);
614
615 uint64_t vert_id = vert ? vert_gl->id : 0;
616 size_t vert_offset = vert ? params->buf_offset : 0;
617 if (!pass_gl->vao || pass_gl->vao_id != vert_id ||
618 pass_gl->vao_offset != vert_offset)
619 {
620 // We need to update the VAO when the buffer ID or offset changes
621 gl_update_va(pass, vert_offset);
622 pass_gl->vao_id = vert_id;
623 pass_gl->vao_offset = vert_offset;
624 }
625
626 gl_check_err(gpu, "gl_pass_run: update/bind vertex buffer");
627
628 static const GLenum map_prim[PL_PRIM_TYPE_COUNT] = {
629 [PL_PRIM_TRIANGLE_LIST] = GL_TRIANGLES,
630 [PL_PRIM_TRIANGLE_STRIP] = GL_TRIANGLE_STRIP,
631 };
632 GLenum mode = map_prim[pass->params.vertex_type];
633
634 gl_timer_begin(params->timer);
635
636 if (params->index_data) {
637
638 // GL allows taking indices directly from a pointer
639 glDrawElements(mode, params->vertex_count, GL_UNSIGNED_SHORT,
640 params->index_data);
641
642 } else if (params->index_buf) {
643
644 // The pointer argument becomes the index buffer offset
645 struct pl_buf_gl *index_gl = PL_PRIV(params->index_buf);
646 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_gl->buffer);
647 glDrawElements(mode, params->vertex_count, GL_UNSIGNED_SHORT,
648 (void *) params->index_offset);
649 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
650
651 } else {
652
653 // Note: the VBO offset is handled in the VAO
654 glDrawArrays(mode, 0, params->vertex_count);
655 }
656
657 gl_timer_end(params->timer);
658 gl_check_err(gpu, "gl_pass_run: drawing");
659
660 if (pass_gl->vao) {
661 glBindVertexArray(0);
662 } else {
663 for (int i = 0; i < pass->params.num_vertex_attribs; i++)
664 glDisableVertexAttribArray(i);
665 }
666
667 glBindBuffer(GL_ARRAY_BUFFER, 0);
668 glDisable(GL_SCISSOR_TEST);
669 glDisable(GL_BLEND);
670 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
671 break;
672 }
673
674 case PL_PASS_COMPUTE:
675 gl_timer_begin(params->timer);
676 glDispatchCompute(params->compute_groups[0],
677 params->compute_groups[1],
678 params->compute_groups[2]);
679 gl_timer_end(params->timer);
680 break;
681
682 case PL_PASS_INVALID:
683 case PL_PASS_TYPE_COUNT:
684 pl_unreachable();
685 }
686
687 for (int i = 0; i < pass->params.num_descriptors; i++)
688 unbind_desc(pass, i, ¶ms->desc_bindings[i]);
689 glActiveTexture(GL_TEXTURE0);
690
691 glUseProgram(0);
692 gl_check_err(gpu, "gl_pass_run");
693 RELEASE_CURRENT();
694 }
695