Merge branch 'master' into blender2.8
[blender.git] / source / blender / gpu / intern / gpu_draw.c
index d7e744951c483e94c3b6bf8f383e1c08be2ed6f1..ca569d68dee13a2d8e063577bf414a18c911dbc5 100644 (file)
@@ -38,8 +38,6 @@
 
 #include <string.h>
 
-#include "GPU_glew.h"
-
 #include "BLI_blenlib.h"
 #include "BLI_hash.h"
 #include "BLI_linklist.h"
@@ -81,6 +79,7 @@
 #include "GPU_draw.h"
 #include "GPU_extensions.h"
 #include "GPU_material.h"
+#include "GPU_matrix.h"
 #include "GPU_shader.h"
 #include "GPU_texture.h"
 
@@ -109,23 +108,27 @@ static void gpu_mcol(unsigned int ucol)
 }
 
 void GPU_render_text(
-        MTexPoly *mtexpoly, int mode,
-        const char *textstr, int textlen, unsigned int *col,
+        int mode, const char *textstr, int textlen, unsigned int *col,
         const float *v_quad[4], const float *uv_quad[4],
         int glattrib)
 {
-       if ((mode & GEMAT_TEXT) && (textlen > 0) && mtexpoly->tpage) {
+       /* XXX, 2.8 removes texface */
+#if 0
+       Image *ima = mtexpoly->tpage;
+#else
+       Image *ima = NULL;
+#endif
+       if ((mode & GEMAT_TEXT) && (textlen > 0) && ima) {
                const float *v1 = v_quad[0];
                const float *v2 = v_quad[1];
                const float *v3 = v_quad[2];
                const float *v4 = v_quad[3];
-               Image *ima = (Image *)mtexpoly->tpage;
                const size_t textlen_st = textlen;
                float centerx, centery, sizex, sizey, transx, transy, movex, movey, advance;
-               
+
                /* multiline */
                float line_start = 0.0f, line_height;
-               
+
                if (v4)
                        line_height = max_ffff(v1[1], v2[1], v3[1], v4[2]) - min_ffff(v1[1], v2[1], v3[1], v4[2]);
                else
@@ -133,50 +136,48 @@ void GPU_render_text(
                line_height *= 1.2f; /* could be an option? */
                /* end multiline */
 
-               
+
                /* color has been set */
-               if (mtexpoly->mode & TF_OBCOL)
-                       col = NULL;
-               else if (!col)
+               if (!col)
                        glColor3f(1.0f, 1.0f, 1.0f);
 
-               glPushMatrix();
-               
+               gpuPushMatrix();
+
                /* get the tab width */
                ImBuf *first_ibuf = BKE_image_get_first_ibuf(ima);
                matrixGlyph(first_ibuf, ' ', &centerx, &centery,
-                       &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
-               
+                   &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
+
                float advance_tab = advance * 4; /* tab width could also be an option */
-               
-               
+
+
                for (size_t index = 0; index < textlen_st; ) {
                        unsigned int character;
                        float uv[4][2];
 
                        /* lets calculate offset stuff */
                        character = BLI_str_utf8_as_unicode_and_size_safe(textstr + index, &index);
-                       
+
                        if (character == '\n') {
-                               glTranslatef(line_start, -line_height, 0.0f);
+                               gpuTranslate2f(line_start, -line_height);
                                line_start = 0.0f;
                                continue;
                        }
                        else if (character == '\t') {
-                               glTranslatef(advance_tab, 0.0f, 0.0f);
+                               gpuTranslate2f(advance_tab, 0.0f);
                                line_start -= advance_tab; /* so we can go back to the start of the line */
                                continue;
-                               
+
                        }
                        else if (character > USHRT_MAX) {
                                /* not much we can do here bmfonts take ushort */
                                character = '?';
                        }
-                       
+
                        /* space starts at offset 1 */
                        /* character = character - ' ' + 1; */
                        matrixGlyph(first_ibuf, character, & centerx, &centery,
-                               &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
+                           &sizex, &sizey, &transx, &transy, &movex, &movey, &advance);
 
                        uv[0][0] = (uv_quad[0][0] - centerx) * sizex + transx;
                        uv[0][1] = (uv_quad[0][1] - centery) * sizey + transy;
@@ -184,13 +185,13 @@ void GPU_render_text(
                        uv[1][1] = (uv_quad[1][1] - centery) * sizey + transy;
                        uv[2][0] = (uv_quad[2][0] - centerx) * sizex + transx;
                        uv[2][1] = (uv_quad[2][1] - centery) * sizey + transy;
-                       
+
                        glBegin(GL_POLYGON);
                        if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[0]);
                        else glTexCoord2fv(uv[0]);
                        if (col) gpu_mcol(col[0]);
                        glVertex3f(sizex * v1[0] + movex, sizey * v1[1] + movey, v1[2]);
-                       
+
                        if (glattrib >= 0) glVertexAttrib2fv(glattrib, uv[1]);
                        else glTexCoord2fv(uv[1]);
                        if (col) gpu_mcol(col[1]);
@@ -212,28 +213,29 @@ void GPU_render_text(
                        }
                        glEnd();
 
-                       glTranslatef(advance, 0.0f, 0.0f);
+                       gpuTranslate2f(advance, 0.0f);
                        line_start -= advance; /* so we can go back to the start of the line */
                }
-               glPopMatrix();
+               gpuPopMatrix();
 
                BKE_image_release_ibuf(ima, first_ibuf, NULL);
        }
 }
 
 /* Checking powers of two for images since OpenGL ES requires it */
-
+#ifdef WITH_DDS
 static bool is_power_of_2_resolution(int w, int h)
 {
        return is_power_of_2_i(w) && is_power_of_2_i(h);
 }
+#endif
 
 static bool is_over_resolution_limit(GLenum textarget, int w, int h)
 {
        int size = (textarget == GL_TEXTURE_2D) ?
                GPU_max_texture_size() : GPU_max_cube_map_size();
        int reslimit = (U.glreslimit != 0) ?
-               min_ii(U.glreslimit, size) : size;
+           min_ii(U.glreslimit, size) : size;
 
        return (w > reslimit || h > reslimit);
 }
@@ -269,8 +271,7 @@ static struct GPUTextureState {
        int alphablend;
        float anisotropic;
        int gpu_mipmap;
-       MTexPoly *lasttface;
-} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0, NULL};
+} GTS = {0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL, 1, 0, 0, -1, 1.0f, 0};
 
 /* Mipmap settings */
 
@@ -279,36 +280,13 @@ void GPU_set_gpu_mipmapping(int gpu_mipmap)
        int old_value = GTS.gpu_mipmap;
 
        /* only actually enable if it's supported */
-       GTS.gpu_mipmap = gpu_mipmap && GLEW_EXT_framebuffer_object;
+       GTS.gpu_mipmap = gpu_mipmap;
 
        if (old_value != GTS.gpu_mipmap) {
                GPU_free_images();
        }
 }
 
