1 /*
2 * This program is free software; you can redistribute it and/or
3 * modify it under the terms of the GNU General Public License
4 * as published by the Free Software Foundation; either version 2
5 * of the License, or (at your option) any later version.
6 *
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
11 *
12 * You should have received a copy of the GNU General Public License
13 * along with this program; if not, write to the Free Software Foundation,
14 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15 *
16 * The Original Code is Copyright (C) 2005 Blender Foundation.
17 * All rights reserved.
18 */
19
20 /** \file
21 * \ingroup gpu
22 */
23
24 #include "MEM_guardedalloc.h"
25
26 #include "BLI_dynstr.h"
27 #include "BLI_math_base.h"
28 #include "BLI_math_vector.h"
29 #include "BLI_path_util.h"
30 #include "BLI_string.h"
31 #include "BLI_string_utils.h"
32 #include "BLI_utildefines.h"
33 #include "BLI_vector.hh"
34
35 #include "BKE_appdir.h"
36 #include "BKE_global.h"
37
38 #include "DNA_space_types.h"
39
40 #include "GPU_capabilities.h"
41 #include "GPU_matrix.h"
42 #include "GPU_platform.h"
43 #include "GPU_shader.h"
44 #include "GPU_texture.h"
45 #include "GPU_uniform_buffer.h"
46
47 #include "gpu_backend.hh"
48 #include "gpu_context_private.hh"
49 #include "gpu_shader_private.hh"
50
51 #include "CLG_log.h"
52
53 extern "C" char datatoc_gpu_shader_colorspace_lib_glsl[];
54
55 static CLG_LogRef LOG = {"gpu.shader"};
56
57 using namespace blender;
58 using namespace blender::gpu;
59
60 /* -------------------------------------------------------------------- */
61 /** \name Debug functions
62 * \{ */
63
print_log(Span<const char * > sources,char * log,const char * stage,const bool error)64 void Shader::print_log(Span<const char *> sources, char *log, const char *stage, const bool error)
65 {
66 const char line_prefix[] = " | ";
67 char err_col[] = "\033[31;1m";
68 char warn_col[] = "\033[33;1m";
69 char info_col[] = "\033[0;2m";
70 char reset_col[] = "\033[0;0m";
71 char *sources_combined = BLI_string_join_arrayN((const char **)sources.data(), sources.size());
72 DynStr *dynstr = BLI_dynstr_new();
73
74 if (!CLG_color_support_get(&LOG)) {
75 err_col[0] = warn_col[0] = info_col[0] = reset_col[0] = '\0';
76 }
77
78 BLI_dynstr_appendf(dynstr, "\n");
79
80 char *log_line = log, *line_end;
81 char *error_line_number_end;
82 int error_line, error_char, last_error_line = -2, last_error_char = -1;
83 bool found_line_id = false;
84 while ((line_end = strchr(log_line, '\n'))) {
85 /* Skip empty lines. */
86 if (line_end == log_line) {
87 log_line++;
88 continue;
89 }
90 /* 0 = error, 1 = warning. */
91 int type = -1;
92 /* Skip ERROR: or WARNING:. */
93 const char *prefix[] = {"ERROR", "WARNING"};
94 for (int i = 0; i < ARRAY_SIZE(prefix); i++) {
95 if (STREQLEN(log_line, prefix[i], strlen(prefix[i]))) {
96 log_line += strlen(prefix[i]);
97 type = i;
98 break;
99 }
100 }
101 /* Skip whitespaces and separators. */
102 while (ELEM(log_line[0], ':', '(', ' ')) {
103 log_line++;
104 }
105 /* Parse error line & char numbers. */
106 error_line = error_char = -1;
107 if (log_line[0] >= '0' && log_line[0] <= '9') {
108 error_line = (int)strtol(log_line, &error_line_number_end, 10);
109 /* Try to fetch the error caracter (not always available). */
110 if (ELEM(error_line_number_end[0], '(', ':') && error_line_number_end[1] != ' ') {
111 error_char = (int)strtol(error_line_number_end + 1, &log_line, 10);
112 }
113 else {
114 log_line = error_line_number_end;
115 }
116 /* There can be a 3rd number (case of mesa driver). */
117 if (ELEM(log_line[0], '(', ':') && log_line[1] >= '0' && log_line[1] <= '9') {
118 error_line = error_char;
119 error_char = (int)strtol(log_line + 1, &error_line_number_end, 10);
120 log_line = error_line_number_end;
121 }
122 }
123 /* Skip whitespaces and separators. */
124 while (ELEM(log_line[0], ':', ')', ' ')) {
125 log_line++;
126 }
127 if (error_line == -1) {
128 found_line_id = false;
129 }
130 const char *src_line = sources_combined;
131 if ((error_line != -1) && (error_char != -1)) {
132 if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OFFICIAL)) {
133 /* source:line */
134 int error_source = error_line;
135 if (error_source < sources.size()) {
136 src_line = sources[error_source];
137 error_line = error_char;
138 error_char = -1;
139 }
140 }
141 else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_OFFICIAL) ||
142 GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_OFFICIAL)) {
143 /* 0:line */
144 error_line = error_char;
145 error_char = -1;
146 }
147 else {
148 /* line:char */
149 }
150 }
151 /* Separate from previous block. */
152 if (last_error_line != error_line) {
153 BLI_dynstr_appendf(dynstr, "%s%s%s\n", info_col, line_prefix, reset_col);
154 }
155 else if (error_char != last_error_char) {
156 BLI_dynstr_appendf(dynstr, "%s\n", line_prefix);
157 }
158 /* Print line from the source file that is producing the error. */
159 if ((error_line != -1) && (error_line != last_error_line || error_char != last_error_char)) {
160 const char *src_line_end = src_line;
161 found_line_id = false;
162 /* error_line is 1 based in this case. */
163 int src_line_index = 1;
164 while ((src_line_end = strchr(src_line, '\n'))) {
165 if (src_line_index == error_line) {
166 found_line_id = true;
167 break;
168 }
169 /* Continue to next line. */
170 src_line = src_line_end + 1;
171 src_line_index++;
172 }
173 /* Print error source. */
174 if (found_line_id) {
175 if (error_line != last_error_line) {
176 BLI_dynstr_appendf(dynstr, "%5d | ", src_line_index);
177 }
178 else {
179 BLI_dynstr_appendf(dynstr, line_prefix);
180 }
181 BLI_dynstr_nappend(dynstr, src_line, (src_line_end + 1) - src_line);
182 /* Print char offset. */
183 BLI_dynstr_appendf(dynstr, line_prefix);
184 if (error_char != -1) {
185 for (int i = 0; i < error_char; i++) {
186 BLI_dynstr_appendf(dynstr, " ");
187 }
188 BLI_dynstr_appendf(dynstr, "^");
189 }
190 BLI_dynstr_appendf(dynstr, "\n");
191 }
192 }
193 BLI_dynstr_appendf(dynstr, line_prefix);
194 /* Skip to message. Avoid redundant info. */
195 const char *keywords[] = {"error", "warning"};
196 for (int i = 0; i < ARRAY_SIZE(prefix); i++) {
197 if (STREQLEN(log_line, keywords[i], strlen(keywords[i]))) {
198 log_line += strlen(keywords[i]);
199 type = i;
200 break;
201 }
202 }
203 /* Skip and separators. */
204 while (ELEM(log_line[0], ':', ')')) {
205 log_line++;
206 }
207 if (type == 0) {
208 BLI_dynstr_appendf(dynstr, "%s%s%s: ", err_col, "Error", info_col);
209 }
210 else if (type == 1) {
211 BLI_dynstr_appendf(dynstr, "%s%s%s: ", warn_col, "Warning", info_col);
212 }
213 /* Print the error itself. */
214 BLI_dynstr_append(dynstr, info_col);
215 BLI_dynstr_nappend(dynstr, log_line, (line_end + 1) - log_line);
216 BLI_dynstr_append(dynstr, reset_col);
217 /* Continue to next line. */
218 log_line = line_end + 1;
219 last_error_line = error_line;
220 last_error_char = error_char;
221 }
222 MEM_freeN(sources_combined);
223
224 CLG_Severity severity = error ? CLG_SEVERITY_ERROR : CLG_SEVERITY_WARN;
225
226 if (((LOG.type->flag & CLG_FLAG_USE) && (LOG.type->level >= 0)) ||
227 (severity >= CLG_SEVERITY_WARN)) {
228 const char *_str = BLI_dynstr_get_cstring(dynstr);
229 CLG_log_str(LOG.type, severity, this->name, stage, _str);
230 MEM_freeN((void *)_str);
231 }
232
233 BLI_dynstr_free(dynstr);
234 }
235
236 /** \} */
237
238 /* -------------------------------------------------------------------- */
239 /** \name Creation / Destruction
240 * \{ */
241
Shader(const char * sh_name)242 Shader::Shader(const char *sh_name)
243 {
244 BLI_strncpy(this->name, sh_name, sizeof(this->name));
245 }
246
~Shader()247 Shader::~Shader()
248 {
249 delete interface;
250 }
251
standard_defines(Vector<const char * > & sources)252 static void standard_defines(Vector<const char *> &sources)
253 {
254 BLI_assert(sources.size() == 0);
255 /* Version needs to be first. Exact values will be added by implementation. */
256 sources.append("version");
257 /* some useful defines to detect GPU type */
258 if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY)) {
259 sources.append("#define GPU_ATI\n");
260 }
261 else if (GPU_type_matches(GPU_DEVICE_NVIDIA, GPU_OS_ANY, GPU_DRIVER_ANY)) {
262 sources.append("#define GPU_NVIDIA\n");
263 }
264 else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
265 sources.append("#define GPU_INTEL\n");
266 }
267 /* some useful defines to detect OS type */
268 if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_WIN, GPU_DRIVER_ANY)) {
269 sources.append("#define OS_WIN\n");
270 }
271 else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_MAC, GPU_DRIVER_ANY)) {
272 sources.append("#define OS_MAC\n");
273 }
274 else if (GPU_type_matches(GPU_DEVICE_ANY, GPU_OS_UNIX, GPU_DRIVER_ANY)) {
275 sources.append("#define OS_UNIX\n");
276 }
277
278 if (GPU_crappy_amd_driver()) {
279 sources.append("#define GPU_DEPRECATED_AMD_DRIVER\n");
280 }
281 }
282
GPU_shader_create_ex(const char * vertcode,const char * fragcode,const char * geomcode,const char * libcode,const char * defines,const eGPUShaderTFBType tf_type,const char ** tf_names,const int tf_count,const char * shname)283 GPUShader *GPU_shader_create_ex(const char *vertcode,
284 const char *fragcode,
285 const char *geomcode,
286 const char *libcode,
287 const char *defines,
288 const eGPUShaderTFBType tf_type,
289 const char **tf_names,
290 const int tf_count,
291 const char *shname)
292 {
293 /* At least a vertex shader and a fragment shader are required. */
294 BLI_assert((fragcode != NULL) && (vertcode != NULL));
295
296 Shader *shader = GPUBackend::get()->shader_alloc(shname);
297
298 if (vertcode) {
299 Vector<const char *> sources;
300 standard_defines(sources);
301 sources.append("#define GPU_VERTEX_SHADER\n");
302 sources.append("#define IN_OUT out\n");
303 if (geomcode) {
304 sources.append("#define USE_GEOMETRY_SHADER\n");
305 }
306 if (defines) {
307 sources.append(defines);
308 }
309 sources.append(vertcode);
310
311 shader->vertex_shader_from_glsl(sources);
312 }
313
314 if (fragcode) {
315 Vector<const char *> sources;
316 standard_defines(sources);
317 sources.append("#define GPU_FRAGMENT_SHADER\n");
318 sources.append("#define IN_OUT in\n");
319 if (geomcode) {
320 sources.append("#define USE_GEOMETRY_SHADER\n");
321 }
322 if (defines) {
323 sources.append(defines);
324 }
325 if (libcode) {
326 sources.append(libcode);
327 }
328 sources.append(fragcode);
329
330 shader->fragment_shader_from_glsl(sources);
331 }
332
333 if (geomcode) {
334 Vector<const char *> sources;
335 standard_defines(sources);
336 sources.append("#define GPU_GEOMETRY_SHADER\n");
337 if (defines) {
338 sources.append(defines);
339 }
340 sources.append(geomcode);
341
342 shader->geometry_shader_from_glsl(sources);
343 }
344
345 if (tf_names != NULL && tf_count > 0) {
346 BLI_assert(tf_type != GPU_SHADER_TFB_NONE);
347 shader->transform_feedback_names_set(Span<const char *>(tf_names, tf_count), tf_type);
348 }
349
350 if (!shader->finalize()) {
351 delete shader;
352 return NULL;
353 };
354
355 return wrap(shader);
356 }
357
GPU_shader_free(GPUShader * shader)358 void GPU_shader_free(GPUShader *shader)
359 {
360 delete unwrap(shader);
361 }
362
363 /** \} */
364
365 /* -------------------------------------------------------------------- */
366 /** \name Creation utils
367 * \{ */
368
GPU_shader_create(const char * vertcode,const char * fragcode,const char * geomcode,const char * libcode,const char * defines,const char * shname)369 GPUShader *GPU_shader_create(const char *vertcode,
370 const char *fragcode,
371 const char *geomcode,
372 const char *libcode,
373 const char *defines,
374 const char *shname)
375 {
376 return GPU_shader_create_ex(
377 vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, shname);
378 }
379
GPU_shader_create_from_python(const char * vertcode,const char * fragcode,const char * geomcode,const char * libcode,const char * defines)380 GPUShader *GPU_shader_create_from_python(const char *vertcode,
381 const char *fragcode,
382 const char *geomcode,
383 const char *libcode,
384 const char *defines)
385 {
386 char *libcodecat = NULL;
387
388 if (libcode == NULL) {
389 libcode = datatoc_gpu_shader_colorspace_lib_glsl;
390 }
391 else {
392 libcode = libcodecat = BLI_strdupcat(libcode, datatoc_gpu_shader_colorspace_lib_glsl);
393 }
394
395 GPUShader *sh = GPU_shader_create_ex(
396 vertcode, fragcode, geomcode, libcode, defines, GPU_SHADER_TFB_NONE, NULL, 0, "pyGPUShader");
397
398 MEM_SAFE_FREE(libcodecat);
399 return sh;
400 }
401
string_join_array_maybe_alloc(const char ** str_arr,bool * r_is_alloc)402 static const char *string_join_array_maybe_alloc(const char **str_arr, bool *r_is_alloc)
403 {
404 bool is_alloc = false;
405 if (str_arr == NULL) {
406 *r_is_alloc = false;
407 return NULL;
408 }
409 /* Skip empty strings (avoid alloc if we can). */
410 while (str_arr[0] && str_arr[0][0] == '\0') {
411 str_arr++;
412 }
413 int i;
414 for (i = 0; str_arr[i]; i++) {
415 if (i != 0 && str_arr[i][0] != '\0') {
416 is_alloc = true;
417 }
418 }
419 *r_is_alloc = is_alloc;
420 if (is_alloc) {
421 return BLI_string_join_arrayN(str_arr, i);
422 }
423
424 return str_arr[0];
425 }
426
427 /**
428 * Use via #GPU_shader_create_from_arrays macro (avoids passing in param).
429 *
430 * Similar to #DRW_shader_create_with_lib with the ability to include libs for each type of shader.
431 *
432 * It has the advantage that each item can be conditionally included
433 * without having to build the string inline, then free it.
434 *
435 * \param params: NULL terminated arrays of strings.
436 *
437 * Example:
438 * \code{.c}
439 * sh = GPU_shader_create_from_arrays({
440 * .vert = (const char *[]){shader_lib_glsl, shader_vert_glsl, NULL},
441 * .geom = (const char *[]){shader_geom_glsl, NULL},
442 * .frag = (const char *[]){shader_frag_glsl, NULL},
443 * .defs = (const char *[]){"#define DEFINE\n", test ? "#define OTHER_DEFINE\n" : "", NULL},
444 * });
445 * \endcode
446 */
GPU_shader_create_from_arrays_impl(const struct GPU_ShaderCreateFromArray_Params * params,const char * func,int line)447 struct GPUShader *GPU_shader_create_from_arrays_impl(
448 const struct GPU_ShaderCreateFromArray_Params *params, const char *func, int line)
449 {
450 struct {
451 const char *str;
452 bool is_alloc;
453 } str_dst[4] = {{0}};
454 const char **str_src[4] = {params->vert, params->frag, params->geom, params->defs};
455
456 for (int i = 0; i < ARRAY_SIZE(str_src); i++) {
457 str_dst[i].str = string_join_array_maybe_alloc(str_src[i], &str_dst[i].is_alloc);
458 }
459
460 char name[64];
461 BLI_snprintf(name, sizeof(name), "%s_%d", func, line);
462
463 GPUShader *sh = GPU_shader_create(
464 str_dst[0].str, str_dst[1].str, str_dst[2].str, NULL, str_dst[3].str, name);
465
466 for (int i = 0; i < ARRAY_SIZE(str_dst); i++) {
467 if (str_dst[i].is_alloc) {
468 MEM_freeN((void *)str_dst[i].str);
469 }
470 }
471 return sh;
472 }
473
474 /** \} */
475
476 /* -------------------------------------------------------------------- */
477 /** \name Binding
478 * \{ */
479
GPU_shader_bind(GPUShader * gpu_shader)480 void GPU_shader_bind(GPUShader *gpu_shader)
481 {
482 Shader *shader = unwrap(gpu_shader);
483
484 Context *ctx = Context::get();
485
486 if (ctx->shader != shader) {
487 ctx->shader = shader;
488 shader->bind();
489 GPU_matrix_bind(gpu_shader);
490 GPU_shader_set_srgb_uniform(gpu_shader);
491 }
492
493 if (GPU_matrix_dirty_get()) {
494 GPU_matrix_bind(gpu_shader);
495 }
496 }
497
GPU_shader_unbind(void)498 void GPU_shader_unbind(void)
499 {
500 #ifndef NDEBUG
501 Context *ctx = Context::get();
502 if (ctx->shader) {
503 ctx->shader->unbind();
504 }
505 ctx->shader = NULL;
506 #endif
507 }
508
509 /** \} */
510
511 /* -------------------------------------------------------------------- */
512 /** \name Transform feedback
513 *
514 * TODO(fclem): Should be replaced by compute shaders.
515 * \{ */
516
GPU_shader_transform_feedback_enable(GPUShader * shader,GPUVertBuf * vertbuf)517 bool GPU_shader_transform_feedback_enable(GPUShader *shader, GPUVertBuf *vertbuf)
518 {
519 return unwrap(shader)->transform_feedback_enable(vertbuf);
520 }
521
GPU_shader_transform_feedback_disable(GPUShader * shader)522 void GPU_shader_transform_feedback_disable(GPUShader *shader)
523 {
524 unwrap(shader)->transform_feedback_disable();
525 }
526
527 /** \} */
528
529 /* -------------------------------------------------------------------- */
530 /** \name Uniforms / Resource location
531 * \{ */
532
GPU_shader_get_uniform(GPUShader * shader,const char * name)533 int GPU_shader_get_uniform(GPUShader *shader, const char *name)
534 {
535 ShaderInterface *interface = unwrap(shader)->interface;
536 const ShaderInput *uniform = interface->uniform_get(name);
537 return uniform ? uniform->location : -1;
538 }
539
GPU_shader_get_builtin_uniform(GPUShader * shader,int builtin)540 int GPU_shader_get_builtin_uniform(GPUShader *shader, int builtin)
541 {
542 ShaderInterface *interface = unwrap(shader)->interface;
543 return interface->uniform_builtin((GPUUniformBuiltin)builtin);
544 }
545
GPU_shader_get_builtin_block(GPUShader * shader,int builtin)546 int GPU_shader_get_builtin_block(GPUShader *shader, int builtin)
547 {
548 ShaderInterface *interface = unwrap(shader)->interface;
549 return interface->ubo_builtin((GPUUniformBlockBuiltin)builtin);
550 }
551
552 /* DEPRECATED. */
GPU_shader_get_uniform_block(GPUShader * shader,const char * name)553 int GPU_shader_get_uniform_block(GPUShader *shader, const char *name)
554 {
555 ShaderInterface *interface = unwrap(shader)->interface;
556 const ShaderInput *ubo = interface->ubo_get(name);
557 return ubo ? ubo->location : -1;
558 }
559
GPU_shader_get_uniform_block_binding(GPUShader * shader,const char * name)560 int GPU_shader_get_uniform_block_binding(GPUShader *shader, const char *name)
561 {
562 ShaderInterface *interface = unwrap(shader)->interface;
563 const ShaderInput *ubo = interface->ubo_get(name);
564 return ubo ? ubo->binding : -1;
565 }
566
GPU_shader_get_texture_binding(GPUShader * shader,const char * name)567 int GPU_shader_get_texture_binding(GPUShader *shader, const char *name)
568 {
569 ShaderInterface *interface = unwrap(shader)->interface;
570 const ShaderInput *tex = interface->uniform_get(name);
571 return tex ? tex->binding : -1;
572 }
573
GPU_shader_get_attribute(GPUShader * shader,const char * name)574 int GPU_shader_get_attribute(GPUShader *shader, const char *name)
575 {
576 ShaderInterface *interface = unwrap(shader)->interface;
577 const ShaderInput *attr = interface->attr_get(name);
578 return attr ? attr->location : -1;
579 }
580
581 /** \} */
582
583 /* -------------------------------------------------------------------- */
584 /** \name Getters
585 * \{ */
586
587 /* Clement : Temp */
GPU_shader_get_program(GPUShader * UNUSED (shader))588 int GPU_shader_get_program(GPUShader *UNUSED(shader))
589 {
590 /* TODO fixme */
591 return (int)0;
592 }
593
594 /** \} */
595
596 /* -------------------------------------------------------------------- */
597 /** \name Uniforms setters
598 * \{ */
599
GPU_shader_uniform_vector(GPUShader * shader,int loc,int len,int arraysize,const float * value)600 void GPU_shader_uniform_vector(
601 GPUShader *shader, int loc, int len, int arraysize, const float *value)
602 {
603 unwrap(shader)->uniform_float(loc, len, arraysize, value);
604 }
605
GPU_shader_uniform_vector_int(GPUShader * shader,int loc,int len,int arraysize,const int * value)606 void GPU_shader_uniform_vector_int(
607 GPUShader *shader, int loc, int len, int arraysize, const int *value)
608 {
609 unwrap(shader)->uniform_int(loc, len, arraysize, value);
610 }
611
GPU_shader_uniform_int(GPUShader * shader,int location,int value)612 void GPU_shader_uniform_int(GPUShader *shader, int location, int value)
613 {
614 GPU_shader_uniform_vector_int(shader, location, 1, 1, &value);
615 }
616
GPU_shader_uniform_float(GPUShader * shader,int location,float value)617 void GPU_shader_uniform_float(GPUShader *shader, int location, float value)
618 {
619 GPU_shader_uniform_vector(shader, location, 1, 1, &value);
620 }
621
GPU_shader_uniform_1i(GPUShader * sh,const char * name,int value)622 void GPU_shader_uniform_1i(GPUShader *sh, const char *name, int value)
623 {
624 const int loc = GPU_shader_get_uniform(sh, name);
625 GPU_shader_uniform_int(sh, loc, value);
626 }
627
GPU_shader_uniform_1b(GPUShader * sh,const char * name,bool value)628 void GPU_shader_uniform_1b(GPUShader *sh, const char *name, bool value)
629 {
630 GPU_shader_uniform_1i(sh, name, value ? 1 : 0);
631 }
632
GPU_shader_uniform_2f(GPUShader * sh,const char * name,float x,float y)633 void GPU_shader_uniform_2f(GPUShader *sh, const char *name, float x, float y)
634 {
635 const float data[2] = {x, y};
636 GPU_shader_uniform_2fv(sh, name, data);
637 }
638
GPU_shader_uniform_3f(GPUShader * sh,const char * name,float x,float y,float z)639 void GPU_shader_uniform_3f(GPUShader *sh, const char *name, float x, float y, float z)
640 {
641 const float data[3] = {x, y, z};
642 GPU_shader_uniform_3fv(sh, name, data);
643 }
644
GPU_shader_uniform_4f(GPUShader * sh,const char * name,float x,float y,float z,float w)645 void GPU_shader_uniform_4f(GPUShader *sh, const char *name, float x, float y, float z, float w)
646 {
647 const float data[4] = {x, y, z, w};
648 GPU_shader_uniform_4fv(sh, name, data);
649 }
650
GPU_shader_uniform_1f(GPUShader * sh,const char * name,float value)651 void GPU_shader_uniform_1f(GPUShader *sh, const char *name, float value)
652 {
653 const int loc = GPU_shader_get_uniform(sh, name);
654 GPU_shader_uniform_float(sh, loc, value);
655 }
656
GPU_shader_uniform_2fv(GPUShader * sh,const char * name,const float data[2])657 void GPU_shader_uniform_2fv(GPUShader *sh, const char *name, const float data[2])
658 {
659 const int loc = GPU_shader_get_uniform(sh, name);
660 GPU_shader_uniform_vector(sh, loc, 2, 1, data);
661 }
662
GPU_shader_uniform_3fv(GPUShader * sh,const char * name,const float data[3])663 void GPU_shader_uniform_3fv(GPUShader *sh, const char *name, const float data[3])
664 {
665 const int loc = GPU_shader_get_uniform(sh, name);
666 GPU_shader_uniform_vector(sh, loc, 3, 1, data);
667 }
668
GPU_shader_uniform_4fv(GPUShader * sh,const char * name,const float data[4])669 void GPU_shader_uniform_4fv(GPUShader *sh, const char *name, const float data[4])
670 {
671 const int loc = GPU_shader_get_uniform(sh, name);
672 GPU_shader_uniform_vector(sh, loc, 4, 1, data);
673 }
674
GPU_shader_uniform_mat4(GPUShader * sh,const char * name,const float data[4][4])675 void GPU_shader_uniform_mat4(GPUShader *sh, const char *name, const float data[4][4])
676 {
677 const int loc = GPU_shader_get_uniform(sh, name);
678 GPU_shader_uniform_vector(sh, loc, 16, 1, (const float *)data);
679 }
680
GPU_shader_uniform_2fv_array(GPUShader * sh,const char * name,int len,const float (* val)[2])681 void GPU_shader_uniform_2fv_array(GPUShader *sh, const char *name, int len, const float (*val)[2])
682 {
683 const int loc = GPU_shader_get_uniform(sh, name);
684 GPU_shader_uniform_vector(sh, loc, 2, len, (const float *)val);
685 }
686
GPU_shader_uniform_4fv_array(GPUShader * sh,const char * name,int len,const float (* val)[4])687 void GPU_shader_uniform_4fv_array(GPUShader *sh, const char *name, int len, const float (*val)[4])
688 {
689 const int loc = GPU_shader_get_uniform(sh, name);
690 GPU_shader_uniform_vector(sh, loc, 4, len, (const float *)val);
691 }
692
693 /** \} */
694
695 /* -------------------------------------------------------------------- */
696 /** \name sRGB Rendering Workaround
697 *
698 * The viewport overlay frame-buffer is sRGB and will expect shaders to output display referred
699 * Linear colors. But other frame-buffers (i.e: the area frame-buffers) are not sRGB and require
700 * the shader output color to be in sRGB space
701 * (assumed display encoded color-space as the time of writing).
702 * For this reason we have a uniform to switch the transform on and off depending on the current
703 * frame-buffer color-space.
704 * \{ */
705
706 static int g_shader_builtin_srgb_transform = 0;
707
GPU_shader_set_srgb_uniform(GPUShader * shader)708 void GPU_shader_set_srgb_uniform(GPUShader *shader)
709 {
710 int32_t loc = GPU_shader_get_builtin_uniform(shader, GPU_UNIFORM_SRGB_TRANSFORM);
711 if (loc != -1) {
712 GPU_shader_uniform_vector_int(shader, loc, 1, 1, &g_shader_builtin_srgb_transform);
713 }
714 }
715
GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)716 void GPU_shader_set_framebuffer_srgb_target(int use_srgb_to_linear)
717 {
718 g_shader_builtin_srgb_transform = use_srgb_to_linear;
719 }
720
721 /** \} */
722