Merge branch 'master' into 28
[blender.git] / source / blender / gpu / intern / gpu_framebuffer.c
index e7a8beae5cc93aa5b36760221f1f9fe429787326..ce3b37b3a662b5f6bafa69902700e47c70430ef4 100644 (file)
 
 #include "BKE_global.h"
 
 
 #include "BKE_global.h"
 
-#include "GPU_debug.h"
-#include "GPU_glew.h"
+#include "GPU_batch.h"
+#include "GPU_draw.h"
 #include "GPU_framebuffer.h"
 #include "GPU_framebuffer.h"
+#include "GPU_matrix.h"
 #include "GPU_shader.h"
 #include "GPU_texture.h"
 
 #include "GPU_shader.h"
 #include "GPU_texture.h"
 
@@ -50,48 +51,42 @@ struct GPUFrameBuffer {
        GLuint object;
        GPUTexture *colortex[GPU_FB_MAX_SLOTS];
        GPUTexture *depthtex;
        GLuint object;
        GPUTexture *colortex[GPU_FB_MAX_SLOTS];
        GPUTexture *depthtex;
+       struct GPUStateValues attribs;
 };
 
 static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
 {
 };
 
 static void gpu_print_framebuffer_error(GLenum status, char err_out[256])
 {
+       const char *format = "GPUFrameBuffer: framebuffer status %s\n";
        const char *err = "unknown";
 
        const char *err = "unknown";
 
+#define format_status(X) \
+       case GL_FRAMEBUFFER_##X: err = "GL_FRAMEBUFFER_"#X; \
+               break;
+
        switch (status) {
        switch (status) {
-               case GL_FRAMEBUFFER_COMPLETE_EXT:
-                       break;
-               case GL_INVALID_OPERATION:
-                       err = "Invalid operation";
-                       break;
-               case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT_EXT:
-                       err = "Incomplete attachment";
-                       break;
-               case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
-                       err = "Unsupported framebuffer format";
-                       break;
-               case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT_EXT:
-                       err = "Missing attachment";
-                       break;
-               case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS_EXT:
-                       err = "Attached images must have same dimensions";
-                       break;
-               case GL_FRAMEBUFFER_INCOMPLETE_FORMATS_EXT:
-                       err = "Attached images must have same format";
-                       break;
-               case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER_EXT:
-                       err = "Missing draw buffer";
-                       break;
-               case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER_EXT:
-                       err = "Missing read buffer";
-                       break;
+               /* success */
+               format_status(COMPLETE)
+               /* errors shared by OpenGL desktop & ES */
+               format_status(INCOMPLETE_ATTACHMENT)
+               format_status(INCOMPLETE_MISSING_ATTACHMENT)
+               format_status(UNSUPPORTED)
+#if 0 /* for OpenGL ES only */
+               format_status(INCOMPLETE_DIMENSIONS)
+#else /* for desktop GL only */
+               format_status(INCOMPLETE_DRAW_BUFFER)
+               format_status(INCOMPLETE_READ_BUFFER)
+               format_status(INCOMPLETE_MULTISAMPLE)
+               format_status(UNDEFINED)
+#endif
        }
 
        }
 
+#undef format_status
+
        if (err_out) {
        if (err_out) {
-               BLI_snprintf(err_out, 256, "GPUFrameBuffer: framebuffer incomplete error %d '%s'",
-                       (int)status, err);
+               BLI_snprintf(err_out, 256, format, err);
        }
        else {
        }
        else {
-               fprintf(stderr, "GPUFrameBuffer: framebuffer incomplete error %d '%s'\n",
-                       (int)status, err);
+               fprintf(stderr, format, err);
        }
 }
 
        }
 }
 
