Fix: multisample viewport drawing didn't work well with selection or particle
authorBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 15 Mar 2013 19:56:33 +0000 (19:56 +0000)
committerBrecht Van Lommel <brechtvanlommel@pandora.be>
Fri, 15 Mar 2013 19:56:33 +0000 (19:56 +0000)
brushes, due to issues with color coded drawing or slow/buggy reading from such
a buffer on some systems.

In case multisample is enabled now, it uses an offscreen buffer for such drawing,
which is not multisampled and so should not cause issues. This does mean there is
some extra GPU memory usage when multisample is enabled, and we could optimize
triple buffer to work together here somehow to share buffers, but it's better than
having selection not working.

source/blender/blenloader/intern/readfile.c
source/blender/editors/include/ED_view3d.h
source/blender/editors/mesh/editface.c
source/blender/editors/physics/particle_edit.c
source/blender/editors/space_view3d/drawobject.c
source/blender/editors/space_view3d/space_view3d.c
source/blender/editors/space_view3d/view3d_draw.c
source/blender/gpu/GPU_extensions.h
source/blender/gpu/intern/gpu_extensions.c
source/blender/makesdna/DNA_view3d_types.h

index cef53b6339771b8313f9886682292aa4bcace259..335e80eac158c109fa5fe758895b52f17eaec7ea 100644 (file)
@@ -5917,6 +5917,7 @@ static void direct_link_region(FileData *fd, ARegion *ar, int spacetype)
                        rv3d->clipbb = newdataadr(fd, rv3d->clipbb);
                        
                        rv3d->depths = NULL;
+                       rv3d->gpuoffscreen = NULL;
                        rv3d->ri = NULL;
                        rv3d->render_engine = NULL;
                        rv3d->sms = NULL;
index c2eb7f42bb0b94650b97596e95ad18b5ba64298b..470bbe616cf4c418794ca2a46668e83e9c6d9ff7 100644 (file)
@@ -260,6 +260,7 @@ void view3d_set_viewcontext(struct bContext *C, struct ViewContext *vc);
 void view3d_operator_needs_opengl(const struct bContext *C);
 void view3d_region_operator_needs_opengl(struct wmWindow *win, struct ARegion *ar);
 bool view3d_get_view_aligned_coordinate(struct ARegion *ar, float fp[3], const int mval[2], const bool do_fallback);
+void view3d_opengl_read_pixels(struct ARegion *ar, int x, int y, int w, int h, int format, int type, void *data);
 void view3d_get_transformation(const struct ARegion *ar, struct RegionView3D *rv3d, struct Object *ob, struct bglMats *mats);
 
 /* XXX should move to BLI_math */
index 9b26959ea28a7dedd9c2551109fdd98f35f7733c..ec146380111e938d38b0e541f5047689fdb434d6 100644 (file)
@@ -570,7 +570,7 @@ int do_paintface_box_select(ViewContext *vc, rcti *rect, int select, int extend)
 
        ibuf = IMB_allocImBuf(sx, sy, 32, IB_rect);
        rt = ibuf->rect;
