Cleanup: style, use braces for editors
[blender.git] / source / blender / editors / screen / glutil.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  */
19
20 /** \file
21  * \ingroup edscr
22  */
23
24 #include <stdio.h>
25 #include <string.h>
26
27 #include "MEM_guardedalloc.h"
28
29 #include "DNA_userdef_types.h"
30 #include "DNA_vec_types.h"
31
32 #include "BLI_utildefines.h"
33 #include "BLI_math.h"
34
35 #include "BKE_context.h"
36
37 #include "BIF_glutil.h"
38
39 #include "IMB_colormanagement.h"
40 #include "IMB_imbuf_types.h"
41
42 #include "GPU_immediate.h"
43 #include "GPU_matrix.h"
44 #include "GPU_state.h"
45
46 #include "UI_interface.h"
47
48 /* ******************************************** */
49
50 /* Invert line handling */
51
52 #define GL_TOGGLE(mode, onoff) (((onoff) ? glEnable : glDisable)(mode))
53
54 void set_inverted_drawing(int enable)
55 {
56   glLogicOp(enable ? GL_INVERT : GL_COPY);
57   GL_TOGGLE(GL_COLOR_LOGIC_OP, enable);
58   GL_TOGGLE(GL_DITHER, !enable);
59 }
60
61 static int get_cached_work_texture(int *r_w, int *r_h)
62 {
63   static GLint texid = -1;
64   static int tex_w = 256;
65   static int tex_h = 256;
66
67   if (texid == -1) {
68     glGenTextures(1, (GLuint *)&texid);
69
70     glBindTexture(GL_TEXTURE_2D, texid);
71
72     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
73     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
74
75     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
76
77     glBindTexture(GL_TEXTURE_2D, 0);
78   }
79
80   *r_w = tex_w;
81   *r_h = tex_h;
82   return texid;
83 }
84
85 static void immDrawPixelsTexSetupAttributes(IMMDrawPixelsTexState *state)
86 {
87   GPUVertFormat *vert_format = immVertexFormat();
88   state->pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
89   state->texco = GPU_vertformat_attr_add(
90       vert_format, "texCoord", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
91 }
92
93 /* To be used before calling immDrawPixelsTex
94  * Default shader is GPU_SHADER_2D_IMAGE_COLOR
95  * You can still set uniforms with :
96  * GPU_shader_uniform_int(shader, GPU_shader_get_uniform_ensure(shader, "name"), 0);
97  * */
98 IMMDrawPixelsTexState immDrawPixelsTexSetup(int builtin)
99 {
100   IMMDrawPixelsTexState state;
101   immDrawPixelsTexSetupAttributes(&state);
102
103   state.shader = GPU_shader_get_builtin_shader(builtin);
104
105   /* Shader will be unbind by immUnbindProgram in immDrawPixelsTexScaled_clipping */
106   immBindBuiltinProgram(builtin);
107   immUniform1i("image", 0);
108   state.do_shader_unbind = true;
109
110   return state;
111 }
112
113 /* Use the currently bound shader.
114  *
115  * Use immDrawPixelsTexSetup to bind the shader you
116  * want before calling immDrawPixelsTex.
117  *
118  * If using a special shader double check it uses the same
119  * attributes "pos" "texCoord" and uniform "image".
120  *
121  * If color is NULL then use white by default
122  *
123  * Be also aware that this function unbinds the shader when
124  * it's finished.
125  * */
126 void immDrawPixelsTexScaled_clipping(IMMDrawPixelsTexState *state,
127                                      float x,
128                                      float y,
129                                      int img_w,
130                                      int img_h,
131                                      int format,
132                                      int type,
133                                      int zoomfilter,
134                                      void *rect,
135                                      float scaleX,
136                                      float scaleY,
137                                      float clip_min_x,
138                                      float clip_min_y,
139                                      float clip_max_x,
140                                      float clip_max_y,
141                                      float xzoom,
142                                      float yzoom,
143                                      float color[4])
144 {
145   unsigned char *uc_rect = (unsigned char *)rect;
146   const float *f_rect = (float *)rect;
147   int subpart_x, subpart_y, tex_w, tex_h;
148   int seamless, offset_x, offset_y, nsubparts_x, nsubparts_y;
149   int texid = get_cached_work_texture(&tex_w, &tex_h);
150   int components;
151   const bool use_clipping = ((clip_min_x < clip_max_x) && (clip_min_y < clip_max_y));
152   float white[4] = {1.0f, 1.0f, 1.0f, 1.0f};
153
154   GLint unpack_row_length;
155   glGetIntegerv(GL_UNPACK_ROW_LENGTH, &unpack_row_length);
156
157   glPixelStorei(GL_UNPACK_ROW_LENGTH, img_w);
158   glActiveTexture(GL_TEXTURE0);
159   glBindTexture(GL_TEXTURE_2D, texid);
160
161   /* don't want nasty border artifacts */
162   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
163   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
164   glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, zoomfilter);
165
166   /* setup seamless 2=on, 0=off */
167   seamless = ((tex_w < img_w || tex_h < img_h) && tex_w > 2 && tex_h > 2) ? 2 : 0;
168
169   offset_x = tex_w - seamless;
170   offset_y = tex_h - seamless;
171
172   nsubparts_x = (img_w + (offset_x - 1)) / (offset_x);
173   nsubparts_y = (img_h + (offset_y - 1)) / (offset_y);
174
175   if (format == GL_RGBA) {
176     components = 4;
177   }
178   else if (format == GL_RGB) {
179     components = 3;
180   }
181   else if (format == GL_RED) {
182     components = 1;
183   }
184   else {
185     BLI_assert(!"Incompatible format passed to glaDrawPixelsTexScaled");
186     return;
187   }
188
189   if (type == GL_FLOAT) {
190     /* need to set internal format to higher range float */
191     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA16F, tex_w, tex_h, 0, format, GL_FLOAT, NULL);
192   }
193   else {
194     /* switch to 8bit RGBA for byte buffer */
195     glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, tex_w, tex_h, 0, format, GL_UNSIGNED_BYTE, NULL);
196   }
197
198   unsigned int pos = state->pos, texco = state->texco;
199
200   /* optional */
201   /* NOTE: Shader could be null for GLSL OCIO drawing, it is fine, since
202    * it does not need color.
203    */
204   if (state->shader != NULL && GPU_shader_get_uniform_ensure(state->shader, "color") != -1) {
205     immUniformColor4fv((color) ? color : white);
206   }
207
208   for (subpart_y = 0; subpart_y < nsubparts_y; subpart_y++) {
209     for (subpart_x = 0; subpart_x < nsubparts_x; subpart_x++) {
210       int remainder_x = img_w - subpart_x * offset_x;
211       int remainder_y = img_h - subpart_y * offset_y;
212       int subpart_w = (remainder_x < tex_w) ? remainder_x : tex_w;
213       int subpart_h = (remainder_y < tex_h) ? remainder_y : tex_h;
214       int offset_left = (seamless && subpart_x != 0) ? 1 : 0;
215       int offset_bot = (seamless && subpart_y != 0) ? 1 : 0;
216       int offset_right = (seamless && remainder_x > tex_w) ? 1 : 0;
217       int offset_top = (seamless && remainder_y > tex_h) ? 1 : 0;
218       float rast_x = x + subpart_x * offset_x * xzoom;
219       float rast_y = y + subpart_y * offset_y * yzoom;
220       /* check if we already got these because we always get 2 more when doing seamless */
221       if (subpart_w <= seamless || subpart_h <= seamless) {
222         continue;
223       }
224
225       if (use_clipping) {
226         if (rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX < clip_min_x ||
227             rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY < clip_min_y) {
228           continue;
229         }
230         if (rast_x + (float)offset_left * xzoom > clip_max_x ||
231             rast_y + (float)offset_bot * yzoom > clip_max_y) {
232           continue;
233         }
234       }
235
236       if (type == GL_FLOAT) {
237         glTexSubImage2D(GL_TEXTURE_2D,
238                         0,
239                         0,
240                         0,
241                         subpart_w,
242                         subpart_h,
243                         format,
244                         GL_FLOAT,
245                         &f_rect[((size_t)subpart_y) * offset_y * img_w * components +
246                                 subpart_x * offset_x * components]);
247
248         /* add an extra border of pixels so linear looks ok at edges of full image */
249         if (subpart_w < tex_w) {
250           glTexSubImage2D(GL_TEXTURE_2D,
251                           0,
252                           subpart_w,
253                           0,
254                           1,
255                           subpart_h,
256                           format,
257                           GL_FLOAT,
258                           &f_rect[((size_t)subpart_y) * offset_y * img_w * components +
259                                   (subpart_x * offset_x + subpart_w - 1) * components]);
260         }
261         if (subpart_h < tex_h) {
262           glTexSubImage2D(
263               GL_TEXTURE_2D,
264               0,
265               0,
266               subpart_h,
267               subpart_w,
268               1,
269               format,
270               GL_FLOAT,
271               &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components +
272                       subpart_x * offset_x * components]);
273         }
274         if (subpart_w < tex_w && subpart_h < tex_h) {
275           glTexSubImage2D(
276               GL_TEXTURE_2D,
277               0,
278               subpart_w,
279               subpart_h,
280               1,
281               1,
282               format,
283               GL_FLOAT,
284               &f_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components +
285                       (subpart_x * offset_x + subpart_w - 1) * components]);
286         }
287       }
288       else {
289         glTexSubImage2D(GL_TEXTURE_2D,
290                         0,
291                         0,
292                         0,
293                         subpart_w,
294                         subpart_h,
295                         format,
296                         GL_UNSIGNED_BYTE,
297                         &uc_rect[((size_t)subpart_y) * offset_y * img_w * components +
298                                  subpart_x * offset_x * components]);
299
300         if (subpart_w < tex_w) {
301           glTexSubImage2D(GL_TEXTURE_2D,
302                           0,
303                           subpart_w,
304                           0,
305                           1,
306                           subpart_h,
307                           format,
308                           GL_UNSIGNED_BYTE,
309                           &uc_rect[((size_t)subpart_y) * offset_y * img_w * components +
310                                    (subpart_x * offset_x + subpart_w - 1) * components]);
311         }
312         if (subpart_h < tex_h) {
313           glTexSubImage2D(
314               GL_TEXTURE_2D,
315               0,
316               0,
317               subpart_h,
318               subpart_w,
319               1,
320               format,
321               GL_UNSIGNED_BYTE,
322               &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components +
323                        subpart_x * offset_x * components]);
324         }
325         if (subpart_w < tex_w && subpart_h < tex_h) {
326           glTexSubImage2D(
327               GL_TEXTURE_2D,
328               0,
329               subpart_w,
330               subpart_h,
331               1,
332               1,
333               format,
334               GL_UNSIGNED_BYTE,
335               &uc_rect[(((size_t)subpart_y) * offset_y + subpart_h - 1) * img_w * components +
336                        (subpart_x * offset_x + subpart_w - 1) * components]);
337         }
338       }
339
340       immBegin(GPU_PRIM_TRI_FAN, 4);
341       immAttr2f(texco, (float)(0 + offset_left) / tex_w, (float)(0 + offset_bot) / tex_h);
342       immVertex2f(pos, rast_x + (float)offset_left * xzoom, rast_y + (float)offset_bot * yzoom);
343
344       immAttr2f(texco, (float)(subpart_w - offset_right) / tex_w, (float)(0 + offset_bot) / tex_h);
345       immVertex2f(pos,
346                   rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX,
347                   rast_y + (float)offset_bot * yzoom);
348
349       immAttr2f(texco,
350                 (float)(subpart_w - offset_right) / tex_w,
351                 (float)(subpart_h - offset_top) / tex_h);
352       immVertex2f(pos,
353                   rast_x + (float)(subpart_w - offset_right) * xzoom * scaleX,
354                   rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
355
356       immAttr2f(texco, (float)(0 + offset_left) / tex_w, (float)(subpart_h - offset_top) / tex_h);
357       immVertex2f(pos,
358                   rast_x + (float)offset_left * xzoom,
359                   rast_y + (float)(subpart_h - offset_top) * yzoom * scaleY);
360       immEnd();
361
362       /* NOTE: Weirdly enough this is only required on macOS. Without this there is some sort of
363        * bleeding of data is happening from tiles which are drawn later on.
364        * This doesn't seem to be too slow,
365        * but still would be nice to have fast and nice solution. */
366 #ifdef __APPLE__
367       GPU_flush();
368 #endif
369     }
370   }
371
372   if (state->do_shader_unbind) {
373     immUnbindProgram();
374   }
375
376   glBindTexture(GL_TEXTURE_2D, 0);
377   glPixelStorei(GL_UNPACK_ROW_LENGTH, unpack_row_length);
378 }
379
380 void immDrawPixelsTexScaled(IMMDrawPixelsTexState *state,
381                             float x,
382                             float y,
383                             int img_w,
384                             int img_h,
385                             int format,
386                             int type,
387                             int zoomfilter,
388                             void *rect,
389                             float scaleX,
390                             float scaleY,
391                             float xzoom,
392                             float yzoom,
393                             float color[4])
394 {
395   immDrawPixelsTexScaled_clipping(state,
396                                   x,
397                                   y,
398                                   img_w,
399                                   img_h,
400                                   format,
401                                   type,
402                                   zoomfilter,
403                                   rect,
404                                   scaleX,
405                                   scaleY,
406                                   0.0f,
407                                   0.0f,
408                                   0.0f,
409                                   0.0f,
410                                   xzoom,
411                                   yzoom,
412                                   color);
413 }
414
415 void immDrawPixelsTex(IMMDrawPixelsTexState *state,
416                       float x,
417                       float y,
418                       int img_w,
419                       int img_h,
420                       int format,
421                       int type,
422                       int zoomfilter,
423                       void *rect,
424                       float xzoom,
425                       float yzoom,
426                       float color[4])
427 {
428   immDrawPixelsTexScaled_clipping(state,
429                                   x,
430                                   y,
431                                   img_w,
432                                   img_h,
433                                   format,
434                                   type,
435                                   zoomfilter,
436                                   rect,
437                                   1.0f,
438                                   1.0f,
439                                   0.0f,
440                                   0.0f,
441                                   0.0f,
442                                   0.0f,
443                                   xzoom,
444                                   yzoom,
445                                   color);
446 }
447
448 void immDrawPixelsTex_clipping(IMMDrawPixelsTexState *state,
449                                float x,
450                                float y,
451                                int img_w,
452                                int img_h,
453                                int format,
454                                int type,
455                                int zoomfilter,
456                                void *rect,
457                                float clip_min_x,
458                                float clip_min_y,
459                                float clip_max_x,
460                                float clip_max_y,
461                                float xzoom,
462                                float yzoom,
463                                float color[4])
464 {
465   immDrawPixelsTexScaled_clipping(state,
466                                   x,
467                                   y,
468                                   img_w,
469                                   img_h,
470                                   format,
471                                   type,
472                                   zoomfilter,
473                                   rect,
474                                   1.0f,
475                                   1.0f,
476                                   clip_min_x,
477                                   clip_min_y,
478                                   clip_max_x,
479                                   clip_max_y,
480                                   xzoom,
481                                   yzoom,
482                                   color);
483 }
484
485 /* *************** glPolygonOffset hack ************* */
486
487 float bglPolygonOffsetCalc(const float winmat[16], float viewdist, float dist)
488 {
489   if (winmat[15] > 0.5f) {
490 #if 1
491     return 0.00001f * dist * viewdist;  // ortho tweaking
492 #else
493     static float depth_fac = 0.0f;
494     if (depth_fac == 0.0f) {
495       int depthbits;
496       glGetIntegerv(GL_DEPTH_BITS, &depthbits);
497       depth_fac = 1.0f / (float)((1 << depthbits) - 1);
498     }
499     offs = (-1.0 / winmat[10]) * dist * depth_fac;
500
501     UNUSED_VARS(viewdist);
502 #endif
503   }
504   else {
505     /* This adjustment effectively results in reducing the Z value by 0.25%.
506      *
507      * winmat[14] actually evaluates to `-2 * far * near / (far - near)`,
508      * is very close to -0.2 with default clip range,
509      * and is used as the coefficient multiplied by `w / z`,
510      * thus controlling the z dependent part of the depth value.
511      */
512     return winmat[14] * -0.0025f * dist;
513   }
514 }
515
516 /**
517  * \note \a viewdist is only for ortho at the moment.
518  */
519 void bglPolygonOffset(float viewdist, float dist)
520 {
521   static float winmat[16], offset = 0.0f;
522
523   if (dist != 0.0f) {
524     // glEnable(GL_POLYGON_OFFSET_FILL);
525     // glPolygonOffset(-1.0, -1.0);
526
527     /* hack below is to mimic polygon offset */
528     GPU_matrix_projection_get(winmat);
529
530     /* dist is from camera to center point */
531
532     float offs = bglPolygonOffsetCalc(winmat, viewdist, dist);
533
534     winmat[14] -= offs;
535     offset += offs;
536   }
537   else {
538     winmat[14] += offset;
539     offset = 0.0;
540   }
541
542   GPU_matrix_projection_set(winmat);
543 }
544
545 /* **** Color management helper functions for GLSL display/transform ***** */
546
547 /* Draw given image buffer on a screen using GLSL for display transform */
548 void ED_draw_imbuf_clipping(ImBuf *ibuf,
549                             float x,
550                             float y,
551                             int zoomfilter,
552                             ColorManagedViewSettings *view_settings,
553                             ColorManagedDisplaySettings *display_settings,
554                             float clip_min_x,
555                             float clip_min_y,
556                             float clip_max_x,
557                             float clip_max_y,
558                             float zoom_x,
559                             float zoom_y)
560 {
561   bool force_fallback = false;
562   bool need_fallback = true;
563
564   /* Early out */
565   if (ibuf->rect == NULL && ibuf->rect_float == NULL) {
566     return;
567   }
568
569   /* Single channel images could not be transformed using GLSL yet */
570   force_fallback |= ibuf->channels == 1;
571
572   /* If user decided not to use GLSL, fallback to glaDrawPixelsAuto */
573   force_fallback |= (ED_draw_imbuf_method(ibuf) != IMAGE_DRAW_METHOD_GLSL);
574
575   /* Try to draw buffer using GLSL display transform */
576   if (force_fallback == false) {
577     int ok;
578
579     IMMDrawPixelsTexState state = {0};
580     /* We want GLSL state to be fully handled by OCIO. */
581     state.do_shader_unbind = false;
582     immDrawPixelsTexSetupAttributes(&state);
583
584     if (ibuf->rect_float) {
585       if (ibuf->float_colorspace) {
586         ok = IMB_colormanagement_setup_glsl_draw_from_space(
587             view_settings, display_settings, ibuf->float_colorspace, ibuf->dither, true);
588       }
589       else {
590         ok = IMB_colormanagement_setup_glsl_draw(
591             view_settings, display_settings, ibuf->dither, true);
592       }
593     }
594     else {
595       ok = IMB_colormanagement_setup_glsl_draw_from_space(
596           view_settings, display_settings, ibuf->rect_colorspace, ibuf->dither, false);
597     }
598
599     if (ok) {
600       if (ibuf->rect_float) {
601         int format = 0;
602
603         if (ibuf->channels == 3) {
604           format = GL_RGB;
605         }
606         else if (ibuf->channels == 4) {
607           format = GL_RGBA;
608         }
609         else {
610           BLI_assert(!"Incompatible number of channels for GLSL display");
611         }
612
613         if (format != 0) {
614           immDrawPixelsTex_clipping(&state,
615                                     x,
616                                     y,
617                                     ibuf->x,
618                                     ibuf->y,
619                                     format,
620                                     GL_FLOAT,
621                                     zoomfilter,
622                                     ibuf->rect_float,
623                                     clip_min_x,
624                                     clip_min_y,
625                                     clip_max_x,
626                                     clip_max_y,
627                                     zoom_x,
628                                     zoom_y,
629                                     NULL);
630         }
631       }
632       else if (ibuf->rect) {
633         /* ibuf->rect is always RGBA */
634         immDrawPixelsTex_clipping(&state,
635                                   x,
636                                   y,
637                                   ibuf->x,
638                                   ibuf->y,
639                                   GL_RGBA,
640                                   GL_UNSIGNED_BYTE,
641                                   zoomfilter,
642                                   ibuf->rect,
643                                   clip_min_x,
644                                   clip_min_y,
645                                   clip_max_x,
646                                   clip_max_y,
647                                   zoom_x,
648                                   zoom_y,
649                                   NULL);
650       }
651
652       IMB_colormanagement_finish_glsl_draw();
653
654       need_fallback = false;
655     }
656   }
657
658   /* In case GLSL failed or not usable, fallback to glaDrawPixelsAuto */
659   if (need_fallback) {
660     unsigned char *display_buffer;
661     void *cache_handle;
662
663     display_buffer = IMB_display_buffer_acquire(
664         ibuf, view_settings, display_settings, &cache_handle);
665
666     if (display_buffer) {
667       IMMDrawPixelsTexState state = immDrawPixelsTexSetup(GPU_SHADER_2D_IMAGE_COLOR);
668       immDrawPixelsTex_clipping(&state,
669                                 x,
670                                 y,
671                                 ibuf->x,
672                                 ibuf->y,
673                                 GL_RGBA,
674                                 GL_UNSIGNED_BYTE,
675                                 zoomfilter,
676                                 display_buffer,
677                                 clip_min_x,
678                                 clip_min_y,
679                                 clip_max_x,
680                                 clip_max_y,
681                                 zoom_x,
682                                 zoom_y,
683                                 NULL);
684     }
685
686     IMB_display_buffer_release(cache_handle);
687   }
688 }
689
690 void ED_draw_imbuf(ImBuf *ibuf,
691                    float x,
692                    float y,
693                    int zoomfilter,
694                    ColorManagedViewSettings *view_settings,
695                    ColorManagedDisplaySettings *display_settings,
696                    float zoom_x,
697                    float zoom_y)
698 {
699   ED_draw_imbuf_clipping(ibuf,
700                          x,
701                          y,
702                          zoomfilter,
703                          view_settings,
704                          display_settings,
705                          0.0f,
706                          0.0f,
707                          0.0f,
708                          0.0f,
709                          zoom_x,
710                          zoom_y);
711 }
712
713 void ED_draw_imbuf_ctx_clipping(const bContext *C,
714                                 ImBuf *ibuf,
715                                 float x,
716                                 float y,
717                                 int zoomfilter,
718                                 float clip_min_x,
719                                 float clip_min_y,
720                                 float clip_max_x,
721                                 float clip_max_y,
722                                 float zoom_x,
723                                 float zoom_y)
724 {
725   ColorManagedViewSettings *view_settings;
726   ColorManagedDisplaySettings *display_settings;
727
728   IMB_colormanagement_display_settings_from_ctx(C, &view_settings, &display_settings);
729
730   ED_draw_imbuf_clipping(ibuf,
731                          x,
732                          y,
733                          zoomfilter,
734                          view_settings,
735                          display_settings,
736                          clip_min_x,
737                          clip_min_y,
738                          clip_max_x,
739                          clip_max_y,
740                          zoom_x,
741                          zoom_y);
742 }
743
744 void ED_draw_imbuf_ctx(
745     const bContext *C, ImBuf *ibuf, float x, float y, int zoomfilter, float zoom_x, float zoom_y)
746 {
747   ED_draw_imbuf_ctx_clipping(C, ibuf, x, y, zoomfilter, 0.0f, 0.0f, 0.0f, 0.0f, zoom_x, zoom_y);
748 }
749
750 int ED_draw_imbuf_method(ImBuf *ibuf)
751 {
752   if (U.image_draw_method == IMAGE_DRAW_METHOD_AUTO) {
753     /* Use faster GLSL when CPU to GPU transfer is unlikely to be a bottleneck,
754      * otherwise do color management on CPU side. */
755     const size_t threshold = 2048 * 2048 * 4 * sizeof(float);
756     const size_t data_size = (ibuf->rect_float) ? sizeof(float) : sizeof(uchar);
757     const size_t size = ibuf->x * ibuf->y * ibuf->channels * data_size;
758
759     return (size > threshold) ? IMAGE_DRAW_METHOD_2DTEXTURE : IMAGE_DRAW_METHOD_GLSL;
760   }
761   else {
762     return U.image_draw_method;
763   }
764 }
765
766 /* don't move to GPU_immediate_util.h because this uses user-prefs
767  * and isn't very low level */
768 void immDrawBorderCorners(unsigned int pos, const rcti *border, float zoomx, float zoomy)
769 {
770   float delta_x = 4.0f * UI_DPI_FAC / zoomx;
771   float delta_y = 4.0f * UI_DPI_FAC / zoomy;
772
773   delta_x = min_ff(delta_x, border->xmax - border->xmin);
774   delta_y = min_ff(delta_y, border->ymax - border->ymin);
775
776   /* left bottom corner */
777   immBegin(GPU_PRIM_LINE_STRIP, 3);
778   immVertex2f(pos, border->xmin, border->ymin + delta_y);
779   immVertex2f(pos, border->xmin, border->ymin);
780   immVertex2f(pos, border->xmin + delta_x, border->ymin);
781   immEnd();
782
783   /* left top corner */
784   immBegin(GPU_PRIM_LINE_STRIP, 3);
785   immVertex2f(pos, border->xmin, border->ymax - delta_y);
786   immVertex2f(pos, border->xmin, border->ymax);
787   immVertex2f(pos, border->xmin + delta_x, border->ymax);
788   immEnd();
789
790   /* right bottom corner */
791   immBegin(GPU_PRIM_LINE_STRIP, 3);
792   immVertex2f(pos, border->xmax - delta_x, border->ymin);
793   immVertex2f(pos, border->xmax, border->ymin);
794   immVertex2f(pos, border->xmax, border->ymin + delta_y);
795   immEnd();
796
797   /* right top corner */
798   immBegin(GPU_PRIM_LINE_STRIP, 3);
799   immVertex2f(pos, border->xmax - delta_x, border->ymax);
800   immVertex2f(pos, border->xmax, border->ymax);
801   immVertex2f(pos, border->xmax, border->ymax - delta_y);
802   immEnd();
803 }