Ghost Context Refactor
[blender-staging.git] / source / blender / windowmanager / intern / wm_draw.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version. 
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2007 Blender Foundation.
19  * All rights reserved.
20  *
21  * 
22  * Contributor(s): Blender Foundation
23  *
24  * ***** END GPL LICENSE BLOCK *****
25  */
26
27 /** \file blender/windowmanager/intern/wm_draw.c
28  *  \ingroup wm
29  *
30  * Handle OpenGL buffers for windowing, also paint cursor.
31  */
32
33 #include <stdlib.h>
34 #include <string.h>
35
36 #include "DNA_listBase.h"
37 #include "DNA_screen_types.h"
38 #include "DNA_windowmanager_types.h"
39 #include "DNA_userdef_types.h"
40 #include "DNA_view3d_types.h"
41
42 #include "MEM_guardedalloc.h"
43
44 #include "BLI_blenlib.h"
45 #include "BLI_utildefines.h"
46 #include "BLI_math_base.h"
47
48 #include "BIF_gl.h"
49
50 #include "BKE_context.h"
51
52 #include "GHOST_C-api.h"
53
54 #include "ED_view3d.h"
55 #include "ED_screen.h"
56
57 #include "GPU_draw.h"
58 #include "GPU_extensions.h"
59 #include "GPU_glew.h"
60
61 #include "RE_engine.h"
62
63 #include "WM_api.h"
64 #include "WM_types.h"
65 #include "wm.h"
66 #include "wm_draw.h"
67 #include "wm_window.h"
68 #include "wm_event_system.h"
69
70 /* swap */
71 #define WIN_NONE_OK     0
72 #define WIN_BACK_OK     1
73 #define WIN_FRONT_OK    2
74 #define WIN_BOTH_OK     3
75
76 /* ******************* drawing, overlays *************** */
77
78
79 static void wm_paintcursor_draw(bContext *C, ARegion *ar)
80 {
81         wmWindowManager *wm = CTX_wm_manager(C);
82         
83         if (wm->paintcursors.first) {
84                 wmWindow *win = CTX_wm_window(C);
85                 bScreen *screen = win->screen;
86                 wmPaintCursor *pc;
87
88                 if (ar->swinid && screen->subwinactive == ar->swinid) {
89                         for (pc = wm->paintcursors.first; pc; pc = pc->next) {
90                                 if (pc->poll == NULL || pc->poll(C)) {
91                                         ARegion *ar_other = CTX_wm_region(C);
92                                         if (ELEM(win->grabcursor, GHOST_kGrabWrap, GHOST_kGrabHide)) {
93                                                 int x = 0, y = 0;
94                                                 wm_get_cursor_position(win, &x, &y);
95                                                 pc->draw(C,
96                                                          x - ar_other->winrct.xmin,
97                                                          y - ar_other->winrct.ymin,
98                                                          pc->customdata);
99                                         }
100                                         else {
101                                                 pc->draw(C,
102                                                          win->eventstate->x - ar_other->winrct.xmin,
103                                                          win->eventstate->y - ar_other->winrct.ymin,
104                                                          pc->customdata);
105                                         }
106                                 }
107                         }
108                 }
109         }
110 }
111
112 /* ********************* drawing, swap ****************** */
113
114 static void wm_area_mark_invalid_backbuf(ScrArea *sa)
115 {
116         if (sa->spacetype == SPACE_VIEW3D)
117                 ((View3D *)sa->spacedata.first)->flag |= V3D_INVALID_BACKBUF;
118 }
119
120 static bool wm_area_test_invalid_backbuf(ScrArea *sa)
121 {
122         if (sa->spacetype == SPACE_VIEW3D)
123                 return (((View3D *)sa->spacedata.first)->flag & V3D_INVALID_BACKBUF) != 0;
124         else
125                 return 1;
126 }
127
128 static void wm_region_test_render_do_draw(bScreen *screen, ScrArea *sa, ARegion *ar)
129 {
130         /* tag region for redraw from render engine preview running inside of it */
131         if (sa->spacetype == SPACE_VIEW3D) {
132                 RegionView3D *rv3d = ar->regiondata;
133                 RenderEngine *engine = (rv3d) ? rv3d->render_engine : NULL;
134
135                 if (engine && (engine->flag & RE_ENGINE_DO_DRAW)) {
136                         Scene *scene = screen->scene;
137                         View3D *v3d = sa->spacedata.first;
138                         rcti border_rect;
139
140                         /* do partial redraw when possible */
141                         if (ED_view3d_calc_render_border(scene, v3d, ar, &border_rect))
142                                 ED_region_tag_redraw_partial(ar, &border_rect);
143                         else
144                                 ED_region_tag_redraw(ar);
145
146                         engine->flag &= ~RE_ENGINE_DO_DRAW;
147                 }
148         }
149 }
150
151 /********************** draw all **************************/
152 /* - reference method, draw all each time                 */
153
154 static void wm_method_draw_full(bContext *C, wmWindow *win)
155 {
156         bScreen *screen = win->screen;
157         ScrArea *sa;
158         ARegion *ar;
159
160         /* draw area regions */
161         for (sa = screen->areabase.first; sa; sa = sa->next) {
162                 CTX_wm_area_set(C, sa);
163
164                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
165                         if (ar->swinid) {
166                                 CTX_wm_region_set(C, ar);
167                                 ED_region_do_draw(C, ar);
168                                 wm_paintcursor_draw(C, ar);
169                                 CTX_wm_region_set(C, NULL);
170                         }
171                 }
172                 
173                 wm_area_mark_invalid_backbuf(sa);
174                 CTX_wm_area_set(C, NULL);
175         }
176
177         ED_screen_draw(win);
178
179         /* draw overlapping regions */
180         for (ar = screen->regionbase.first; ar; ar = ar->next) {
181                 if (ar->swinid) {
182                         CTX_wm_menu_set(C, ar);
183                         ED_region_do_draw(C, ar);
184                         CTX_wm_menu_set(C, NULL);
185                 }
186         }
187
188         if (screen->do_draw_gesture)
189                 wm_gesture_draw(win);
190 }
191
192 /****************** draw overlap all **********************/
193 /* - redraw marked areas, and anything that overlaps it   */
194 /* - it also handles swap exchange optionally, assuming   */
195 /*   that on swap no clearing happens and we get back the */
196 /*   same buffer as we swapped to the front               */
197
198 /* mark area-regions to redraw if overlapped with rect */
199 static void wm_flush_regions_down(bScreen *screen, rcti *dirty)
200 {
201         ScrArea *sa;
202         ARegion *ar;
203
204         for (sa = screen->areabase.first; sa; sa = sa->next) {
205                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
206                         if (BLI_rcti_isect(dirty, &ar->winrct, NULL)) {
207                                 ar->do_draw = RGN_DRAW;
208                                 memset(&ar->drawrct, 0, sizeof(ar->drawrct));
209                                 ar->swap = WIN_NONE_OK;
210                         }
211                 }
212         }
213 }
214
215 /* mark menu-regions to redraw if overlapped with rect */
216 static void wm_flush_regions_up(bScreen *screen, rcti *dirty)
217 {
218         ARegion *ar;
219         
220         for (ar = screen->regionbase.first; ar; ar = ar->next) {
221                 if (BLI_rcti_isect(dirty, &ar->winrct, NULL)) {
222                         ar->do_draw = RGN_DRAW;
223                         memset(&ar->drawrct, 0, sizeof(ar->drawrct));
224                         ar->swap = WIN_NONE_OK;
225                 }
226         }
227 }
228
229 static void wm_method_draw_overlap_all(bContext *C, wmWindow *win, int exchange)
230 {
231         wmWindowManager *wm = CTX_wm_manager(C);
232         bScreen *screen = win->screen;
233         ScrArea *sa;
234         ARegion *ar;
235         static rcti rect = {0, 0, 0, 0};
236
237         /* after backbuffer selection draw, we need to redraw */
238         for (sa = screen->areabase.first; sa; sa = sa->next)
239                 for (ar = sa->regionbase.first; ar; ar = ar->next)
240                         if (ar->swinid && !wm_area_test_invalid_backbuf(sa))
241                                 ED_region_tag_redraw(ar);
242
243         /* flush overlapping regions */
244         if (screen->regionbase.first) {
245                 /* flush redraws of area regions up to overlapping regions */
246                 for (sa = screen->areabase.first; sa; sa = sa->next)
247                         for (ar = sa->regionbase.first; ar; ar = ar->next)
248                                 if (ar->swinid && ar->do_draw)
249                                         wm_flush_regions_up(screen, &ar->winrct);
250                 
251                 /* flush between overlapping regions */
252                 for (ar = screen->regionbase.last; ar; ar = ar->prev)
253                         if (ar->swinid && ar->do_draw)
254                                 wm_flush_regions_up(screen, &ar->winrct);
255                 
256                 /* flush redraws of overlapping regions down to area regions */
257                 for (ar = screen->regionbase.last; ar; ar = ar->prev)
258                         if (ar->swinid && ar->do_draw)
259                                 wm_flush_regions_down(screen, &ar->winrct);
260         }
261
262         /* flush drag item */
263         if (rect.xmin != rect.xmax) {
264                 wm_flush_regions_down(screen, &rect);
265                 rect.xmin = rect.xmax = 0;
266         }
267         if (wm->drags.first) {
268                 /* doesnt draw, fills rect with boundbox */
269                 wm_drags_draw(C, win, &rect);
270         }
271         
272         /* draw marked area regions */
273         for (sa = screen->areabase.first; sa; sa = sa->next) {
274                 CTX_wm_area_set(C, sa);
275
276                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
277                         if (ar->swinid) {
278                                 if (ar->do_draw) {
279                                         CTX_wm_region_set(C, ar);
280                                         ED_region_do_draw(C, ar);
281                                         wm_paintcursor_draw(C, ar);
282                                         CTX_wm_region_set(C, NULL);
283
284                                         if (exchange)
285                                                 ar->swap = WIN_FRONT_OK;
286                                 }
287                                 else if (exchange) {
288                                         if (ar->swap == WIN_FRONT_OK) {
289                                                 CTX_wm_region_set(C, ar);
290                                                 ED_region_do_draw(C, ar);
291                                                 wm_paintcursor_draw(C, ar);
292                                                 CTX_wm_region_set(C, NULL);
293
294                                                 ar->swap = WIN_BOTH_OK;
295                                         }
296                                         else if (ar->swap == WIN_BACK_OK)
297                                                 ar->swap = WIN_FRONT_OK;
298                                         else if (ar->swap == WIN_BOTH_OK)
299                                                 ar->swap = WIN_BOTH_OK;
300                                 }
301                         }
302                 }
303                 
304                 wm_area_mark_invalid_backbuf(sa);
305                 CTX_wm_area_set(C, NULL);
306         }
307
308         /* after area regions so we can do area 'overlay' drawing */
309         if (screen->do_draw) {
310                 ED_screen_draw(win);
311
312                 if (exchange)
313                         screen->swap = WIN_FRONT_OK;
314         }
315         else if (exchange) {
316                 if (screen->swap == WIN_FRONT_OK) {
317                         ED_screen_draw(win);
318                         screen->swap = WIN_BOTH_OK;
319                 }
320                 else if (screen->swap == WIN_BACK_OK)
321                         screen->swap = WIN_FRONT_OK;
322                 else if (screen->swap == WIN_BOTH_OK)
323                         screen->swap = WIN_BOTH_OK;
324         }
325
326         /* draw marked overlapping regions */
327         for (ar = screen->regionbase.first; ar; ar = ar->next) {
328                 if (ar->swinid && ar->do_draw) {
329                         CTX_wm_menu_set(C, ar);
330                         ED_region_do_draw(C, ar);
331                         CTX_wm_menu_set(C, NULL);
332                 }
333         }
334
335         if (screen->do_draw_gesture)
336                 wm_gesture_draw(win);
337         
338         /* needs pixel coords in screen */
339         if (wm->drags.first) {
340                 wm_drags_draw(C, win, NULL);
341         }
342 }
343
344 #if 0
345 /******************** draw damage ************************/
346 /* - not implemented                                      */
347
348 static void wm_method_draw_damage(bContext *C, wmWindow *win)
349 {
350         wm_method_draw_all(C, win);
351 }
352 #endif
353
354 /****************** draw triple buffer ********************/
355 /* - area regions are written into a texture, without any */
356 /*   of the overlapping menus, brushes, gestures. these   */
357 /*   are redrawn each time.                               */
358 /*                                                        */
359 /* - if non-power of two textures are supported, that is  */
360 /*   used. if not, multiple smaller ones are used, with   */
361 /*   worst case wasted space being 23.4% for 3x3 textures */
362
363 #define MAX_N_TEX 3
364
365 typedef struct wmDrawTriple {
366         GLuint bind[MAX_N_TEX * MAX_N_TEX];
367         int x[MAX_N_TEX], y[MAX_N_TEX];
368         int nx, ny;
369         GLenum target;
370 } wmDrawTriple;
371
372 static void split_width(int x, int n, int *splitx, int *nx)
373 {
374         int a, newnx, waste;
375
376         /* if already power of two just use it */
377         if (is_power_of_2_i(x)) {
378                 splitx[0] = x;
379                 (*nx)++;
380                 return;
381         }
382
383         if (n == 1) {
384                 /* last part, we have to go larger */
385                 splitx[0] = power_of_2_max_i(x);
386                 (*nx)++;
387         }
388         else {
389                 /* two or more parts to go, use smaller part */
390                 splitx[0] = power_of_2_min_i(x);
391                 newnx = ++(*nx);
392                 split_width(x - splitx[0], n - 1, splitx + 1, &newnx);
393
394                 for (waste = 0, a = 0; a < n; a++)
395                         waste += splitx[a];
396
397                 /* if we waste more space or use the same amount,
398                  * revert deeper splits and just use larger */
399                 if (waste >= power_of_2_max_i(x)) {
400                         splitx[0] = power_of_2_max_i(x);
401                         memset(splitx + 1, 0, sizeof(int) * (n - 1));
402                 }
403                 else
404                         *nx = newnx;
405         }
406 }
407
408 static void wm_draw_triple_free(wmWindow *win)
409 {
410         if (win->drawdata) {
411                 wmDrawTriple *triple = win->drawdata;
412
413                 glDeleteTextures(triple->nx * triple->ny, triple->bind);
414
415                 MEM_freeN(triple);
416
417                 win->drawdata = NULL;
418         }
419 }
420
421 static void wm_draw_triple_fail(bContext *C, wmWindow *win)
422 {
423         wm_draw_window_clear(win);
424
425         win->drawfail = 1;
426         wm_method_draw_overlap_all(C, win, 0);
427 }
428
429 static int wm_triple_gen_textures(wmWindow *win, wmDrawTriple *triple)
430 {
431         const int winsize_x = WM_window_pixels_x(win);
432         const int winsize_y = WM_window_pixels_y(win);
433
434         GLint maxsize;
435         int x, y;
436
437         /* compute texture sizes */
438         if (GLEW_ARB_texture_rectangle || GLEW_NV_texture_rectangle || GLEW_EXT_texture_rectangle) {
439                 triple->target = GL_TEXTURE_RECTANGLE_ARB;
440                 triple->nx = 1;
441                 triple->ny = 1;
442                 triple->x[0] = winsize_x;
443                 triple->y[0] = winsize_y;
444         }
445         else if (GPU_non_power_of_two_support()) {
446                 triple->target = GL_TEXTURE_2D;
447                 triple->nx = 1;
448                 triple->ny = 1;
449                 triple->x[0] = winsize_x;
450                 triple->y[0] = winsize_y;
451         }
452         else {
453                 triple->target = GL_TEXTURE_2D;
454                 triple->nx = 0;
455                 triple->ny = 0;
456                 split_width(winsize_x, MAX_N_TEX, triple->x, &triple->nx);
457                 split_width(winsize_y, MAX_N_TEX, triple->y, &triple->ny);
458         }
459
460         /* generate texture names */
461         glGenTextures(triple->nx * triple->ny, triple->bind);
462
463         if (!triple->bind[0]) {
464                 /* not the typical failure case but we handle it anyway */
465                 printf("WM: failed to allocate texture for triple buffer drawing (glGenTextures).\n");
466                 return 0;
467         }
468
469         for (y = 0; y < triple->ny; y++) {
470                 for (x = 0; x < triple->nx; x++) {
471                         /* proxy texture is only guaranteed to test for the cases that
472                          * there is only one texture in use, which may not be the case */
473                         maxsize = GPU_max_texture_size();
474
475                         if (triple->x[x] > maxsize || triple->y[y] > maxsize) {
476                                 glBindTexture(triple->target, 0);
477                                 printf("WM: failed to allocate texture for triple buffer drawing "
478                                        "(texture too large for graphics card).\n");
479                                 return 0;
480                         }
481
482                         /* setup actual texture */
483                         glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
484                         glTexImage2D(triple->target, 0, GL_RGB8, triple->x[x], triple->y[y], 0, GL_RGB, GL_UNSIGNED_BYTE, NULL);
485                         glTexParameteri(triple->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
486                         glTexParameteri(triple->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
487                         /* The current color is ignored if the GL_REPLACE texture environment is used. */
488                         // glTexEnvi(triple->target, GL_TEXTURE_ENV_MODE, GL_REPLACE);
489                         glBindTexture(triple->target, 0);
490
491                         /* not sure if this works everywhere .. */
492                         if (glGetError() == GL_OUT_OF_MEMORY) {
493                                 printf("WM: failed to allocate texture for triple buffer drawing (out of memory).\n");
494                                 return 0;
495                         }
496                 }
497         }
498
499         return 1;
500 }
501
502 static void wm_triple_draw_textures(wmWindow *win, wmDrawTriple *triple, float alpha)
503 {
504         const int winsize_x = WM_window_pixels_x(win);
505         const int winsize_y = WM_window_pixels_y(win);
506
507         float halfx, halfy, ratiox, ratioy;
508         int x, y, sizex, sizey, offx, offy;
509
510         glEnable(triple->target);
511
512         for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
513                 for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
514                         sizex = (x == triple->nx - 1) ? winsize_x - offx : triple->x[x];
515                         sizey = (y == triple->ny - 1) ? winsize_y - offy : triple->y[y];
516
517                         /* wmOrtho for the screen has this same offset */
518                         ratiox = sizex;
519                         ratioy = sizey;
520                         halfx = GLA_PIXEL_OFS;
521                         halfy = GLA_PIXEL_OFS;
522
523                         /* texture rectangle has unnormalized coordinates */
524                         if (triple->target == GL_TEXTURE_2D) {
525                                 ratiox /= triple->x[x];
526                                 ratioy /= triple->y[y];
527                                 halfx /= triple->x[x];
528                                 halfy /= triple->y[y];
529                         }
530
531                         glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
532
533                         glColor4f(1.0f, 1.0f, 1.0f, alpha);
534                         glBegin(GL_QUADS);
535                         glTexCoord2f(halfx, halfy);
536                         glVertex2f(offx, offy);
537
538                         glTexCoord2f(ratiox + halfx, halfy);
539                         glVertex2f(offx + sizex, offy);
540
541                         glTexCoord2f(ratiox + halfx, ratioy + halfy);
542                         glVertex2f(offx + sizex, offy + sizey);
543
544                         glTexCoord2f(halfx, ratioy + halfy);
545                         glVertex2f(offx, offy + sizey);
546                         glEnd();
547                 }
548         }
549
550         glBindTexture(triple->target, 0);
551         glDisable(triple->target);
552 }
553
554 static void wm_triple_copy_textures(wmWindow *win, wmDrawTriple *triple)
555 {
556         const int winsize_x = WM_window_pixels_x(win);
557         const int winsize_y = WM_window_pixels_y(win);
558
559         int x, y, sizex, sizey, offx, offy;
560
561         for (y = 0, offy = 0; y < triple->ny; offy += triple->y[y], y++) {
562                 for (x = 0, offx = 0; x < triple->nx; offx += triple->x[x], x++) {
563                         sizex = (x == triple->nx - 1) ? winsize_x - offx : triple->x[x];
564                         sizey = (y == triple->ny - 1) ? winsize_y - offy : triple->y[y];
565
566                         glBindTexture(triple->target, triple->bind[x + y * triple->nx]);
567                         glCopyTexSubImage2D(triple->target, 0, 0, 0, offx, offy, sizex, sizey);
568                 }
569         }
570
571         glBindTexture(triple->target, 0);
572 }
573
574 static void wm_draw_region_blend(wmWindow *win, ARegion *ar)
575 {
576         float fac = ED_region_blend_factor(ar);
577         
578         /* region blend always is 1, except when blend timer is running */
579         if (fac < 1.0f) {
580                 wmSubWindowScissorSet(win, win->screen->mainwin, &ar->winrct, true);
581
582                 glEnable(GL_BLEND);
583                 wm_triple_draw_textures(win, win->drawdata, 1.0f - fac);
584                 glDisable(GL_BLEND);
585         }
586 }
587
588 static void wm_method_draw_triple(bContext *C, wmWindow *win)
589 {
590         wmWindowManager *wm = CTX_wm_manager(C);
591         wmDrawTriple *triple;
592         bScreen *screen = win->screen;
593         ScrArea *sa;
594         ARegion *ar;
595         int copytex = 0;
596
597         if (win->drawdata) {
598                 glClearColor(0, 0, 0, 0);
599                 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
600
601                 wmSubWindowSet(win, screen->mainwin);
602
603                 wm_triple_draw_textures(win, win->drawdata, 1.0f);
604         }
605         else {
606                 win->drawdata = MEM_callocN(sizeof(wmDrawTriple), "wmDrawTriple");
607
608                 if (!wm_triple_gen_textures(win, win->drawdata)) {
609                         wm_draw_triple_fail(C, win);
610                         return;
611                 }
612         }
613
614         triple = win->drawdata;
615
616         /* draw marked area regions */
617         for (sa = screen->areabase.first; sa; sa = sa->next) {
618                 CTX_wm_area_set(C, sa);
619
620                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
621                         if (ar->swinid && ar->do_draw) {
622                                 
623                                 if (ar->overlap == 0) {
624                                         CTX_wm_region_set(C, ar);
625                                         ED_region_do_draw(C, ar);
626                                         CTX_wm_region_set(C, NULL);
627                                         copytex = 1;
628                                 }
629                         }
630                 }
631                 
632                 wm_area_mark_invalid_backbuf(sa);
633                 CTX_wm_area_set(C, NULL);
634         }
635
636         if (copytex) {
637                 wmSubWindowSet(win, screen->mainwin);
638
639                 wm_triple_copy_textures(win, triple);
640         }
641
642         if (wm->paintcursors.first) {
643                 for (sa = screen->areabase.first; sa; sa = sa->next) {
644                         for (ar = sa->regionbase.first; ar; ar = ar->next) {
645                                 if (ar->swinid && ar->swinid == screen->subwinactive) {
646                                         CTX_wm_area_set(C, sa);
647                                         CTX_wm_region_set(C, ar);
648
649                                         /* make region ready for draw, scissor, pixelspace */
650                                         ED_region_set(C, ar);
651                                         wm_paintcursor_draw(C, ar);
652
653                                         CTX_wm_region_set(C, NULL);
654                                         CTX_wm_area_set(C, NULL);
655                                 }
656                         }
657                 }
658
659                 wmSubWindowSet(win, screen->mainwin);
660         }
661
662         /* draw overlapping area regions (always like popups) */
663         for (sa = screen->areabase.first; sa; sa = sa->next) {
664                 CTX_wm_area_set(C, sa);
665                 
666                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
667                         if (ar->swinid && ar->overlap) {
668                                 CTX_wm_region_set(C, ar);
669                                 ED_region_do_draw(C, ar);
670                                 CTX_wm_region_set(C, NULL);
671                                 
672                                 wm_draw_region_blend(win, ar);
673                         }
674                 }
675
676                 CTX_wm_area_set(C, NULL);
677         }
678
679         /* after area regions so we can do area 'overlay' drawing */
680         ED_screen_draw(win);
681
682         /* draw floating regions (menus) */
683         for (ar = screen->regionbase.first; ar; ar = ar->next) {
684                 if (ar->swinid) {
685                         CTX_wm_menu_set(C, ar);
686                         ED_region_do_draw(C, ar);
687                         CTX_wm_menu_set(C, NULL);
688                 }
689         }
690
691         /* always draw, not only when screen tagged */
692         if (win->gesture.first)
693                 wm_gesture_draw(win);
694         
695         /* needs pixel coords in screen */
696         if (wm->drags.first) {
697                 wm_drags_draw(C, win, NULL);
698         }
699 }
700
701
702 /****************** main update call **********************/
703
704 /* quick test to prevent changing window drawable */
705 static bool wm_draw_update_test_window(wmWindow *win)
706 {
707         ScrArea *sa;
708         ARegion *ar;
709         bool do_draw = false;
710
711         for (ar = win->screen->regionbase.first; ar; ar = ar->next) {
712                 if (ar->do_draw_overlay) {
713                         wm_tag_redraw_overlay(win, ar);
714                         ar->do_draw_overlay = false;
715                 }
716                 if (ar->swinid && ar->do_draw)
717                         do_draw = true;
718         }
719
720         for (sa = win->screen->areabase.first; sa; sa = sa->next) {
721                 for (ar = sa->regionbase.first; ar; ar = ar->next) {
722                         wm_region_test_render_do_draw(win->screen, sa, ar);
723
724                         if (ar->swinid && ar->do_draw)
725                                 do_draw = true;
726                 }
727         }
728
729         if (do_draw)
730                 return 1;
731         
732         if (win->screen->do_refresh)
733                 return 1;
734         if (win->screen->do_draw)
735                 return 1;
736         if (win->screen->do_draw_gesture)
737                 return 1;
738         if (win->screen->do_draw_paintcursor)
739                 return 1;
740         if (win->screen->do_draw_drag)
741                 return 1;
742         
743         return 0;
744 }
745
746 static int wm_automatic_draw_method(wmWindow *win)
747 {
748         /* Ideally all cards would work well with triple buffer, since if it works
749          * well gives the least redraws and is considerably faster at partial redraw
750          * for sculpting or drawing overlapping menus. For typically lower end cards
751          * copy to texture is slow though and so we use overlap instead there. */
752
753         if (win->drawmethod == USER_DRAW_AUTOMATIC) {
754                 /* ATI opensource driver is known to be very slow at this */
755                 if (GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE))
756                         return USER_DRAW_OVERLAP;
757                 /* also Intel drivers are slow */
758 #if 0   /* 2.64 BCon3 period, let's try if intel now works... */
759                 else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_UNIX, GPU_DRIVER_ANY))
760                         return USER_DRAW_OVERLAP;
761                 else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_WIN, GPU_DRIVER_ANY))
762                         return USER_DRAW_OVERLAP_FLIP;
763                 else if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY))
764                         return USER_DRAW_OVERLAP_FLIP;
765 #endif
766                 /* Windows software driver darkens color on each redraw */
767                 else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_WIN, GPU_DRIVER_SOFTWARE))
768                         return USER_DRAW_OVERLAP_FLIP;
769                 else if (GPU_type_matches(GPU_DEVICE_SOFTWARE, GPU_OS_UNIX, GPU_DRIVER_SOFTWARE))
770                         return USER_DRAW_OVERLAP;
771                 /* drawing lower color depth again degrades colors each time */
772                 else if (GPU_color_depth() < 24)
773                         return USER_DRAW_OVERLAP;
774                 else
775                         return USER_DRAW_TRIPLE;
776         }
777         else
778                 return win->drawmethod;
779 }
780
781 bool WM_is_draw_triple(wmWindow *win)
782 {
783         /* function can get called before this variable is set in drawing code below */
784         if (win->drawmethod != U.wmdrawmethod)
785                 win->drawmethod = U.wmdrawmethod;
786         return (USER_DRAW_TRIPLE == wm_automatic_draw_method(win));
787 }
788
789 void wm_tag_redraw_overlay(wmWindow *win, ARegion *ar)
790 {
791         /* for draw triple gestures, paint cursors don't need region redraw */
792         if (ar && win) {
793                 if (wm_automatic_draw_method(win) != USER_DRAW_TRIPLE)
794                         ED_region_tag_redraw(ar);
795                 win->screen->do_draw_paintcursor = true;
796         }
797 }
798
799 void WM_paint_cursor_tag_redraw(wmWindow *win, ARegion *ar)
800 {
801         win->screen->do_draw_paintcursor = true;
802         wm_tag_redraw_overlay(win, ar);
803 }
804
805 void wm_draw_update(bContext *C)
806 {
807         wmWindowManager *wm = CTX_wm_manager(C);
808         wmWindow *win;
809         int drawmethod;
810
811         GPU_free_unused_buffers();
812         
813         for (win = wm->windows.first; win; win = win->next) {
814 #ifdef WIN32
815                 if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
816                         GHOST_TWindowState state = GHOST_GetWindowState(win->ghostwin);
817
818                         if (state == GHOST_kWindowStateMinimized) {
819                                 /* do not update minimized windows, it gives issues on intel drivers (see [#33223])
820                                  * anyway, it seems logical to skip update for invisible windows
821                                  */
822                                 continue;
823                         }
824                 }
825 #endif
826                 if (win->drawmethod != U.wmdrawmethod) {
827                         wm_draw_window_clear(win);
828                         win->drawmethod = U.wmdrawmethod;
829                 }
830
831                 if (wm_draw_update_test_window(win)) {
832                         CTX_wm_window_set(C, win);
833                         
834                         /* sets context window+screen */
835                         wm_window_make_drawable(wm, win);
836
837                         /* notifiers for screen redraw */
838                         if (win->screen->do_refresh)
839                                 ED_screen_refresh(wm, win);
840
841                         drawmethod = wm_automatic_draw_method(win);
842
843                         if (win->drawfail)
844                                 wm_method_draw_overlap_all(C, win, 0);
845                         else if (drawmethod == USER_DRAW_FULL)
846                                 wm_method_draw_full(C, win);
847                         else if (drawmethod == USER_DRAW_OVERLAP)
848                                 wm_method_draw_overlap_all(C, win, 0);
849                         else if (drawmethod == USER_DRAW_OVERLAP_FLIP)
850                                 wm_method_draw_overlap_all(C, win, 1);
851                         else // if (drawmethod == USER_DRAW_TRIPLE)
852                                 wm_method_draw_triple(C, win);
853
854                         win->screen->do_draw_gesture = false;
855                         win->screen->do_draw_paintcursor = false;
856                         win->screen->do_draw_drag = false;
857                 
858                         wm_window_swap_buffers(win);
859
860                         CTX_wm_window_set(C, NULL);
861                 }
862         }
863 }
864
865 void wm_draw_window_clear(wmWindow *win)
866 {
867         bScreen *screen = win->screen;
868         ScrArea *sa;
869         ARegion *ar;
870         int drawmethod = wm_automatic_draw_method(win);
871
872         if (drawmethod == USER_DRAW_TRIPLE)
873                 wm_draw_triple_free(win);
874
875         /* clear screen swap flags */
876         if (screen) {
877                 for (sa = screen->areabase.first; sa; sa = sa->next)
878                         for (ar = sa->regionbase.first; ar; ar = ar->next)
879                                 ar->swap = WIN_NONE_OK;
880                 
881                 screen->swap = WIN_NONE_OK;
882         }
883 }
884
885 void wm_draw_region_clear(wmWindow *win, ARegion *ar)
886 {
887         int drawmethod = wm_automatic_draw_method(win);
888
889         if (ELEM(drawmethod, USER_DRAW_OVERLAP, USER_DRAW_OVERLAP_FLIP))
890                 wm_flush_regions_down(win->screen, &ar->winrct);
891
892         win->screen->do_draw = true;
893 }
894
895 void WM_redraw_windows(bContext *C)
896 {
897         wmWindow *win_prev = CTX_wm_window(C);
898         ScrArea *area_prev = CTX_wm_area(C);
899         ARegion *ar_prev = CTX_wm_region(C);
900
901         wm_draw_update(C);
902
903         CTX_wm_window_set(C, win_prev);
904         CTX_wm_area_set(C, area_prev);
905         CTX_wm_region_set(C, ar_prev);
906 }
907