-static void gpu_generate_mipmap(GLenum target)
-{
-       const bool is_ati = GPU_type_matches(GPU_DEVICE_ATI, GPU_OS_ANY, GPU_DRIVER_ANY);
-       int target_enabled = 0;
-
-       /* work around bug in ATI driver, need to have GL_TEXTURE_2D enabled
-        * http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation */
-       if (is_ati) {
-               target_enabled = glIsEnabled(target);
-               if (!target_enabled)
-                       glEnable(target);
-       }
-
-       /* TODO: simplify when we transition to GL >= 3 */
-       if (GLEW_VERSION_3_0 || GLEW_ARB_framebuffer_object)
-               glGenerateMipmap(target);
-       else if (GLEW_EXT_framebuffer_object)
-               glGenerateMipmapEXT(target);
-
-       if (is_ati && !target_enabled)
-               glDisable(target);
-}
-
 void GPU_set_mipmap(bool mipmap)
 {
        if (GTS.domipmap != mipmap) {
@@ -415,43 +393,16 @@ static unsigned int *gpu_get_image_bindcode(Image *ima, GLenum textarget)
        return bind;
 }
 
-void GPU_clear_tpage(bool force)
-{
-       if (GTS.lasttface == NULL && !force)
-               return;
-       
-       GTS.lasttface = NULL;
-       GTS.curtile = 0;
-       GTS.curima = NULL;
-       if (GTS.curtilemode != 0) {
-               glMatrixMode(GL_TEXTURE);
-               glLoadIdentity();
-               glMatrixMode(GL_MODELVIEW);
-       }
-       GTS.curtilemode = 0;
-       GTS.curtileXRep = 0;
-       GTS.curtileYRep = 0;
-       GTS.alphablend = -1;
-       
-       glDisable(GL_BLEND);
-       glDisable(GL_TEXTURE_2D);
-       glDisable(GL_TEXTURE_GEN_S);
-       glDisable(GL_TEXTURE_GEN_T);
-       glDisable(GL_ALPHA_TEST);
-}
-
 static void gpu_set_alpha_blend(GPUBlendMode alphablend)
 {
        if (alphablend == GPU_BLEND_SOLID) {
                glDisable(GL_BLEND);
-               glDisable(GL_ALPHA_TEST);
                glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
-               glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+               glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
        }
        else if (alphablend == GPU_BLEND_ADD) {
                glEnable(GL_BLEND);
                glBlendFunc(GL_ONE, GL_ONE);
-               glDisable(GL_ALPHA_TEST);
                glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
        }
        else if (ELEM(alphablend, GPU_BLEND_ALPHA, GPU_BLEND_ALPHA_SORT)) {
@@ -460,59 +411,20 @@ static void gpu_set_alpha_blend(GPUBlendMode alphablend)
 
                /* for OpenGL render we use the alpha channel, this makes alpha blend correct */
                glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-               
+
                /* if U.glalphaclip == 1.0, some cards go bonkers...
                 * turn off alpha test in this case */
 
-               /* added after 2.45 to clip alpha */
-               if (U.glalphaclip == 1.0f) {
-                       glDisable(GL_ALPHA_TEST);
-               }
-               else {
-                       glEnable(GL_ALPHA_TEST);
-                       glAlphaFunc(GL_GREATER, U.glalphaclip);
-               }
        }
        else if (alphablend == GPU_BLEND_CLIP) {
                glDisable(GL_BLEND);
                glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE);
-               glEnable(GL_ALPHA_TEST);
-               glAlphaFunc(GL_GREATER, 0.5f);
        }
        else if (alphablend == GPU_BLEND_ALPHA_TO_COVERAGE) {
-               glEnable(GL_ALPHA_TEST);
-               glAlphaFunc(GL_GREATER, U.glalphaclip);
                glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE);
        }
 }
 