-       glReadPixels(rect->xmin + vc->ar->winrct.xmin,  rect->ymin + vc->ar->winrct.ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
+       view3d_opengl_read_pixels(vc->ar, rect->xmin, rect->ymin, sx, sy, GL_RGBA, GL_UNSIGNED_BYTE,  ibuf->rect);
        if (ENDIAN_ORDER == B_ENDIAN) IMB_convert_rgba_to_abgr(ibuf);
 
        a = sx * sy;
index 6c80f9377dfb7d0dee129412eac5cf04647063a2..329f1f67c4a5f2d475fa6ed87cdfc521a22518a9 100644 (file)
@@ -430,15 +430,6 @@ static int key_test_depth(PEData *data, const float co[3], const int screen_co[2
        gluProject(co[0], co[1], co[2], data->mats.modelview, data->mats.projection,
                   (GLint *)data->mats.viewport, &ux, &uy, &uz);
 
-#if 0 /* works well but too slow on some systems [#23118] */
-       screen_co[0] += (short)data->vc.ar->winrct.xmin;
-       screen_co[1] += (short)data->vc.ar->winrct.ymin;
-
-       /* PE_set_view3d_data calls this. no need to call here */
-       /* view3d_validate_backbuf(&data->vc); */
-       glReadPixels(screen_co[0], screen_co[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
-#else /* faster to use depths, these are calculated in PE_set_view3d_data */
-
        /* check if screen_co is within bounds because brush_cut uses out of screen coords */
        if (screen_co[0] >= 0 && screen_co[0] < vd->w && screen_co[1] >= 0 && screen_co[1] < vd->h) {
                BLI_assert(vd && vd->depths);
@@ -447,7 +438,6 @@ static int key_test_depth(PEData *data, const float co[3], const int screen_co[2
        }
        else
                return 0;
-#endif
 
        if ((float)uz - 0.00001f > depth)
                return 0;
index fa09b93ee4d8888824d14c6945835d9ab1a9f3d0..da3ebf586e91dd5ef750984f38b792d9ad91ec69 100644 (file)
@@ -808,17 +808,6 @@ void view3d_cached_text_draw_end(View3D *v3d, ARegion *ar, int depth_write, floa
                }
                
                for (vos = strings->first; vos; vos = vos->next) {
-                       /* too slow, reading opengl info while drawing is very bad,
-                        * better to see if we can use the zbuffer while in pixel space - campbell */
-#if 0
-                       if (v3d->zbuf && (vos->flag & V3D_CACHE_TEXT_ZBUF)) {
-                               gluProject(vos->vec[0], vos->vec[1], vos->vec[2], mats.modelview, mats.projection, (GLint *)mats.viewport, &ux, &uy, &uz);
-                               glReadPixels(ar->winrct.xmin + vos->mval[0] + vos->xoffs, ar->winrct.ymin + vos->mval[1], 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);
-
-                               if (uz > depth)
-                                       continue;
-                       }
-#endif
                        if (vos->sco[0] != IS_CLIPPED) {
                                const char *str = (char *)(vos + 1);
 
index a3f5055c284486942edf02f8c579ea61257ad658..2eba28858bc6f436c836b540ac7a8bbaaa69206a 100644 (file)
@@ -53,6 +53,7 @@
 #include "ED_screen.h"
 #include "ED_object.h"
 
+#include "GPU_extensions.h"
 #include "GPU_material.h"
 
 #include "BIF_gl.h"
@@ -478,6 +479,11 @@ static void view3d_main_area_exit(wmWindowManager *wm, ARegion *ar)
                RE_engine_free(rv3d->render_engine);
                rv3d->render_engine = NULL;
        }
+
+       if (rv3d->gpuoffscreen) {
+               GPU_offscreen_free(rv3d->gpuoffscreen);
+               rv3d->gpuoffscreen = NULL;
+       }
 }
 
 static int view3d_ob_drop_poll(bContext *UNUSED(C), wmDrag *drag, const wmEvent *UNUSED(event))
@@ -626,6 +632,10 @@ static void view3d_main_area_free(ARegion *ar)
                if (rv3d->sms) {
                        MEM_freeN(rv3d->sms);
                }
+               if (rv3d->gpuoffscreen) {
+                       GPU_offscreen_free(rv3d->gpuoffscreen);
+               }
+
                MEM_freeN(rv3d);
                ar->regiondata = NULL;
        }
@@ -644,6 +654,7 @@ static void *view3d_main_area_duplicate(void *poin)
                        new->clipbb = MEM_dupallocN(rv3d->clipbb);
                
                new->depths = NULL;
+               new->gpuoffscreen = NULL;
                new->ri = NULL;
                new->render_engine = NULL;
                new->gpd = NULL;
index 5b1e1e75f8501bbbd5cfb138e0921f8f0dc1c151..252a27947fb31b9a7836b9c506b7434bc242dca7 100644 (file)
@@ -1348,7 +1348,34 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
        if (multisample_enabled)
                glDisable(GL_MULTISAMPLE_ARB);
 
-       glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
+       if (U.ogl_multisamples != USER_MULTISAMPLE_NONE) {
+               /* for multisample we use an offscreen FBO. multisample drawing can fail
+                * with color coded selection drawing, and reading back depths from such
+                * a buffer can also cause a few seconds freeze on OS X / NVidia. */
+               int w = BLI_rcti_size_x(&ar->winrct);
+               int h = BLI_rcti_size_y(&ar->winrct);
+               char error[256];
+
+               if (rv3d->gpuoffscreen) {
+                       if (GPU_offscreen_width(rv3d->gpuoffscreen) != w ||
+                           GPU_offscreen_height(rv3d->gpuoffscreen) != h) {
+                               GPU_offscreen_free(rv3d->gpuoffscreen);
+                               rv3d->gpuoffscreen = NULL;
+                       }
+               }
+
+               if (!rv3d->gpuoffscreen) {
+                       rv3d->gpuoffscreen = GPU_offscreen_create(w, h, error);
+
+                       if (!rv3d->gpuoffscreen)
+                               fprintf(stderr, "Failed to create offscreen selection buffer for multisample: %s\n", error);
+               }
+       }
+
+       if (rv3d->gpuoffscreen)
+               GPU_offscreen_bind(rv3d->gpuoffscreen);
+       else
+               glScissor(ar->winrct.xmin, ar->winrct.ymin, BLI_rcti_size_x(&ar->winrct), BLI_rcti_size_y(&ar->winrct));
 
        glClearColor(0.0, 0.0, 0.0, 0.0); 
        if (v3d->zbuf) {
@@ -1367,9 +1394,13 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
        
        if (base && (base->lay & v3d->lay))
                draw_object_backbufsel(scene, v3d, rv3d, base->object);
+       
+       if (rv3d->gpuoffscreen)
+               GPU_offscreen_unbind(rv3d->gpuoffscreen);
+       else
+               ar->swap = 0; /* mark invalid backbuf for wm draw */
 
        v3d->flag &= ~V3D_INVALID_BACKBUF;
-       ar->swap = 0; /* mark invalid backbuf for wm draw */
 
        G.f &= ~G_BACKBUFSEL;
        v3d->zbuf = FALSE;
@@ -1386,6 +1417,21 @@ static void backdrawview3d(Scene *scene, ARegion *ar, View3D *v3d)
 
 }
 
+void view3d_opengl_read_pixels(ARegion *ar, int x, int y, int w, int h, int format, int type, void *data)
+{
+       RegionView3D *rv3d = ar->regiondata;
+
+       if (rv3d->gpuoffscreen) {
+               GPU_offscreen_bind(rv3d->gpuoffscreen);
+               glReadBuffer(GL_COLOR_ATTACHMENT0_EXT);
+               glReadPixels(x, y, w, h, format, type, data);
+               GPU_offscreen_unbind(rv3d->gpuoffscreen);
+       }
+       else {
+               glReadPixels(ar->winrct.xmin + x, ar->winrct.ymin + y, w, h, format, type, data);
+       }
+}
+
 void view3d_validate_backbuf(ViewContext *vc)
 {
        if (vc->v3d->flag & V3D_INVALID_BACKBUF)
@@ -1401,12 +1447,9 @@ unsigned int view3d_sample_backbuf(ViewContext *vc, int x, int y)
                return 0;
        }
 
-       x += vc->ar->winrct.xmin;
-       y += vc->ar->winrct.ymin;
-       
        view3d_validate_backbuf(vc);
 
-       glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
+       view3d_opengl_read_pixels(vc->ar, x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &col);
        glReadBuffer(GL_BACK);
        
        if (ENDIAN_ORDER == B_ENDIAN) {
@@ -1437,8 +1480,8 @@ ImBuf *view3d_read_backbuf(ViewContext *vc, short xmin, short ymin, short xmax,
 
        view3d_validate_backbuf(vc);
 
-       glReadPixels(vc->ar->winrct.xmin + xminc,
-                    vc->ar->winrct.ymin + yminc,
+       view3d_opengl_read_pixels(vc->ar,
+                    xminc, yminc,
                     (xmaxc - xminc + 1),
                     (ymaxc - yminc + 1),
                     GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
@@ -2104,7 +2147,7 @@ void view3d_update_depths_rect(ARegion *ar, ViewDepths *d, rcti *rect)
        }
 
        if (d->damaged) {
-               glReadPixels(ar->winrct.xmin + d->x, ar->winrct.ymin + d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
+               view3d_opengl_read_pixels(ar, d->x, d->y, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
                glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
                d->damaged = FALSE;
        }
@@ -2132,9 +2175,7 @@ void ED_view3d_depth_update(ARegion *ar)
                }
                
                if (d->damaged) {
-                       glReadPixels(ar->winrct.xmin, ar->winrct.ymin, d->w, d->h,
-                                    GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
-                       
+                       view3d_opengl_read_pixels(ar, 0, 0, d->w, d->h, GL_DEPTH_COMPONENT, GL_FLOAT, d->depths);
                        glGetDoublev(GL_DEPTH_RANGE, d->depth_range);
                        
                        d->damaged = 0;
index 07269d3e2b5a72603401b560856d04785c439aaf..0ae45775473c1667c3d45c4518295eeb44f26608 100644 (file)
@@ -157,6 +157,8 @@ void GPU_offscreen_free(GPUOffScreen *ofs);
 void GPU_offscreen_bind(GPUOffScreen *ofs);
 void GPU_offscreen_unbind(GPUOffScreen *ofs);
 void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels);
+int GPU_offscreen_width(GPUOffScreen *ofs);
+int GPU_offscreen_height(GPUOffScreen *ofs);
 
 /* GPU Shader
  * - only for fragment shaders now
index f5eaa716dfa1adfbe6cbd255b4f0203dc23286bc..c7a421a49fcd69c61cc008339b8f4fe94e9885e6 100644 (file)
@@ -905,10 +905,8 @@ void GPU_framebuffer_texture_bind(GPUFrameBuffer *UNUSED(fb), GPUTexture *tex, i
 
        glMatrixMode(GL_PROJECTION);
        glPushMatrix();
-       glLoadIdentity();
        glMatrixMode(GL_MODELVIEW);
        glPushMatrix();
-       glLoadIdentity();
 }
 
 void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex))
@@ -1096,6 +1094,16 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels)
        glReadPixels(0, 0, ofs->w, ofs->h, GL_RGBA, type, pixels);
 }
 
+int GPU_offscreen_width(GPUOffScreen *ofs)
+{
+       return ofs->w;
+}
+
+int GPU_offscreen_height(GPUOffScreen *ofs)
+{
+       return ofs->h;
+}
+
 /* GPUShader */
 
 struct GPUShader {
index 5397b06dc15a27e555562f408cae66991a274d25..294c47aa9db2834fc206136807c3a8b4fba8740e 100644 (file)
@@ -107,6 +107,7 @@ typedef struct RegionView3D {
        struct RenderInfo *ri;
        struct RenderEngine *render_engine;
        struct ViewDepths *depths;
+       void *gpuoffscreen;
 
        /* animated smooth view */
        struct SmoothView3DStore *sms;