Merge branch 'master' into 28
[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_utildefines.h"
32
33 #include "BKE_global.h"
34
35 #include "GPU_batch.h"
36 #include "GPU_draw.h"
37 #include "GPU_framebuffer.h"
38 #include "GPU_matrix.h"
39 #include "GPU_shader.h"
40 #include "GPU_texture.h"
41
42 static struct GPUFrameBufferGlobal {
43         GLuint currentfb;
44 } GG = {0};
45
46 /* Number of maximum output slots.
47  * We support 4 outputs for now (usually we wouldn't need more to preserve fill rate) */
48 #define GPU_FB_MAX_SLOTS 4
49
50 struct GPUFrameBuffer {
51         GLuint object;
52         GPUTexture *colortex[GPU_FB_MAX_SLOTS];
53         GPUTexture *depthtex;
54         struct GPUStateValues attribs;
55 };
56
57 static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
58 {
59         const char *format = "GPUFrameBuffer: framebuffer status %s\n";
60         const char *err = "unknown";
61
62 #define format_status(X) \
63         case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \
64                 break;
65
66         switch (status) {
67                 /* success */
68                 format_status(COMPLETE)
69                 /* errors shared by OpenGL desktop & ES */
70                 format_status(INCOMPLETE_ATTACHMENT)
71                 format_status(INCOMPLETE_MISSING_ATTACHMENT)
72                 format_status(UNSUPPORTED)
73 #if 0 /* for OpenGL ES only */
74                 format_status(INCOMPLETE_DIMENSIONS)
75 #else /* for desktop GL only */
76                 format_status(INCOMPLETE_DRAW_BUFFER)
77                 format_status(INCOMPLETE_READ_BUFFER)
78                 format_status(INCOMPLETE_MULTISAMPLE)
79                 format_status(UNDEFINED)
80 #endif
81         }
82
83 #undef format_status
84
85         if (err_out) {
86                 BLI_snprintf(err_out, 256, format, err);
87         }
88         else {
89                 fprintf(stderr, format, err);
90         }
91 }
92
93 /* GPUFrameBuffer */
94
95 GPUFrameBuffer *GPU_framebuffer_create(void)
96 {
97         GPUFrameBuffer *fb;
98
99         fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
100         glGenFramebuffers(1, &fb->object);
101
102         if (!fb->object) {
103                 fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n");
104                 GPU_framebuffer_free(fb);
105                 return NULL;
106         }
107
108         /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
109         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
110         glReadBuffer(GL_NONE);
111         glDrawBuffer(GL_NONE);
112         glBindFramebuffer(GL_FRAMEBUFFER, 0);
113         
114         return fb;
115 }
116
117 bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot)
118 {
119         GLenum attachment;
120
121         if (slot >= GPU_FB_MAX_SLOTS) {
122                 fprintf(stderr,
123                         "Attaching to index %d framebuffer slot unsupported. "
124                         "Use at most %d\n", slot, GPU_FB_MAX_SLOTS);
125                 return false;
126         }
127
128         if ((G.debug & G_DEBUG)) {
129                 if (GPU_texture_bound_number(tex) != -1) {
130                         fprintf(stderr,
131                                 "Feedback loop warning!: "
132                                 "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n");
133                 }
134         }
135
136         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
137         GG.currentfb = fb->object;
138
139         if (GPU_texture_stencil(tex) && GPU_texture_depth(tex))
140                 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
141         else if (GPU_texture_depth(tex))
142                 attachment = GL_DEPTH_ATTACHMENT;
143         else
144                 attachment = GL_COLOR_ATTACHMENT0 + slot;
145
146         glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), 0);
147
148         if (GPU_texture_depth(tex))
149                 fb->depthtex = tex;
150         else
151                 fb->colortex[slot] = tex;
152
153         GPU_texture_framebuffer_set(tex, fb, slot);
154
155         return true;
156 }
157
158 void GPU_framebuffer_texture_detach(GPUTexture *tex)
159 {
160         GLenum attachment;
161         GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
162         int fb_attachment = GPU_texture_framebuffer_attachment(tex);
163
164         if (!fb)
165                 return;
166
167         if (GG.currentfb != fb->object) {
168                 glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
169                 GG.currentfb = fb->object;
170         }
171
172         if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) {
173                 fb->depthtex = NULL;
174                 attachment = GL_DEPTH_STENCIL_ATTACHMENT;
175         }
176         else if (GPU_texture_depth(tex)) {
177                 fb->depthtex = NULL;
178                 attachment = GL_DEPTH_ATTACHMENT;
179         }
180         else {
181                 BLI_assert(fb->colortex[fb_attachment] == tex);
182                 fb->colortex[fb_attachment] = NULL;
183                 attachment = GL_COLOR_ATTACHMENT0 + fb_attachment;
184         }
185
186         glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), 0, 0);
187
188         GPU_texture_framebuffer_set(tex, NULL, -1);
189 }
190
191 void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
192 {
193         GPUFrameBuffer *fb = GPU_texture_framebuffer(tex);
194         int fb_attachment = GPU_texture_framebuffer_attachment(tex);
195
196         if (!fb) {
197                 fprintf(stderr, "Error, texture not bound to framebuffer!\n");
198                 return;
199         }
200
201         /* push attributes */
202         gpuSaveState(&fb->attribs, GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
203         glDisable(GL_SCISSOR_TEST);
204
205         /* bind framebuffer */
206         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
207
208         if (GPU_texture_depth(tex)) {
209                 glDrawBuffer(GL_NONE);
210                 glReadBuffer(GL_NONE);
211         }
212         else {
213                 /* last bound prevails here, better allow explicit control here too */
214                 glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment);
215                 glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment);
216         }
217         
218         if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
219                 glEnable(GL_MULTISAMPLE);
220         }
221
222         /* set default viewport */
223         glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
224         GG.currentfb = fb->object;
225 }
226
227 void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
228 {
229         int numslots = 0, i;
230         GLenum attachments[4];
231         
232         if (!fb->colortex[slot]) {
233                 fprintf(stderr, "Error, framebuffer slot empty!\n");
234                 return;
235         }
236         
237         for (i = 0; i < 4; i++) {
238                 if (fb->colortex[i]) {
239                         attachments[numslots] = GL_COLOR_ATTACHMENT0 + i;
240                         numslots++;
241                 }
242         }
243         
244         /* push attributes */
245         gpuSaveState(&fb->attribs, GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
246         glDisable(GL_SCISSOR_TEST);
247
248         /* bind framebuffer */
249         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
250
251         /* last bound prevails here, better allow explicit control here too */
252         glDrawBuffers(numslots, attachments);
253         glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
254
255         /* set default viewport */
256         glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
257         GG.currentfb = fb->object;
258 }
259
260 void GPU_framebuffer_bind(GPUFrameBuffer *fb)
261 {
262         int numslots = 0, i;
263         GLenum attachments[4];
264         GLenum readattachement = 0;
265         GPUTexture *tex;
266
267         for (i = 0; i < 4; i++) {
268                 if (fb->colortex[i]) {
269                         attachments[numslots] = GL_COLOR_ATTACHMENT0 + i;
270                         tex = fb->colortex[i];
271
272                         if (!readattachement)
273                                 readattachement = GL_COLOR_ATTACHMENT0 + i;
274
275                         numslots++;
276                 }
277         }
278
279         /* bind framebuffer */
280         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
281
282         if (numslots == 0) {
283                 glDrawBuffer(GL_NONE);
284                 glReadBuffer(GL_NONE);
285                 tex = fb->depthtex;
286         }
287         else {
288                 /* last bound prevails here, better allow explicit control here too */
289                 glDrawBuffers(numslots, attachments);
290                 glReadBuffer(readattachement);
291         }
292
293         glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
294         GG.currentfb = fb->object;
295 }
296
297
298 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *UNUSED(tex))
299 {
300         /* restore attributes */
301         gpuRestoreState(&fb->attribs);
302 }
303
304 void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
305 {
306         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
307         /* last bound prevails here, better allow explicit control here too */
308         glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot);
309         glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
310
311         /* push matrices and set default viewport and matrix */
312         glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
313         GG.currentfb = fb->object;
314 }
315
316 bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
317 {
318         return fb->object == GG.currentfb;
319 }
320
321 bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
322 {
323         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
324         GG.currentfb = fb->object;
325
326         GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
327
328         if (status != GL_FRAMEBUFFER_COMPLETE) {
329                 GPU_framebuffer_restore();
330                 gpu_print_framebuffer_error(status, err_out);
331                 return false;
332         }
333
334         return true;
335 }
336
337 void GPU_framebuffer_free(GPUFrameBuffer *fb)
338 {
339         int i;
340         if (fb->depthtex)
341                 GPU_framebuffer_texture_detach(fb->depthtex);
342
343         for (i = 0; i < GPU_FB_MAX_SLOTS; i++) {
344                 if (fb->colortex[i]) {
345                         GPU_framebuffer_texture_detach(fb->colortex[i]);
346                 }
347         }
348
349         if (fb->object) {
350                 glDeleteFramebuffers(1, &fb->object);
351
352                 if (GG.currentfb == fb->object) {
353                         glBindFramebuffer(GL_FRAMEBUFFER, 0);
354                         GG.currentfb = 0;
355                 }
356         }
357
358         MEM_freeN(fb);
359 }
360
361 void GPU_framebuffer_restore(void)
362 {
363         if (GG.currentfb != 0) {
364                 glBindFramebuffer(GL_FRAMEBUFFER, 0);
365                 GG.currentfb = 0;
366         }
367 }
368
369 void GPU_framebuffer_blur(
370         GPUFrameBuffer *fb, GPUTexture *tex,
371         GPUFrameBuffer *blurfb, GPUTexture *blurtex)
372 {
373         const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}};
374         const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}};
375
376         static VertexFormat format = {0};
377         static VertexBuffer vbo = {{0}};
378         static Batch batch = {{0}};
379
380         const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
381         const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
382
383         GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
384
385         if (!blur_shader)
386                 return;
387
388         /* Preparing to draw quad */
389         if (format.attrib_ct == 0) {
390                 unsigned int i = 0;
391                 /* Vertex format */
392                 unsigned int pos = VertexFormat_add_attrib(&format, "pos", COMP_F32, 2, KEEP_FLOAT);
393                 unsigned int uvs = VertexFormat_add_attrib(&format, "uvs", COMP_F32, 2, KEEP_FLOAT);
394
395                 /* Vertices */
396                 VertexBuffer_init_with_format(&vbo, &format);
397                 VertexBuffer_allocate_data(&vbo, 36);
398
399                 for (int j = 0; j < 3; ++j) {
400                         VertexBuffer_set_attrib(&vbo, uvs, i, fullscreenuvs[j]);
401                         VertexBuffer_set_attrib(&vbo, pos, i++, fullscreencos[j]);
402                 }
403                 for (int j = 1; j < 4; ++j) {
404                         VertexBuffer_set_attrib(&vbo, uvs, i, fullscreenuvs[j]);
405                         VertexBuffer_set_attrib(&vbo, pos, i++, fullscreencos[j]);
406                 }
407
408                 Batch_init(&batch, GL_TRIANGLES, &vbo, NULL);
409         }
410                 
411         glDisable(GL_DEPTH_TEST);
412         
413         /* Load fresh matrices */
414         gpuMatrixBegin3D(); /* TODO: finish 2D API */
415
416         /* Blurring horizontally */
417         /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
418          * pushing unnecessary matrices onto the OpenGL stack. */
419         glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object);
420         glDrawBuffer(GL_COLOR_ATTACHMENT0);
421         
422         /* avoid warnings from texture binding */
423         GG.currentfb = blurfb->object;
424
425         glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
426
427         GPU_texture_bind(tex, 0);
428
429         Batch_set_builtin_program(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR);
430         Batch_Uniform2f(&batch, "ScaleU", scaleh[0], scaleh[1]);
431         Batch_Uniform1i(&batch, "textureSource", GL_TEXTURE0);
432         Batch_draw(&batch);
433
434         /* Blurring vertically */
435         glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
436         glDrawBuffer(GL_COLOR_ATTACHMENT0);
437         
438         GG.currentfb = fb->object;
439         
440         glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
441
442         GPU_texture_bind(blurtex, 0);
443
444         /* Hack to make the following uniform stick */
445         Batch_set_builtin_program(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR);
446         Batch_Uniform2f(&batch, "ScaleU", scalev[0], scalev[1]);
447         Batch_Uniform1i(&batch, "textureSource", GL_TEXTURE0);
448         Batch_draw(&batch);
449
450         gpuMatrixEnd();
451 }
452
453 void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, bool use_depth)
454 {
455         GPUTexture *read_tex = (use_depth) ? fb_read->depthtex : fb_read->colortex[read_slot];
456         GPUTexture *write_tex = (use_depth) ? fb_write->depthtex : fb_write->colortex[write_slot];
457         int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex);
458         int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex);
459         int read_bind = GPU_texture_opengl_bindcode(read_tex);
460         int write_bind = GPU_texture_opengl_bindcode(write_tex);
461         const int read_w = GPU_texture_width(read_tex);
462         const int read_h = GPU_texture_height(read_tex);
463         const int write_w = GPU_texture_width(write_tex);
464         const int write_h = GPU_texture_height(write_tex);
465
466         /* read from multi-sample buffer */
467         glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
468         glFramebufferTexture2D(
469                 GL_READ_FRAMEBUFFER, read_attach,
470                 GL_TEXTURE_2D, read_bind, 0);
471         BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
472
473         /* write into new single-sample buffer */
474         glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
475         glFramebufferTexture2D(
476                 GL_DRAW_FRAMEBUFFER, write_attach,
477                 GL_TEXTURE_2D, write_bind, 0);
478         BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
479
480         glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, (use_depth) ? GL_DEPTH_BUFFER_BIT : GL_COLOR_BUFFER_BIT, GL_NEAREST);
481
482         /* Restore previous framebuffer */
483         glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb);
484         glDrawBuffer(GL_COLOR_ATTACHMENT0);
485 }
486
487 /* GPUOffScreen */
488
489 struct GPUOffScreen {
490         GPUFrameBuffer *fb;
491         GPUTexture *color;
492         GPUTexture *depth;
493 };
494
495 GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_out[256])
496 {
497         GPUOffScreen *ofs;
498
499         ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen");
500
501         ofs->fb = GPU_framebuffer_create();
502         if (!ofs->fb) {
503                 GPU_offscreen_free(ofs);
504                 return NULL;
505         }
506
507         if (samples) {
508                 if (!GLEW_ARB_texture_multisample ||
509                     /* This is required when blitting from a multi-sampled buffers,
510                      * even though we're not scaling. */
511                     !GLEW_EXT_framebuffer_multisample_blit_scaled)
512                 {
513                         samples = 0;
514                 }
515         }
516
517         ofs->depth = GPU_texture_create_depth_multisample(width, height, samples, err_out);
518         if (!ofs->depth) {
519                 GPU_offscreen_free(ofs);
520                 return NULL;
521         }
522
523         if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0)) {
524                 GPU_offscreen_free(ofs);
525                 return NULL;
526         }
527
528         ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out);
529         if (!ofs->color) {
530                 GPU_offscreen_free(ofs);
531                 return NULL;
532         }
533
534         if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0)) {
535                 GPU_offscreen_free(ofs);
536                 return NULL;
537         }
538         
539         /* check validity at the very end! */
540         if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) {
541                 GPU_offscreen_free(ofs);
542                 return NULL;            
543         }
544
545         GPU_framebuffer_restore();
546
547         return ofs;
548 }
549
550 void GPU_offscreen_free(GPUOffScreen *ofs)
551 {
552         if (ofs->fb)
553                 GPU_framebuffer_free(ofs->fb);
554         if (ofs->color)
555                 GPU_texture_free(ofs->color);
556         if (ofs->depth)
557                 GPU_texture_free(ofs->depth);
558         
559         MEM_freeN(ofs);
560 }
561
562 void GPU_offscreen_bind(GPUOffScreen *ofs, bool save)
563 {
564         glDisable(GL_SCISSOR_TEST);
565         if (save)
566                 GPU_texture_bind_as_framebuffer(ofs->color);
567         else {
568                 GPU_framebuffer_bind_no_save(ofs->fb, 0);
569         }
570 }
571
572 void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore)
573 {
574         if (restore)
575                 GPU_framebuffer_texture_unbind(ofs->fb, ofs->color);
576         GPU_framebuffer_restore();
577         glEnable(GL_SCISSOR_TEST);
578 }
579
580 void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
581 {
582         const int w = GPU_texture_width(ofs->color);
583         const int h = GPU_texture_height(ofs->color);
584
585         if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) {
586                 /* For a multi-sample texture,
587                  * we need to create an intermediate buffer to blit to,
588                  * before its copied using 'glReadPixels' */
589
590                 /* not needed since 'ofs' needs to be bound to the framebuffer already */
591 // #define USE_FBO_CTX_SWITCH
592
593                 GLuint fbo_blit = 0;
594                 GLuint tex_blit = 0;
595                 GLenum status;
596
597                 /* create texture for new 'fbo_blit' */
598                 glGenTextures(1, &tex_blit);
599                 if (!tex_blit) {
600                         goto finally;
601                 }
602
603                 glBindTexture(GL_TEXTURE_2D, tex_blit);
604                 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0);
605
606 #ifdef USE_FBO_CTX_SWITCH
607                 /* read from multi-sample buffer */
608                 glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object);
609                 glFramebufferTexture2D(
610                         GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment,
611                         GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
612                 status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
613                 if (status != GL_FRAMEBUFFER_COMPLETE) {
614                         goto finally;
615                 }
616 #endif
617
618                 /* write into new single-sample buffer */
619                 glGenFramebuffers(1, &fbo_blit);
620                 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit);
621                 glFramebufferTexture2D(
622                         GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
623                         GL_TEXTURE_2D, tex_blit, 0);
624                 status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
625                 if (status != GL_FRAMEBUFFER_COMPLETE) {
626                         goto finally;
627                 }
628
629                 /* perform the copy */
630                 glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
631
632                 /* read the results */
633                 glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit);
634                 glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
635
636 #ifdef USE_FBO_CTX_SWITCH
637                 /* restore the original frame-bufer */
638                 glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object);
639 #undef USE_FBO_CTX_SWITCH
640 #endif
641
642
643 finally:
644                 /* cleanup */
645                 if (tex_blit) {
646                         glDeleteTextures(1, &tex_blit);
647                 }
648                 if (fbo_blit) {
649                         glDeleteFramebuffers(1, &fbo_blit);
650                 }
651         }
652         else {
653                 glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
654         }
655 }
656
657 int GPU_offscreen_width(const GPUOffScreen *ofs)
658 {
659         return GPU_texture_width(ofs->color);
660 }
661
662 int GPU_offscreen_height(const GPUOffScreen *ofs)
663 {
664         return GPU_texture_height(ofs->color);
665 }
666
667 int GPU_offscreen_color_texture(const GPUOffScreen *ofs)
668 {
669         return GPU_texture_opengl_bindcode(ofs->color);
670 }
671