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