@@ -101,41 +96,33 @@ GPUFrameBuffer *GPU_framebuffer_create(void)
 {
        GPUFrameBuffer *fb;
 
 {
        GPUFrameBuffer *fb;
 
-       if (!(GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object ||
-             (GLEW_EXT_framebuffer_object && GLEW_EXT_framebuffer_blit)))
-       {
-               return NULL;
-       }
-       
        fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
        fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");
-       glGenFramebuffersEXT(1, &fb->object);
+       glGenFramebuffers(1, &fb->object);
 
        if (!fb->object) {
 
        if (!fb->object) {
-               fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed. %d\n",
-                       (int)glGetError());
+               fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n");
                GPU_framebuffer_free(fb);
                return NULL;
        }
 
        /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
                GPU_framebuffer_free(fb);
                return NULL;
        }
 
        /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
        glReadBuffer(GL_NONE);
        glDrawBuffer(GL_NONE);
        glReadBuffer(GL_NONE);
        glDrawBuffer(GL_NONE);
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+       glBindFramebuffer(GL_FRAMEBUFFER, 0);
        
        return fb;
 }
 
        
        return fb;
 }
 
-int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, char err_out[256])
+bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot)
 {
        GLenum attachment;
 {
        GLenum attachment;
-       GLenum error;
 
        if (slot >= GPU_FB_MAX_SLOTS) {
                fprintf(stderr,
                        "Attaching to index %d framebuffer slot unsupported. "
                        "Use at most %d\n", slot, GPU_FB_MAX_SLOTS);
 
        if (slot >= GPU_FB_MAX_SLOTS) {
                fprintf(stderr,
                        "Attaching to index %d framebuffer slot unsupported. "
                        "Use at most %d\n", slot, GPU_FB_MAX_SLOTS);
-               return 0;
+               return false;
        }
 
        if ((G.debug & G_DEBUG)) {
        }
 
        if ((G.debug & G_DEBUG)) {
@@ -146,27 +133,17 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot
                }
        }
 
                }
        }
 
-       if (GPU_texture_depth(tex))
-               attachment = GL_DEPTH_ATTACHMENT_EXT;
-       else
-               attachment = GL_COLOR_ATTACHMENT0_EXT + slot;
-
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
        GG.currentfb = fb->object;
 
        GG.currentfb = fb->object;
 
-       /* Clean glError buffer. */
-       while (glGetError() != GL_NO_ERROR) {}
-
-       glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, 
-               GPU_texture_target(tex), GPU_texture_opengl_bindcode(tex), 0);
-
-       error = glGetError();
+       if (GPU_texture_stencil(tex) && GPU_texture_depth(tex))
+               attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+       else if (GPU_texture_depth(tex))
+               attachment = GL_DEPTH_ATTACHMENT;
+       else
+               attachment = GL_COLOR_ATTACHMENT0 + slot;
 
 
-       if (error == GL_INVALID_OPERATION) {
-               GPU_framebuffer_restore();
-               gpu_print_framebuffer_error(error, err_out);
-               return 0;
-       }
+       glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), 0);
 
        if (GPU_texture_depth(tex))
                fb->depthtex = tex;
 
        if (GPU_texture_depth(tex))
                fb->depthtex = tex;
@@ -175,7 +152,7 @@ int GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot
 
        GPU_texture_framebuffer_set(tex, fb, slot);
 
 
        GPU_texture_framebuffer_set(tex, fb, slot);
 
-       return 1;
+       return true;
 }
 
 void GPU_framebuffer_texture_detach(GPUTexture *tex)
 }
 
 void GPU_framebuffer_texture_detach(GPUTexture *tex)
@@ -188,21 +165,25 @@ void GPU_framebuffer_texture_detach(GPUTexture *tex)
                return;
 
        if (GG.currentfb != fb->object) {
                return;
 
        if (GG.currentfb != fb->object) {
-               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+               glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
                GG.currentfb = fb->object;
        }
 
                GG.currentfb = fb->object;
        }
 
-       if (GPU_texture_depth(tex)) {
+       if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) {
                fb->depthtex = NULL;
                fb->depthtex = NULL;
-               attachment = GL_DEPTH_ATTACHMENT_EXT;
+               attachment = GL_DEPTH_STENCIL_ATTACHMENT;
+       }
+       else if (GPU_texture_depth(tex)) {
+               fb->depthtex = NULL;
+               attachment = GL_DEPTH_ATTACHMENT;
        }
        else {
                BLI_assert(fb->colortex[fb_attachment] == tex);
                fb->colortex[fb_attachment] = NULL;
        }
        else {
                BLI_assert(fb->colortex[fb_attachment] == tex);
                fb->colortex[fb_attachment] = NULL;
-               attachment = GL_COLOR_ATTACHMENT0_EXT + fb_attachment;
+               attachment = GL_COLOR_ATTACHMENT0 + fb_attachment;
        }
 
        }
 