-static void gpu_verify_alpha_blend(int alphablend)
-{
-       /* verify alpha blending modes */
-       if (GTS.alphablend == alphablend)
-               return;
-
-       gpu_set_alpha_blend(alphablend);
-       GTS.alphablend = alphablend;
-}
-
-static void gpu_verify_reflection(Image *ima)
-{
-       if (ima && (ima->flag & IMA_REFLECT)) {
-               /* enable reflection mapping */
-               glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-               glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-
-               glEnable(GL_TEXTURE_GEN_S);
-               glEnable(GL_TEXTURE_GEN_T);
-       }
-       else {
-               /* disable reflection mapping */
-               glDisable(GL_TEXTURE_GEN_S);
-               glDisable(GL_TEXTURE_GEN_T);
-       }
-}
-
 typedef struct VerifyThreadData {
        ImBuf *ibuf;
        float *srgb_frect;
@@ -534,8 +446,6 @@ static void gpu_verify_high_bit_srgb_buffer_slice(float *srgb_frect,
                                    ibuf->x, height,
                                    ibuf->x, ibuf->x);
        IMB_buffer_float_unpremultiply(current_srgb_frect, ibuf->x, height);
-       /* Clamp buffer colors to 1.0 to avoid artifacts due to glu for hdr images. */
-       IMB_buffer_float_clamp(current_srgb_frect, ibuf->x, height);
 }
 
 static void verify_thread_do(void *data_v,
@@ -604,19 +514,6 @@ int GPU_verify_image(
                return (ima != NULL);
        }
 
-       /* if tiling mode or repeat changed, change texture matrix to fit */
-       if (GTS.tilemode != GTS.curtilemode || GTS.curtileXRep != GTS.tileXRep ||
-           GTS.curtileYRep != GTS.tileYRep)
-       {
-               glMatrixMode(GL_TEXTURE);
-               glLoadIdentity();
-
-               if (ima && (ima->tpageflag & IMA_TILES))
-                       glScalef(ima->xrep, ima->yrep, 1.0f);
-
-               glMatrixMode(GL_MODELVIEW);
-       }
-
        /* check if we have a valid image */
        if (ima == NULL || ima->ok == 0)
                return 0;
@@ -652,29 +549,29 @@ int GPU_verify_image(
                GPU_free_image(ima);
                ima->tpageflag &= ~IMA_TPAGE_REFRESH;
        }
-       
+
        if (GTS.tilemode) {
                /* tiled mode */
                if (ima->repbind == NULL) gpu_make_repbind(ima);
                if (GTS.tile >= ima->totbind) GTS.tile = 0;
-               
+
                /* this happens when you change repeat buttons */
                if (ima->repbind && textarget == GL_TEXTURE_2D) bind = &ima->repbind[GTS.tile];
                else bind = gpu_get_image_bindcode(ima, textarget);
-               
+
                if (*bind == 0) {
                        short texwindx = ibuf->x / ima->xrep;
                        short texwindy = ibuf->y / ima->yrep;
-                       
+
                        if (GTS.tile >= ima->xrep * ima->yrep)
                                GTS.tile = ima->xrep * ima->yrep - 1;
-       
+
                        short texwinsy = GTS.tile / ima->xrep;
                        short texwinsx = GTS.tile - texwinsy * ima->xrep;
-       
+
                        texwinsx *= texwindx;
                        texwinsy *= texwindy;
-       
+
                        tpx = texwindx;
                        tpy = texwindy;
 
@@ -748,7 +645,7 @@ int GPU_verify_image(
 
                                memcpy(tilerectrow, rectrow, tpx * sizeof(*rectrow));
                        }
-                       
+
                        rect = tilerect;
                }
        }
@@ -759,13 +656,13 @@ int GPU_verify_image(
        else
 #endif
                GPU_create_gl_tex(bind, rect, frect, rectw, recth, textarget, mipmap, use_high_bit_depth, ima);
-       
+
        /* mark as non-color data texture */
        if (*bind) {
                if (is_data)
-                       ima->tpageflag |= IMA_GLBIND_IS_DATA;   
+                       ima->tpageflag |= IMA_GLBIND_IS_DATA;
                else
-                       ima->tpageflag &= ~IMA_GLBIND_IS_DATA;  
+                       ima->tpageflag &= ~IMA_GLBIND_IS_DATA;
        }
 
        /* clean up */
@@ -858,30 +755,6 @@ void GPU_create_gl_tex(
        int tpx = rectw;
        int tpy = recth;
 
-       /* scale if not a power of two. this is not strictly necessary for newer
-        * GPUs (OpenGL version >= 2.0) since they support non-power-of-two-textures 
-        * Then don't bother scaling for hardware that supports NPOT textures! */
-       if (textarget == GL_TEXTURE_2D &&
-           ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(rectw, recth)) ||
-            is_over_resolution_limit(textarget, rectw, recth)))
-       {
-               rectw = smaller_power_of_2_limit(rectw);
-               recth = smaller_power_of_2_limit(recth);
-
-               if (use_high_bit_depth) {
-                       ibuf = IMB_allocFromBuffer(NULL, frect, tpx, tpy);
-                       IMB_scaleImBuf(ibuf, rectw, recth);
-
-                       frect = ibuf->rect_float;
-               }
-               else {
-                       ibuf = IMB_allocFromBuffer(rect, NULL, tpx, tpy);
-                       IMB_scaleImBuf(ibuf, rectw, recth);
-
-                       rect = ibuf->rect;
-               }
-       }
-
        /* create image */
        glGenTextures(1, (GLuint *)bind);
        glBindTexture(textarget, *bind);
@@ -900,7 +773,7 @@ void GPU_create_gl_tex(
 
                if (GPU_get_mipmap() && mipmap) {
                        if (GTS.gpu_mipmap) {
-                               gpu_generate_mipmap(GL_TEXTURE_2D);
+                               glGenerateMipmap(GL_TEXTURE_2D);
                        }
                        else {
                                int i;
@@ -951,7 +824,7 @@ void GPU_create_gl_tex(
 
                        if (GPU_get_mipmap() && mipmap) {
                                if (GTS.gpu_mipmap) {
-                                       gpu_generate_mipmap(GL_TEXTURE_CUBE_MAP);
+                                       glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
                                }
                                else {
                                        if (!ibuf) {
@@ -975,7 +848,7 @@ void GPU_create_gl_tex(
                                                if (mip_cube_map) {
                                                        for (int j = 0; j < 6; j++) {
                                                                glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + j, i,
-                                                                       informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
+                                                                   informat, mipw, miph, 0, GL_RGBA, type, mip_cube_map[j]);
                                                        }
                                                }
                                                gpu_del_cube_map(mip_cube_map);
@@ -1056,7 +929,7 @@ bool GPU_upload_dxt_texture(ImBuf *ibuf)
                size = ((width + 3) / 4) * ((height + 3) / 4) * blocksize;
 
                glCompressedTexImage2D(GL_TEXTURE_2D, i, format, width, height,
-                       0, size, ibuf->dds_data.data + offset);
+                   0, size, ibuf->dds_data.data + offset);
 
                offset += size;
                width >>= 1;
@@ -1091,62 +964,6 @@ void GPU_create_gl_tex_compressed(
        }
 #endif
 }
-static void gpu_verify_repeat(Image *ima)
-{
-       /* set either clamp or repeat in X/Y */
-       if (ima->tpageflag & IMA_CLAMP_U)
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-       else
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-
-       if (ima->tpageflag & IMA_CLAMP_V)
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-       else
-               glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-}
-
-int GPU_set_tpage(MTexPoly *mtexpoly, int mipmap, int alphablend)
-{
-       /* check if we need to clear the state */
-       if (mtexpoly == NULL) {
-               GPU_clear_tpage(false);
-               return 0;
-       }
-
-       Image *ima = mtexpoly->tpage;
-       GTS.lasttface = mtexpoly;
-
-       gpu_verify_alpha_blend(alphablend);
-       gpu_verify_reflection(ima);
-
-       if (GPU_verify_image(ima, NULL, GL_TEXTURE_2D, mtexpoly->tile, 1, mipmap, false)) {
-               GTS.curtile = GTS.tile;
-               GTS.curima = GTS.ima;
-               GTS.curtilemode = GTS.tilemode;
-               GTS.curtileXRep = GTS.tileXRep;
-               GTS.curtileYRep = GTS.tileYRep;
-
-               glEnable(GL_TEXTURE_2D);
-       }
-       else {
-               glDisable(GL_TEXTURE_2D);
-               
-               GTS.curtile = 0;
-               GTS.curima = NULL;
-               GTS.curtilemode = 0;
-               GTS.curtileXRep = 0;
-               GTS.curtileYRep = 0;
-
-               return 0;
-       }
-       
-       gpu_verify_repeat(ima);
-       
-       /* Did this get lost in the image recode? */
-       /* BKE_image_tag_time(ima);*/
-
-       return 1;
-}
 
 /* these two functions are called on entering and exiting texture paint mode,
  * temporary disabling/enabling mipmapping on all images for quick texture
@@ -1206,9 +1023,7 @@ void GPU_paint_set_mipmap(bool mipmap)
 /* check if image has been downscaled and do scaled partial update */
 static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x, int y, int w, int h)
 {
-       if ((!GPU_full_non_power_of_two_support() && !is_power_of_2_resolution(ibuf->x, ibuf->y)) ||
-           is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y))
-       {
+       if (is_over_resolution_limit(GL_TEXTURE_2D, ibuf->x, ibuf->y)) {
                int x_limit = smaller_power_of_2_limit(ibuf->x);
                int y_limit = smaller_power_of_2_limit(ibuf->y);
 
@@ -1261,7 +1076,7 @@ static bool gpu_check_scaled_image(ImBuf *ibuf, Image *ima, float *frect, int x,
                }
 
                if (GPU_get_mipmap()) {
-                       gpu_generate_mipmap(GL_TEXTURE_2D);
+                       glGenerateMipmap(GL_TEXTURE_2D);
                }
                else {
                        ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@ -1296,7 +1111,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
                        float *buffer = MEM_mallocN(w * h * sizeof(float) * 4, "temp_texpaint_float_buf");
                        bool is_data = (ima->tpageflag & IMA_GLBIND_IS_DATA) != 0;
                        IMB_partial_rect_from_float(ibuf, buffer, x, y, w, h, is_data);
-                       
+
                        if (gpu_check_scaled_image(ibuf, ima, buffer, x, y, w, h)) {
                                MEM_freeN(buffer);
                                BKE_image_release_ibuf(ima, ibuf, NULL);
@@ -1311,7 +1126,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
                        /* we have already accounted for the case where GTS.gpu_mipmap is false
                         * so we will be using GPU mipmap generation here */
                        if (GPU_get_mipmap()) {
-                               gpu_generate_mipmap(GL_TEXTURE_2D);
+                               glGenerateMipmap(GL_TEXTURE_2D);
                        }
                        else {
                                ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@ -1337,7 +1152,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
                glPixelStorei(GL_UNPACK_SKIP_ROWS, y);
 
                glTexSubImage2D(GL_TEXTURE_2D, 0, x, y, w, h, GL_RGBA,
-                       GL_UNSIGNED_BYTE, ibuf->rect);
+                   GL_UNSIGNED_BYTE, ibuf->rect);
 
                glPixelStorei(GL_UNPACK_ROW_LENGTH, row_length);
                glPixelStorei(GL_UNPACK_SKIP_PIXELS, skip_pixels);
@@ -1345,7 +1160,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i
 
                /* see comment above as to why we are using gpu mipmap generation here */
                if (GPU_get_mipmap()) {
-                       gpu_generate_mipmap(GL_TEXTURE_2D);
+                       glGenerateMipmap(GL_TEXTURE_2D);
                }
                else {
                        ima->tpageflag &= ~IMA_MIPMAP_COMPLETE;
@@ -1361,9 +1176,9 @@ void GPU_update_images_framechange(void)
                if (ima->tpageflag & IMA_TWINANIM) {
                        if (ima->twend >= ima->xrep * ima->yrep)
                                ima->twend = ima->xrep * ima->yrep - 1;
-               
+
                        /* check: is bindcode not in the array? free. (to do) */
-                       
+
                        ima->lastframe++;
                        if (ima->lastframe > ima->twend)
                                ima->lastframe = ima->twsta;
@@ -1386,9 +1201,9 @@ int GPU_update_image_time(Image *ima, double time)
 
        if (ima->tpageflag & IMA_TWINANIM) {
                if (ima->twend >= ima->xrep * ima->yrep) ima->twend = ima->xrep * ima->yrep - 1;
-               
+
                /* check: is the bindcode not in the array? Then free. (still to do) */
-               
+
                float diff = (float)((float)time - ima->lastupdate);
                inc = (int)(diff * (float)ima->animspeed);
 
@@ -1437,31 +1252,60 @@ void GPU_create_smoke(SmokeModifierData *smd, int highres)
                        if (smoke_has_colors(sds->fluid)) {
                                float *data = MEM_callocN(sizeof(float) * sds->total_cells * 4, "smokeColorTexture");
                                smoke_get_rgba(sds->fluid, data, 0);
-                               sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 4, data);
+                               sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], data, NULL);
                                MEM_freeN(data);
                        }
                        /* density only */
                        else {
-                               sds->tex = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_density(sds->fluid));
+                               sds->tex = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+                                                                GPU_R8, smoke_get_density(sds->fluid), NULL);
+
+                               /* Swizzle the RGBA components to read the Red channel so
+                                * that the shader stay the same for colored and non color
+                                * density textures. */
+                               GPU_texture_bind(sds->tex, 0);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
+                               GPU_texture_unbind(sds->tex);
                        }
-                       sds->tex_flame = (smoke_has_fuel(sds->fluid)) ? GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, smoke_get_flame(sds->fluid)) : NULL;
+                       sds->tex_flame = (smoke_has_fuel(sds->fluid)) ?
+                                         GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+                                         GPU_R8, smoke_get_flame(sds->fluid), NULL) :
+                                         NULL;
                }
                else if (!sds->tex && highres) {
                        /* rgba texture for color + density */
                        if (smoke_turbulence_has_colors(sds->wt)) {
                                float *data = MEM_callocN(sizeof(float) * smoke_turbulence_get_cells(sds->wt) * 4, "smokeColorTexture");
                                smoke_turbulence_get_rgba(sds->wt, data, 0);
-                               sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 4, data);
+                               sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], data, NULL);
                                MEM_freeN(data);
                        }
                        /* density only */
                        else {
-                               sds->tex = GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_density(sds->wt));
+                               sds->tex = GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
+                                                                       GPU_R8, smoke_turbulence_get_density(sds->wt), NULL);
+
+                               /* Swizzle the RGBA components to read the Red channel so
+                                * that the shader stay the same for colored and non color
+                                * density textures. */
+                               GPU_texture_bind(sds->tex, 0);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED);
+                               glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED);
+                               GPU_texture_unbind(sds->tex);
                        }
