• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2018 Google Inc.
3  *
4  * Use of this source code is governed by a BSD-style license that can
5  * be found in the LICENSE file.
6  *
7  */
8 
9 //
10 //
11 //
12 
13 #include <glad/glad.h>
14 #include <glfw/glfw3.h>
15 
16 //
17 //
18 //
19 
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <stdbool.h>
23 #include <math.h>
24 
25 //
26 //
27 //
28 
29 #include "common/cl/assert_cl.h"
30 
31 //
32 //
33 //
34 
35 #include "interop.h"
36 
37 //
38 //
39 //
40 
41 #include "skc_cl.h"
42 #include "runtime_cl_12.h"
43 
44 //
45 //
46 //
47 
48 #include "ts/transform_stack.h"
49 
50 //
51 //
52 //
53 
54 #if 1
55 #define SKC_IMAGE_FORMAT GL_RGBA8
56 #else
57 #define SKC_IMAGE_FORMAT GL_RGBA16F
58 #endif
59 
60 //
61 //
62 //
63 
64 #ifndef M_PI
65 #define M_PI 3.14159265358979323846
66 #endif
67 
68 //
69 //
70 //
71 
72 struct skc_interop
73 {
74   GLFWwindow              * window;
75 
76   cl_context                context_cl;
77 
78   GLuint                    fbo;
79   GLuint                    rbo;
80 
81   struct skc_framebuffer_cl fb;
82 
83   int                       width;
84   int                       height;
85 
86   bool                      is_msecs;
87   bool                      is_srgb;
88   bool                      is_vsync_on;
89   bool                      is_fullscreen;
90   bool                      is_iconified;
91   bool                      is_resized;
92   bool                      is_spinning;
93   bool                      is_transform;
94 
95   skc_float                 scale;
96   skc_float2                translate;
97   float                     rotate_theta;
98 
99   int                       key;
100 };
101 
102 //
103 // INITIALIZE GLFW/GLAD
104 //
105 
106 static
107 void
skc_interop_error_callback(int error,char const * description)108 skc_interop_error_callback(int error, char const * description)
109 {
110   fputs(description,stderr);
111 }
112 
113 //
114 //
115 //
116 
117 static
118 void
skc_interop_iconify_callback(GLFWwindow * window,int iconified)119 skc_interop_iconify_callback(GLFWwindow * window, int iconified)
120 {
121   struct skc_interop * interop = glfwGetWindowUserPointer(window);
122 
123   interop->is_iconified = iconified;
124 }
125 
126 //
127 //
128 //
129 
130 static
131 void
skc_interop_key_callback(GLFWwindow * window,int key,int scancode,int action,int mods)132 skc_interop_key_callback(GLFWwindow * window, int key, int scancode, int action, int mods)
133 {
134   struct skc_interop * interop = glfwGetWindowUserPointer(window);
135 
136   if (action == GLFW_RELEASE)
137     return;
138 
139   switch (key)
140     {
141     case GLFW_KEY_EQUAL:
142       interop->rotate_theta = 0.0f;
143       interop->is_transform = true;
144       break;
145 
146     case GLFW_KEY_M:
147       interop->is_msecs ^= true;
148       break;
149 
150     case GLFW_KEY_R:
151       interop->is_spinning ^= true;
152       break;
153 
154     case GLFW_KEY_S:
155       interop->is_srgb ^= true;
156       if (interop->is_srgb)
157         glEnable(GL_FRAMEBUFFER_SRGB);
158       else
159         glDisable(GL_FRAMEBUFFER_SRGB);
160       break;
161 
162     case GLFW_KEY_V:
163       interop->is_vsync_on ^= true;
164       glfwSwapInterval(interop->is_vsync_on ? 1 : 0);
165       break;
166 
167     case GLFW_KEY_W:
168       glfwSetWindowSize(window,1024,1024);
169       break;
170 
171     case GLFW_KEY_ESCAPE:
172       glfwSetWindowShouldClose(window,GL_TRUE);
173       break;
174 
175     default:
176       interop->key = key;
177     }
178 }
179 
180 static
181 void
skc_interop_window_size_callback(GLFWwindow * window,int width,int height)182 skc_interop_window_size_callback(GLFWwindow * window, int width, int height)
183 {
184   struct skc_interop * interop = glfwGetWindowUserPointer(window);
185 
186   interop->width        = width;
187   interop->height       = height;
188   interop->is_resized   = true;
189   interop->is_transform = true;
190 
191 #if 0
192   skc_render_kernel_set_clip(0,0,width,height);
193 #endif
194 }
195 
196 static
197 void
skc_interop_scale(struct skc_interop * interop,double const scale_offset)198 skc_interop_scale(struct skc_interop * interop, double const scale_offset)
199 {
200 #define SKC_SCALE_FACTOR 1.05
201 
202   static double scale_exp = 0.0;
203 
204   scale_exp += scale_offset;
205 
206   interop->scale = (float)pow(SKC_SCALE_FACTOR,scale_exp);
207 }
208 
209 static
210 void
skc_interop_scroll_callback(GLFWwindow * window,double xoffset,double yoffset)211 skc_interop_scroll_callback(GLFWwindow * window, double xoffset, double yoffset)
212 {
213   bool const ctrl =
214     (glfwGetKey(window,GLFW_KEY_LEFT_CONTROL)  == GLFW_PRESS) ||
215     (glfwGetKey(window,GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS);
216 
217   if (!ctrl)
218     return;
219 
220   struct skc_interop * interop = glfwGetWindowUserPointer(window);
221 
222   skc_interop_scale(interop,yoffset);
223 
224   interop->is_transform = true;
225 }
226 
227 static
228 void
skc_interop_translate(struct skc_interop * interop,float const dx,float const dy)229 skc_interop_translate(struct skc_interop * interop, float const dx, float const dy)
230 {
231   float const dx_scaled = dx / interop->scale;
232   float const dy_scaled = dy / interop->scale;
233 
234   float const cos_theta = cosf(interop->rotate_theta); // replace with cospi if available
235   float const sin_theta = sinf(interop->rotate_theta); // replace with sinpi if available
236 
237   interop->translate.x += dx_scaled*cos_theta + dy_scaled*sin_theta;
238   interop->translate.y += dy_scaled*cos_theta - dx_scaled*sin_theta;
239 }
240 
241 static
242 void
skc_interop_cursor_position_callback(GLFWwindow * window,double x,double y)243 skc_interop_cursor_position_callback(GLFWwindow * window, double x, double y)
244 {
245 
246   int const state = glfwGetMouseButton(window,GLFW_MOUSE_BUTTON_LEFT);
247 
248   static bool  is_mouse_dragging = false;
249   static float x_prev=0.0, y_prev=0.0;
250 
251   float const mx = (float)x;
252   float const my = (float)y;
253 
254   if (state == GLFW_PRESS)
255     {
256       struct skc_interop * interop = glfwGetWindowUserPointer(window);
257 
258       if (is_mouse_dragging)
259         {
260           const bool ctrl =
261             (glfwGetKey(window,GLFW_KEY_LEFT_CONTROL)  == GLFW_PRESS) ||
262             (glfwGetKey(window,GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS);
263 
264           if (ctrl)
265             {
266               float const cx  = 0.5f * interop->width;
267               float const cy  = 0.5f * interop->height;
268 
269               // find angle between mouse and center
270               float const vx  = x_prev - cx;
271               float const vy  = y_prev - cy;
272 
273               float const wx  = mx - cx;
274               float const wy  = my - cy;
275 
276               float const len = sqrtf((vx*vx + vy*vy) * (wx*wx + wy*wy));
277 
278               if (len > 0.0f)
279                 {
280                   float const dot = vx*wx + vy*wy;
281                   float const da  = acosf(dot / len);
282 
283                   if (vx*wy - vy*wx >= 0.0f)
284                     interop->rotate_theta += da;
285                   else
286                     interop->rotate_theta -= da;
287 
288                   interop->rotate_theta = fmodf(interop->rotate_theta,(float)(M_PI*2.0));
289                 }
290             }
291           else
292             {
293               skc_interop_translate(interop,
294                                     mx - x_prev,
295                                     my - y_prev);
296             }
297 
298           interop->is_transform = true;
299         }
300       else
301         {
302           is_mouse_dragging = true;
303         }
304 
305       x_prev = mx;
306       y_prev = my;
307     }
308   else
309     {
310       is_mouse_dragging = false;
311     }
312 }
313 
314 //
315 //
316 //
317 
318 static
319 void
skc_interop_acquire(struct skc_interop * interop)320 skc_interop_acquire(struct skc_interop * interop)
321 {
322   // frame buffer object
323   glCreateFramebuffers(1,&interop->fbo);
324 
325   // render buffer object w/a color buffer
326   glCreateRenderbuffers(1,&interop->rbo);
327 
328   // size rbo
329   glNamedRenderbufferStorage(interop->rbo,
330                              SKC_IMAGE_FORMAT,
331                              interop->width,
332                              interop->height);
333 
334   // attach rbo to fbo
335   glNamedFramebufferRenderbuffer(interop->fbo,
336                                  GL_COLOR_ATTACHMENT0,
337                                  GL_RENDERBUFFER,
338                                  interop->rbo);
339 }
340 
341 //
342 //
343 //
344 
345 struct skc_interop *
skc_interop_create()346 skc_interop_create()
347 {
348   struct skc_interop * interop = malloc(sizeof(*interop));
349 
350   *interop = (struct skc_interop)
351     {
352       .fb            = { .type        = SKC_FRAMEBUFFER_CL_GL_RENDERBUFFER,
353                          .mem         = NULL,
354                          .interop     = interop,
355                          .post_render = skc_interop_blit },
356 
357       .is_msecs      = false,
358       .is_srgb       = true,
359       .is_vsync_on   = false,
360       .is_fullscreen = false,
361       .is_iconified  = false,
362       .is_resized    = true,
363       .is_spinning   = false,
364       .is_transform  = true,
365 
366       .scale         = 1.0f,
367       .translate     = { 0.0f, 0.0f },
368       .rotate_theta  = 0.0f,
369 
370       .key           = 0
371     };
372 
373   //
374   // INITIALIZE GLFW/GLAD
375   //
376   glfwSetErrorCallback(skc_interop_error_callback);
377 
378   if (!glfwInit())
379     exit(EXIT_FAILURE);
380 
381   GLFWmonitor       * const primary = glfwGetPrimaryMonitor();
382   GLFWvidmode const * const mode    = glfwGetVideoMode(primary);
383 
384   if (interop->is_fullscreen)
385     {
386       interop->width  = mode->width;
387       interop->height = mode->height;
388     }
389   else
390     {
391       interop->width  = 1600;
392       interop->height = 1600;
393     }
394 
395   glfwWindowHint(GLFW_ALPHA_BITS,            0);
396   glfwWindowHint(GLFW_DEPTH_BITS,            0);
397   glfwWindowHint(GLFW_STENCIL_BITS,          0);
398 
399   glfwWindowHint(GLFW_SRGB_CAPABLE,          GL_TRUE);
400 
401   glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
402   glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 5);
403 
404   glfwWindowHint(GLFW_OPENGL_PROFILE,        GLFW_OPENGL_CORE_PROFILE);
405 
406   interop->window = glfwCreateWindow(interop->width,
407                                      interop->height,
408                                      "Skia Compute",
409                                      interop->is_fullscreen ? primary : NULL,
410                                      NULL);
411 
412   if (interop->window == NULL)
413     {
414       glfwTerminate();
415       exit(EXIT_FAILURE);
416     }
417 
418   // save back pointer
419   glfwSetWindowUserPointer(interop->window,interop);
420 
421   glfwMakeContextCurrent(interop->window);
422 
423   // set up GLAD
424   gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
425 
426   // ignore vsync for now
427   glfwSwapInterval(interop->is_vsync_on ? 1 : 0);
428 
429   // only copy r/g/b
430   glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_FALSE);
431 
432   // enable SRGB, disable scissor
433   glEnable(GL_FRAMEBUFFER_SRGB);
434   glDisable(GL_SCISSOR_TEST);
435 
436   //
437   // SET USER POINTER AND CALLBACKS
438   //
439   glfwSetKeyCallback            (interop->window,skc_interop_key_callback);
440   glfwSetFramebufferSizeCallback(interop->window,skc_interop_window_size_callback);
441   glfwSetScrollCallback         (interop->window,skc_interop_scroll_callback);
442   glfwSetCursorPosCallback      (interop->window,skc_interop_cursor_position_callback);
443   glfwSetWindowIconifyCallback  (interop->window,skc_interop_iconify_callback);
444 
445   //
446   //
447   //
448   fprintf(stderr,
449           "GL_VENDOR   : %s\n"
450           "GL_RENDERER : %s\n",
451           glGetString(GL_VENDOR),
452           glGetString(GL_RENDERER));
453 
454   //
455   // acquire an FBO/RBO
456   //
457   skc_interop_acquire(interop);
458 
459   return interop;
460 }
461 
462 //
463 //
464 //
465 
466 void
skc_interop_destroy(struct skc_interop * interop)467 skc_interop_destroy(struct skc_interop * interop)
468 {
469   glfwDestroyWindow(interop->window);
470   glfwTerminate();
471 
472   free(interop);
473 }
474 
475 //
476 //
477 //
478 
479 void
skc_interop_set_cl_context(struct skc_interop * interop,cl_context context_cl)480 skc_interop_set_cl_context(struct skc_interop * interop,
481                            cl_context           context_cl)
482 {
483   interop->context_cl = context_cl;
484 }
485 
486 //
487 //
488 //
489 
490 cl_context_properties
skc_interop_get_wgl_context()491 skc_interop_get_wgl_context()
492 {
493   return (cl_context_properties)wglGetCurrentContext();
494 }
495 
496 cl_context_properties
skc_interop_get_wgl_dc()497 skc_interop_get_wgl_dc()
498 {
499   return (cl_context_properties)wglGetCurrentDC();
500 }
501 
502 //
503 //
504 //
505 
506 #define SKC_ROTATE_STEP ((float)(M_PI / 180.0))
507 
508 void
skc_interop_transform(struct skc_interop * interop,struct ts_transform_stack * ts)509 skc_interop_transform(struct skc_interop        * interop,
510                       struct ts_transform_stack * ts)
511 {
512 #if 1
513   // move the origin from the lower left to the top left
514   ts_transform_stack_push_affine(ts,
515                                  1.0f, 0.0f,0.0f,
516                                  0.0f,-1.0f,(float)interop->height);
517   // multiply
518   ts_transform_stack_concat(ts);
519 #endif
520 
521 #if 0
522   ts_transform_stack_push_matrix(ts,
523                                  0.87004626f, -0.35519487f,   72.14745f,
524                                  0.0f,         0.2600208f,    86.16314f,
525                                  0.0f,        -0.0029599573f, 1.0f);
526   ts_transform_stack_concat(ts);
527 #endif
528 
529   // spinner...
530   if (interop->is_spinning)
531     interop->rotate_theta = fmodf(interop->rotate_theta + SKC_ROTATE_STEP,(float)(M_PI*2.0));
532 
533   // always rotate and scale around surface center point
534   ts_transform_stack_push_rotate_scale_xy(ts,
535                                           interop->rotate_theta,
536                                           interop->scale,
537                                           interop->scale,
538                                           0.5f*interop->width,
539                                           0.5f*interop->height);
540   ts_transform_stack_concat(ts);
541 
542   // where did the mouse take us?
543   ts_transform_stack_push_translate(ts,
544                                     interop->translate.x,
545                                     interop->translate.y);
546   ts_transform_stack_concat(ts);
547 }
548 
549 //
550 //
551 //
552 
553 static
554 void
skc_interop_resize(struct skc_interop * interop)555 skc_interop_resize(struct skc_interop * interop)
556 {
557   interop->is_resized = false;
558 
559   // release the image2d
560   if (interop->fb.mem != NULL)
561     cl(ReleaseMemObject(interop->fb.mem));
562 
563   // resize rbo
564   glNamedRenderbufferStorage(interop->rbo,
565                              SKC_IMAGE_FORMAT,
566                              interop->width,
567                              interop->height);
568 
569   // attach rbo to fbo
570   glNamedFramebufferRenderbuffer(interop->fbo,
571                                  GL_COLOR_ATTACHMENT0,
572                                  GL_RENDERBUFFER,
573                                  interop->rbo);
574   //
575   //
576   //
577   cl_int cl_err;
578 
579   interop->fb.mem = clCreateFromGLRenderbuffer(interop->context_cl,
580                                                CL_MEM_WRITE_ONLY,
581                                                interop->rbo,
582                                                &cl_err); cl_ok(cl_err);
583   //
584   // for debugging porpoises!
585   //
586 #if 0
587   cl_image_format format;
588 
589   cl(GetImageInfo(interop->fb.mem,
590                   CL_IMAGE_FORMAT,
591                   sizeof(format),
592                   &format,
593                   NULL));
594 #endif
595 }
596 
597 //
598 // FPS COUNTER FROM HERE:
599 //
600 // http://antongerdelan.net/opengl/glcontext2.html
601 //
602 
603 static
604 void
skc_interop_fps(struct skc_interop * interop)605 skc_interop_fps(struct skc_interop * interop)
606 {
607   if (interop->is_fullscreen)
608     return;
609 
610   // static fps counters
611   static double stamp_prev  = 0.0;
612   static int    frame_count = 0;
613 
614   // locals
615   double const  stamp_curr  = glfwGetTime();
616   double const  elapsed     = stamp_curr - stamp_prev;
617 
618   if (elapsed >= 0.5)
619     {
620       stamp_prev = stamp_curr;
621 
622       char tmp[64];
623 
624       if (interop->is_msecs)
625         {
626           double const msecs = min(elapsed * 1000 / frame_count,9999.9);
627 
628           sprintf_s(tmp,64,"%5.1f MSECS - (%d x %d) - VSync %s - sRGB %s",
629                     msecs,
630                     interop->width,interop->height,
631                     interop->is_vsync_on ? "ON"      : "OFF",
632                     interop->is_srgb     ? "ENABLED" : "DISABLED");
633         }
634       else
635         {
636           double const fps = min((double)frame_count / elapsed,9999.9);
637 
638           sprintf_s(tmp,64,"%5.1f FPS - (%d x %d) - VSync %s - sRGB %s",
639                     fps,
640                     interop->width,interop->height,
641                     interop->is_vsync_on ? "ON"      : "OFF",
642                     interop->is_srgb     ? "ENABLED" : "DISABLED");
643         }
644 
645       glfwSetWindowTitle(interop->window,tmp);
646 
647       frame_count = 0;
648     }
649 
650   frame_count++;
651 }
652 
653 //
654 //
655 //
656 
657 bool
skc_interop_poll(struct skc_interop * interop,int * key)658 skc_interop_poll(struct skc_interop * interop, int * key)
659 {
660   // wait until uniconified
661   while (interop->is_iconified)
662     {
663       glfwWaitEvents();
664       continue;
665     }
666 
667   // what's happended?
668   glfwPollEvents();
669 
670   // resize?
671   if (interop->is_resized)
672     skc_interop_resize(interop);
673 
674   // monitor fps
675   skc_interop_fps(interop);
676 
677   if (key != NULL)
678     {
679       *key         = interop->key;
680       interop->key = 0;
681     }
682 
683   bool const is_transform = interop->is_transform || interop->is_spinning;
684 
685   interop->is_transform = false;
686 
687   return is_transform;
688 }
689 
690 //
691 //
692 //
693 
694 void
skc_interop_blit(struct skc_interop * interop)695 skc_interop_blit(struct skc_interop * interop)
696 {
697   // blit skc rbo
698   glBlitNamedFramebuffer(interop->fbo,0,
699                          0,0,interop->width,interop->height,
700                          0,0,interop->width,interop->height,
701                          GL_COLOR_BUFFER_BIT,
702                          GL_NEAREST);
703 
704   // swap buffers
705   glfwSwapBuffers(interop->window);
706 
707 #if 0
708   //
709   // FIXME -- this clear does nothing!
710   //
711   // As a hack we're clearing the interop'd RBO with a
712   // clEnqueueFillImage().
713   //
714   GLenum const attachments[] = { GL_COLOR_ATTACHMENT0 };
715   glInvalidateNamedFramebufferData(interop->fbo,1,attachments);
716   float  const rgba[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
717   glClearNamedFramebufferfv(interop->fbo,GL_COLOR,0,rgba);
718 #endif
719 }
720 
721 //
722 //
723 //
724 
725 skc_framebuffer_t
skc_interop_get_framebuffer(struct skc_interop * interop)726 skc_interop_get_framebuffer(struct skc_interop * interop)
727 {
728   // glFlush();
729   glFinish();
730 
731   return &interop->fb;
732 }
733 
734 //
735 //
736 //
737 
738 bool
skc_interop_should_exit(struct skc_interop * interop)739 skc_interop_should_exit(struct skc_interop * interop)
740 {
741   return glfwWindowShouldClose(interop->window);
742 }
743 
744 //
745 //
746 //
747 
748 void
skc_interop_get_size(struct skc_interop * interop,uint32_t * width,uint32_t * height)749 skc_interop_get_size(struct skc_interop * interop,
750                      uint32_t           * width,
751                      uint32_t           * height)
752 {
753   *width  = interop->width;
754   *height = interop->height;
755 }
756 
757 //
758 //
759 //
760