-       glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attachment, GPU_texture_target(tex), 0, 0);
+       glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, GPU_texture_target(tex), 0, 0);
 
        GPU_texture_framebuffer_set(tex, NULL, -1);
 }
 
        GPU_texture_framebuffer_set(tex, NULL, -1);
 }
@@ -218,11 +199,11 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
        }
 
        /* push attributes */
        }
 
        /* push attributes */
-       glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
+       gpuSaveState(&fb->attribs, GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
        glDisable(GL_SCISSOR_TEST);
 
        /* bind framebuffer */
        glDisable(GL_SCISSOR_TEST);
 
        /* bind framebuffer */
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
 
        if (GPU_texture_depth(tex)) {
                glDrawBuffer(GL_NONE);
 
        if (GPU_texture_depth(tex)) {
                glDrawBuffer(GL_NONE);
@@ -230,22 +211,17 @@ void GPU_texture_bind_as_framebuffer(GPUTexture *tex)
        }
        else {
                /* last bound prevails here, better allow explicit control here too */
        }
        else {
                /* last bound prevails here, better allow explicit control here too */
-               glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
-               glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + fb_attachment);
+               glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment);
+               glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment);
        }
        
        if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
                glEnable(GL_MULTISAMPLE);
        }
 
        }
        
        if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) {
                glEnable(GL_MULTISAMPLE);
        }
 
-       /* push matrices and set default viewport and matrix */
+       /* set default viewport */
        glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
        GG.currentfb = fb->object;
        glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
        GG.currentfb = fb->object;
-
-       glMatrixMode(GL_PROJECTION);
-       glPushMatrix();
-       glMatrixMode(GL_MODELVIEW);
-       glPushMatrix();
 }
 
 void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
 }
 
 void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
@@ -260,56 +236,81 @@ void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot)
        
        for (i = 0; i < 4; i++) {
                if (fb->colortex[i]) {
        
        for (i = 0; i < 4; i++) {
                if (fb->colortex[i]) {
-                       attachments[numslots] = GL_COLOR_ATTACHMENT0_EXT + i;
+                       attachments[numslots] = GL_COLOR_ATTACHMENT0 + i;
                        numslots++;
                }
        }
        
        /* push attributes */
                        numslots++;
                }
        }
        
        /* push attributes */
-       glPushAttrib(GL_ENABLE_BIT | GL_VIEWPORT_BIT);
+       gpuSaveState(&fb->attribs, GPU_ENABLE_BIT | GPU_VIEWPORT_BIT);
        glDisable(GL_SCISSOR_TEST);
 
        /* bind framebuffer */
        glDisable(GL_SCISSOR_TEST);
 
        /* bind framebuffer */
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
 
        /* last bound prevails here, better allow explicit control here too */
        glDrawBuffers(numslots, attachments);
 
        /* last bound prevails here, better allow explicit control here too */
        glDrawBuffers(numslots, attachments);
-       glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+       glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
 
 
-       /* push matrices and set default viewport and matrix */
+       /* set default viewport */
        glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
        GG.currentfb = fb->object;
        glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
        GG.currentfb = fb->object;
