Merge branch 'blender2.7'
[blender.git] / source / blender / gpu / intern / gpu_immediate.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program 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 General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2016 by Mike Erwin.
19  * All rights reserved.
20  *
21  * Contributor(s): Blender Foundation
22  *
23  * ***** END GPL LICENSE BLOCK *****
24  */
25
26 /** \file blender/gpu/intern/gpu_immediate.c
27  *  \ingroup gpu
28  *
29  * GPU immediate mode work-alike
30  */
31
32 #include "UI_resources.h"
33
34 #include "GPU_attr_binding.h"
35 #include "GPU_immediate.h"
36
37 #include "gpu_attr_binding_private.h"
38 #include "gpu_context_private.h"
39 #include "gpu_primitive_private.h"
40 #include "gpu_shader_private.h"
41 #include "gpu_vertex_format_private.h"
42
43 #include <string.h>
44 #include <stdlib.h>
45
46 /* necessary functions from matrix API */
47 extern void GPU_matrix_bind(const GPUShaderInterface *);
48 extern bool GPU_matrix_dirty_get(void);
49
50 typedef struct {
51         /* TODO: organize this struct by frequency of change (run-time) */
52
53         GPUBatch *batch;
54         GPUContext *context;
55
56         /* current draw call */
57         GLubyte *buffer_data;
58         uint buffer_offset;
59         uint buffer_bytes_mapped;
60         uint vertex_len;
61         bool strict_vertex_len;
62         GPUPrimType prim_type;
63
64         GPUVertFormat vertex_format;
65
66         /* current vertex */
67         uint vertex_idx;
68         GLubyte *vertex_data;
69         uint16_t unassigned_attr_bits; /* which attributes of current vertex have not been given values? */
70
71         GLuint vbo_id;
72         GLuint vao_id;
73
74         GLuint bound_program;
75         const GPUShaderInterface *shader_interface;
76         GPUAttrBinding attr_binding;
77         uint16_t prev_enabled_attr_bits; /* <-- only affects this VAO, so we're ok */
78 } Immediate;
79
80 /* size of internal buffer -- make this adjustable? */
81 #define IMM_BUFFER_SIZE (4 * 1024 * 1024)
82
83 static bool initialized = false;
84 static Immediate imm;
85
86 void immInit(void)
87 {
88 #if TRUST_NO_ONE
89         assert(!initialized);
90 #endif
91         memset(&imm, 0, sizeof(Immediate));
92
93         imm.vbo_id = GPU_buf_alloc();
94         glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
95         glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
96
97         imm.prim_type = GPU_PRIM_NONE;
98         imm.strict_vertex_len = true;
99
100         glBindBuffer(GL_ARRAY_BUFFER, 0);
101         initialized = true;
102 }
103
104 void immActivate(void)
105 {
106 #if TRUST_NO_ONE
107         assert(initialized);
108         assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we're not between a Begin/End pair */
109         assert(imm.vao_id == 0);
110 #endif
111         imm.vao_id = GPU_vao_alloc();
112         imm.context = GPU_context_active_get();
113 }
114
115 void immDeactivate(void)
116 {
117 #if TRUST_NO_ONE
118         assert(initialized);
119         assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we're not between a Begin/End pair */
120         assert(imm.vao_id != 0);
121 #endif
122         GPU_vao_free(imm.vao_id, imm.context);
123         imm.vao_id = 0;
124         imm.prev_enabled_attr_bits = 0;
125 }
126
127 void immDestroy(void)
128 {
129         GPU_buf_free(imm.vbo_id);
130         initialized = false;
131 }
132
133 GPUVertFormat *immVertexFormat(void)
134 {
135         GPU_vertformat_clear(&imm.vertex_format);
136         return &imm.vertex_format;
137 }
138
139 void immBindProgram(GLuint program, const GPUShaderInterface *shaderface)
140 {
141 #if TRUST_NO_ONE
142         assert(imm.bound_program == 0);
143         assert(glIsProgram(program));
144 #endif
145
146         imm.bound_program = program;
147         imm.shader_interface = shaderface;
148
149         if (!imm.vertex_format.packed)
150                 VertexFormat_pack(&imm.vertex_format);
151
152         glUseProgram(program);
153         get_attr_locations(&imm.vertex_format, &imm.attr_binding, shaderface);
154         GPU_matrix_bind(shaderface);
155 }
156
157 void immBindBuiltinProgram(eGPUBuiltinShader shader_id)
158 {
159         GPUShader *shader = GPU_shader_get_builtin_shader(shader_id);
160         immBindProgram(shader->program, shader->interface);
161 }
162
163 void immUnbindProgram(void)
164 {
165 #if TRUST_NO_ONE
166         assert(imm.bound_program != 0);
167 #endif
168 #if PROGRAM_NO_OPTI
169         glUseProgram(0);
170 #endif
171         imm.bound_program = 0;
172 }
173
174 #if TRUST_NO_ONE
175 static bool vertex_count_makes_sense_for_primitive(uint vertex_len, GPUPrimType prim_type)
176 {
177         /* does vertex_len make sense for this primitive type? */
178         if (vertex_len == 0) {
179                 return false;
180         }
181
182         switch (prim_type) {
183                 case GPU_PRIM_POINTS:
184                         return true;
185                 case GPU_PRIM_LINES:
186                         return vertex_len % 2 == 0;
187                 case GPU_PRIM_LINE_STRIP:
188                 case GPU_PRIM_LINE_LOOP:
189                         return vertex_len >= 2;
190                 case GPU_PRIM_LINE_STRIP_ADJ:
191                         return vertex_len >= 4;
192                 case GPU_PRIM_TRIS:
193                         return vertex_len % 3 == 0;
194                 case GPU_PRIM_TRI_STRIP:
195                 case GPU_PRIM_TRI_FAN:
196                         return vertex_len >= 3;
197                 default:
198                         return false;
199         }
200 }
201 #endif
202
203 void immBegin(GPUPrimType prim_type, uint vertex_len)
204 {
205 #if TRUST_NO_ONE
206         assert(initialized);
207         assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
208         assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
209 #endif
210         imm.prim_type = prim_type;
211         imm.vertex_len = vertex_len;
212         imm.vertex_idx = 0;
213         imm.unassigned_attr_bits = imm.attr_binding.enabled_bits;
214
215         /* how many bytes do we need for this draw call? */
216         const uint bytes_needed = vertex_buffer_size(&imm.vertex_format, vertex_len);
217
218 #if TRUST_NO_ONE
219         assert(bytes_needed <= IMM_BUFFER_SIZE);
220 #endif
221
222         glBindBuffer(GL_ARRAY_BUFFER, imm.vbo_id);
223
224         /* does the current buffer have enough room? */
225         const uint available_bytes = IMM_BUFFER_SIZE - imm.buffer_offset;
226         /* ensure vertex data is aligned */
227         const uint pre_padding = padding(imm.buffer_offset, imm.vertex_format.stride); /* might waste a little space, but it's safe */
228         if ((bytes_needed + pre_padding) <= available_bytes) {
229                 imm.buffer_offset += pre_padding;
230         }
231         else {
232                 /* orphan this buffer & start with a fresh one */
233                 /* this method works on all platforms, old & new */
234                 glBufferData(GL_ARRAY_BUFFER, IMM_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW);
235
236                 imm.buffer_offset = 0;
237         }
238
239 /*      printf("mapping %u to %u\n", imm.buffer_offset, imm.buffer_offset + bytes_needed - 1); */
240
241         imm.buffer_data = glMapBufferRange(GL_ARRAY_BUFFER, imm.buffer_offset, bytes_needed,
242                                            GL_MAP_WRITE_BIT | GL_MAP_UNSYNCHRONIZED_BIT | (imm.strict_vertex_len ? 0 : GL_MAP_FLUSH_EXPLICIT_BIT));
243
244 #if TRUST_NO_ONE
245         assert(imm.buffer_data != NULL);
246 #endif
247
248         imm.buffer_bytes_mapped = bytes_needed;
249         imm.vertex_data = imm.buffer_data;
250 }
251
252 void immBeginAtMost(GPUPrimType prim_type, uint vertex_len)
253 {
254 #if TRUST_NO_ONE
255         assert(vertex_len > 0);
256 #endif
257
258         imm.strict_vertex_len = false;
259         immBegin(prim_type, vertex_len);
260 }
261
262
263 GPUBatch *immBeginBatch(GPUPrimType prim_type, uint vertex_len)
264 {
265 #if TRUST_NO_ONE
266         assert(initialized);
267         assert(imm.prim_type == GPU_PRIM_NONE); /* make sure we haven't already begun */
268         assert(vertex_count_makes_sense_for_primitive(vertex_len, prim_type));
269 #endif
270         imm.prim_type = prim_type;
271         imm.vertex_len = vertex_len;
272         imm.vertex_idx = 0;
273         imm.unassigned_attr_bits = imm.attr_binding.enabled_bits;
274
275         GPUVertBuf *verts = GPU_vertbuf_create_with_format(&imm.vertex_format);
276         GPU_vertbuf_data_alloc(verts, vertex_len);
277
278         imm.buffer_bytes_mapped = GPU_vertbuf_size_get(verts);
279         imm.vertex_data = verts->data;
280
281         imm.batch = GPU_batch_create_ex(prim_type, verts, NULL, GPU_BATCH_OWNS_VBO);
282         imm.batch->phase = GPU_BATCH_BUILDING;
283
284         return imm.batch;
285 }
286
287 GPUBatch *immBeginBatchAtMost(GPUPrimType prim_type, uint vertex_len)
288 {
289         imm.strict_vertex_len = false;
290         return immBeginBatch(prim_type, vertex_len);
291 }
292
293 static void immDrawSetup(void)
294 {
295         /* set up VAO -- can be done during Begin or End really */
296         glBindVertexArray(imm.vao_id);
297
298         /* Enable/Disable vertex attributes as needed. */
299         if (imm.attr_binding.enabled_bits != imm.prev_enabled_attr_bits) {
300                 for (uint loc = 0; loc < GPU_VERT_ATTR_MAX_LEN; ++loc) {
301                         bool is_enabled = imm.attr_binding.enabled_bits & (1 << loc);
302                         bool was_enabled = imm.prev_enabled_attr_bits & (1 << loc);
303
304                         if (is_enabled && !was_enabled) {
305                                 glEnableVertexAttribArray(loc);
306                         }
307                         else if (was_enabled && !is_enabled) {
308                                 glDisableVertexAttribArray(loc);
309                         }
310                 }
311
312                 imm.prev_enabled_attr_bits = imm.attr_binding.enabled_bits;
313         }
314
315         const uint stride = imm.vertex_format.stride;
316
317         for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
318                 const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
319
320                 const uint offset = imm.buffer_offset + a->offset;
321                 const GLvoid *pointer = (const GLubyte *)0 + offset;
322
323                 const uint loc = read_attr_location(&imm.attr_binding, a_idx);
324
325                 switch (a->fetch_mode) {
326                         case GPU_FETCH_FLOAT:
327                         case GPU_FETCH_INT_TO_FLOAT:
328                                 glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_FALSE, stride, pointer);
329                                 break;
330                         case GPU_FETCH_INT_TO_FLOAT_UNIT:
331                                 glVertexAttribPointer(loc, a->comp_len, a->gl_comp_type, GL_TRUE, stride, pointer);
332                                 break;
333                         case GPU_FETCH_INT:
334                                 glVertexAttribIPointer(loc, a->comp_len, a->gl_comp_type, stride, pointer);
335                 }
336         }
337
338         if (GPU_matrix_dirty_get()) {
339                 GPU_matrix_bind(imm.shader_interface);
340         }
341 }
342
343 void immEnd(void)
344 {
345 #if TRUST_NO_ONE
346         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
347 #endif
348
349         uint buffer_bytes_used;
350         if (imm.strict_vertex_len) {
351 #if TRUST_NO_ONE
352                 assert(imm.vertex_idx == imm.vertex_len); /* with all vertices defined */
353 #endif
354                 buffer_bytes_used = imm.buffer_bytes_mapped;
355         }
356         else {
357 #if TRUST_NO_ONE
358                 assert(imm.vertex_idx <= imm.vertex_len);
359 #endif
360                 if (imm.vertex_idx == imm.vertex_len) {
361                         buffer_bytes_used = imm.buffer_bytes_mapped;
362                 }
363                 else {
364 #if TRUST_NO_ONE
365                         assert(imm.vertex_idx == 0 || vertex_count_makes_sense_for_primitive(imm.vertex_idx, imm.prim_type));
366 #endif
367                         imm.vertex_len = imm.vertex_idx;
368                         buffer_bytes_used = vertex_buffer_size(&imm.vertex_format, imm.vertex_len);
369                         /* unused buffer bytes are available to the next immBegin */
370                 }
371                 /* tell OpenGL what range was modified so it doesn't copy the whole mapped range */
372                 glFlushMappedBufferRange(GL_ARRAY_BUFFER, 0, buffer_bytes_used);
373         }
374
375         if (imm.batch) {
376                 if (buffer_bytes_used != imm.buffer_bytes_mapped) {
377                         GPU_vertbuf_data_resize(imm.batch->verts[0], imm.vertex_len);
378                         /* TODO: resize only if vertex count is much smaller */
379                 }
380                 GPU_batch_program_set(imm.batch, imm.bound_program, imm.shader_interface);
381                 imm.batch->phase = GPU_BATCH_READY_TO_DRAW;
382                 imm.batch = NULL; /* don't free, batch belongs to caller */
383         }
384         else {
385                 glUnmapBuffer(GL_ARRAY_BUFFER);
386                 if (imm.vertex_len > 0) {
387                         immDrawSetup();
388                         glDrawArrays(convert_prim_type_to_gl(imm.prim_type), 0, imm.vertex_len);
389                 }
390                 /* These lines are causing crash on startup on some old GPU + drivers.
391                  * They are not required so just comment them. (T55722) */
392                 // glBindBuffer(GL_ARRAY_BUFFER, 0);
393                 // glBindVertexArray(0);
394                 /* prep for next immBegin */
395                 imm.buffer_offset += buffer_bytes_used;
396         }
397
398         /* prep for next immBegin */
399         imm.prim_type = GPU_PRIM_NONE;
400         imm.strict_vertex_len = true;
401 }
402
403 static void setAttrValueBit(uint attr_id)
404 {
405         uint16_t mask = 1 << attr_id;
406 #if TRUST_NO_ONE
407         assert(imm.unassigned_attr_bits & mask); /* not already set */
408 #endif
409         imm.unassigned_attr_bits &= ~mask;
410 }
411
412
413 /* --- generic attribute functions --- */
414
415 void immAttr1f(uint attr_id, float x)
416 {
417         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
418 #if TRUST_NO_ONE
419         assert(attr_id < imm.vertex_format.attr_len);
420         assert(attr->comp_type == GPU_COMP_F32);
421         assert(attr->comp_len == 1);
422         assert(imm.vertex_idx < imm.vertex_len);
423         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
424 #endif
425         setAttrValueBit(attr_id);
426
427         float *data = (float *)(imm.vertex_data + attr->offset);
428 /*      printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
429
430         data[0] = x;
431 }
432
433 void immAttr2f(uint attr_id, float x, float y)
434 {
435         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
436 #if TRUST_NO_ONE
437         assert(attr_id < imm.vertex_format.attr_len);
438         assert(attr->comp_type == GPU_COMP_F32);
439         assert(attr->comp_len == 2);
440         assert(imm.vertex_idx < imm.vertex_len);
441         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
442 #endif
443         setAttrValueBit(attr_id);
444
445         float *data = (float *)(imm.vertex_data + attr->offset);
446 /*      printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
447
448         data[0] = x;
449         data[1] = y;
450 }
451
452 void immAttr3f(uint attr_id, float x, float y, float z)
453 {
454         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
455 #if TRUST_NO_ONE
456         assert(attr_id < imm.vertex_format.attr_len);
457         assert(attr->comp_type == GPU_COMP_F32);
458         assert(attr->comp_len == 3);
459         assert(imm.vertex_idx < imm.vertex_len);
460         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
461 #endif
462         setAttrValueBit(attr_id);
463
464         float *data = (float *)(imm.vertex_data + attr->offset);
465 /*      printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
466
467         data[0] = x;
468         data[1] = y;
469         data[2] = z;
470 }
471
472 void immAttr4f(uint attr_id, float x, float y, float z, float w)
473 {
474         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
475 #if TRUST_NO_ONE
476         assert(attr_id < imm.vertex_format.attr_len);
477         assert(attr->comp_type == GPU_COMP_F32);
478         assert(attr->comp_len == 4);
479         assert(imm.vertex_idx < imm.vertex_len);
480         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
481 #endif
482         setAttrValueBit(attr_id);
483
484         float *data = (float *)(imm.vertex_data + attr->offset);
485 /*      printf("%s %td %p\n", __FUNCTION__, (GLubyte*)data - imm.buffer_data, data); */
486
487         data[0] = x;
488         data[1] = y;
489         data[2] = z;
490         data[3] = w;
491 }
492
493 void immAttr1u(uint attr_id, uint x)
494 {
495         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
496 #if TRUST_NO_ONE
497         assert(attr_id < imm.vertex_format.attr_len);
498         assert(attr->comp_type == GPU_COMP_U32);
499         assert(attr->comp_len == 1);
500         assert(imm.vertex_idx < imm.vertex_len);
501         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
502 #endif
503         setAttrValueBit(attr_id);
504
505         uint *data = (uint *)(imm.vertex_data + attr->offset);
506
507         data[0] = x;
508 }
509
510 void immAttr2i(uint attr_id, int x, int y)
511 {
512         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
513 #if TRUST_NO_ONE
514         assert(attr_id < imm.vertex_format.attr_len);
515         assert(attr->comp_type == GPU_COMP_I32);
516         assert(attr->comp_len == 2);
517         assert(imm.vertex_idx < imm.vertex_len);
518         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
519 #endif
520         setAttrValueBit(attr_id);
521
522         int *data = (int *)(imm.vertex_data + attr->offset);
523
524         data[0] = x;
525         data[1] = y;
526 }
527
528 void immAttr2s(uint attr_id, short x, short y)
529 {
530         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
531 #if TRUST_NO_ONE
532         assert(attr_id < imm.vertex_format.attr_len);
533         assert(attr->comp_type == GPU_COMP_I16);
534         assert(attr->comp_len == 2);
535         assert(imm.vertex_idx < imm.vertex_len);
536         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
537 #endif
538         setAttrValueBit(attr_id);
539
540         short *data = (short *)(imm.vertex_data + attr->offset);
541
542         data[0] = x;
543         data[1] = y;
544 }
545
546 void immAttr2fv(uint attr_id, const float data[2])
547 {
548         immAttr2f(attr_id, data[0], data[1]);
549 }
550
551 void immAttr3fv(uint attr_id, const float data[3])
552 {
553         immAttr3f(attr_id, data[0], data[1], data[2]);
554 }
555
556 void immAttr4fv(uint attr_id, const float data[4])
557 {
558         immAttr4f(attr_id, data[0], data[1], data[2], data[3]);
559 }
560
561 void immAttr3ub(uint attr_id, uchar r, uchar g, uchar b)
562 {
563         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
564 #if TRUST_NO_ONE
565         assert(attr_id < imm.vertex_format.attr_len);
566         assert(attr->comp_type == GPU_COMP_U8);
567         assert(attr->comp_len == 3);
568         assert(imm.vertex_idx < imm.vertex_len);
569         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
570 #endif
571         setAttrValueBit(attr_id);
572
573         GLubyte *data = imm.vertex_data + attr->offset;
574 /*      printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */
575
576         data[0] = r;
577         data[1] = g;
578         data[2] = b;
579 }
580
581 void immAttr4ub(uint attr_id, uchar r, uchar g, uchar b, uchar a)
582 {
583         GPUVertAttr *attr = &imm.vertex_format.attrs[attr_id];
584 #if TRUST_NO_ONE
585         assert(attr_id < imm.vertex_format.attr_len);
586         assert(attr->comp_type == GPU_COMP_U8);
587         assert(attr->comp_len == 4);
588         assert(imm.vertex_idx < imm.vertex_len);
589         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
590 #endif
591         setAttrValueBit(attr_id);
592
593         GLubyte *data = imm.vertex_data + attr->offset;
594 /*      printf("%s %td %p\n", __FUNCTION__, data - imm.buffer_data, data); */
595
596         data[0] = r;
597         data[1] = g;
598         data[2] = b;
599         data[3] = a;
600 }
601
602 void immAttr3ubv(uint attr_id, const uchar data[3])
603 {
604         immAttr3ub(attr_id, data[0], data[1], data[2]);
605 }
606
607 void immAttr4ubv(uint attr_id, const uchar data[4])
608 {
609         immAttr4ub(attr_id, data[0], data[1], data[2], data[3]);
610 }
611
612 void immAttrSkip(uint attr_id)
613 {
614 #if TRUST_NO_ONE
615         assert(attr_id < imm.vertex_format.attr_len);
616         assert(imm.vertex_idx < imm.vertex_len);
617         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
618 #endif
619         setAttrValueBit(attr_id);
620 }
621
622 static void immEndVertex(void) /* and move on to the next vertex */
623 {
624 #if TRUST_NO_ONE
625         assert(imm.prim_type != GPU_PRIM_NONE); /* make sure we're between a Begin/End pair */
626         assert(imm.vertex_idx < imm.vertex_len);
627 #endif
628
629         /* Have all attributes been assigned values?
630          * If not, copy value from previous vertex. */
631         if (imm.unassigned_attr_bits) {
632 #if TRUST_NO_ONE
633                 assert(imm.vertex_idx > 0); /* first vertex must have all attributes specified */
634 #endif
635                 for (uint a_idx = 0; a_idx < imm.vertex_format.attr_len; ++a_idx) {
636                         if ((imm.unassigned_attr_bits >> a_idx) & 1) {
637                                 const GPUVertAttr *a = &imm.vertex_format.attrs[a_idx];
638
639 /*                              printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx); */
640
641                                 GLubyte *data = imm.vertex_data + a->offset;
642                                 memcpy(data, data - imm.vertex_format.stride, a->sz);
643                                 /* TODO: consolidate copy of adjacent attributes */
644                         }
645                 }
646         }
647
648         imm.vertex_idx++;
649         imm.vertex_data += imm.vertex_format.stride;
650         imm.unassigned_attr_bits = imm.attr_binding.enabled_bits;
651 }
652
653 void immVertex2f(uint attr_id, float x, float y)
654 {
655         immAttr2f(attr_id, x, y);
656         immEndVertex();
657 }
658
659 void immVertex3f(uint attr_id, float x, float y, float z)
660 {
661         immAttr3f(attr_id, x, y, z);
662         immEndVertex();
663 }
664
665 void immVertex4f(uint attr_id, float x, float y, float z, float w)
666 {
667         immAttr4f(attr_id, x, y, z, w);
668         immEndVertex();
669 }
670
671 void immVertex2i(uint attr_id, int x, int y)
672 {
673         immAttr2i(attr_id, x, y);
674         immEndVertex();
675 }
676
677 void immVertex2s(uint attr_id, short x, short y)
678 {
679         immAttr2s(attr_id, x, y);
680         immEndVertex();
681 }
682
683 void immVertex2fv(uint attr_id, const float data[2])
684 {
685         immAttr2f(attr_id, data[0], data[1]);
686         immEndVertex();
687 }
688
689 void immVertex3fv(uint attr_id, const float data[3])
690 {
691         immAttr3f(attr_id, data[0], data[1], data[2]);
692         immEndVertex();
693 }
694
695 void immVertex2iv(uint attr_id, const int data[2])
696 {
697         immAttr2i(attr_id, data[0], data[1]);
698         immEndVertex();
699 }
700
701
702 /* --- generic uniform functions --- */
703
704 #if 0
705 #  if TRUST_NO_ONE
706 #    define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, name); assert(uniform);
707 #  else
708 #    define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, name);
709 #  endif
710 #else
711         /* NOTE: It is possible to have uniform fully optimized out from the shader.
712          *       In this case we can't assert failure or allow NULL-pointer dereference.
713          * TODO(sergey): How can we detect existing-but-optimized-out uniform but still
714          *               catch typos in uniform names passed to immUniform*() functions? */
715 #  define GET_UNIFORM const GPUShaderInput* uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, name); if (uniform == NULL) return;
716 #endif
717
718 void immUniform1f(const char *name, float x)
719 {
720         GET_UNIFORM
721         glUniform1f(uniform->location, x);
722 }
723
724 void immUniform2f(const char *name, float x, float y)
725 {
726         GET_UNIFORM
727         glUniform2f(uniform->location, x, y);
728 }
729
730 void immUniform2fv(const char *name, const float data[2])
731 {
732         GET_UNIFORM
733         glUniform2fv(uniform->location, 1, data);
734 }
735
736 void immUniform3f(const char *name, float x, float y, float z)
737 {
738         GET_UNIFORM
739         glUniform3f(uniform->location, x, y, z);
740 }
741
742 void immUniform3fv(const char *name, const float data[3])
743 {
744         GET_UNIFORM
745         glUniform3fv(uniform->location, 1, data);
746 }
747
748 /* can increase this limit or move to another file */
749 #define MAX_UNIFORM_NAME_LEN 60
750
751 void immUniformArray3fv(const char *bare_name, const float *data, int count)
752 {
753         /* look up "name[0]" when given "name" */
754         const size_t len = strlen(bare_name);
755 #if TRUST_NO_ONE
756         assert(len <= MAX_UNIFORM_NAME_LEN);
757 #endif
758         char name[MAX_UNIFORM_NAME_LEN];
759         strcpy(name, bare_name);
760         name[len + 0] = '[';
761         name[len + 1] = '0';
762         name[len + 2] = ']';
763         name[len + 3] = '\0';
764
765         GET_UNIFORM
766         glUniform3fv(uniform->location, count, data);
767 }
768
769 void immUniform4f(const char *name, float x, float y, float z, float w)
770 {
771         GET_UNIFORM
772         glUniform4f(uniform->location, x, y, z, w);
773 }
774
775 void immUniform4fv(const char *name, const float data[4])
776 {
777         GET_UNIFORM
778         glUniform4fv(uniform->location, 1, data);
779 }
780
781 void immUniformArray4fv(const char *bare_name, const float *data, int count)
782 {
783         /* look up "name[0]" when given "name" */
784         const size_t len = strlen(bare_name);
785 #if TRUST_NO_ONE
786         assert(len <= MAX_UNIFORM_NAME_LEN);
787 #endif
788         char name[MAX_UNIFORM_NAME_LEN];
789         strcpy(name, bare_name);
790         name[len + 0] = '[';
791         name[len + 1] = '0';
792         name[len + 2] = ']';
793         name[len + 3] = '\0';
794
795         GET_UNIFORM
796         glUniform4fv(uniform->location, count, data);
797 }
798
799 void immUniformMatrix4fv(const char *name, const float data[4][4])
800 {
801         GET_UNIFORM
802         glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data);
803 }
804
805 void immUniform1i(const char *name, int x)
806 {
807         GET_UNIFORM
808         glUniform1i(uniform->location, x);
809 }
810
811 void immUniform4iv(const char *name, const int data[4])
812 {
813         GET_UNIFORM
814         glUniform4iv(uniform->location, 1, data);
815 }
816
817 /* --- convenience functions for setting "uniform vec4 color" --- */
818
819 void immUniformColor4f(float r, float g, float b, float a)
820 {
821         const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface, GPU_UNIFORM_COLOR);
822 #if TRUST_NO_ONE
823         assert(uniform != NULL);
824 #endif
825         glUniform4f(uniform->location, r, g, b, a);
826 }
827
828 void immUniformColor4fv(const float rgba[4])
829 {
830         immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
831 }
832
833 void immUniformColor3f(float r, float g, float b)
834 {
835         immUniformColor4f(r, g, b, 1.0f);
836 }
837
838 void immUniformColor3fv(const float rgb[3])
839 {
840         immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f);
841 }
842
843 void immUniformColor3fvAlpha(const float rgb[3], float a)
844 {
845         immUniformColor4f(rgb[0], rgb[1], rgb[2], a);
846 }
847
848 /* TODO: v-- treat as sRGB? --v */
849
850 void immUniformColor3ub(uchar r, uchar g, uchar b)
851 {
852         const float scale = 1.0f / 255.0f;
853         immUniformColor4f(scale * r, scale * g, scale * b, 1.0f);
854 }
855
856 void immUniformColor4ub(uchar r, uchar g, uchar b, uchar a)
857 {
858         const float scale = 1.0f / 255.0f;
859         immUniformColor4f(scale * r, scale * g, scale * b, scale * a);
860 }
861
862 void immUniformColor3ubv(const uchar rgb[3])
863 {
864         immUniformColor3ub(rgb[0], rgb[1], rgb[2]);
865 }
866
867 void immUniformColor3ubvAlpha(const uchar rgb[3], uchar alpha)
868 {
869         immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha);
870 }
871
872 void immUniformColor4ubv(const uchar rgba[4])
873 {
874         immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]);
875 }
876
877 void immUniformThemeColor(int color_id)
878 {
879         float color[4];
880         UI_GetThemeColor4fv(color_id, color);
881         immUniformColor4fv(color);
882 }
883
884 void immUniformThemeColor3(int color_id)
885 {
886         float color[3];
887         UI_GetThemeColor3fv(color_id, color);
888         immUniformColor3fv(color);
889 }
890
891 void immUniformThemeColorShade(int color_id, int offset)
892 {
893         float color[4];
894         UI_GetThemeColorShade4fv(color_id, offset, color);
895         immUniformColor4fv(color);
896 }
897
898 void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
899 {
900         float color[4];
901         UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color);
902         immUniformColor4fv(color);
903 }
904
905 void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset)
906 {
907         float color[4];
908         UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color);
909         immUniformColor4fv(color);
910 }
911
912 void immUniformThemeColorBlend(int color_id1, int color_id2, float fac)
913 {
914         uint8_t color[3];
915         UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color);
916         immUniformColor3ubv(color);
917 }
918
919 void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
920 {
921         uchar col[4];
922         UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col);
923         immUniformColor4ub(col[0], col[1], col[2], col[3]);
924 }