-                       sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ? GPU_texture_create_3D(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1, smoke_turbulence_get_flame(sds->wt)) : NULL;
+                       sds->tex_flame = (smoke_turbulence_has_fuel(sds->wt)) ?
+                                         GPU_texture_create_3D_custom(sds->res_wt[0], sds->res_wt[1], sds->res_wt[2], 1,
+                                                                      GPU_R8, smoke_turbulence_get_flame(sds->wt), NULL) :
+                                         NULL;
                }
 
-               sds->tex_shadow = GPU_texture_create_3D(sds->res[0], sds->res[1], sds->res[2], 1, sds->shadow);
+               sds->tex_shadow = GPU_texture_create_3D_custom(sds->res[0], sds->res[1], sds->res[2], 1,
+                                                       GPU_R8, sds->shadow, NULL);
        }
 #else // WITH_SMOKE
        (void)highres;
@@ -1528,7 +1372,7 @@ void GPU_free_image(Image *ima)
        /* free repeated image binding */
        if (ima->repbind) {
                glDeleteTextures(ima->totbind, (GLuint *)ima->repbind);
-       
+
                MEM_freeN(ima->repbind);
                ima->repbind = NULL;
        }
@@ -1601,7 +1445,7 @@ typedef struct GPUMaterialFixed {
        float spec[3];
        int hard;
        float alpha;
-} GPUMaterialFixed; 
+} GPUMaterialFixed;
 
 static struct GPUMaterialState {
        GPUMaterialFixed (*matbuf);
@@ -1616,10 +1460,10 @@ static struct GPUMaterialState {
        Material *gmatbuf_fixed[FIXEDMAT];
        Material *gboundmat;
        Object *gob;
+       eObjectMode gob_object_mode;
        DupliObject *dob;
        Scene *gscene;
        int glay;
-       bool gscenelock;
        float (*gviewmat)[4];
        float (*gviewinv)[4];
        float (*gviewcamtexcofac);
@@ -1657,12 +1501,12 @@ static void gpu_material_to_fixed(
                copy_v3_v3(smat->spec, &bmat->specr);
                smat->alpha = 1.0f;
                smat->hard = CLAMPIS(bmat->har, 0, 128);
-               
+
                if (dimdown) {
                        mul_v3_fl(smat->diff, 0.8f);
                        mul_v3_fl(smat->spec, 0.5f);
                }
-               
+
                if (gamma) {
                        linearrgb_to_srgb_v3_v3(smat->diff, smat->diff);
                        linearrgb_to_srgb_v3_v3(smat->spec, smat->spec);
@@ -1673,7 +1517,7 @@ static void gpu_material_to_fixed(
 
                if (bmat->shade_flag & MA_OBCOLOR)
                        mul_v3_v3(smat->diff, ob->col);
-               
+
                mul_v3_v3fl(smat->spec, &bmat->specr, bmat->spec);
                smat->hard = CLAMPIS(bmat->har, 1, 128);
                smat->alpha = 1.0f;
@@ -1710,8 +1554,8 @@ void GPU_end_dupli_object(void)
 }
 
 void GPU_begin_object_materials(
-        View3D *v3d, RegionView3D *rv3d, Scene *scene, Object *ob,
-        bool glsl, bool *do_alpha_after)
+        View3D *v3d, RegionView3D *rv3d, Scene *scene, ViewLayer *view_layer, Object *ob,
+        bool glsl, const eObjectMode object_mode, bool *do_alpha_after)
 {
        Material *ma;
        GPUMaterial *gpumat;
@@ -1749,8 +1593,10 @@ void GPU_begin_object_materials(
 
 #ifdef WITH_GAMEENGINE
        if (rv3d->rflag & RV3D_IS_GAME_ENGINE) {
-               ob = BKE_object_lod_matob_get(ob, scene);
+               ob = BKE_object_lod_matob_get(ob, view_layer, object_mode);
        }
+#else
+       UNUSED_VARS(view_layer);
 #endif
 
        /* initialize state */
@@ -1771,11 +1617,11 @@ void GPU_begin_object_materials(
                GMS.two_sided_lighting = (((Mesh *)ob->data)->flag & ME_TWOSIDED) != 0;
 
        GMS.gob = ob;
+       GMS.gob_object_mode = object_mode;
        GMS.gscene = scene;
        GMS.is_opensubdiv = use_opensubdiv;
        GMS.totmat = use_matcap ? 1 : ob->totcol + 1;  /* materials start from 1, default material is 0 */
        GMS.glay = (v3d->localvd) ? v3d->localvd->lay : v3d->lay; /* keep lamps visible in local view */
-       GMS.gscenelock = (v3d->scenelock != 0);
        GMS.gviewmat = rv3d->viewmat;
        GMS.gviewinv = rv3d->viewinv;
        GMS.gviewcamtexcofac = rv3d->viewcamtexcofac;
@@ -1789,7 +1635,7 @@ void GPU_begin_object_materials(
        GMS.is_alpha_pass = (v3d->transp != false);
        if (GMS.use_alpha_pass)
                *do_alpha_after = false;
-       
+
        if (GMS.totmat > FIXEDMAT) {
                GMS.matbuf = MEM_callocN(sizeof(GPUMaterialFixed) * GMS.totmat, "GMS.matbuf");
                GMS.gmatbuf = MEM_callocN(sizeof(*GMS.gmatbuf) * GMS.totmat, "GMS.matbuf");
@@ -1808,11 +1654,11 @@ void GPU_begin_object_materials(
 
                /* do material 1 too, for displists! */
                memcpy(&GMS.matbuf[1], &GMS.matbuf[0], sizeof(GPUMaterialFixed));
-       
+
                GMS.alphablend[0] = GPU_BLEND_SOLID;
        }
        else {
-       
+
                /* no materials assigned? */
                if (ob->totcol == 0) {
                        gpu_material_to_fixed(&GMS.matbuf[0], &defmaterial, 0, ob, new_shading_nodes, true);
@@ -1827,7 +1673,7 @@ void GPU_begin_object_materials(
 
                        GMS.alphablend[0] = GPU_BLEND_SOLID;
                }
-               
+
                /* setup materials */
                for (a = 1; a <= ob->totcol; a++) {
                        /* find a suitable material */
@@ -1985,13 +1831,13 @@ int GPU_object_material_bind(int nr, void *attribs)
                                gpu_get_particle_info(&partile_info);
                        }
                        
-                       if (GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) {
+                       if ((GPU_get_material_builtins(gpumat) & GPU_OBJECT_INFO) != 0) {
                                GPU_get_object_info(object_info, mat);
                        }
 
                        GPU_material_bind(
-                               gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob->mode & OB_MODE_TEXTURE_PAINT),
-                               GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac, GMS.gscenelock);
+                               gpumat, GMS.gob->lay, GMS.glay, 1.0, !(GMS.gob_object_mode & OB_MODE_TEXTURE_PAINT),
+                               GMS.gviewmat, GMS.gviewinv, GMS.gviewcamtexcofac);
 
                        auto_bump_scale = GMS.gob->derivedFinal != NULL ? GMS.gob->derivedFinal->auto_bump_scale : 1.0f;
                        GPU_material_bind_uniforms(gpumat, GMS.gob->obmat, GMS.gviewmat, GMS.gob->col, auto_bump_scale, &partile_info, object_info);
@@ -2062,7 +1908,7 @@ void GPU_set_material_alpha_blend(int alphablend)
 {
        if (GMS.lastalphablend == alphablend)
                return;
-       
+
        gpu_set_alpha_blend(alphablend);
        GMS.lastalphablend = alphablend;
 }
@@ -2133,13 +1979,6 @@ void GPU_end_object_materials(void)
        GMS.gmatbuf = NULL;
        GMS.alphablend = NULL;
        GMS.two_sided_lighting = false;
-
-       /* resetting the texture matrix after the scaling needed for tiled textures */
-       if (GTS.tilemode) {
-               glMatrixMode(GL_TEXTURE);
-               glLoadIdentity();
-               glMatrixMode(GL_MODELVIEW);
-       }
 }
 
 /* Lights */
@@ -2153,13 +1992,13 @@ int GPU_default_lights(void)
                U.light[0].col[0] = 0.8; U.light[0].col[1] = 0.8; U.light[0].col[2] = 0.8;
                U.light[0].spec[0] = 0.5; U.light[0].spec[1] = 0.5; U.light[0].spec[2] = 0.5;
                U.light[0].spec[3] = 1.0;
-               
+
                U.light[1].flag = 0;
                U.light[1].vec[0] = 0.5; U.light[1].vec[1] = 0.5; U.light[1].vec[2] = 0.1;
                U.light[1].col[0] = 0.4; U.light[1].col[1] = 0.4; U.light[1].col[2] = 0.8;
                U.light[1].spec[0] = 0.3; U.light[1].spec[1] = 0.3; U.light[1].spec[2] = 0.5;
                U.light[1].spec[3] = 1.0;
-       
+
                U.light[2].flag = 0;
                U.light[2].vec[0] = 0.3; U.light[2].vec[1] = -0.3; U.light[2].vec[2] = -0.2;
                U.light[2].col[0] = 0.8; U.light[2].col[1] = 0.5; U.light[2].col[2] = 0.4;
@@ -2192,31 +2031,28 @@ int GPU_default_lights(void)
        return count;
 }
 
-int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][4], int ortho)
+int GPU_scene_object_lights(ViewLayer *view_layer, float viewmat[4][4], int ortho)
 {
        /* disable all lights */
        for (int count = 0; count < 8; count++)
                GPU_basic_shader_light_set(count, NULL);
-       
+
        /* view direction for specular is not computed correct by default in
         * opengl, so we set the settings ourselves */
        GPU_basic_shader_light_set_viewer(!ortho);
 
        int count = 0;
 
-       for (Base *base = scene->base.first; base; base = base->next) {
+       for (Base *base = FIRSTBASE(view_layer); base; base = base->next) {
                if (base->object->type != OB_LAMP)
                        continue;
 
-               if (!(base->lay & lay) || !(base->lay & ob->lay))
-                       continue;
-
                Lamp *la = base->object->data;
-               
+
                /* setup lamp transform */
-               glPushMatrix();
-               glLoadMatrixf((float *)viewmat);
-               
+               gpuPushMatrix();
+               gpuLoadMatrix(viewmat);
+
                /* setup light */
                GPULightData light = {0};
 
@@ -2235,7 +2071,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
                        light.constant_attenuation = 1.0f;
                        light.linear_attenuation = la->att1 / la->dist;
                        light.quadratic_attenuation = la->att2 / (la->dist * la->dist);
-                       
+
                        if (la->type == LA_SPOT) {
                                light.type = GPU_LIGHT_SPOT;
                                negate_v3_v3(light.direction, base->object->obmat[2]);
@@ -2246,11 +2082,11 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
                        else
                                light.type = GPU_LIGHT_POINT;
                }
-               
+
                GPU_basic_shader_light_set(count, &light);
-               
-               glPopMatrix();
-               
+
+               gpuPopMatrix();
+
                count++;
                if (count == 8)
                        break;
@@ -2259,7 +2095,7 @@ int GPU_scene_object_lights(Scene *scene, Object *ob, int lay, float viewmat[4][
        return count;
 }
 
-static void gpu_multisample(bool enable)
+static void gpu_disable_multisample()
 {
 #ifdef __linux__
        /* changing multisample from the default (enabled) causes problems on some
@@ -2275,16 +2111,10 @@ static void gpu_multisample(bool enable)
        }
 
        if (toggle_ok) {
-               if (enable)
-                       glEnable(GL_MULTISAMPLE);
-               else
-                       glDisable(GL_MULTISAMPLE);
+               glDisable(GL_MULTISAMPLE);
        }
 #else
-       if (enable)
-               glEnable(GL_MULTISAMPLE);
-       else
-               glDisable(GL_MULTISAMPLE);
+       glDisable(GL_MULTISAMPLE);
 #endif
 }
 
@@ -2297,64 +2127,36 @@ static void gpu_multisample(bool enable)
 
 void GPU_state_init(void)
 {
-       float mat_ambient[] = { 0.0, 0.0, 0.0, 0.0 };
-       float mat_specular[] = { 0.5, 0.5, 0.5, 1.0 };
-       
-       glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
-       glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, mat_specular);
-       glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
-       glMateriali(GL_FRONT_AND_BACK, GL_SHININESS, 35);
-       glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE);
-
        GPU_default_lights();
-       
+
+       GPU_disable_program_point_size();
+
+       glEnable(GL_TEXTURE_CUBE_MAP_SEAMLESS);
+
        glDepthFunc(GL_LEQUAL);
-       /* scaling matrices */
-       glEnable(GL_NORMALIZE);
 
-       glDisable(GL_ALPHA_TEST);
        glDisable(GL_BLEND);
        glDisable(GL_DEPTH_TEST);
-       glDisable(GL_FOG);
-       glDisable(GL_LIGHTING);
-       glDisable(GL_COLOR_MATERIAL);
-       glDisable(GL_LOGIC_OP);
+       glDisable(GL_COLOR_LOGIC_OP);
        glDisable(GL_STENCIL_TEST);
-       glDisable(GL_TEXTURE_1D);
-       glDisable(GL_TEXTURE_2D);
-       glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-
-       /* default disabled, enable should be local per function */
-       glDisableClientState(GL_VERTEX_ARRAY);
-       glDisableClientState(GL_NORMAL_ARRAY);
-       glDisableClientState(GL_COLOR_ARRAY);
-       glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-       
-       glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
-       glPixelTransferi(GL_RED_SCALE, 1);
-       glPixelTransferi(GL_RED_BIAS, 0);
-       glPixelTransferi(GL_GREEN_SCALE, 1);
-       glPixelTransferi(GL_GREEN_BIAS, 0);
-       glPixelTransferi(GL_BLUE_SCALE, 1);
-       glPixelTransferi(GL_BLUE_BIAS, 0);
-       glPixelTransferi(GL_ALPHA_SCALE, 1);
-       glPixelTransferi(GL_ALPHA_BIAS, 0);
-       
-       glPixelTransferi(GL_DEPTH_BIAS, 0);
-       glPixelTransferi(GL_DEPTH_SCALE, 1);
-       glDepthRange(0.0, 1.0);
 
-       glMatrixMode(GL_TEXTURE);
-       glLoadIdentity();
-       glMatrixMode(GL_MODELVIEW);
+       glDepthRange(0.0, 1.0);
 
        glFrontFace(GL_CCW);
        glCullFace(GL_BACK);
        glDisable(GL_CULL_FACE);
 
-       gpu_multisample(false);
+       gpu_disable_multisample();
+}
 
-       GPU_basic_shader_bind(GPU_SHADER_USE_COLOR);
+void GPU_enable_program_point_size(void)
+{
+       glEnable(GL_PROGRAM_POINT_SIZE);
+}
+
+void GPU_disable_program_point_size(void)
+{
+       glDisable(GL_PROGRAM_POINT_SIZE);
 }
 
 #ifdef WITH_OPENSUBDIV
@@ -2500,10 +2302,10 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
 {
 #define INDEX_BUF_ARRAY(INDEX_FROM_BUF_BITS) \
        for (i = size; i--; col++) { \
-               if ((c = *col)) { \
-                       *col = INDEX_FROM_BUF_BITS(c); \
-               } \
-       } ((void)0)
+           if ((c = *col)) { \
+               *col = INDEX_FROM_BUF_BITS(c); \
+        } \
+    } ((void)0)
 
        if (size > 0) {
                unsigned int i, c;
@@ -2531,4 +2333,173 @@ void GPU_select_to_index_array(unsigned int *col, const unsigned int size)
 #undef INDEX_BUF_ARRAY
 }
 
+#define STATE_STACK_DEPTH 16
+
+typedef struct {
+       eGPUAttribMask mask;
+
+       /* GL_ENABLE_BIT */
+       unsigned int is_blend : 1;
+       unsigned int is_cull_face : 1;
+       unsigned int is_depth_test : 1;
+       unsigned int is_dither : 1;
+       unsigned int is_lighting : 1;
+       unsigned int is_line_smooth : 1;
+       unsigned int is_color_logic_op : 1;
+       unsigned int is_multisample : 1;
+       unsigned int is_polygon_offset_line : 1;
+       unsigned int is_polygon_offset_fill : 1;
+       unsigned int is_polygon_smooth : 1;
+       unsigned int is_sample_alpha_to_coverage : 1;
+       unsigned int is_scissor_test : 1;
+       unsigned int is_stencil_test : 1;
+
+       bool is_clip_plane[6];
+
+       /* GL_DEPTH_BUFFER_BIT */
+       /* unsigned int is_depth_test : 1; */
+       int depth_func;
+       double depth_clear_value;
+       bool depth_write_mask;
+
+       /* GL_SCISSOR_BIT */
+       int scissor_box[4];
+       /* unsigned int is_scissor_test : 1; */
+
+       /* GL_VIEWPORT_BIT */
+       int viewport[4];
+       double near_far[2];
+}  GPUAttribValues;
+
+typedef struct {
+       GPUAttribValues attrib_stack[STATE_STACK_DEPTH];
+       unsigned int top;
+} GPUAttribStack;
+
+static GPUAttribStack state = {
+       .top = 0
+};
+
+#define AttribStack state
+#define Gwn_VertAttr state.attrib_stack[state.top]
+
+/**
+ * Replacement for glPush/PopAttributes
+ *
+ * We don't need to cover all the options of legacy OpenGL
+ * but simply the ones used by Blender.
+ */
+void gpuPushAttrib(eGPUAttribMask mask)
+{
+       Gwn_VertAttr.mask = mask;
+
+       if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+               Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+               glGetIntegerv(GL_DEPTH_FUNC, &Gwn_VertAttr.depth_func);
+               glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Gwn_VertAttr.depth_clear_value);
+               glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Gwn_VertAttr.depth_write_mask);
+       }
+
+       if ((mask & GPU_ENABLE_BIT) != 0) {
+               Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND);
+
+               for (int i = 0; i < 6; i++) {
+                       Gwn_VertAttr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i);
+               }
+
+               Gwn_VertAttr.is_cull_face = glIsEnabled(GL_CULL_FACE);
+               Gwn_VertAttr.is_depth_test = glIsEnabled(GL_DEPTH_TEST);
+               Gwn_VertAttr.is_dither = glIsEnabled(GL_DITHER);
+               Gwn_VertAttr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH);
+               Gwn_VertAttr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP);
+               Gwn_VertAttr.is_multisample = glIsEnabled(GL_MULTISAMPLE);
+               Gwn_VertAttr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE);
+               Gwn_VertAttr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL);
+               Gwn_VertAttr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH);
+               Gwn_VertAttr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE);
+               Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+               Gwn_VertAttr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST);
+       }
+
+       if ((mask & GPU_SCISSOR_BIT) != 0) {
+               Gwn_VertAttr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST);
+               glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Gwn_VertAttr.scissor_box);
+       }
+
+       if ((mask & GPU_VIEWPORT_BIT) != 0) {
+               glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Gwn_VertAttr.near_far);
+               glGetIntegerv(GL_VIEWPORT, (GLint *)&Gwn_VertAttr.viewport);
+       }
+
+       if ((mask & GPU_BLEND_BIT) != 0) {
+               Gwn_VertAttr.is_blend = glIsEnabled(GL_BLEND);
+       }
+
+       BLI_assert(AttribStack.top < STATE_STACK_DEPTH);
+       AttribStack.top++;
+}
+
+static void restore_mask(GLenum cap, const bool value)
+{
+       if (value) {
+               glEnable(cap);
+       }
+       else {
+               glDisable(cap);
+       }
+}
+
+void gpuPopAttrib(void)
+{
+       BLI_assert(AttribStack.top > 0);
+       AttribStack.top--;
+
+       GLint mask = Gwn_VertAttr.mask;
+
+       if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) {
+               restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test);
+               glDepthFunc(Gwn_VertAttr.depth_func);
+               glClearDepth(Gwn_VertAttr.depth_clear_value);
+               glDepthMask(Gwn_VertAttr.depth_write_mask);
+       }
+
+       if ((mask & GPU_ENABLE_BIT) != 0) {
+               restore_mask(GL_BLEND, Gwn_VertAttr.is_blend);
+
+               for (int i = 0; i < 6; i++) {
+                       restore_mask(GL_CLIP_PLANE0 + i, Gwn_VertAttr.is_clip_plane[i]);
+               }
+
+               restore_mask(GL_CULL_FACE, Gwn_VertAttr.is_cull_face);
+               restore_mask(GL_DEPTH_TEST, Gwn_VertAttr.is_depth_test);
+               restore_mask(GL_DITHER, Gwn_VertAttr.is_dither);
+               restore_mask(GL_LINE_SMOOTH, Gwn_VertAttr.is_line_smooth);
+               restore_mask(GL_COLOR_LOGIC_OP, Gwn_VertAttr.is_color_logic_op);
+               restore_mask(GL_MULTISAMPLE, Gwn_VertAttr.is_multisample);
+               restore_mask(GL_POLYGON_OFFSET_LINE, Gwn_VertAttr.is_polygon_offset_line);
+               restore_mask(GL_POLYGON_OFFSET_FILL, Gwn_VertAttr.is_polygon_offset_fill);
+               restore_mask(GL_POLYGON_SMOOTH, Gwn_VertAttr.is_polygon_smooth);
+               restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Gwn_VertAttr.is_sample_alpha_to_coverage);
+               restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test);
+               restore_mask(GL_STENCIL_TEST, Gwn_VertAttr.is_stencil_test);
+       }
+
+       if ((mask & GPU_VIEWPORT_BIT) != 0) {
+               glViewport(Gwn_VertAttr.viewport[0], Gwn_VertAttr.viewport[1], Gwn_VertAttr.viewport[2], Gwn_VertAttr.viewport[3]);
+               glDepthRange(Gwn_VertAttr.near_far[0], Gwn_VertAttr.near_far[1]);
+       }
+
+       if ((mask & GPU_SCISSOR_BIT) != 0) {
+               restore_mask(GL_SCISSOR_TEST, Gwn_VertAttr.is_scissor_test);
+               glScissor(Gwn_VertAttr.scissor_box[0], Gwn_VertAttr.scissor_box[1], Gwn_VertAttr.scissor_box[2], Gwn_VertAttr.scissor_box[3]);
+       }
+
+       if ((mask & GPU_BLEND_BIT) != 0) {
+               restore_mask(GL_BLEND, Gwn_VertAttr.is_blend);
+       }
+}
+
+#undef Gwn_VertAttr
+#undef AttribStack
+
 /** \} */