d31ba79d9ed07bdf886e9faabdc3644ffe58fcc2
[blender.git] / source / blender / gpu / intern / gpu_framebuffer.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) 2005 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): Brecht Van Lommel.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 #include "MEM_guardedalloc.h"
29
30 #include "BLI_blenlib.h"
31 #include "BLI_threads.h"
32 #include "BLI_utildefines.h"
33 #include "BLI_math_base.h"
34
35 #include "BKE_global.h"
36
37 #include "GPU_batch.h"
38 #include "GPU_draw.h"
39 #include "GPU_extensions.h"
40 #include "GPU_framebuffer.h"
41 #include "GPU_matrix.h"
42 #include "GPU_shader.h"
43 #include "GPU_texture.h"
44
45 static ThreadLocal(GLuint) g_currentfb;
46
47 typedef enum {
48         GPU_FB_DEPTH_ATTACHMENT = 0,
49         GPU_FB_DEPTH_STENCIL_ATTACHMENT,
50         GPU_FB_COLOR_ATTACHMENT0,
51         GPU_FB_COLOR_ATTACHMENT1,
52         GPU_FB_COLOR_ATTACHMENT2,
53         GPU_FB_COLOR_ATTACHMENT3,
54         GPU_FB_COLOR_ATTACHMENT4,
55         /* Number of maximum output slots.
56          * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */
57         /* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to
58          * the maximum number of COLOR attachments specified by glDrawBuffers. */
59         GPU_FB_MAX_ATTACHEMENT
60 } GPUAttachmentType;
61
62 #define GPU_FB_MAX_COLOR_ATTACHMENT (GPU_FB_MAX_ATTACHEMENT - GPU_FB_COLOR_ATTACHMENT0)
63
64 #define GPU_FB_DIRTY_DRAWBUFFER (1 << 15)
65
66 #define GPU_FB_ATTACHEMENT_IS_DIRTY(flag, type) ((flag & (1 << type)) != 0)
67 #define GPU_FB_ATTACHEMENT_SET_DIRTY(flag, type) (flag |= (1 << type))
68
69 struct GPUFrameBuffer {
70         GLuint object;
71         GPUAttachment attachments[GPU_FB_MAX_ATTACHEMENT];
72         uint16_t dirty_flag;
73         int width, height;
74         bool multisample;
75         /* TODO Check that we always use the right context when binding
76          * (FBOs are not shared accross ogl contexts). */
77         // void *ctx;
78 };
79
80 static GLenum convert_attachment_type_to_gl(GPUAttachmentType type)
81 {
82         static const GLenum table[] = {
83                 [GPU_FB_DEPTH_ATTACHMENT] = GL_DEPTH_ATTACHMENT,
84                 [GPU_FB_DEPTH_STENCIL_ATTACHMENT] = GL_DEPTH_STENCIL_ATTACHMENT,
85                 [GPU_FB_COLOR_ATTACHMENT0] = GL_COLOR_ATTACHMENT0,
86                 [GPU_FB_COLOR_ATTACHMENT1] = GL_COLOR_ATTACHMENT1,
87                 [GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2,
88                 [GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3,
89                 [GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4
90         };
91         return table[type];
92 }
93
94 static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot)
95 {
96         switch (GPU_texture_format(tex)) {
97                 case GPU_DEPTH_COMPONENT32F:
98                 case GPU_DEPTH_COMPONENT24:
99                 case GPU_DEPTH_COMPONENT16:
100                         return GPU_FB_DEPTH_ATTACHMENT;
101                 case GPU_DEPTH24_STENCIL8:
102                         return GPU_FB_DEPTH_STENCIL_ATTACHMENT;
103                 default:
104                         return GPU_FB_COLOR_ATTACHMENT0 + slot;
105         }
106 }
107
108 static GLenum convert_buffer_bits_to_gl(GPUFrameBufferBits bits)
109 {
110         GLbitfield mask = 0;
111         mask |= (bits & GPU_DEPTH_BIT) ? GL_DEPTH_BUFFER_BIT : 0;
112         mask |= (bits & GPU_STENCIL_BIT) ? GL_STENCIL_BUFFER_BIT : 0;
113         mask |= (bits & GPU_COLOR_BIT) ? GL_COLOR_BUFFER_BIT : 0;
114         return mask;
115 }
116
117 static GPUTexture *framebuffer_get_depth_tex(GPUFrameBuffer *fb)
118 {
119         if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex)
120                 return fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex;
121         else
122                 return fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex;;
123 }
124
125 static GPUTexture *framebuffer_get_color_tex(GPUFrameBuffer *fb, int slot)
126 {
127         return fb->attachments[GPU_FB_COLOR_ATTACHMENT0 + slot].tex;
128 }
129
130 static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
131 {
132         const char *format = "GPUFrameBuffer: framebuffer status %s\n";
133         const char *err = "unknown";
134
135 #define format_status(X) \
136         case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \
137                 break;
138
139         switch (status) {
140                 /* success */
141                 format_status(COMPLETE)
142                 /* errors shared by OpenGL desktop & ES */
143                 format_status(INCOMPLETE_ATTACHMENT)
144                 format_status(INCOMPLETE_MISSING_ATTACHMENT)
145                 format_status(UNSUPPORTED)
146 #if 0 /* for OpenGL ES only */
147                 format_status(INCOMPLETE_DIMENSIONS)
148 #else /* for desktop GL only */
149                 format_status(INCOMPLETE_DRAW_BUFFER)
150                 format_status(INCOMPLETE_READ_BUFFER)
151                 format_status(INCOMPLETE_MULTISAMPLE)
152                 format_status(UNDEFINED)
153 #endif
154         }
155
156 #undef format_status
157
158         if (err_out) {
159                 BLI_snprintf(err_out, 256, format, err);
160         }
161         else {
162                 fprintf(stderr, format, err);
163         }
164 }
165
166 /* GPUFrameBuffer */
167
168 GPUFrameBuffer *GPU_framebuffer_create(void)
169 {
170         /* We generate the FB object later at first use in order to
171          * create the framebuffer in the right opengl context. */
172         return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");;
173 }
174
175 static void gpu_framebuffer_init(GPUFrameBuffer *fb)
176 {
177         glGenFramebuffers(1, &fb->object);
178 }
179
180 void GPU_framebuffer_free(GPUFrameBuffer *fb)
181 {
182         for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) {
183                 if (fb->attachments[type].tex != NULL) {
184                         GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex);
185                 }
186         }
187
188         /* This restores the framebuffer if it was bound */
189         glDeleteFramebuffers(1, &fb->object);
190
191         if (g_currentfb == fb->object) {
192                 g_currentfb = 0;
193         }
194
195         MEM_freeN(fb);
196 }
197
198 /* ---------- Attach ----------- */
199
200 static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
201 {
202         if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) {
203                 fprintf(stderr,
204                         "Attaching to index %d framebuffer slot unsupported. "
205                         "Use at most %d\n", slot, GPU_FB_MAX_COLOR_ATTACHMENT);
206                 return;
207         }
208
209         GPUAttachmentType type = attachment_type_from_tex(tex, slot);
210         GPUAttachment *attachment = &fb->attachments[type];
211
212         if ((attachment->tex == tex) &&
213                 (attachment->mip == mip) &&
214                 (attachment->layer == layer))
215         {
216                 return; /* Exact same texture already bound here. */
217         }
218         else if (attachment->tex != NULL) {
219                 GPU_framebuffer_texture_detach(fb, attachment->tex);
220         }
221
222         if (attachment->tex == NULL) {
223                 GPU_texture_attach_framebuffer(tex, fb, type);
224         }
225
226         attachment->tex = tex;
227         attachment->mip = mip;
228         attachment->layer = layer;
229         GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
230 }
231
232 void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip)
233 {
234         gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip);
235 }
236
237 void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip)
238 {
239         /* NOTE: We could support 1D ARRAY texture. */
240         BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY);
241         gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip);
242 }
243
244 void GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip)
245 {
246         BLI_assert(GPU_texture_cube(tex));
247         gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip);
248 }
249
250 /* ---------- Detach ----------- */
251
252 void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *fb, GPUTexture *tex, int type)
253 {
254         GPUAttachment *attachment = &fb->attachments[type];
255
256         if (attachment->tex != tex) {
257                 fprintf(stderr,
258                         "Warning, attempting to detach Texture %p from framebuffer %p "
259                         "but texture is not attached.\n", tex, fb);
260                 return;
261         }
262
263         attachment->tex = NULL;
264         GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type);
265 }
266
267 void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex)
268 {
269         GPUAttachmentType type = GPU_texture_detach_framebuffer(tex, fb);
270         GPU_framebuffer_texture_detach_slot(fb, tex, type);
271 }
272
273 /* ---------- Config (Attach & Detach) ----------- */
274
275 /**
276  * First GPUAttachment in *config is always the depth/depth_stencil buffer.
277  * Following GPUAttachments are color buffers.
278  * Setting GPUAttachment.mip to -1 will leave the texture in this slot.
279  * Setting GPUAttachment.tex to NULL will detach the texture in this slot.
280  **/
281 void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_ct)
282 {
283         if (config[0].tex) {
284                 BLI_assert(GPU_texture_depth(config[0].tex));
285                 gpu_framebuffer_texture_attach_ex(fb, config[0].tex, 0, config[0].layer, config[0].mip);
286         }
287         else if (config[0].mip == -1) {
288                 /* Leave texture attached */
289         }
290         else if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex != NULL) {
291                 GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex);
292         }
293         else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) {
294                 GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex);
295         }
296
297         int slot = 0;
298         for (int i = 1; i < config_ct; ++i, ++slot) {
299                 if (config[i].tex != NULL) {
300                         BLI_assert(GPU_texture_depth(config[i].tex) == false);
301                         gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip);
302                 }
303                 else if (config[i].mip != -1) {
304                         GPUTexture *tex = framebuffer_get_color_tex(fb, slot);
305                         if (tex != NULL) {
306                                 GPU_framebuffer_texture_detach(fb, tex);
307                         }
308                 }
309         }
310 }
311
312 /* ---------- Bind / Restore ----------- */
313
314 static void gpu_framebuffer_attachment_attach(GPUAttachment *attach, GPUAttachmentType attach_type)
315 {
316         int tex_bind = GPU_texture_opengl_bindcode(attach->tex);
317         GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
318
319         if (attach->layer > -1) {
320                 if (GPU_texture_cube(attach->tex)) {
321                         glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach->layer,
322                                                tex_bind, attach->mip);
323                 }
324                 else {
325                         glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip, attach->layer);
326                 }
327         }
328         else {
329                 glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip);
330         }
331 }
332
333 static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment), GPUAttachmentType attach_type)
334 {
335         GLenum gl_attachment = convert_attachment_type_to_gl(attach_type);
336         glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0);
337 }
338
339 static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb)
340 {
341         GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT];
342         int numslots = 0;
343
344         BLI_assert(g_currentfb == fb->object);
345
346         /* Update attachments */
347         for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
348
349                 if (type >= GPU_FB_COLOR_ATTACHMENT0) {
350                         if (fb->attachments[type].tex) {
351                                 gl_attachments[numslots] = convert_attachment_type_to_gl(type);
352                         }
353                         else {
354                                 gl_attachments[numslots] = GL_NONE;
355                         }
356                         numslots++;
357                 }
358
359                 if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) {
360                         continue;
361                 }
362                 else if (fb->attachments[type].tex != NULL) {
363                         gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
364
365                         fb->multisample = (GPU_texture_samples(fb->attachments[type].tex) > 0);
366                         fb->width = GPU_texture_width(fb->attachments[type].tex);
367                         fb->height = GPU_texture_height(fb->attachments[type].tex);
368                 }
369                 else {
370                         gpu_framebuffer_attachment_detach(&fb->attachments[type], type);
371                 }
372         }
373         fb->dirty_flag = 0;
374
375         /* Update draw buffers (color targets)
376          * This state is saved in the FBO */
377         if (numslots)
378                 glDrawBuffers(numslots, gl_attachments);
379         else
380                 glDrawBuffer(GL_NONE);
381 }
382
383 void GPU_framebuffer_bind(GPUFrameBuffer *fb)
384 {
385         if (fb->object == 0)
386                 gpu_framebuffer_init(fb);
387
388         if (g_currentfb != fb->object)
389                 glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
390
391         g_currentfb = fb->object;
392
393         if (fb->dirty_flag != 0)
394                 gpu_framebuffer_update_attachments(fb);
395
396         /* TODO manually check for errors? */
397 #if 0
398         char err_out[256];
399         if (!GPU_framebuffer_check_valid(fb, err_out)) {
400                 printf("Invalid %s\n", err_out);
401         }
402 #endif
403
404         if (fb->multisample)
405                 glEnable(GL_MULTISAMPLE);
406
407         glViewport(0, 0, fb->width, fb->height);
408 }
409
410 void GPU_framebuffer_restore(void)
411 {
412         if (g_currentfb != 0) {
413                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
414                 g_currentfb = 0;
415         }
416 }
417
418 bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
419 {
420         return (fb->object == g_currentfb) && (fb->object != 0);
421 }
422
423 unsigned int GPU_framebuffer_current_get(void)
424 {
425         return g_currentfb;
426 }
427
428 bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
429 {
430         if (!GPU_framebuffer_bound(fb))
431                 GPU_framebuffer_bind(fb);
432
433         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
434
435         if (status != GL_FRAMEBUFFER_COMPLETE) {
436                 GPU_framebuffer_restore();
437                 gpu_print_framebuffer_error(status, err_out);
438                 return false;
439         }
440
441         return true;
442 }
443
444 /* ---------- Framebuffer Operations ----------- */
445
446 #define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \
447         BLI_assert(GPU_framebuffer_bound(_fb)); \
448         UNUSED_VARS_NDEBUG(_fb);
449
450 /* Needs to be done after binding. */
451 void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h)
452 {
453         CHECK_FRAMEBUFFER_IS_BOUND(fb);
454
455         glViewport(x, y, w, h);
456 }
457
458 void GPU_framebuffer_clear(
459         GPUFrameBuffer *fb, GPUFrameBufferBits buffers,
460         const float clear_col[4], float clear_depth, unsigned int clear_stencil)
461 {
462         CHECK_FRAMEBUFFER_IS_BOUND(fb);
463
464         if (buffers & GPU_COLOR_BIT) {
465                 glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
466                 glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]);
467         }
468         if (buffers & GPU_DEPTH_BIT) {
469                 glDepthMask(GL_TRUE);
470                 glClearDepth(clear_depth);
471         }
472         if (buffers & GPU_STENCIL_BIT) {
473                 glStencilMask(clear_stencil);
474         }
475
476         GLbitfield mask = convert_buffer_bits_to_gl(buffers);
477         glClear(mask);
478 }
479
480 void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data)
481 {
482         CHECK_FRAMEBUFFER_IS_BOUND(fb);
483
484         GLenum type = GL_DEPTH_COMPONENT;
485         glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */
486         glReadPixels(x, y, w, h, type, GL_FLOAT, data);
487 }
488
489 void GPU_framebuffer_read_color(
490         GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data)
491 {
492         CHECK_FRAMEBUFFER_IS_BOUND(fb);
493
494         GLenum type;
495         switch (channels) {
496                 case 1: type = GL_RED; break;
497                 case 2: type = GL_RG; break;
498                 case 3: type = GL_RGB; break;
499                 case 4: type = GL_RGBA; break;
500                 default:
501                         BLI_assert(false && "wrong number of read channels");
502                         return;
503         }
504         glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
505         glReadPixels(x, y, w, h, type, GL_FLOAT, data);
506 }
507
508 /* read_slot and write_slot are only used for color buffers. */
509 void GPU_framebuffer_blit(
510         GPUFrameBuffer *fb_read, int read_slot,
511         GPUFrameBuffer *fb_write, int write_slot,
512         GPUFrameBufferBits blit_buffers)
513 {
514         BLI_assert(blit_buffers != 0);
515
516         GLuint prev_fb = g_currentfb;
517
518         /* Framebuffers must be up to date. This simplify this function. */
519         if (fb_read->dirty_flag != 0 || fb_read->object == 0) {
520                 GPU_framebuffer_bind(fb_read);
521         }
522         if (fb_write->dirty_flag != 0 || fb_write->object == 0) {
523                 GPU_framebuffer_bind(fb_write);
524         }
525
526         const bool do_color = (blit_buffers & GPU_COLOR_BIT);
527         const bool do_depth = (blit_buffers & GPU_DEPTH_BIT);
528         const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT);
529
530         GPUTexture *read_tex = (do_depth || do_stencil)
531                                ? framebuffer_get_depth_tex(fb_read)
532                                : framebuffer_get_color_tex(fb_read, read_slot);
533         GPUTexture *write_tex = (do_depth || do_stencil)
534                                 ? framebuffer_get_depth_tex(fb_write)
535                                 : framebuffer_get_color_tex(fb_write, read_slot);
536
537         if (do_depth) {
538                 BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex));
539                 BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
540         }
541         if (do_stencil) {
542                 BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex));
543                 BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex));
544         }
545         if (GPU_texture_samples(write_tex) != 0 ||
546                 GPU_texture_samples(read_tex) != 0)
547         {
548                 /* Can only blit multisample textures to another texture of the same size. */
549                 BLI_assert((fb_read->width == fb_write->width) &&
550                            (fb_read->height == fb_write->height));
551         }
552
553         glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
554         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
555
556         if (do_color) {
557                 glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot);
558                 glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot);
559                 /* XXX we messed with the glDrawBuffer, this will reset the
560                  * glDrawBuffers the next time we bind fb_write. */
561                 fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER;
562         }
563
564         GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers);
565
566         glBlitFramebuffer(0, 0, fb_read->width, fb_read->height,
567                           0, 0, fb_write->width, fb_write->height,
568                           mask, GL_NEAREST);
569
570         /* Restore previous framebuffer */
571         if (fb_write->object == prev_fb) {
572                 GPU_framebuffer_bind(fb_write); /* To update drawbuffers */
573         }
574         else {
575                 glBindFramebuffer(GL_FRAMEBUFFER, prev_fb);
576                 g_currentfb = prev_fb;
577         }
578 }
579
580 /**
581  * Use this if you need to custom downsample your texture and use the previous mip level as input.
582  * This function only takes care of the correct texture handling. It execute the callback for each texture level.
583  **/
584 void GPU_framebuffer_recursive_downsample(
585         GPUFrameBuffer *fb, int max_lvl,
586         void (*callback)(void *userData, int level), void *userData)
587 {
588         /* Framebuffer must be up to date and bound. This simplify this function. */
589         if (g_currentfb != fb->object || fb->dirty_flag != 0 || fb->object == 0) {
590                 GPU_framebuffer_bind(fb);
591         }
592         /* HACK: We make the framebuffer appear not bound in order to
593          * not trigger any error in GPU_texture_bind().  */
594         GLuint prev_fb = g_currentfb;
595         g_currentfb = 0;
596
597         int i;
598         int current_dim[2] = {fb->width, fb->height};
599         for (i = 1; i < max_lvl + 1; i++) {
600                 /* calculate next viewport size */
601                 current_dim[0] = max_ii(current_dim[0] / 2, 1);
602                 current_dim[1] = max_ii(current_dim[1] / 2, 1);
603
604                 for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
605                         if (fb->attachments[type].tex != NULL) {
606                                 /* bind next level for rendering but first restrict fetches only to previous level */
607                                 GPUTexture *tex = fb->attachments[type].tex;
608                                 GPU_texture_bind(tex, 0);
609                                 glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1);
610                                 glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1);
611                                 GPU_texture_unbind(tex);
612                                 /* copy attachment and replace miplevel. */
613                                 GPUAttachment attachment = fb->attachments[type];
614                                 attachment.mip = i;
615                                 gpu_framebuffer_attachment_attach(&attachment, type);
616                         }
617                 }
618
619                 BLI_assert(GL_FRAMEBUFFER_COMPLETE == glCheckFramebufferStatus(GL_FRAMEBUFFER));
620
621                 glViewport(0, 0, current_dim[0], current_dim[1]);
622                 callback(userData, i);
623
624                 if (current_dim[0] == 1 && current_dim[1] == 1)
625                         break;
626         }
627
628         for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) {
629                 if (fb->attachments[type].tex != NULL) {
630                         /* reset mipmap level range */
631                         GPUTexture *tex = fb->attachments[type].tex;
632                         GPU_texture_bind(tex, 0);
633                         glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0);
634                         glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1);
635                         GPU_texture_unbind(tex);
636                         /* Reattach original level */
637                         /* NOTE: This is not necessary but this makes the FBO config
638                          *       remain in sync with the GPUFrameBuffer config. */
639                         gpu_framebuffer_attachment_attach(&fb->attachments[type], type);
640                 }
641         }
642
643         g_currentfb = prev_fb;
644 }
645
646 /* GPUOffScreen */
647
648 struct GPUOffScreen {
649         GPUFrameBuffer *fb;
650         GPUTexture *color;
651         GPUTexture *depth;
652 };
653
654 GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool depth, bool high_bitdepth, char err_out[256])
655 {
656         GPUOffScreen *ofs;
657
658         ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
659
660         ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4,
661                 (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out);
662
663         if (depth) {
664                 ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out);
665         }
666
667         if (!ofs->depth || !ofs->color) {
668                 GPU_offscreen_free(ofs);
669                 return NULL;
670         }
671         
672         GPU_framebuffer_ensure_config(&ofs->fb, {
673                 GPU_ATTACHMENT_TEXTURE(ofs->depth),
674                 GPU_ATTACHMENT_TEXTURE(ofs->color)
675         });
676
677         /* check validity at the very end! */
678         if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
679                 GPU_offscreen_free(ofs);
680                 return NULL;            
681         }
682
683         GPU_framebuffer_restore();
684
685         return ofs;
686 }
687
688 void GPU_offscreen_free(GPUOffScreen *ofs)
689 {
690         if (ofs->fb)
691                 GPU_framebuffer_free(ofs->fb);
692         if (ofs->color)
693                 GPU_texture_free(ofs->color);
694         if (ofs->depth)
695                 GPU_texture_free(ofs->depth);
696         
697         MEM_freeN(ofs);
698 }
699
700 void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
701 {
702         if (save) {
703                 gpuPushAttrib(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT);
704         }
705         glDisable(GL_SCISSOR_TEST);
706         GPU_framebuffer_bind(ofs->fb);
707 }
708
709 void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore)
710 {
711         GPU_framebuffer_restore();
712         if (restore) {
713                 gpuPopAttrib();
714         }
715 }
716
717 void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
718 {
719         const int w = GPU_texture_width(ofs->color);
720         const int h = GPU_texture_height(ofs->color);
721
722         BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT);
723
724         if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) {
725                 /* For a multi-sample texture,
726                  * we need to create an intermediate buffer to blit to,
727                  * before its copied using 'glReadPixels' */
728                 GLuint fbo_blit = 0;
729                 GLuint tex_blit = 0;
730
731                 /* create texture for new 'fbo_blit' */
732                 glGenTextures(1, &tex_blit);
733                 glBindTexture(GL_TEXTURE_2D, tex_blit);
734                 glTexImage2D(GL_TEXTURE_2D, 0, (type == GL_FLOAT) ? GL_RGBA16F : GL_RGBA8,
735                              w, h, 0, GL_RGBA, type, 0);
736
737                 /* write into new single-sample buffer */
738                 glGenFramebuffers(1, &fbo_blit);
739                 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit);
740                 glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
741                                        GL_TEXTURE_2D, tex_blit, 0);
742
743                 GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
744                 if (status != GL_FRAMEBUFFER_COMPLETE) {
745                         goto finally;
746                 }
747
748                 /* perform the copy */
749                 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
750
751                 /* read the results */
752                 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit);
753                 glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
754
755                 /* restore the original frame-bufer */
756                 glBindFramebuffer(GL_FRAMEBUFFER, ofs->fb->object);
757
758 finally:
759                 /* cleanup */
760                 glDeleteTextures(1, &tex_blit);
761                 glDeleteFramebuffers(1, &fbo_blit);
762         }
763         else {
764                 glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
765         }
766 }
767
768 int GPU_offscreen_width(const GPUOffScreen *ofs)
769 {
770         return GPU_texture_width(ofs->color);
771 }
772
773 int GPU_offscreen_height(const GPUOffScreen *ofs)
774 {
775         return GPU_texture_height(ofs->color);
776 }
777
778 GPUTexture *GPU_offscreen_color_texture(const GPUOffScreen *ofs)
779 {
780         return ofs->color;
781 }
782
783 /* only to be used by viewport code! */
784 void GPU_offscreen_viewport_data_get(
785         GPUOffScreen *ofs,
786         GPUFrameBuffer **r_fb, GPUTexture **r_color, GPUTexture **r_depth)
787 {
788         *r_fb = ofs->fb;
789         *r_color = ofs->color;
790         *r_depth = ofs->depth;
791 }