+}
+
+void GPU_framebuffer_bind(GPUFrameBuffer *fb)
+{
+       int numslots = 0, i;
+       GLenum attachments[4];
+       GLenum readattachement = 0;
+       GPUTexture *tex;
+
+       for (i = 0; i < 4; i++) {
+               if (fb->colortex[i]) {
+                       attachments[numslots] = GL_COLOR_ATTACHMENT0 + i;
+                       tex = fb->colortex[i];
 
 
-       glMatrixMode(GL_PROJECTION);
-       glPushMatrix();
-       glMatrixMode(GL_MODELVIEW);
-       glPushMatrix();
+                       if (!readattachement)
+                               readattachement = GL_COLOR_ATTACHMENT0 + i;
+
+                       numslots++;
+               }
+       }
+
+       /* bind framebuffer */
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+
+       if (numslots == 0) {
+               glDrawBuffer(GL_NONE);
+               glReadBuffer(GL_NONE);
+               tex = fb->depthtex;
+       }
+       else {
+               /* last bound prevails here, better allow explicit control here too */
+               glDrawBuffers(numslots, attachments);
+               glReadBuffer(readattachement);
+       }
+
+       glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
+       GG.currentfb = fb->object;
 }
 
 
 }
 
 
-void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
+void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, GPUTexture *UNUSED(tex))
 {
 {
-       /* restore matrix */
-       glMatrixMode(GL_PROJECTION);
-       glPopMatrix();
-       glMatrixMode(GL_MODELVIEW);
-       glPopMatrix();
-
        /* restore attributes */
        /* restore attributes */
-       glPopAttrib();
+       gpuRestoreState(&fb->attribs);
 }
 
 void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
 {
 }
 
 void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot)
 {
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
        /* last bound prevails here, better allow explicit control here too */
        /* last bound prevails here, better allow explicit control here too */
-       glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
-       glReadBuffer(GL_COLOR_ATTACHMENT0_EXT + slot);
+       glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot);
+       glReadBuffer(GL_COLOR_ATTACHMENT0 + slot);
 
        /* push matrices and set default viewport and matrix */
        glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
        GG.currentfb = fb->object;
 
        /* push matrices and set default viewport and matrix */
        glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot]));
        GG.currentfb = fb->object;
-       GG.currentfb = fb->object;
 }
 
 bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
 }
 
 bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
@@ -319,22 +320,17 @@ bool GPU_framebuffer_bound(GPUFrameBuffer *fb)
 
 bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
 {
 
 bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256])
 {
-       GLenum status;
-       
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
        GG.currentfb = fb->object;
        GG.currentfb = fb->object;
-       
-       /* Clean glError buffer. */
-       while (glGetError() != GL_NO_ERROR) {}
-       
-       status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
-       
-       if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+
+       GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+
+       if (status != GL_FRAMEBUFFER_COMPLETE) {
                GPU_framebuffer_restore();
                gpu_print_framebuffer_error(status, err_out);
                return false;
        }
                GPU_framebuffer_restore();
                gpu_print_framebuffer_error(status, err_out);
                return false;
        }
-       
+
        return true;
 }
 
        return true;
 }
 
@@ -351,10 +347,10 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb)
        }
 
        if (fb->object) {
        }
 
        if (fb->object) {
-               glDeleteFramebuffersEXT(1, &fb->object);
+               glDeleteFramebuffers(1, &fb->object);
 
                if (GG.currentfb == fb->object) {
 
                if (GG.currentfb == fb->object) {
-                       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+                       glBindFramebuffer(GL_FRAMEBUFFER, 0);
                        GG.currentfb = 0;
                }
        }
                        GG.currentfb = 0;
                }
        }
@@ -365,7 +361,7 @@ void GPU_framebuffer_free(GPUFrameBuffer *fb)
 void GPU_framebuffer_restore(void)
 {
        if (GG.currentfb != 0) {
 void GPU_framebuffer_restore(void)
 {
        if (GG.currentfb != 0) {
-               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
+               glBindFramebuffer(GL_FRAMEBUFFER, 0);
                GG.currentfb = 0;
        }
 }
                GG.currentfb = 0;
        }
 }
