Cleanup: comments (long lines) in gpu
[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 #if 0
638         printf("copying %s from vertex %u to %u\n", a->name, imm.vertex_idx - 1, imm.vertex_idx);
639 #endif
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 /* --- generic uniform functions --- */
702
703 #if 0
704 #  if TRUST_NO_ONE
705 #    define GET_UNIFORM \
706       const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \
707                                                                          name); \
708       assert(uniform);
709 #  else
710 #    define GET_UNIFORM \
711       const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \
712                                                                          name);
713 #  endif
714 #else
715 /* NOTE: It is possible to have uniform fully optimized out from the shader.
716  *       In this case we can't assert failure or allow NULL-pointer dereference.
717  * TODO(sergey): How can we detect existing-but-optimized-out uniform but still
718  *               catch typos in uniform names passed to immUniform*() functions? */
719 #  define GET_UNIFORM \
720     const GPUShaderInput *uniform = GPU_shaderinterface_uniform_ensure(imm.shader_interface, \
721                                                                        name); \
722     if (uniform == NULL) \
723       return;
724 #endif
725
726 void immUniform1f(const char *name, float x)
727 {
728   GET_UNIFORM
729   glUniform1f(uniform->location, x);
730 }
731
732 void immUniform2f(const char *name, float x, float y)
733 {
734   GET_UNIFORM
735   glUniform2f(uniform->location, x, y);
736 }
737
738 void immUniform2fv(const char *name, const float data[2])
739 {
740   GET_UNIFORM
741   glUniform2fv(uniform->location, 1, data);
742 }
743
744 void immUniform3f(const char *name, float x, float y, float z)
745 {
746   GET_UNIFORM
747   glUniform3f(uniform->location, x, y, z);
748 }
749
750 void immUniform3fv(const char *name, const float data[3])
751 {
752   GET_UNIFORM
753   glUniform3fv(uniform->location, 1, data);
754 }
755
756 /* can increase this limit or move to another file */
757 #define MAX_UNIFORM_NAME_LEN 60
758
759 void immUniformArray3fv(const char *bare_name, const float *data, int count)
760 {
761   /* look up "name[0]" when given "name" */
762   const size_t len = strlen(bare_name);
763 #if TRUST_NO_ONE
764   assert(len <= MAX_UNIFORM_NAME_LEN);
765 #endif
766   char name[MAX_UNIFORM_NAME_LEN];
767   strcpy(name, bare_name);
768   name[len + 0] = '[';
769   name[len + 1] = '0';
770   name[len + 2] = ']';
771   name[len + 3] = '\0';
772
773   GET_UNIFORM
774   glUniform3fv(uniform->location, count, data);
775 }
776
777 void immUniform4f(const char *name, float x, float y, float z, float w)
778 {
779   GET_UNIFORM
780   glUniform4f(uniform->location, x, y, z, w);
781 }
782
783 void immUniform4fv(const char *name, const float data[4])
784 {
785   GET_UNIFORM
786   glUniform4fv(uniform->location, 1, data);
787 }
788
789 void immUniformArray4fv(const char *bare_name, const float *data, int count)
790 {
791   /* look up "name[0]" when given "name" */
792   const size_t len = strlen(bare_name);
793 #if TRUST_NO_ONE
794   assert(len <= MAX_UNIFORM_NAME_LEN);
795 #endif
796   char name[MAX_UNIFORM_NAME_LEN];
797   strcpy(name, bare_name);
798   name[len + 0] = '[';
799   name[len + 1] = '0';
800   name[len + 2] = ']';
801   name[len + 3] = '\0';
802
803   GET_UNIFORM
804   glUniform4fv(uniform->location, count, data);
805 }
806
807 void immUniformMatrix4fv(const char *name, const float data[4][4])
808 {
809   GET_UNIFORM
810   glUniformMatrix4fv(uniform->location, 1, GL_FALSE, (float *)data);
811 }
812
813 void immUniform1i(const char *name, int x)
814 {
815   GET_UNIFORM
816   glUniform1i(uniform->location, x);
817 }
818
819 void immUniform4iv(const char *name, const int data[4])
820 {
821   GET_UNIFORM
822   glUniform4iv(uniform->location, 1, data);
823 }
824
825 /* --- convenience functions for setting "uniform vec4 color" --- */
826
827 void immUniformColor4f(float r, float g, float b, float a)
828 {
829   const GPUShaderInput *uniform = GPU_shaderinterface_uniform_builtin(imm.shader_interface,
830                                                                       GPU_UNIFORM_COLOR);
831 #if TRUST_NO_ONE
832   assert(uniform != NULL);
833 #endif
834   glUniform4f(uniform->location, r, g, b, a);
835 }
836
837 void immUniformColor4fv(const float rgba[4])
838 {
839   immUniformColor4f(rgba[0], rgba[1], rgba[2], rgba[3]);
840 }
841
842 void immUniformColor3f(float r, float g, float b)
843 {
844   immUniformColor4f(r, g, b, 1.0f);
845 }
846
847 void immUniformColor3fv(const float rgb[3])
848 {
849   immUniformColor4f(rgb[0], rgb[1], rgb[2], 1.0f);
850 }
851
852 void immUniformColor3fvAlpha(const float rgb[3], float a)
853 {
854   immUniformColor4f(rgb[0], rgb[1], rgb[2], a);
855 }
856
857 /* TODO: v-- treat as sRGB? --v */
858
859 void immUniformColor3ub(uchar r, uchar g, uchar b)
860 {
861   const float scale = 1.0f / 255.0f;
862   immUniformColor4f(scale * r, scale * g, scale * b, 1.0f);
863 }
864
865 void immUniformColor4ub(uchar r, uchar g, uchar b, uchar a)
866 {
867   const float scale = 1.0f / 255.0f;
868   immUniformColor4f(scale * r, scale * g, scale * b, scale * a);
869 }
870
871 void immUniformColor3ubv(const uchar rgb[3])
872 {
873   immUniformColor3ub(rgb[0], rgb[1], rgb[2]);
874 }
875
876 void immUniformColor3ubvAlpha(const uchar rgb[3], uchar alpha)
877 {
878   immUniformColor4ub(rgb[0], rgb[1], rgb[2], alpha);
879 }
880
881 void immUniformColor4ubv(const uchar rgba[4])
882 {
883   immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]);
884 }
885
886 void immUniformThemeColor(int color_id)
887 {
888   float color[4];
889   UI_GetThemeColor4fv(color_id, color);
890   immUniformColor4fv(color);
891 }
892
893 void immUniformThemeColor3(int color_id)
894 {
895   float color[3];
896   UI_GetThemeColor3fv(color_id, color);
897   immUniformColor3fv(color);
898 }
899
900 void immUniformThemeColorShade(int color_id, int offset)
901 {
902   float color[4];
903   UI_GetThemeColorShade4fv(color_id, offset, color);
904   immUniformColor4fv(color);
905 }
906
907 void immUniformThemeColorShadeAlpha(int color_id, int color_offset, int alpha_offset)
908 {
909   float color[4];
910   UI_GetThemeColorShadeAlpha4fv(color_id, color_offset, alpha_offset, color);
911   immUniformColor4fv(color);
912 }
913
914 void immUniformThemeColorBlendShade(int color_id1, int color_id2, float fac, int offset)
915 {
916   float color[4];
917   UI_GetThemeColorBlendShade4fv(color_id1, color_id2, fac, offset, color);
918   immUniformColor4fv(color);
919 }
920
921 void immUniformThemeColorBlend(int color_id1, int color_id2, float fac)
922 {
923   uint8_t color[3];
924   UI_GetThemeColorBlend3ubv(color_id1, color_id2, fac, color);
925   immUniformColor3ubv(color);
926 }
927
928 void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset)
929 {
930   uchar col[4];
931   UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col);
932   immUniformColor4ub(col[0], col[1], col[2], col[3]);
933 }