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