@@ -374,73 +370,118 @@ void GPU_framebuffer_blur(
         GPUFrameBuffer *fb, GPUTexture *tex,
         GPUFrameBuffer *blurfb, GPUTexture *blurtex)
 {
         GPUFrameBuffer *fb, GPUTexture *tex,
         GPUFrameBuffer *blurfb, GPUTexture *blurtex)
 {
+       const float fullscreencos[4][2] = {{-1.0f, -1.0f}, {1.0f, -1.0f}, {-1.0f, 1.0f}, {1.0f, 1.0f}};
+       const float fullscreenuvs[4][2] = {{0.0f, 0.0f}, {1.0f, 0.0f}, {0.0f, 1.0f}, {1.0f, 1.0f}};
+
+       static VertexFormat format = {0};
+       static VertexBuffer vbo = {{0}};
+       static Batch batch = {{0}};
+
        const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
        const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
 
        GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
        const float scaleh[2] = {1.0f / GPU_texture_width(blurtex), 0.0f};
        const float scalev[2] = {0.0f, 1.0f / GPU_texture_height(tex)};
 
        GPUShader *blur_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SEP_GAUSSIAN_BLUR);
-       int scale_uniform, texture_source_uniform;
 
        if (!blur_shader)
                return;
 
 
        if (!blur_shader)
                return;
 
-       scale_uniform = GPU_shader_get_uniform(blur_shader, "ScaleU");
-       texture_source_uniform = GPU_shader_get_uniform(blur_shader, "textureSource");
+       /* Preparing to draw quad */
+       if (format.attrib_ct == 0) {
+               unsigned int i = 0;
+               /* Vertex format */
+               unsigned int pos = VertexFormat_add_attrib(&format, "pos", COMP_F32, 2, KEEP_FLOAT);
+               unsigned int uvs = VertexFormat_add_attrib(&format, "uvs", COMP_F32, 2, KEEP_FLOAT);
+
+               /* Vertices */
+               VertexBuffer_init_with_format(&vbo, &format);
+               VertexBuffer_allocate_data(&vbo, 36);
+
+               for (int j = 0; j < 3; ++j) {
+                       VertexBuffer_set_attrib(&vbo, uvs, i, fullscreenuvs[j]);
+                       VertexBuffer_set_attrib(&vbo, pos, i++, fullscreencos[j]);
+               }
+               for (int j = 1; j < 4; ++j) {
+                       VertexBuffer_set_attrib(&vbo, uvs, i, fullscreenuvs[j]);
+                       VertexBuffer_set_attrib(&vbo, pos, i++, fullscreencos[j]);
+               }
+
+               Batch_init(&batch, GL_TRIANGLES, &vbo, NULL);
+       }
                
                
-       /* Blurring horizontally */
+       glDisable(GL_DEPTH_TEST);
+       
+       /* Load fresh matrices */
+       gpuMatrixBegin3D(); /* TODO: finish 2D API */
 
 
+       /* Blurring horizontally */
        /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
         * pushing unnecessary matrices onto the OpenGL stack. */
        /* We do the bind ourselves rather than using GPU_framebuffer_texture_bind() to avoid
         * pushing unnecessary matrices onto the OpenGL stack. */
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, blurfb->object);
-       glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+       glBindFramebuffer(GL_FRAMEBUFFER, blurfb->object);
+       glDrawBuffer(GL_COLOR_ATTACHMENT0);
        
        /* avoid warnings from texture binding */
        GG.currentfb = blurfb->object;
 
        
        /* avoid warnings from texture binding */
        GG.currentfb = blurfb->object;
 
-       GPU_shader_bind(blur_shader);
-       GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scaleh);
-       GPU_shader_uniform_texture(blur_shader, texture_source_uniform, tex);
        glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
 
        glViewport(0, 0, GPU_texture_width(blurtex), GPU_texture_height(blurtex));
 
-       /* Preparing to draw quad */
-       glMatrixMode(GL_TEXTURE);
-       glLoadIdentity();
-       glMatrixMode(GL_PROJECTION);
-       glLoadIdentity();
-       glMatrixMode(GL_MODELVIEW);
-       glLoadIdentity();
-
-       glDisable(GL_DEPTH_TEST);
-
        GPU_texture_bind(tex, 0);
 
        GPU_texture_bind(tex, 0);
 
