1 // Copyright (c) 2015 Sergio Gonzalez. All rights reserved.
2 // License: https://github.com/serge-rgb/milton#license
3 
4 #include "shaders.gen.h"
5 
6 #include "color.h"
7 #include "gl_helpers.h"
8 #include "gui.h"
9 #include "milton.h"
10 #include "vector.h"
11 
12 #define MAX_DEPTH_VALUE (1<<20)     // Strokes have MAX_DEPTH_VALUE different z values. 1/i for each i in [1, MAX_DEPTH_VALUE)
13                                     // Also defined in stroke_raster.v.glsl
14                                     //
15                                     // NOTE: Using this technique means that the algorithm is not correct.
16                                     //  There is a low probability that one stroke will cover another
17                                     //  stroke with the same z value.
18 
19 
20 #define RENDER_CHUNK_SIZE_LOG2 28
21 
22 
23 enum ImmediateFlag
24 {
25     ImmediateFlag_RECT = (1<<0),
26 };
27 
28 // Draw data for single stroke
29 enum RenderElementFlags
30 {
31     RenderElementFlags_NONE = 0,
32     RenderElementFlags_LAYER                = 1<<0,
33     RenderElementFlags_PRESSURE_TO_OPACITY  = 1<<1,
34     RenderElementFlags_DISTANCE_TO_OPACITY  = 1<<2,
35     RenderElementFlags_ERASER               = 1<<3,
36 };
37 
38 struct RenderElement
39 {
40     GLuint  vbo_stroke;
41     GLuint  vbo_pointa;
42     GLuint  vbo_pointb;
43     GLuint  indices;
44 #if STROKE_DEBUG_VIZ
45     GLuint vbo_debug;
46 #endif
47 
48     i64     count;
49 
50     union {
51         struct {  // For when element is a stroke.
52             v4f     color;
53             i32     radius;
54             f32     min_opacity;
55             f32     hardness;
56         };
57         struct {  // For when element is layer.
58             f32          layer_alpha;
59             LayerEffect* effects;
60         };
61     };
62 
63     int     flags;  // RenderElementFlags enum;
64 };
65 
66 struct RenderBackend
67 {
68     f32 viewport_limits[2];  // OpenGL limits to the framebuffer size.
69 
70     v2i render_center;
71 
72     // OpenGL programs.
73 
74     GLuint stroke_program;
75     GLuint stroke_eraser_program;
76 
77     GLuint stroke_clear_program;
78     GLuint stroke_info_program;
79 
80     // TODO: If we add more variations we probably will want to automate this...
81     GLuint stroke_fill_program_pressure;
82     GLuint stroke_fill_program_distance;
83     GLuint stroke_fill_program_pressure_distance;
84 
85     GLuint quad_program;
86     GLuint picker_program;
87     GLuint layer_blend_program;
88     GLuint outline_program;
89     GLuint exporter_program;
90     GLuint texture_fill_program;
91     GLuint postproc_program;
92     GLuint blur_program;
93 #if MILTON_DEBUG
94     GLuint simple_program;
95 #endif
96 
97     // VBO for the screen-covering quad.
98     GLuint vbo_screen_quad;
99 
100     // Handles for color picker.
101     GLuint vbo_picker;
102     GLuint vbo_picker_norm;
103 
104     // Handles for brush outline.
105     GLuint vbo_outline;
106     GLuint vbo_outline_sizes;
107 
108     // Handles for exporter rectangle.
109     GLuint vbo_exporter;
110     GLuint exporter_indices;
111     int exporter_indices_count;
112 
113     u32 imm_flags;  // ImmediateFlag
114 
115     // Objects used in rendering.
116     GLuint canvas_texture;
117     GLuint eraser_texture;
118     GLuint helper_texture;  // Used for various effects..
119     GLuint stencil_texture;
120     GLuint stroke_info_texture;
121 
122     GLuint fbo;
123 
124     i32 flags;  // RenderBackendFlags enum
125 
126     DArray<RenderElement> clip_array;
127 
128     // Screen size.
129     i32 width;
130     i32 height;
131 
132     v3f background_color;
133     i32 scale;  // zoom
134 
135     // See MAX_DEPTH_VALUE
136     i32 stroke_z;
137 
138     // TODO: Re-enable these?
139     // Cached values for stroke rendering uniforms.
140     // v4f current_color;
141     // float current_radius;
142 
143 #if MILTON_ENABLE_PROFILING
144     u64 clipped_count;
145 #endif
146 };
147 
148 enum GLVendor
149 {
150     GLVendor_NVIDIA,
151     GLVendor_INTEL,
152     GLVendor_AMD,
153     GLVendor_UNKNOWN,
154 };
155 
156 char DEBUG_g_buffers[100000];
157 
158 static void
DEBUG_gl_mark_buffer(GLuint buffer)159 DEBUG_gl_mark_buffer(GLuint buffer)
160 {
161     mlt_assert(buffer < 100000);
162     DEBUG_g_buffers[buffer] = 1;
163 }
164 
165 static void
DEBUG_gl_unmark_buffer(GLuint buffer)166 DEBUG_gl_unmark_buffer(GLuint buffer)
167 {
168     mlt_assert(buffer < 100000);
169     DEBUG_g_buffers[buffer] = 0;
170 }
171 
172 static void
DEBUG_gl_validate_buffer(GLuint buffer)173 DEBUG_gl_validate_buffer(GLuint buffer)
174 {
175     mlt_assert(buffer < 100000);
176     mlt_assert(DEBUG_g_buffers[buffer]);
177 }
178 
179 static void
print_framebuffer_status()180 print_framebuffer_status()
181 {
182     GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
183     char* msg = NULL;
184     switch ( status ) {
185         case GL_FRAMEBUFFER_COMPLETE: {
186             // OK!
187             break;
188         }
189         case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: {
190             msg = "Incomplete Attachment";
191             break;
192         }
193         case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: {
194             msg = "Missing Attachment";
195             break;
196         }
197         case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: {
198             msg = "Incomplete Draw Buffer";
199             break;
200         }
201         case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: {
202             msg = "Incomplete Read Buffer";
203             break;
204         }
205         case GL_FRAMEBUFFER_UNSUPPORTED: {
206             msg = "Unsupported Framebuffer";
207             break;
208         }
209         case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: {
210             msg = "Incomplete Multisample";
211             break;
212         }
213         default: {
214             msg = "Unknown";
215             break;
216         }
217     }
218 
219     if ( status != GL_FRAMEBUFFER_COMPLETE ) {
220         char warning[1024];
221         snprintf(warning, 1024, "Framebuffer Error: %s", msg);
222         milton_log("Warning %s\n", warning);
223     }
224 }
225 
226 static RenderElement*
get_render_element(RenderHandle handle)227 get_render_element(RenderHandle handle)
228 {
229     RenderElement* e = reinterpret_cast<RenderElement*>(handle);
230     return e;
231 }
232 
233 RenderBackend*
gpu_allocate_render_backend(Arena * arena)234 gpu_allocate_render_backend(Arena* arena)
235 {
236     RenderBackend* p = arena_alloc_elem(arena, RenderBackend);
237     return p;
238 }
239 
240 // Send Color Picker data to OpenGL.
241 void
gpu_update_picker(RenderBackend * r,ColorPicker * picker)242 gpu_update_picker(RenderBackend* r, ColorPicker* picker)
243 {
244     gl::use_program(r->picker_program);
245     // Transform to [-1,1]
246     v2f a = picker->data.a;
247     v2f b = picker->data.b;
248     v2f c = picker->data.c;
249     Rect bounds = picker_get_bounds(picker);
250     int w = bounds.right-bounds.left;
251     int h = bounds.bottom-bounds.top;
252     // The center of the picker has an offset of (25,35)
253     // and the bounds radius is 100 px
254     auto transform = [&](v2f p) { return v2f{2*p.x/w-1 - .25f, 2*p.y/h-1 -0.35f}; };
255     a = transform(a);
256     b = transform(b);
257     c = transform(c);
258     gl::set_uniform_vec2(r->picker_program, "u_pointa", 1, a.d);
259     gl::set_uniform_vec2(r->picker_program, "u_pointb", 1, b.d);
260     gl::set_uniform_vec2(r->picker_program, "u_pointc", 1, c.d);
261     gl::set_uniform_f(r->picker_program, "u_angle", picker->data.hsv.h);
262 
263     v3f hsv = picker->data.hsv;
264     gl::set_uniform_vec3(r->picker_program, "u_color", 1, hsv_to_rgb(hsv).d);
265 
266     // Point within triangle
267     {
268         v2f point = lerp(picker->data.b, lerp(picker->data.a, picker->data.c, hsv.s), hsv.v);
269         // Move to [-1,1]^2
270         point = transform(point);
271         gl::set_uniform_vec2(r->picker_program, "u_triangle_point", 1, point.d);
272     }
273     v4f colors[5] = {};
274     ColorButton* button = picker->color_buttons;
275     colors[0] = button->rgba; button = button->next;
276     colors[1] = button->rgba; button = button->next;
277     colors[2] = button->rgba; button = button->next;
278     colors[3] = button->rgba; button = button->next;
279     colors[4] = button->rgba; button = button->next;
280     gl::set_uniform_vec4(r->picker_program, "u_colors", 5, (float*)colors);
281 
282     // Update VBO for picker
283     {
284         Rect rect = get_bounds_for_picker_and_colors(picker);
285         // convert to clip space
286         v2i screen_size = {r->width, r->height};
287         float top = (float)rect.top / screen_size.h;
288         float bottom = (float)rect.bottom / screen_size.h;
289         float left = (float)rect.left / screen_size.w;
290         float right = (float)rect.right / screen_size.w;
291         top = (top*2.0f - 1.0f) * -1;
292         bottom = (bottom*2.0f - 1.0f) *-1;
293         left = left*2.0f - 1.0f;
294         right = right*2.0f - 1.0f;
295         // a------d
296         // |  \   |
297         // |    \ |
298         // b______c
299         GLfloat data[] =
300         {
301             left, top,
302             left, bottom,
303             right, bottom,
304             right, top,
305         };
306         float ratio = (float)(rect.bottom-rect.top) / (float)(rect.right-rect.left);
307         ratio = (ratio*2)-1;
308         // normalized positions.
309         GLfloat norm[] =
310         {
311             -1, -1,
312             -1, ratio,
313             1, ratio,
314             1, -1,
315         };
316 
317         // Create buffers and upload
318         glBindBuffer(GL_ARRAY_BUFFER, r->vbo_picker);
319         DEBUG_gl_mark_buffer(r->vbo_picker);
320         glBufferData(GL_ARRAY_BUFFER, array_count(data)*sizeof(*data), data, GL_STATIC_DRAW);
321 
322         glBindBuffer(GL_ARRAY_BUFFER, r->vbo_picker_norm);
323         DEBUG_gl_mark_buffer(r->vbo_picker_norm);
324         glBufferData(GL_ARRAY_BUFFER, array_count(norm)*sizeof(*norm), norm, GL_STATIC_DRAW);
325     }
326 }
327 
328 void
gpu_update_brush_outline(RenderBackend * r,i32 cx,i32 cy,i32 radius,BrushOutlineEnum outline_enum,v4f color)329 gpu_update_brush_outline(RenderBackend* r, i32 cx, i32 cy, i32 radius,
330                          BrushOutlineEnum outline_enum, v4f color)
331 {
332     if ( r->vbo_outline == 0 ) {
333         mlt_assert(r->vbo_outline_sizes == 0);
334         glGenBuffers(1, &r->vbo_outline);
335         glGenBuffers(1, &r->vbo_outline_sizes);
336     }
337     mlt_assert(r->vbo_outline_sizes != 0);
338 
339     float radius_plus_girth = radius + 4.0f; // Girth defined in outline.f.glsl
340 
341     auto w = r->width;
342     auto h = r->height;
343 
344     // Normalized to [-1,1]
345     GLfloat data[] = {
346         2*((cx-radius_plus_girth) / w)-1,  -2*((cy-radius_plus_girth) / h)+1,
347         2*((cx-radius_plus_girth) / w)-1,  -2*((cy+radius_plus_girth) / h)+1,
348         2*((cx+radius_plus_girth) / w)-1,  -2*((cy+radius_plus_girth) / h)+1,
349         2*((cx+radius_plus_girth) / w)-1,  -2*((cy-radius_plus_girth) / h)+1,
350     };
351 
352     GLfloat sizes[] = {
353         -radius_plus_girth, -radius_plus_girth,
354         -radius_plus_girth,  radius_plus_girth,
355          radius_plus_girth,  radius_plus_girth,
356          radius_plus_girth, -radius_plus_girth,
357     };
358 
359     glBindBuffer(GL_ARRAY_BUFFER, r->vbo_outline_sizes);
360     DEBUG_gl_mark_buffer(r->vbo_outline_sizes);
361     glBufferData(GL_ARRAY_BUFFER, array_count(sizes)*sizeof(*sizes), sizes, GL_DYNAMIC_DRAW);
362 
363     glBindBuffer(GL_ARRAY_BUFFER, r->vbo_outline);
364     DEBUG_gl_mark_buffer(r->vbo_outline);
365     glBufferData(GL_ARRAY_BUFFER, array_count(data)*sizeof(*data), data, GL_DYNAMIC_DRAW);
366 
367     gl::set_uniform_i(r->outline_program, "u_radius", radius);
368     if ( outline_enum == BrushOutline_FILL ) {
369         gl::set_uniform_i(r->outline_program, "u_fill", true);
370         gl::set_uniform_vec4(r->outline_program, "u_color", 1, color.d);
371     }
372     else if ( outline_enum == BrushOutline_NO_FILL ) {
373         gl::set_uniform_i(r->outline_program, "u_fill", false);
374     }
375 }
376 
GL_DEBUG_CALLBACK(milton_gl_debug_callback)377 GL_DEBUG_CALLBACK(milton_gl_debug_callback)
378 {
379     switch ( type ) {
380         case GL_DEBUG_TYPE_ERROR:
381         case GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR:
382         case GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR:
383         case GL_DEBUG_SOURCE_APPLICATION: {
384             milton_log("[OpenGl Debug message (severity: %d)]: %s\n", severity, message);
385         } break;
386     }
387 }
388 
389 
390 b32
gpu_init(RenderBackend * r,CanvasView * view,ColorPicker * picker)391 gpu_init(RenderBackend* r, CanvasView* view, ColorPicker* picker)
392 {
393     #if MILTON_DEBUG
394         glEnable(GL_DEBUG_OUTPUT);
395         if (glDebugMessageCallback) {  glDebugMessageCallback(milton_gl_debug_callback, NULL); }
396     #endif
397 
398     r->stroke_z = MAX_DEPTH_VALUE - 20;
399 
400     if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
401         glEnable(GL_MULTISAMPLE);
402         // TODO: remove sample shading
403         if ( gl::check_flags(GLHelperFlags_SAMPLE_SHADING) ) {
404             glEnable(GL_SAMPLE_SHADING_ARB);
405             // glMinSampleShadingARB(1.0f);
406         }
407     }
408 
409     {
410         GLfloat viewport_dims[2] = {};
411         glGetFloatv(GL_MAX_VIEWPORT_DIMS, viewport_dims);
412         milton_log("Maximum viewport dimensions, %fx%f\n", viewport_dims[0], viewport_dims[1]);
413         r->viewport_limits[0] = viewport_dims[0];
414         r->viewport_limits[1] = viewport_dims[1];
415     }
416 
417     // r->current_color = {-1,-1,-1,-1};
418     // r->current_radius = -1;
419 
420     glEnable(GL_SCISSOR_TEST);
421     glActiveTexture(GL_TEXTURE0);
422     bool result = true;
423 
424     // Create a single VAO and bind it.
425     #if USE_GL_3_2
426         GLuint proxy_vao = 0;
427         glGenVertexArrays(1, &proxy_vao);
428         glBindVertexArray(proxy_vao);
429     #endif
430 
431     GLVendor vendor = GLVendor_UNKNOWN;
432     {
433         char *vendor_string = (char *)glGetString(GL_VENDOR);
434         if ( vendor_string ) {
435             if ( strcmp("NVIDIA Corporation", vendor_string) == 0 ) {
436                 vendor = GLVendor_NVIDIA;
437             }
438             else if ( strcmp("AMD", vendor_string) == 0 ) {
439                 vendor = GLVendor_AMD;
440             }
441             else if ( strcmp("Intel", vendor_string) == 0 ) {
442                 vendor = GLVendor_INTEL;
443             }
444         }
445         milton_log("Vendor string: \"%s\"\n", vendor_string);
446     }
447     // Quad that fills the screen.
448     {
449         // a------d
450         // |  \   |
451         // |    \ |
452         // b______c
453         //  Triangle fan:
454         GLfloat quad_data[] = {
455             -1 , -1 , // a
456             -1 , 1  , // b
457             1  , 1  , // c
458             1  , -1 , // d
459         };
460 
461         // Create buffers and upload
462         GLuint vbo = 0;
463         glGenBuffers(1, &vbo);
464         glBindBuffer(GL_ARRAY_BUFFER, vbo);
465         DEBUG_gl_mark_buffer(vbo);
466         glBufferData(GL_ARRAY_BUFFER, array_count(quad_data)*sizeof(*quad_data), quad_data, GL_STATIC_DRAW);
467 
468         float u = 1.0f;
469         GLfloat uv_data[] = {
470             0,0,
471             0,u,
472             u,u,
473             u,0,
474         };
475         GLuint vbo_uv = 0;
476         glGenBuffers(1, &vbo_uv);
477         glBindBuffer(GL_ARRAY_BUFFER, vbo_uv);
478         DEBUG_gl_mark_buffer(vbo_uv);
479         glBufferData(GL_ARRAY_BUFFER, array_count(uv_data)*sizeof(*uv_data), uv_data, GL_STATIC_DRAW);
480 
481         r->vbo_screen_quad = vbo;
482 
483         GLuint objs[2] = {};
484         objs[0] = gl::compile_shader(g_quad_v, GL_VERTEX_SHADER);
485         objs[1] = gl::compile_shader(g_quad_f, GL_FRAGMENT_SHADER);
486         r->quad_program = glCreateProgram();
487         gl::link_program(r->quad_program, objs, array_count(objs));
488     }
489 
490     GLuint stroke_vs = gl::compile_shader(g_stroke_raster_v, GL_VERTEX_SHADER);
491 
492     {  // Stroke raster program
493         GLuint objs[2];
494 
495         char* config_string = "";
496         if ( gl::check_flags(GLHelperFlags_SAMPLE_SHADING) ) {
497             if ( vendor == GLVendor_NVIDIA ) {
498                 config_string =
499                         "#define HAS_SAMPLE_SHADING 1 \n"
500                         "#define VENDOR_NVIDIA 1 \n";
501             }
502             else if ( vendor == GLVendor_INTEL ) {
503                 config_string =
504                     "#define HAS_SAMPLE_SHADING 1 \n"
505                     "#define VENDOR_INTEL 1 \n";
506             }
507             else {
508                 config_string =
509                         "#define HAS_SAMPLE_SHADING 1 \n";
510             }
511         }
512 
513         objs[0] = stroke_vs;
514         objs[1] = gl::compile_shader(g_stroke_raster_f, GL_FRAGMENT_SHADER, config_string);
515 
516         r->stroke_program = glCreateProgram();
517 
518         gl::link_program(r->stroke_program, objs, array_count(objs));
519     }
520     // Stroke eraser
521     {
522         GLuint objs[2];
523         objs[0] = stroke_vs;
524         objs[1] = gl::compile_shader(g_stroke_eraser_f, GL_FRAGMENT_SHADER);
525 
526         r->stroke_eraser_program = glCreateProgram();
527         gl::link_program(r->stroke_eraser_program, objs, array_count(objs));
528 
529         gl::set_uniform_i(r->stroke_eraser_program, "u_canvas", 0);
530     }
531     // Stroke info program
532     {
533         GLuint objs[2];
534         objs[0] = stroke_vs;
535         objs[1] = gl::compile_shader(g_stroke_info_f, GL_FRAGMENT_SHADER);
536 
537         r->stroke_info_program = glCreateProgram();
538         gl::link_program(r->stroke_info_program, objs, array_count(objs));
539 
540     }
541     // Stroke fill program
542     {
543         GLuint objs[2];
544         objs[0] = stroke_vs;
545 
546         r->stroke_fill_program_distance = glCreateProgram();
547         r->stroke_fill_program_pressure = glCreateProgram();
548         r->stroke_fill_program_pressure_distance = glCreateProgram();
549 
550         objs[1] = gl::compile_shader(g_stroke_fill_f, GL_FRAGMENT_SHADER);
551         gl::link_program(r->stroke_fill_program_pressure, objs, array_count(objs));
552 
553         objs[1] = gl::compile_shader(g_stroke_fill_f, GL_FRAGMENT_SHADER, "", "#define DISTANCE_TO_OPACITY 1\n#define PRESSURE_TO_OPACITY 0\n");
554         gl::link_program(r->stroke_fill_program_distance, objs, array_count(objs));
555 
556         objs[1] = gl::compile_shader(g_stroke_fill_f, GL_FRAGMENT_SHADER, "", "#define DISTANCE_TO_OPACITY 1\n");
557         gl::link_program(r->stroke_fill_program_pressure_distance, objs, array_count(objs));
558 
559         GLuint ps[] = {
560             r->stroke_fill_program_pressure,
561             r->stroke_fill_program_pressure_distance,
562             r->stroke_fill_program_distance,
563         };
564         for (auto p : ps) {
565             gl::set_uniform_i(p, "u_info", 0);
566         }
567     }
568     // Stroke clear program
569     {
570         GLuint objs[2];
571         objs[0] = stroke_vs;
572         objs[1] = gl::compile_shader(g_stroke_clear_f, GL_FRAGMENT_SHADER);
573 
574         r->stroke_clear_program = glCreateProgram();
575         gl::link_program(r->stroke_clear_program, objs, array_count(objs));
576     }
577     {  // Color picker program
578         r->picker_program = glCreateProgram();
579         GLuint objs[2] = {};
580 
581         // g_picker_* generated by shadergen.cc
582         objs[0] = gl::compile_shader(g_picker_v, GL_VERTEX_SHADER);
583         objs[1] = gl::compile_shader(g_picker_f, GL_FRAGMENT_SHADER);
584         gl::link_program(r->picker_program, objs, array_count(objs));
585         gl::set_uniform_i(r->picker_program, "u_canvas", 0);
586     }
587     {  // Layer blend program
588         r->layer_blend_program = glCreateProgram();
589         GLuint objs[2] = {};
590 
591         objs[0] = gl::compile_shader(g_layer_blend_v, GL_VERTEX_SHADER);
592         objs[1] = gl::compile_shader(g_layer_blend_f, GL_FRAGMENT_SHADER);
593         gl::link_program(r->layer_blend_program, objs, array_count(objs));
594         gl::set_uniform_i(r->layer_blend_program, "u_canvas", 0);
595     }
596     {  // Brush outline program
597         r->outline_program = glCreateProgram();
598         GLuint objs[2] = {};
599         objs[0] = gl::compile_shader(g_outline_v, GL_VERTEX_SHADER);
600         objs[1] = gl::compile_shader(g_outline_f, GL_FRAGMENT_SHADER);
601 
602         gl::link_program(r->outline_program, objs, array_count(objs));
603     }
604     {  // Exporter program
605         r->exporter_program = glCreateProgram();
606 
607         GLuint objs[2] = {};
608         objs[0] = gl::compile_shader(g_simple_v, GL_VERTEX_SHADER);
609         objs[1] = gl::compile_shader(g_exporter_rect_f, GL_FRAGMENT_SHADER);
610 
611         gl::link_program(r->exporter_program, objs, array_count(objs));
612         gl::set_uniform_i(r->exporter_program, "u_canvas", 0);
613     }
614     {
615         r->texture_fill_program = glCreateProgram();
616         GLuint objs[2] = {};
617         objs[0] = gl::compile_shader(g_simple_v, GL_VERTEX_SHADER);
618         objs[1] = gl::compile_shader(g_texture_fill_f, GL_FRAGMENT_SHADER);
619 
620         gl::link_program(r->texture_fill_program, objs, array_count(objs));
621         gl::set_uniform_i(r->texture_fill_program, "u_canvas", 0);
622     }
623     {
624         r->postproc_program = glCreateProgram();
625         GLuint objs[2] = {};
626         objs[0] = gl::compile_shader(g_simple_v, GL_VERTEX_SHADER);
627         objs[1] = gl::compile_shader(g_postproc_f, GL_FRAGMENT_SHADER);
628 
629         gl::link_program(r->postproc_program, objs, array_count(objs));
630         gl::set_uniform_i(r->postproc_program, "u_canvas", 0);
631     }
632     {
633         r->blur_program = glCreateProgram();
634         GLuint objs[2] = {};
635         objs[0] = gl::compile_shader(g_simple_v, GL_VERTEX_SHADER);
636         objs[1] = gl::compile_shader(g_blur_f, GL_FRAGMENT_SHADER);
637         gl::link_program(r->blur_program, objs, array_count(objs));
638         gl::set_uniform_i(r->blur_program, "u_canvas", 0);
639     }
640 #if MILTON_DEBUG
641     {  // Simple program
642         r->simple_program = glCreateProgram();
643 
644         GLuint objs[2] = {};
645         objs[0] = gl::compile_shader(g_simple_v, GL_VERTEX_SHADER);
646         objs[1] = gl::compile_shader(g_simple_f, GL_FRAGMENT_SHADER);
647 
648         gl::link_program(r->simple_program, objs, array_count(objs));
649     }
650 #endif
651 
652     // Framebuffer object for canvas. Layer buffer
653     {
654         if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
655             r->canvas_texture = gl::new_color_texture_multisample(view->screen_size.w, view->screen_size.h);
656         } else {
657             r->canvas_texture = gl::new_color_texture(view->screen_size.w, view->screen_size.h);
658         }
659 
660         if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
661             r->eraser_texture = gl::new_color_texture_multisample(view->screen_size.w, view->screen_size.h);
662         } else {
663             r->eraser_texture = gl::new_color_texture(view->screen_size.w, view->screen_size.h);
664         }
665 
666         glGenTextures(1, &r->helper_texture);
667 
668         if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
669             r->helper_texture = gl::new_color_texture_multisample(view->screen_size.w, view->screen_size.h);
670         } else {
671             r->helper_texture = gl::new_color_texture(view->screen_size.w, view->screen_size.h);
672         }
673 
674         // Stroke info buffer
675         {
676             r->stroke_info_texture = gl::new_color_texture(view->screen_size.w, view->screen_size.h);
677             print_framebuffer_status();
678         }
679 
680 
681         glGenTextures(1, &r->stencil_texture);
682 
683         if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
684             r->stencil_texture = gl::new_depth_stencil_texture_multisample(view->screen_size.w, view->screen_size.h);
685         }
686         else {
687             r->stencil_texture = gl::new_depth_stencil_texture(view->screen_size.w, view->screen_size.h);
688         }
689 
690         // Create framebuffer object.
691         GLenum texture_target;
692         if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
693             texture_target = GL_TEXTURE_2D_MULTISAMPLE;
694         }
695         else{
696             texture_target = GL_TEXTURE_2D;
697         }
698         r->fbo = gl::new_fbo(r->canvas_texture, r->stencil_texture, texture_target);
699         glBindFramebufferEXT(GL_FRAMEBUFFER, r->fbo);
700         print_framebuffer_status();
701         glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
702     }
703     // VBO for picker
704     glGenBuffers(1, &r->vbo_picker);
705     glGenBuffers(1, &r->vbo_picker_norm);
706 
707     // Call gpu_update_picker() to initialize the color picker
708     gpu_update_picker(r, picker);
709     return result;
710 }
711 
712 void
gpu_resize(RenderBackend * r,CanvasView * view)713 gpu_resize(RenderBackend* r, CanvasView* view)
714 {
715     r->width = view->screen_size.w;
716     r->height = view->screen_size.h;
717 
718     if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
719         gl::resize_color_texture_multisample(r->eraser_texture, r->width, r->height);
720         gl::resize_color_texture_multisample(r->canvas_texture, r->width, r->height);
721         gl::resize_color_texture_multisample(r->helper_texture, r->width, r->height);
722         gl::resize_depth_stencil_texture_multisample(r->stencil_texture, r->width, r->height);
723     }
724     else {
725         gl::resize_color_texture(r->eraser_texture, r->width, r->height);
726         gl::resize_color_texture(r->canvas_texture, r->width, r->height);
727         gl::resize_color_texture(r->helper_texture, r->width, r->height);
728         gl::resize_color_texture(r->stroke_info_texture, r->width, r->height);
729         gl::resize_depth_stencil_texture(r->stencil_texture, r->width, r->height);
730     }
731 }
732 
733 void
gpu_reset_render_flags(RenderBackend * r,int flags)734 gpu_reset_render_flags(RenderBackend* r, int flags)
735 {
736     r->flags = flags;
737 }
738 
739 void
gpu_update_scale(RenderBackend * r,i32 scale)740 gpu_update_scale(RenderBackend* r, i32 scale)
741 {
742     r->scale = scale;
743     GLuint ps[] = {
744         r->stroke_program,
745         r->stroke_eraser_program,
746         r->stroke_info_program,
747         r->stroke_fill_program_pressure,
748         r->stroke_fill_program_pressure_distance,
749         r->stroke_fill_program_distance,
750         r->stroke_clear_program,
751     };
752     for (sz i = 0; i < array_count(ps); ++i) {
753         gl::set_uniform_i(ps[i], "u_scale", scale);
754     }
755 }
756 
757 void
gpu_update_export_rect(RenderBackend * r,Exporter * exporter)758 gpu_update_export_rect(RenderBackend* r, Exporter* exporter)
759 {
760     if ( r->vbo_exporter == 0 ) {
761         glGenBuffers(1, &r->vbo_exporter);
762         mlt_assert(r->exporter_indices == 0);
763         glGenBuffers(1, &r->exporter_indices);
764     }
765 
766     i32 x = min(exporter->pivot.x, exporter->needle.x);
767     i32 y = min(exporter->pivot.y, exporter->needle.y);
768     i32 w = MLT_ABS(exporter->pivot.x - exporter->needle.x);
769     i32 h = MLT_ABS(exporter->pivot.y - exporter->needle.y);
770 
771     float left = 2*((float)    x/(r->width))-1;
772     float right = 2*((GLfloat)(x+w)/(r->width))-1;
773     float top = -(2*((GLfloat)y    /(r->height))-1);
774     float bottom = -(2*((GLfloat)(y+h)/(r->height))-1);
775 
776     // Normalize to [-1,1]^2
777     v2f normalized_rect[] = {
778         { 2*((GLfloat)    x/(r->width))-1, -(2*((GLfloat)y    /(r->height))-1) },
779         { 2*((GLfloat)    x/(r->width))-1, -(2*((GLfloat)(y+h)/(r->height))-1) },
780         { 2*((GLfloat)(x+w)/(r->width))-1, -(2*((GLfloat)(y+h)/(r->height))-1) },
781         { 2*((GLfloat)(x+w)/(r->width))-1, -(2*((GLfloat)y    /(r->height))-1) },
782     };
783 
784     float px = 2.0f;
785     float line_width = px / r->height;
786 
787     float toparr[] = {
788         // Top quad
789         left, top - line_width/2,
790         left, top + line_width/2,
791         right, top + line_width/2,
792         right, top - line_width/2,
793 
794         // Bottom quad
795         left, bottom-line_width/2,
796         left, bottom+line_width/2,
797         right, bottom+line_width/2,
798         right, bottom-line_width/2,
799 
800         // Left
801         left-line_width/2, top,
802         left-line_width/2, bottom,
803         left+line_width/2, bottom,
804         left+line_width/2, top,
805 
806         // Right
807         right-line_width/2, top,
808         right-line_width/2, bottom,
809         right+line_width/2, bottom,
810         right+line_width/2, top,
811     };
812     glBindBuffer(GL_ARRAY_BUFFER, r->vbo_exporter);
813     DEBUG_gl_mark_buffer(r->vbo_exporter);
814     glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)array_count(toparr)*sizeof(*toparr), toparr, GL_DYNAMIC_DRAW);
815 
816     u16 indices[] = {
817         // top
818         0,1,2,
819         2,3,0,
820 
821         // bottom
822         4,5,6,
823         6,7,4,
824 
825         // left
826         8,9,10,
827         10,11,8,
828 
829         // right
830         12,13,14,
831         14,15,12,
832     };
833     glBindBuffer(GL_ARRAY_BUFFER, r->exporter_indices);
834     glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)array_count(indices)*sizeof(*indices), indices, GL_STATIC_DRAW);
835 
836     r->exporter_indices_count = array_count(indices);
837 }
838 
839 void
gpu_update_background(RenderBackend * r,v3f background_color)840 gpu_update_background(RenderBackend* r, v3f background_color)
841 {
842     r->background_color = background_color;
843 }
844 
845 void
gpu_get_viewport_limits(RenderBackend * r,float * out_viewport_limits)846 gpu_get_viewport_limits(RenderBackend* r, float* out_viewport_limits)
847 {
848     if ( out_viewport_limits ) {
849         out_viewport_limits[0] = r->viewport_limits[0];
850         out_viewport_limits[1] = r->viewport_limits[1];
851     }
852 }
853 
854 i32
gpu_get_num_clipped_strokes(Layer * root_layer)855 gpu_get_num_clipped_strokes(Layer* root_layer)
856 {
857     i32 count = 0;
858     #if MILTON_ENABLE_PROFILING
859     for ( Layer* l = root_layer; l != NULL; l = l->next ) {
860         StrokeList strokes = l->strokes;
861         for ( i64 si = 0; si < strokes.count; ++si ) {
862             Stroke* s = strokes[si];
863             RenderElement* re = get_render_element(s->render_handle);
864             if ( re && re->vbo_stroke != 0 ) {
865                 ++count;
866             }
867         }
868     }
869     #endif
870     return count;
871 }
872 
873 static void
set_screen_size(RenderBackend * r,float * fscreen)874 set_screen_size(RenderBackend* r, float* fscreen)
875 {
876     GLuint programs[] = {
877         r->stroke_program,
878         r->stroke_eraser_program,
879         r->stroke_info_program,
880         r->stroke_fill_program_pressure,
881         r->stroke_fill_program_pressure_distance,
882         r->stroke_fill_program_distance,
883         r->stroke_clear_program,
884         r->layer_blend_program,
885         r->texture_fill_program,
886         r->exporter_program,
887         r->picker_program,
888         r->postproc_program,
889         r->blur_program,
890     };
891     for ( u64 pi = 0; pi < array_count(programs); ++pi ) {
892         gl::set_uniform_vec2(programs[pi], "u_screen_size", 1, fscreen);
893     }
894 }
895 
896 static
897 v2i
relative_to_render_center(RenderBackend * r,v2l point)898 relative_to_render_center(RenderBackend* r, v2l point)
899 {
900     v2i result = VEC2I(point - VEC2L(r->render_center*(1<<RENDER_CHUNK_SIZE_LOG2)));
901     return result;
902 }
903 
904 void
gpu_update_canvas(RenderBackend * r,CanvasState * canvas,CanvasView * view)905 gpu_update_canvas(RenderBackend* r, CanvasState* canvas, CanvasView* view)
906 {
907     v2i center = view->zoom_center;
908     v2l pan = view->pan_center;
909 
910     v2i new_render_center = VEC2I(pan / (i64)(1<<RENDER_CHUNK_SIZE_LOG2));
911     if ( new_render_center != r->render_center ) {
912         milton_log("Moving to new render center. %d, %d Clearing render data.\n", new_render_center.x, new_render_center.y);
913         r->render_center = new_render_center;
914         gpu_free_strokes(r, canvas);
915     }
916 
917     GLuint ps[] = {
918         r->stroke_program,
919         r->stroke_eraser_program,
920         r->stroke_info_program,
921         r->stroke_fill_program_pressure,
922         r->stroke_fill_program_pressure_distance,
923         r->stroke_fill_program_distance,
924         r->stroke_clear_program,
925     };
926 
927     f32 cos_angle = cosf(view->angle);
928     f32 sin_angle = sinf(view->angle);
929 
930     // GLSL is column-major
931     f32 matrix[] = { cos_angle, sin_angle, -sin_angle, cos_angle };
932 
933     f32 matrix_inverse[] = { cos_angle, -sin_angle, sin_angle, cos_angle };
934 
935     for (sz i = 0; i < array_count(ps); ++i) {
936         gl::set_uniform_mat2(ps[i], "u_rotation", matrix);
937         gl::set_uniform_mat2(ps[i], "u_rotation_inverse", matrix_inverse);
938         gl::set_uniform_vec2i(ps[i], "u_pan_center", 1, relative_to_render_center(r, pan).d);
939         gl::set_uniform_vec2i(ps[i], "u_zoom_center", 1, center.d);
940     }
941 
942     gpu_update_scale(r, view->scale);
943     float fscreen[] = { (float)view->screen_size.x, (float)view->screen_size.y };
944     set_screen_size(r, fscreen);
945 }
946 
947 void
gpu_cook_stroke(Arena * arena,RenderBackend * r,Stroke * stroke,CookStrokeOpt cook_option)948 gpu_cook_stroke(Arena* arena, RenderBackend* r, Stroke* stroke, CookStrokeOpt cook_option)
949 {
950 
951     RenderElement** p_render_element = reinterpret_cast<RenderElement**>(&stroke->render_handle);
952     RenderElement* render_element = *p_render_element;
953     if (render_element == NULL) {
954         render_element = arena_alloc_elem(arena, RenderElement);
955         *p_render_element = render_element;
956     }
957 
958     r->stroke_z = (r->stroke_z + 1) % (MAX_DEPTH_VALUE-1);
959     const i32 stroke_z = r->stroke_z + 1;
960 
961     if ( cook_option == CookStroke_NEW && render_element->vbo_stroke != 0 ) {
962         // We already have our data cooked
963         mlt_assert(render_element->vbo_pointa != 0);
964         mlt_assert(render_element->vbo_pointb != 0);
965     } else {
966         auto npoints = stroke->num_points;
967         if ( npoints == 1 ) {
968             // Create a 2-point stroke and recurse
969             Stroke duplicate = *stroke;
970             duplicate.num_points = 2;
971             Arena scratch_arena = arena_push(arena);
972             duplicate.points = arena_alloc_array(&scratch_arena, 2, v2l);
973             duplicate.pressures = arena_alloc_array(&scratch_arena, 2, f32);
974             duplicate.points[0] = stroke->points[0];  // It will be set relative to the center in the recursed call.
975             duplicate.points[1] = stroke->points[0];
976             duplicate.pressures[0] = stroke->pressures[0];
977             duplicate.pressures[1] = stroke->pressures[0];
978 
979             gpu_cook_stroke(&scratch_arena, r, &duplicate, cook_option);
980 
981             // Copy render element to stroke
982             stroke->render_handle = duplicate.render_handle;
983 
984             arena_pop(&scratch_arena);
985         }
986         else if ( npoints > 1 ) {
987             // 3 (triangle) *
988             // 2 (two per segment) *
989             // N-1 (segments per stroke)
990             // Reduced to 4 by using indices
991             const size_t count_attribs = 4*((size_t)npoints-1);
992 
993             // 6 (3 * 2 from count_attribs)
994             // N-1 (num segments)
995             const size_t count_indices = 6*((size_t)npoints-1);
996 
997             size_t count_debug = 0;
998             v3f* bounds;
999             v3f* apoints;
1000             v3f* bpoints;
1001             v3f* debug = NULL;
1002             u16* indices;
1003             Arena scratch_arena = arena_push(arena,
1004                                              count_attribs*sizeof(decltype(*bounds))  // Bounds
1005                                              + 2*count_attribs*sizeof(decltype(*apoints)) // Attributes a,b
1006                                              + count_debug*sizeof(decltype(*debug))    // Visualization
1007                                              + count_indices*sizeof(decltype(*indices)));  // Interpolation points
1008 
1009             bounds  = arena_alloc_array(&scratch_arena, count_attribs, v3f);
1010             apoints = arena_alloc_array(&scratch_arena, count_attribs, v3f);
1011             bpoints = arena_alloc_array(&scratch_arena, count_attribs, v3f);
1012             indices = arena_alloc_array(&scratch_arena, count_indices, u16);
1013 #if STROKE_DEBUG_VIZ
1014             debug = arena_alloc_array(&scratch_arena, count_debug, v3f);
1015 #endif
1016 
1017             mlt_assert(r->scale > 0);
1018 
1019             size_t bounds_i = 0;
1020             size_t apoints_i = 0;
1021             size_t bpoints_i = 0;
1022             size_t indices_i = 0;
1023             size_t debug_i = 0;
1024             for ( i64 i=0; i < npoints-1; ++i ) {
1025                 v2i point_i = relative_to_render_center(r, stroke->points[i]);
1026                 v2i point_j = relative_to_render_center(r, stroke->points[i+1]);
1027 
1028                 Brush brush = stroke->brush;
1029                 float radius_i = stroke->pressures[i]*brush.radius;
1030                 float radius_j = stroke->pressures[i+1]*brush.radius;
1031 
1032                 u16 idx = (u16)bounds_i;
1033                 if ( point_i == point_j ) {
1034                     i32 min_x = min(point_i.x - radius_i, point_j.x - radius_j);
1035                     i32 min_y = min(point_i.y - radius_i, point_j.y - radius_j);
1036                     i32 max_x = max(point_i.x + radius_i, point_j.x + radius_j);
1037                     i32 max_y = max(point_i.y + radius_i, point_j.y + radius_j);
1038 
1039                     // Bounding geometry and attributes
1040 
1041                     mlt_assert (bounds_i < ((1<<16)-4));
1042 
1043                     bounds[bounds_i++] = { (float)min_x, (float)min_y, (float)stroke_z };
1044                     bounds[bounds_i++] = { (float)min_x, (float)max_y, (float)stroke_z };
1045                     bounds[bounds_i++] = { (float)max_x, (float)max_y, (float)stroke_z };
1046                     bounds[bounds_i++] = { (float)max_x, (float)min_y, (float)stroke_z };
1047                 } else {
1048                     // Points are different. Do a coordinate change for a tighter box.
1049                     v2f d = normalized(v2i_to_v2f(point_j - point_i));
1050                     auto basis_change = [&d](v2f v) {
1051                         v2f res = {
1052                             v.x * d.x + v.y * d.y,
1053                             v.x * d.y - v.y * d.x,
1054                         };
1055 
1056                         return res;
1057                     };
1058                     v2f a = basis_change(v2i_to_v2f(point_i));
1059                     v2f b = basis_change(v2i_to_v2f(point_j));
1060 
1061                     f32 rad = max(radius_i, radius_j);
1062 
1063                     f32 min_x = min(a.x, b.x) - rad;
1064                     f32 min_y = min(a.y, b.y) - rad;
1065                     f32 max_x = max(a.x, b.x) + rad;
1066                     f32 max_y = max(a.y, b.y) + rad;
1067 
1068                     v2f A = basis_change(v2f{ min_x, min_y });
1069                     v2f B = basis_change(v2f{ min_x, max_y });
1070                     v2f C = basis_change(v2f{ max_x, max_y });
1071                     v2f D = basis_change(v2f{ max_x, min_y });
1072 
1073                     mlt_assert (bounds_i < ((1<<16)-4));
1074 
1075                     bounds[bounds_i++] = { A.x, A.y, (float)stroke_z };
1076                     bounds[bounds_i++] = { B.x, B.y, (float)stroke_z };
1077                     bounds[bounds_i++] = { C.x, C.y, (float)stroke_z };
1078                     bounds[bounds_i++] = { D.x, D.y, (float)stroke_z };
1079                 }
1080 
1081                 indices[indices_i++] = (u16)(idx + 0);
1082                 indices[indices_i++] = (u16)(idx + 1);
1083                 indices[indices_i++] = (u16)(idx + 2);
1084 
1085                 indices[indices_i++] = (u16)(idx + 2);
1086                 indices[indices_i++] = (u16)(idx + 0);
1087                 indices[indices_i++] = (u16)(idx + 3);
1088 
1089                 float pressure_a = stroke->pressures[i];
1090                 float pressure_b = stroke->pressures[i+1];
1091 
1092                 // Add attributes for each new vertex.
1093                 for ( int repeat = 0; repeat < 4; ++repeat ) {
1094                     apoints[apoints_i++] = { (float)point_i.x, (float)point_i.y, pressure_a };
1095                     bpoints[bpoints_i++] = { (float)point_j.x, (float)point_j.y, pressure_b };
1096                     #if STROKE_DEBUG_VIZ
1097                         v3f debug_color;
1098 
1099                         if ( stroke->debug_flags[i] & Stroke::INTERPOLATED ) {
1100                             debug_color = { 1.0f, 0.0f, 0.0f };
1101                         }
1102                         else {
1103                             debug_color = { 0.0f, 1.0f, 0.0f };
1104                         }
1105                         debug[debug_i++] = debug_color;
1106                     #endif
1107                 }
1108             }
1109 
1110             mlt_assert(bounds_i == count_attribs);
1111             mlt_assert(apoints_i == bpoints_i);
1112             mlt_assert(apoints_i == bounds_i);
1113 
1114             // TODO: check for GL_OUT_OF_MEMORY
1115 
1116             GLuint vbo_stroke = 0;
1117             GLuint vbo_pointa = 0;
1118             GLuint vbo_pointb = 0;
1119             GLuint indices_buffer = 0;
1120             GLuint vbo_debug = 0;
1121 
1122 
1123             GLenum hint = GL_STATIC_DRAW;
1124             if ( cook_option == CookStroke_UPDATE_WORKING_STROKE ) {
1125                 hint = GL_DYNAMIC_DRAW;
1126             }
1127             if ( render_element->vbo_stroke != 0 ) {
1128                 vbo_stroke = render_element->vbo_stroke;
1129                 vbo_pointa = render_element->vbo_pointa;
1130                 vbo_pointb = render_element->vbo_pointb;
1131                 indices_buffer = render_element->indices;
1132                 #if STROKE_DEBUG_VIZ
1133                     vbo_debug = render_element->vbo_debug;
1134                 #endif
1135 
1136                 auto clear_array_buffer = [hint](GLint vbo, size_t size) {
1137                     glBindBuffer(GL_ARRAY_BUFFER, vbo);
1138                     glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(size), NULL, hint);
1139                 };
1140                 clear_array_buffer(vbo_stroke, bounds_i*sizeof(decltype(*bounds)));
1141                 clear_array_buffer(vbo_pointa, bounds_i*sizeof(decltype(*apoints)));
1142                 clear_array_buffer(vbo_pointb, bounds_i*sizeof(decltype(*bpoints)));
1143                 clear_array_buffer(indices_buffer, indices_i*sizeof(decltype(*indices)));
1144                 #if STROKE_DEBUG_VIZ
1145                     clear_array_buffer(vbo_debug, debug_i*sizeof(decltype(*debug)));
1146                 #endif
1147             }
1148             else {
1149                 glGenBuffers(1, &vbo_stroke);
1150                 glGenBuffers(1, &vbo_pointa);
1151                 glGenBuffers(1, &vbo_pointb);
1152                 glGenBuffers(1, &indices_buffer);
1153                 #if STROKE_DEBUG_VIZ
1154                     glGenBuffers(1, &vbo_debug);
1155                 #endif
1156 
1157                 DEBUG_gl_mark_buffer(vbo_stroke);
1158                 DEBUG_gl_mark_buffer(vbo_pointa);
1159                 DEBUG_gl_mark_buffer(vbo_pointb);
1160                 DEBUG_gl_mark_buffer(indices_buffer);
1161             }
1162 
1163             /*Send data to GPU*/ {
1164                 auto send_buffer_data = [hint](GLint vbo, size_t size, void* data) {
1165                     glBindBuffer(GL_ARRAY_BUFFER, vbo);
1166                     glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)(size), data, hint);
1167                 };
1168 
1169                 send_buffer_data(vbo_stroke, bounds_i*sizeof(decltype(*bounds)), bounds);
1170                 send_buffer_data(vbo_pointa, bounds_i*sizeof(decltype(*apoints)), apoints);
1171                 send_buffer_data(vbo_pointb, bounds_i*sizeof(decltype(*bpoints)), bpoints);
1172                 send_buffer_data(indices_buffer, indices_i*sizeof(decltype(*indices)), indices);
1173                 #if STROKE_DEBUG_VIZ
1174                     send_buffer_data(vbo_debug, debug_i*sizeof(decltype(*debug)), debug);
1175                 #endif
1176             }
1177 
1178             RenderElement* re = get_render_element(stroke->render_handle);
1179             re->vbo_stroke = vbo_stroke;
1180             re->vbo_pointa = vbo_pointa;
1181             re->vbo_pointb = vbo_pointb;
1182             re->indices = indices_buffer;
1183             #if STROKE_DEBUG_VIZ
1184                 re->vbo_debug = vbo_debug;
1185             #endif
1186             re->count = (i64)(indices_i);
1187             re->color = { stroke->brush.color.r, stroke->brush.color.g, stroke->brush.color.b, stroke->brush.color.a };
1188             re->radius = stroke->brush.radius;
1189             re->min_opacity = stroke->brush.pressure_opacity_min;
1190             re->hardness = stroke->brush.hardness;
1191 
1192             re->flags = 0;
1193             if (stroke->flags & StrokeFlag_ERASER) {
1194                 re->flags |= RenderElementFlags_ERASER;
1195             }
1196             if (stroke->flags & StrokeFlag_PRESSURE_TO_OPACITY) {
1197                 re->flags |= RenderElementFlags_PRESSURE_TO_OPACITY;
1198             }
1199             if (stroke->flags & StrokeFlag_DISTANCE_TO_OPACITY) {
1200                 re->flags |= RenderElementFlags_DISTANCE_TO_OPACITY;
1201             }
1202 
1203             mlt_assert(re->count > 1);
1204 
1205             arena_pop(&scratch_arena);
1206         }
1207     }
1208 }
1209 
1210 void
gpu_free_strokes(Stroke * strokes,i64 count,RenderBackend * r)1211 gpu_free_strokes(Stroke* strokes, i64 count, RenderBackend* r)
1212 {
1213     for ( i64 i = 0; i < count; ++i ) {
1214         Stroke* s = &strokes[i];
1215         RenderElement* re = get_render_element(s->render_handle);
1216         if ( re && re->vbo_stroke != 0 ) {
1217             mlt_assert(re->vbo_pointa != 0);
1218             mlt_assert(re->vbo_pointb != 0);
1219             mlt_assert(re->indices != 0);
1220 
1221             DEBUG_gl_validate_buffer(re->vbo_stroke);
1222             DEBUG_gl_validate_buffer(re->vbo_pointa);
1223             DEBUG_gl_validate_buffer(re->vbo_pointb);
1224             DEBUG_gl_validate_buffer(re->indices);
1225 
1226             glDeleteBuffers(1, &re->vbo_stroke);
1227             glDeleteBuffers(1, &re->vbo_pointa);
1228             glDeleteBuffers(1, &re->vbo_pointb);
1229             glDeleteBuffers(1, &re->indices);
1230 
1231             DEBUG_gl_unmark_buffer(re->vbo_stroke);
1232             DEBUG_gl_unmark_buffer(re->vbo_pointa);
1233             DEBUG_gl_unmark_buffer(re->vbo_pointb);
1234             DEBUG_gl_unmark_buffer(re->indices);
1235 
1236             *re = {};
1237         }
1238     }
1239 }
1240 
1241 void
gpu_free_strokes(RenderBackend * r,CanvasState * canvas)1242 gpu_free_strokes(RenderBackend* r, CanvasState* canvas)
1243 {
1244     if ( canvas->root_layer != NULL ) {
1245         for ( Layer* l = canvas->root_layer;
1246               l != NULL;
1247               l = l->next ) {
1248             StrokeList* sl = &l->strokes;
1249             StrokeBucket* bucket = &sl->root;
1250             i64 count = sl->count;
1251             while ( bucket ) {
1252                 if ( count >= STROKELIST_BUCKET_COUNT ) {
1253                     count -= STROKELIST_BUCKET_COUNT;
1254                     gpu_free_strokes(bucket->data, STROKELIST_BUCKET_COUNT, r);
1255                 } else {
1256                     gpu_free_strokes(bucket->data, count, r);
1257                 }
1258                 bucket = bucket->next;
1259             }
1260         }
1261     }
1262 }
1263 
1264 void
gpu_clip_strokes_and_update(Arena * arena,RenderBackend * r,CanvasView * view,i64 scale,Layer * root_layer,Stroke * working_stroke,i32 x,i32 y,i32 w,i32 h,ClipFlags flags)1265 gpu_clip_strokes_and_update(Arena* arena,
1266                             RenderBackend* r,
1267                             CanvasView* view,
1268                             i64 scale,
1269                             Layer* root_layer, Stroke* working_stroke,
1270                             i32 x, i32 y, i32 w, i32 h, ClipFlags flags)
1271 {
1272     DArray<RenderElement>* clip_array = &r->clip_array;
1273 
1274     RenderElement layer_element = {};
1275     layer_element.flags |= RenderElementFlags_LAYER;
1276 
1277     Rect screen_bounds = raster_to_canvas_bounding_rect(view, x, y, w, h, scale);
1278 
1279     reset(clip_array);
1280 
1281     if (screen_bounds.left != screen_bounds.right &&
1282         screen_bounds.top != screen_bounds.bottom) {
1283         #if MILTON_ENABLE_PROFILING
1284         {
1285             r->clipped_count = 0;
1286         }
1287         #endif
1288         for ( Layer* l = root_layer;
1289               l != NULL;
1290               l = l->next ) {
1291             if ( !(l->flags & LayerFlags_VISIBLE) ) {
1292                 // Skip invisible layers.
1293                 continue;
1294             }
1295 
1296             StrokeBucket* bucket = &l->strokes.root;
1297             i64 bucket_i = 0;
1298 
1299             while ( bucket ) {
1300                 i64 count = 0;
1301                 if ( l->strokes.count < bucket_i * STROKELIST_BUCKET_COUNT ) {
1302                     // There is an allocated bucket but we have already iterated
1303                     // through all the actual strokes.
1304                     break;
1305                 }
1306                 if ( l->strokes.count - bucket_i*STROKELIST_BUCKET_COUNT >= STROKELIST_BUCKET_COUNT ) {
1307                     count = STROKELIST_BUCKET_COUNT;
1308                 } else {
1309                     count = l->strokes.count % STROKELIST_BUCKET_COUNT;
1310                 }
1311 
1312                 Rect bbox = bucket->bounding_rect;
1313 
1314                 b32 bucket_outside =   screen_bounds.left   > bbox.right
1315                                     || screen_bounds.top    > bbox.bottom
1316                                     || screen_bounds.right  < bbox.left
1317                                     || screen_bounds.bottom < bbox.top;
1318 
1319                 if ( !bucket_outside ) {
1320                     for ( i64 i = 0; i < count; ++i ) {
1321                         Stroke* s = &bucket->data[i];
1322 
1323                         if ( s != NULL ) {
1324                             Rect bounds = s->bounding_rect;
1325 
1326                             b32 stroke_outside =   screen_bounds.left   > bounds.right
1327                                                 || screen_bounds.top    > bounds.bottom
1328                                                 || screen_bounds.right  < bounds.left
1329                                                 || screen_bounds.bottom < bounds.top;
1330 
1331                             i32 area = (bounds.right-bounds.left) * (bounds.bottom-bounds.top);
1332                             // Area might be 0 if the stroke is smaller than
1333                             // a pixel. We don't draw it in that case.
1334                             if ( !stroke_outside && area!=0 ) {
1335                                 gpu_cook_stroke(arena, r, s);
1336                                 push(clip_array, *get_render_element(s->render_handle));
1337                             }
1338                             else if ( stroke_outside && ( flags & ClipFlags_UPDATE_GPU_DATA ) ) {
1339                                 // If it is far away, delete.
1340                                 i32 distance = MLT_ABS(bounds.left - x + bounds.top - y);
1341                                 const i32 min_number_of_screens = 4;
1342                                 if (    bounds.top    < y - min_number_of_screens*h
1343                                      || bounds.bottom > y+h + min_number_of_screens*h
1344                                      || bounds.left   > x+w + min_number_of_screens*w
1345                                      || bounds.right  < x - min_number_of_screens*w ) {
1346                                     gpu_free_strokes(s, 1, r);
1347                                 }
1348                             }
1349                         }
1350                     }
1351                 }
1352                 else if ( flags & ClipFlags_UPDATE_GPU_DATA ) {
1353                     gpu_free_strokes(bucket->data, count, r);
1354                 }
1355                 #if MILTON_ENABLE_PROFILING
1356                 {
1357                     for ( i64 i = 0; i < count; ++i ) {
1358                         Stroke* s = &bucket->data[i];
1359                         RenderElement* re = get_render_element(s->render_handle);
1360                         if ( re && re->vbo_stroke != 0 ) {
1361                             r->clipped_count++;
1362                         }
1363                     }
1364                 }
1365                 #endif
1366                 bucket = bucket->next;
1367                 bucket_i += 1;
1368             }
1369 
1370             // Add the working stroke on the current layer.
1371             if ( working_stroke->layer_id == l->id ) {
1372                 if ( working_stroke->num_points > 0 ) {
1373                     gpu_cook_stroke(arena, r, working_stroke, CookStroke_UPDATE_WORKING_STROKE);
1374 
1375                     push(clip_array, *get_render_element(working_stroke->render_handle));
1376                 }
1377             }
1378 
1379             auto* p = push(clip_array, layer_element);
1380             p->layer_alpha = l->alpha;
1381             p->effects = l->effects;
1382         }
1383     }
1384 }
1385 
1386 static void
gpu_fill_with_texture(RenderBackend * r,float alpha=1.0f)1387 gpu_fill_with_texture(RenderBackend* r, float alpha = 1.0f)
1388 {
1389     // Assumes that texture object is already bound.
1390     gl::use_program(r->texture_fill_program);
1391     gl::set_uniform_f(r->texture_fill_program, "u_alpha", alpha);
1392     {
1393         GLint t_loc = glGetAttribLocation(r->texture_fill_program, "a_position");
1394         if ( t_loc >= 0 ) {
1395             glBindBuffer(GL_ARRAY_BUFFER, r->vbo_screen_quad);
1396             glEnableVertexAttribArray((GLuint)t_loc);
1397             glVertexAttribPointer(/*attrib location*/ (GLuint)t_loc,
1398                                   /*size*/ 2, GL_FLOAT, /*normalize*/ GL_FALSE,
1399                                   /*stride*/ 0, /*ptr*/ 0);
1400             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1401         }
1402     }
1403 }
1404 
1405 enum BoxFilterPass
1406 {
1407     BoxFilterPass_VERTICAL = 0,
1408     BoxFilterPass_HORIZONTAL = 1,
1409 };
1410 static void
box_filter_pass(RenderBackend * r,int kernel_size,int direction)1411 box_filter_pass(RenderBackend* r, int kernel_size, int direction)
1412 {
1413     gl::use_program(r->blur_program);
1414     gl::set_uniform_i(r->blur_program, "u_kernel_size", kernel_size);
1415     GLint t_loc = glGetAttribLocation(r->blur_program, "a_position");
1416     if ( t_loc >= 0 ) {
1417         gl::set_uniform_i(r->blur_program, "u_direction", direction);
1418         {
1419             glBindBuffer(GL_ARRAY_BUFFER, r->vbo_screen_quad);
1420             glEnableVertexAttribArray((GLuint)t_loc);
1421             glVertexAttribPointer(/*attrib location*/ (GLuint)t_loc,
1422                                   /*size*/ 2, GL_FLOAT, /*normalize*/ GL_FALSE,
1423                                   /*stride*/ 0, /*ptr*/ 0);
1424             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1425         }
1426     }
1427 }
1428 
1429 static void
gpu_render_canvas(RenderBackend * r,i32 view_x,i32 view_y,i32 view_width,i32 view_height,float background_alpha=1.0f)1430 gpu_render_canvas(RenderBackend* r, i32 view_x, i32 view_y,
1431                   i32 view_width, i32 view_height, float background_alpha=1.0f)
1432 {
1433     PUSH_GRAPHICS_GROUP("render_canvas");
1434 
1435     // FLip it. GL is bottom-left.
1436     i32 x = view_x;
1437     i32 y = r->height - (view_y+view_height);
1438     i32 w = view_width;
1439     i32 h = view_height;
1440     glScissor(x, y, w, h);
1441 
1442     glClearDepth(0.0f);
1443 
1444     glBindFramebufferEXT(GL_FRAMEBUFFER, r->fbo);
1445 
1446     GLenum texture_target;
1447     if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
1448         texture_target = GL_TEXTURE_2D_MULTISAMPLE;
1449     } else {
1450         texture_target = GL_TEXTURE_2D;
1451     }
1452 
1453     GLuint layer_texture = r->helper_texture;
1454 
1455     if ( background_alpha != 0.0f ) {
1456         // Not sure if this works OK with background_alpha != 1.0f
1457         glClearColor(r->background_color.r, r->background_color.g,
1458                      r->background_color.b, background_alpha);
1459     } else {
1460         glClearColor(0,0,0,0);
1461     }
1462 
1463     glBindTexture(texture_target, r->eraser_texture);
1464 
1465     glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
1466                               r->eraser_texture, 0);
1467 
1468     glClear(GL_COLOR_BUFFER_BIT);
1469 
1470     glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
1471                               r->canvas_texture, 0);
1472 
1473     glClear(GL_COLOR_BUFFER_BIT);
1474 
1475     glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
1476                               layer_texture, 0);
1477     glClearColor(0,0,0,0);
1478 
1479     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1480 
1481     glEnable(GL_DEPTH_TEST);
1482     glEnable(GL_BLEND);
1483     glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1484     glDepthFunc(GL_NOTEQUAL);
1485 
1486     DArray<RenderElement>* clip_array = &r->clip_array;
1487 
1488     PUSH_GRAPHICS_GROUP("render elements");
1489     for ( i64 i = 0; i < (i64)clip_array->count; i++ ) {
1490         RenderElement* re = &clip_array->data[i];
1491 
1492         if ( re->flags & RenderElementFlags_LAYER ) {
1493 
1494             // Layer render element.
1495             // The current framebuffer's color attachment is layer_texture.
1496 
1497             // Before we fill canvas_texture with the contents of
1498             // layer_texture, we apply all layer effects.
1499 
1500             GLuint layer_post_effects = layer_texture;
1501             {
1502                 // eraser_texture will be rewritten below with the
1503                 // contents of canvas_texture. We use it here for
1504                 // the layer effects.
1505                 GLuint out_texture = r->eraser_texture;
1506                 GLuint in_texture  = layer_texture;
1507                 glDisable(GL_BLEND);
1508                 glDisable(GL_DEPTH_TEST);
1509                 for ( LayerEffect* e = re->effects; e != NULL; e = e->next ) {
1510                     if ( e->enabled == false ) { continue; }
1511 
1512                     if ( e->type == LayerEffectType_BLUR ) {
1513                         glBindTexture(texture_target, in_texture);
1514                         glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1515                                                   texture_target, out_texture, 0);
1516 
1517                         // Three box filter iterations approximate a Gaussian blur
1518                         for (int blur_iter = 0; blur_iter < 3; ++blur_iter) {
1519                             // Box filter implementation uses the separable property.
1520                             // Apply horizontal pass and then vertical pass.
1521                             int kernel_size = e->blur.kernel_size * e->blur.original_scale / r->scale;
1522                             box_filter_pass(r, kernel_size, BoxFilterPass_VERTICAL);
1523                             swap(out_texture, in_texture);
1524                             glBindTexture(texture_target, in_texture);
1525                             glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1526                                                       texture_target, out_texture, 0);
1527 
1528 
1529                             box_filter_pass(r, kernel_size, BoxFilterPass_HORIZONTAL);
1530                             swap(out_texture, in_texture);
1531                             glBindTexture(texture_target, in_texture);
1532                             glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1533                                                       texture_target, out_texture, 0);
1534 
1535                         }
1536                         swap(out_texture, in_texture);
1537                         glBindTexture(texture_target, in_texture);
1538                         glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1539                                                   texture_target, out_texture, 0);
1540                         layer_post_effects = out_texture;
1541                     }
1542                 }
1543                 glEnable(GL_BLEND);
1544                 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
1545                 glEnable(GL_DEPTH_TEST);
1546             }
1547 
1548             // Blit layer contents to canvas_texture
1549             {
1550                 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1551                                           texture_target, r->canvas_texture, 0);
1552                 glBindTexture(texture_target, layer_post_effects);
1553 
1554                 glDisable(GL_DEPTH_TEST);
1555 
1556                 gpu_fill_with_texture(r, re->layer_alpha);
1557 
1558                 glEnable(GL_DEPTH_TEST);
1559             }
1560 
1561             // Copy canvas_texture's contents to the eraser_texture.
1562             {
1563                 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1564                                           texture_target, r->eraser_texture, 0);
1565                 glBindTexture(texture_target, r->canvas_texture);
1566 
1567                 glDisable(GL_BLEND);
1568                 glDisable(GL_DEPTH_TEST);
1569 
1570                 gpu_fill_with_texture(r);
1571 
1572                 // Clear the layer texture.
1573                 glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1574                                           texture_target, layer_texture, 0);
1575                 glClearColor(0,0,0,0);
1576                 glClear(GL_COLOR_BUFFER_BIT);
1577 
1578                 glBindTexture(texture_target, r->eraser_texture);
1579 
1580                 glEnable(GL_DEPTH_TEST);
1581                 glEnable(GL_BLEND);
1582             }
1583         }
1584         // If this render element is not a layer, then it is a stroke.
1585         else {
1586             GLuint program_for_stroke = r->stroke_program;
1587 
1588             auto stroke_pass = [r, texture_target](RenderElement* re, GLuint program_for_stroke) {
1589                 i64 count = re->count;
1590                 gl::use_program(program_for_stroke);
1591                 gl::set_uniform_vec4(program_for_stroke, "u_brush_color", 1, re->color.d);
1592                 gl::set_uniform_i(program_for_stroke, "u_radius", re->radius);
1593 
1594                 DEBUG_gl_validate_buffer(re->vbo_stroke);
1595                 DEBUG_gl_validate_buffer(re->vbo_pointa);
1596                 DEBUG_gl_validate_buffer(re->vbo_pointb);
1597                 DEBUG_gl_validate_buffer(re->indices);
1598 
1599                 gl::vertex_attrib_v3f(program_for_stroke, "a_pointa", re->vbo_pointa);
1600                 gl::vertex_attrib_v3f(program_for_stroke, "a_pointb", re->vbo_pointb);
1601                 gl::vertex_attrib_v3f(program_for_stroke, "a_position", re->vbo_stroke);
1602 
1603                 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, re->indices);
1604 
1605                 glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_SHORT, 0);
1606             };
1607 
1608             if ( re->count > 0 ) {
1609                 if (re->flags & RenderElementFlags_ERASER) {
1610                     glBindTexture(texture_target, r->eraser_texture);
1611                     stroke_pass(re, r->stroke_eraser_program);
1612                 }
1613                 else if ( (re->flags & (RenderElementFlags_PRESSURE_TO_OPACITY | RenderElementFlags_DISTANCE_TO_OPACITY)) ) {
1614                     glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1615                                               texture_target, r->stroke_info_texture, 0);
1616 
1617 
1618                     glDisable(GL_DEPTH_TEST);
1619                     glDisable(GL_BLEND);
1620                     stroke_pass(re, r->stroke_clear_program);
1621 
1622                     glEnable(GL_BLEND);
1623                     glBlendEquationSeparate(GL_MIN, GL_MAX);
1624 
1625                     stroke_pass(re, r->stroke_info_program);
1626 
1627                     glBlendEquation(GL_FUNC_ADD);
1628 
1629                     glEnable(GL_DEPTH_TEST);
1630                     glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
1631                                               texture_target, layer_texture, 0);
1632                     glBindTexture(texture_target, r->stroke_info_texture);
1633 
1634                     if ( (re->flags & RenderElementFlags_PRESSURE_TO_OPACITY) &&
1635                         !(re->flags & RenderElementFlags_DISTANCE_TO_OPACITY)) {
1636                         gl::set_uniform_f(r->stroke_fill_program_pressure, "u_opacity_min", re->min_opacity);
1637                         stroke_pass(re, r->stroke_fill_program_pressure);
1638                     }
1639                     else if ( !(re->flags & RenderElementFlags_PRESSURE_TO_OPACITY) &&
1640                                (re->flags & RenderElementFlags_DISTANCE_TO_OPACITY)) {
1641                         gl::set_uniform_f(r->stroke_fill_program_distance, "u_hardness", re->hardness);
1642                         stroke_pass(re, r->stroke_fill_program_distance);
1643                     }
1644                     else if ( (re->flags & RenderElementFlags_PRESSURE_TO_OPACITY) &&
1645                               (re->flags & RenderElementFlags_DISTANCE_TO_OPACITY)) {
1646                         gl::set_uniform_f(r->stroke_fill_program_pressure_distance, "u_opacity_min", re->min_opacity);
1647                         gl::set_uniform_f(r->stroke_fill_program_pressure_distance, "u_hardness", re->hardness);
1648                         stroke_pass(re, r->stroke_fill_program_pressure_distance);
1649                     }
1650                     else {
1651                         INVALID_CODE_PATH;
1652                     }
1653                 }
1654                 else {
1655                     // Fast path
1656                     stroke_pass(re, r->stroke_program);
1657                 }
1658             } else {
1659                 static int n = 0;
1660                 milton_log("Warning: Render element with count 0 [%d times]\n", ++n);
1661             }
1662         }
1663     }
1664     POP_GRAPHICS_GROUP();  // render elements
1665     glViewport(0, 0, r->width, r->height);
1666     glScissor(0, 0, r->width, r->height);
1667 
1668     POP_GRAPHICS_GROUP();  // render_canvas
1669 }
1670 
1671 void
gpu_render(RenderBackend * r,i32 view_x,i32 view_y,i32 view_width,i32 view_height)1672 gpu_render(RenderBackend* r,  i32 view_x, i32 view_y, i32 view_width, i32 view_height)
1673 {
1674     PUSH_GRAPHICS_GROUP("gpu_render");
1675 
1676     glViewport(0, 0, r->width, r->height);
1677     glScissor(0, 0, r->width, r->height);
1678     glEnable(GL_BLEND);
1679 
1680     print_framebuffer_status();
1681 
1682     // TODO: Do less work when idling
1683     gpu_render_canvas(r, view_x, view_y, view_width, view_height);
1684 
1685     GLenum texture_target;
1686     if ( gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
1687         texture_target = GL_TEXTURE_2D_MULTISAMPLE;
1688     } else {
1689         texture_target = GL_TEXTURE_2D;
1690     }
1691 
1692     // Use helper_texture as a place to do AA.
1693 
1694     // Blit the canvas to helper_texture
1695 
1696     glDisable(GL_DEPTH_TEST);
1697 
1698     PUSH_GRAPHICS_GROUP("blit to helper texture");
1699     if ( !gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
1700         glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
1701                                   r->canvas_texture, 0);
1702         glBindTexture(texture_target, r->helper_texture);
1703         glCopyTexImage2D(texture_target, 0, GL_RGBA8, 0,0, r->width, r->height, 0);
1704 
1705         glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
1706                                   r->helper_texture, 0);
1707         glBindTexture(texture_target, r->canvas_texture);
1708     } else {
1709         glFramebufferTexture2DEXT(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, texture_target,
1710                                   r->helper_texture, 0);
1711         glBindTexture(texture_target, r->canvas_texture);
1712 
1713         gpu_fill_with_texture(r);
1714     }
1715     POP_GRAPHICS_GROUP();
1716 
1717     // Render GUI on top of helper_texture
1718 
1719     // Render color picker
1720     // TODO: Only render if view rect intersects picker rect
1721     if ( r->flags & RenderBackendFlags_GUI_VISIBLE ) {
1722         // Render picker
1723         gl::use_program(r->picker_program);
1724         GLint loc = glGetAttribLocation(r->picker_program, "a_position");
1725 
1726         if ( loc >= 0 ) {
1727             DEBUG_gl_validate_buffer(r->vbo_picker);
1728             glBindBuffer(GL_ARRAY_BUFFER, r->vbo_picker);
1729             glVertexAttribPointer(/*attrib location*/(GLuint)loc,
1730                                   /*size*/2, GL_FLOAT, /*normalize*/GL_FALSE,
1731                                   /*stride*/0, /*ptr*/0);
1732             glEnableVertexAttribArray((GLuint)loc);
1733             GLint loc_norm = glGetAttribLocation(r->picker_program, "a_norm");
1734 
1735             if ( loc_norm >= 0 ) {
1736                 DEBUG_gl_validate_buffer(r->vbo_picker_norm);
1737                 glBindBuffer(GL_ARRAY_BUFFER, r->vbo_picker_norm);
1738                 glVertexAttribPointer(/*attrib location*/(GLuint)loc_norm,
1739                                       /*size*/2, GL_FLOAT, /*normalize*/GL_FALSE,
1740                                       /*stride*/0, /*ptr*/0);
1741                 glEnableVertexAttribArray((GLuint)loc_norm);
1742 
1743             }
1744             glDrawArrays(GL_TRIANGLE_FAN,0,4);
1745         }
1746     }
1747 
1748     // Do post-processing on painting and on GUI elements. Draw to backbuffer
1749 
1750     PUSH_GRAPHICS_GROUP("postproc");
1751     if ( !gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
1752         glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
1753 
1754         // glActiveTexture(GL_TEXTURE0);
1755         glBindTexture(GL_TEXTURE_2D, r->helper_texture);
1756 
1757         gl::set_uniform_i(r->postproc_program, "u_canvas", 0);
1758 
1759         gl::use_program(r->postproc_program);
1760 
1761         GLint loc = glGetAttribLocation(r->postproc_program, "a_position");
1762         if ( loc >= 0 ) {
1763             DEBUG_gl_validate_buffer(r->vbo_screen_quad);
1764             glBindBuffer(GL_ARRAY_BUFFER, r->vbo_screen_quad);
1765             glVertexAttribPointer((GLuint)loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
1766             glEnableVertexAttribArray((GLuint)loc);
1767             glVertexAttribPointer(/*attrib location*/ (GLuint)loc,
1768                                   /*size*/ 2, GL_FLOAT, /*normalize*/ GL_FALSE,
1769                                   /*stride*/ 0, /*ptr*/ 0);
1770 
1771             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1772         }
1773     }
1774     else {  // Resolve
1775         glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
1776         glBindFramebufferEXT(GL_READ_FRAMEBUFFER, r->fbo);
1777         glBlitFramebufferEXT(0, 0, r->width, r->height,
1778                              0, 0, r->width, r->height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
1779     }
1780     POP_GRAPHICS_GROUP();
1781 
1782     // Render outlines after doing AA.
1783 
1784     PUSH_GRAPHICS_GROUP("outlines");
1785     // Brush outline
1786     {
1787         gl::use_program(r->outline_program);
1788         GLint loc = glGetAttribLocation(r->outline_program, "a_position");
1789         if ( loc >= 0 ) {
1790             DEBUG_gl_validate_buffer(r->vbo_outline);
1791             glBindBuffer(GL_ARRAY_BUFFER, r->vbo_outline);
1792 
1793             glVertexAttribPointer(/*attrib location*/(GLuint)loc,
1794                                   /*size*/2, GL_FLOAT, /*normalize*/GL_FALSE,
1795                                   /*stride*/0, /*ptr*/0);
1796             glEnableVertexAttribArray((GLuint)loc);
1797             GLint loc_s = glGetAttribLocation(r->outline_program, "a_sizes");
1798             if ( loc_s >= 0 ) {
1799                 DEBUG_gl_validate_buffer(r->vbo_outline_sizes);
1800                 glBindBuffer(GL_ARRAY_BUFFER, r->vbo_outline_sizes);
1801                 glVertexAttribPointer(/*attrib location*/(GLuint)loc_s,
1802                                       /*size*/2, GL_FLOAT, /*normalize*/GL_FALSE,
1803                                       /*stride*/0, /*ptr*/0);
1804                 glEnableVertexAttribArray((GLuint)loc_s);
1805             }
1806         }
1807         glDrawArrays(GL_TRIANGLE_FAN, 0,4);
1808     }
1809     glDisable(GL_BLEND);
1810 
1811     // Exporter rect
1812     if ( r->imm_flags & ImmediateFlag_RECT ) {
1813         // Update data if rect is not degenerate.
1814         // Draw outline.
1815         gl::use_program(r->exporter_program);
1816         GLint loc = glGetAttribLocation(r->exporter_program, "a_position");
1817         if ( loc>=0 && r->vbo_exporter > 0 ) {
1818             DEBUG_gl_validate_buffer(r->vbo_exporter);
1819             gl::vertex_attrib_v2f(r->exporter_program, "a_position", r->vbo_exporter);
1820 
1821             glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, r->exporter_indices);
1822 
1823             glDrawElements(GL_TRIANGLES, r->exporter_indices_count, GL_UNSIGNED_SHORT, 0);
1824         }
1825     }
1826     POP_GRAPHICS_GROUP();  // outlines
1827 
1828     gl::use_program(0);
1829     POP_GRAPHICS_GROUP(); // gpu_render
1830 }
1831 
1832 void
gpu_render_to_buffer(Milton * milton,u8 * buffer,i32 scale,i32 x,i32 y,i32 w,i32 h,f32 background_alpha)1833 gpu_render_to_buffer(Milton* milton, u8* buffer, i32 scale, i32 x, i32 y, i32 w, i32 h, f32 background_alpha)
1834 {
1835     CanvasView saved_view = *milton->view;
1836     RenderBackend* r = milton->renderer;
1837     CanvasView* view = milton->view;
1838 
1839     i32 saved_width = r->width;
1840     i32 saved_height = r->height;
1841     GLuint saved_fbo = r->fbo;
1842 
1843     i32 buf_w = w * scale;
1844     i32 buf_h = h * scale;
1845 
1846     v2i center = milton->view->screen_size / 2;
1847     v2i pan_delta = v2i{x + (w / 2), y + (h / 2)} - center;
1848 
1849     milton_set_zoom_at_point(milton, center);
1850 
1851     f32 cos_angle = cosf(milton->view->angle);
1852     f32 sin_angle = sinf(milton->view->angle);
1853 
1854     v2f pan_delta_rotated = v2f{pan_delta.x * cos_angle - pan_delta.y * sin_angle, pan_delta.y * cos_angle + pan_delta.x * sin_angle };
1855 
1856     milton->view->pan_center =
1857         milton->view->pan_center + v2f_to_v2l(pan_delta_rotated)*milton->view->scale;
1858 
1859     milton->view->screen_size = v2i{buf_w, buf_h};
1860     r->width = buf_w;
1861     r->height = buf_h;
1862 
1863     milton->view->zoom_center = milton->view->screen_size / 2;
1864     if ( scale > 1 ) {
1865         milton->view->scale = (i32)ceill(((f32)milton->view->scale / (f32)scale));
1866     }
1867 
1868     gpu_resize(r, view);
1869     gpu_update_canvas(r, milton->canvas, view);
1870 
1871     // TODO: Check for out-of-memory errors.
1872 
1873     mlt_assert(buf_w == r->width);
1874     mlt_assert(buf_h == r->height);
1875 
1876     glViewport(0, 0, buf_w, buf_h);
1877     glScissor(0, 0, buf_w, buf_h);
1878     gpu_clip_strokes_and_update(&milton->root_arena, r, milton->view, milton->view->scale, milton->canvas->root_layer,
1879                                 &milton->working_stroke, 0, 0, buf_w, buf_h);
1880 
1881     gpu_render_canvas(r, 0, 0, buf_w, buf_h, background_alpha);
1882 
1883     // Post processing
1884     if ( !gl::check_flags(GLHelperFlags_TEXTURE_MULTISAMPLE) ) {
1885         gl::use_program(r->postproc_program);
1886         glBindTexture(GL_TEXTURE_2D, r->canvas_texture);
1887 
1888         GLint loc = glGetAttribLocation(r->postproc_program, "a_position");
1889         if ( loc >= 0 ) {
1890             DEBUG_gl_validate_buffer(r->vbo_screen_quad);
1891             glBindBuffer(GL_ARRAY_BUFFER, r->vbo_screen_quad);
1892             glVertexAttribPointer((GLuint)loc, 2, GL_FLOAT, GL_FALSE, 0, 0);
1893             glEnableVertexAttribArray((GLuint)loc);
1894 
1895             glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
1896         }
1897     } else {
1898         glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, 0);
1899         glBindFramebufferEXT(GL_READ_FRAMEBUFFER, r->fbo);
1900         glBlitFramebufferEXT(0, 0, buf_w, buf_h,
1901                              0, 0, buf_w, buf_h, GL_COLOR_BUFFER_BIT, GL_LINEAR);
1902         glBindFramebufferEXT(GL_FRAMEBUFFER, 0);
1903     }
1904 
1905     glEnable(GL_DEPTH_TEST);
1906 
1907     // Read onto buffer
1908     glReadPixels(0,0,
1909                  buf_w, buf_h,
1910                  GL_RGBA,
1911                  GL_UNSIGNED_BYTE,
1912                  (GLvoid*)buffer);
1913 
1914     {  // Flip texture
1915         u32* pixels = (u32*)buffer;
1916         for ( i64 j = 0; j < buf_h / 2; ++j ) {
1917             for ( i64 i = 0; i < buf_w; ++i ) {
1918                 i64 idx_up = j * buf_w + i;
1919                 i64 j_down = buf_h - 1 - j;
1920                 i64 idx_down = j_down * buf_w + i;
1921                 // Swap
1922                 u32 pixel = pixels[idx_down];
1923                 pixels[idx_down] = pixels[idx_up];
1924                 pixels[idx_up] = pixel;
1925             }
1926         }
1927     }
1928 
1929     // Cleanup.
1930 
1931     r->fbo = saved_fbo;
1932     *milton->view = saved_view;
1933     r->width = saved_width;
1934     r->height = saved_height;
1935 
1936     glBindFramebufferEXT(GL_FRAMEBUFFER, r->fbo);
1937 
1938     gpu_resize(r, view);
1939     gpu_update_canvas(r, milton->canvas, view);
1940 
1941     // Re-render
1942     gpu_clip_strokes_and_update(&milton->root_arena,
1943                                 r, milton->view, milton->view->scale, milton->canvas->root_layer,
1944                                 &milton->working_stroke, 0, 0, r->width,
1945                                 r->height);
1946     gpu_render(r, 0, 0, r->width, r->height);
1947 }
1948 
1949 void
gpu_release_data(RenderBackend * r)1950 gpu_release_data(RenderBackend* r)
1951 {
1952     release(&r->clip_array);
1953 }
1954 
1955 
1956 void
imm_begin_frame(RenderBackend * r)1957 imm_begin_frame(RenderBackend* r)
1958 {
1959     r->imm_flags = 0;
1960 }
1961 
1962 void
imm_rect(RenderBackend * r,float left,float right,float top,float bottom,float line_width)1963 imm_rect(RenderBackend* r, float left, float right, float top, float bottom, float line_width)
1964 {
1965     if ( r->vbo_exporter == 0 ) {
1966         glGenBuffers(1, &r->vbo_exporter);
1967         mlt_assert(r->exporter_indices == 0);
1968         glGenBuffers(1, &r->exporter_indices);
1969     }
1970 
1971     float toparr[] = {
1972         // Top quad
1973         left, top - line_width/r->height,
1974         left, top + line_width/r->height,
1975         right, top + line_width/r->height,
1976         right, top - line_width/r->height,
1977 
1978         // Bottom quad
1979         left, bottom-line_width/r->height,
1980         left, bottom+line_width/r->height,
1981         right, bottom+line_width/r->height,
1982         right, bottom-line_width/r->height,
1983 
1984         // Left
1985         left-line_width/r->width, top,
1986         left-line_width/r->width, bottom,
1987         left+line_width/r->width, bottom,
1988         left+line_width/r->width, top,
1989 
1990         // Right
1991         right-line_width/r->width, top,
1992         right-line_width/r->width, bottom,
1993         right+line_width/r->width, bottom,
1994         right+line_width/r->width, top,
1995     };
1996     glBindBuffer(GL_ARRAY_BUFFER, r->vbo_exporter);
1997     DEBUG_gl_mark_buffer(r->vbo_exporter);
1998     glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)array_count(toparr)*sizeof(*toparr), toparr, GL_DYNAMIC_DRAW);
1999 
2000     u16 indices[] = {
2001         // top
2002         0,1,2,
2003         2,3,0,
2004 
2005         // bottom
2006         4,5,6,
2007         6,7,4,
2008 
2009         // left
2010         8,9,10,
2011         10,11,8,
2012 
2013         // right
2014         12,13,14,
2015         14,15,12,
2016     };
2017     glBindBuffer(GL_ARRAY_BUFFER, r->exporter_indices);
2018     glBufferData(GL_ARRAY_BUFFER, (GLsizeiptr)array_count(indices)*sizeof(*indices), indices, GL_STATIC_DRAW);
2019 
2020     r->exporter_indices_count = array_count(indices);
2021 
2022     r->imm_flags |= ImmediateFlag_RECT;
2023 }
2024 
2025 void
gpu_reset_stroke(RenderBackend * r,RenderHandle handle)2026 gpu_reset_stroke(RenderBackend* r, RenderHandle handle)
2027 {
2028     RenderElement* re = get_render_element(handle);
2029     if (re) {
2030         re->count = 0;
2031     }
2032 }
2033