-       /* Drawing quad */
-       glBegin(GL_QUADS);
-       glTexCoord2d(0, 0); glVertex2f(1, 1);
-       glTexCoord2d(1, 0); glVertex2f(-1, 1);
-       glTexCoord2d(1, 1); glVertex2f(-1, -1);
-       glTexCoord2d(0, 1); glVertex2f(1, -1);
-       glEnd();
+       Batch_set_builtin_program(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR);
+       Batch_Uniform2f(&batch, "ScaleU", scaleh[0], scaleh[1]);
+       Batch_Uniform1i(&batch, "textureSource", GL_TEXTURE0);
+       Batch_draw(&batch);
 
        /* Blurring vertically */
 
        /* Blurring vertically */
-
-       glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, fb->object);
-       glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+       glBindFramebuffer(GL_FRAMEBUFFER, fb->object);
+       glDrawBuffer(GL_COLOR_ATTACHMENT0);
        
        GG.currentfb = fb->object;
        
        glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
        
        GG.currentfb = fb->object;
        
        glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex));
-       GPU_shader_uniform_vector(blur_shader, scale_uniform, 2, 1, scalev);
-       GPU_shader_uniform_texture(blur_shader, texture_source_uniform, blurtex);
+
        GPU_texture_bind(blurtex, 0);
 
        GPU_texture_bind(blurtex, 0);
 
-       glBegin(GL_QUADS);
-       glTexCoord2d(0, 0); glVertex2f(1, 1);
-       glTexCoord2d(1, 0); glVertex2f(-1, 1);
-       glTexCoord2d(1, 1); glVertex2f(-1, -1);
-       glTexCoord2d(0, 1); glVertex2f(1, -1);
-       glEnd();
+       /* Hack to make the following uniform stick */
+       Batch_set_builtin_program(&batch, GPU_SHADER_SEP_GAUSSIAN_BLUR);
+       Batch_Uniform2f(&batch, "ScaleU", scalev[0], scalev[1]);
+       Batch_Uniform1i(&batch, "textureSource", GL_TEXTURE0);
+       Batch_draw(&batch);
 
 
-       GPU_shader_unbind();
+       gpuMatrixEnd();
+}
+
+void GPU_framebuffer_blit(GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, int write_slot, bool use_depth)
+{
+       GPUTexture *read_tex = (use_depth) ? fb_read->depthtex : fb_read->colortex[read_slot];
+       GPUTexture *write_tex = (use_depth) ? fb_write->depthtex : fb_write->colortex[write_slot];
+       int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex);
+       int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex);
+       int read_bind = GPU_texture_opengl_bindcode(read_tex);
+       int write_bind = GPU_texture_opengl_bindcode(write_tex);
+       const int read_w = GPU_texture_width(read_tex);
+       const int read_h = GPU_texture_height(read_tex);
+       const int write_w = GPU_texture_width(write_tex);
+       const int write_h = GPU_texture_height(write_tex);
+
+       /* read from multi-sample buffer */
+       glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object);
+       glFramebufferTexture2D(
+               GL_READ_FRAMEBUFFER, read_attach,
+               GL_TEXTURE_2D, read_bind, 0);
+       BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+
+       /* write into new single-sample buffer */
+       glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object);
+       glFramebufferTexture2D(
+               GL_DRAW_FRAMEBUFFER, write_attach,
+               GL_TEXTURE_2D, write_bind, 0);
+       BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+
+       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);
+
+       /* Restore previous framebuffer */
+       glBindFramebuffer(GL_FRAMEBUFFER, GG.currentfb);
+       glDrawBuffer(GL_COLOR_ATTACHMENT0);
 }
 
 /* GPUOffScreen */
 }
 
 /* GPUOffScreen */
@@ -464,12 +505,7 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_
        }
 
        if (samples) {
        }
 
        if (samples) {
-               if (!GLEW_EXT_framebuffer_multisample ||
-                   !GLEW_ARB_texture_multisample ||
-                   /* Only needed for GPU_offscreen_read_pixels.
-                    * We could add an arg if we intend to use multi-sample
-                    * offscreen buffers w/o reading their pixels */
-                   !GLEW_EXT_framebuffer_blit ||
+               if (!GLEW_ARB_texture_multisample ||
                    /* This is required when blitting from a multi-sampled buffers,
                     * even though we're not scaling. */
                    !GLEW_EXT_framebuffer_multisample_blit_scaled)
                    /* This is required when blitting from a multi-sampled buffers,
                     * even though we're not scaling. */
                    !GLEW_EXT_framebuffer_multisample_blit_scaled)
@@ -484,18 +520,18 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, char err_
                return NULL;
        }
 
                return NULL;
        }
 
-       if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, err_out)) {
+       if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0)) {
                GPU_offscreen_free(ofs);
                return NULL;
        }
 
                GPU_offscreen_free(ofs);
                return NULL;
        }
 
-       ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, GPU_HDR_NONE, samples, err_out);
+       ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out);
        if (!ofs->color) {
                GPU_offscreen_free(ofs);
                return NULL;
        }
 
        if (!ofs->color) {
                GPU_offscreen_free(ofs);
                return NULL;
        }
 
-       if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, err_out)) {
+       if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0)) {
                GPU_offscreen_free(ofs);
                return NULL;
        }
                GPU_offscreen_free(ofs);
                return NULL;
        }
@@ -569,37 +605,37 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
 
 #ifdef USE_FBO_CTX_SWITCH
                /* read from multi-sample buffer */
 
 #ifdef USE_FBO_CTX_SWITCH
                /* read from multi-sample buffer */
-               glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, ofs->color->fb->object);
-               glFramebufferTexture2DEXT(
-                       GL_READ_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT + ofs->color->fb_attachment,
+               glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object);
+               glFramebufferTexture2D(
+                       GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment,
                        GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
                        GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0);
-               status = glCheckFramebufferStatusEXT(GL_READ_FRAMEBUFFER_EXT);
-               if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+               status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER);
+               if (status != GL_FRAMEBUFFER_COMPLETE) {
                        goto finally;
                }
 #endif
 
                /* write into new single-sample buffer */
                        goto finally;
                }
 #endif
 
                /* write into new single-sample buffer */
-               glGenFramebuffersEXT(1, &fbo_blit);
-               glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER_EXT, fbo_blit);
-               glFramebufferTexture2DEXT(
-                       GL_DRAW_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT,
+               glGenFramebuffers(1, &fbo_blit);
+               glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit);
+               glFramebufferTexture2D(
+                       GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
                        GL_TEXTURE_2D, tex_blit, 0);
                        GL_TEXTURE_2D, tex_blit, 0);
-               status = glCheckFramebufferStatusEXT(GL_DRAW_FRAMEBUFFER_EXT);
-               if (status != GL_FRAMEBUFFER_COMPLETE_EXT) {
+               status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER);
+               if (status != GL_FRAMEBUFFER_COMPLETE) {
                        goto finally;
                }
 
                /* perform the copy */
                        goto finally;
                }
 
                /* perform the copy */
-               glBlitFramebufferEXT(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+               glBlitFramebuffer(0, 0, w, h, 0, 0, w, h, GL_COLOR_BUFFER_BIT, GL_NEAREST);
 
                /* read the results */
 
                /* read the results */
-               glBindFramebufferEXT(GL_READ_FRAMEBUFFER_EXT, fbo_blit);
+               glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit);
                glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
 
 #ifdef USE_FBO_CTX_SWITCH
                /* restore the original frame-bufer */
                glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
 
 #ifdef USE_FBO_CTX_SWITCH
                /* restore the original frame-bufer */
-               glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, ofs->color->fb->object);
+               glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object);
 #undef USE_FBO_CTX_SWITCH
 #endif
 
 #undef USE_FBO_CTX_SWITCH
 #endif
 
@@ -610,10 +646,8 @@ finally:
                        glDeleteTextures(1, &tex_blit);
                }
                if (fbo_blit) {
                        glDeleteTextures(1, &tex_blit);
                }
                if (fbo_blit) {
-                       glDeleteFramebuffersEXT(1, &fbo_blit);
+                       glDeleteFramebuffers(1, &fbo_blit);
                }
                }
-
-               GPU_ASSERT_NO_GL_ERRORS("Read Multi-Sample Pixels");
        }
        else {
                glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);
        }
        else {
                glReadPixels(0, 0, w, h, GL_RGBA, type, pixels);