Camera tracking: use texture buffers (if supported) to display clip editor frames
authorSergey Sharybin <sergey.vfx@gmail.com>
Mon, 30 Apr 2012 16:19:12 +0000 (16:19 +0000)
committerSergey Sharybin <sergey.vfx@gmail.com>
Mon, 30 Apr 2012 16:19:12 +0000 (16:19 +0000)
Use texture buffers to display frames of footage in clip editor. This allows
to apply bilinear filtering of proxied resolution which.

This also resolves incredibly slow performance when drawing 4K footage on
some videocards (was originally noticed on macbook pro). Also this allows
to avoid sending the whole frame to the video memory when working with a
single frame (i.e. before this patch the whole frame would be send to the
videocard when panning frame).

source/blender/blenloader/intern/readfile.c
source/blender/editors/include/ED_clip.h
source/blender/editors/space_clip/CMakeLists.txt
source/blender/editors/space_clip/SConscript
source/blender/editors/space_clip/clip_draw.c
source/blender/editors/space_clip/clip_editor.c
source/blender/makesdna/DNA_space_types.h

index f298ff31814e09a45e06e97a8e63547ad22ecf30..981930119c38fbc8c0bca3e63f242192dbf8c569 100644 (file)
@@ -5390,6 +5390,7 @@ static void lib_link_screen(FileData *fd, Main *main)
                                                sclip->clip= newlibadr_us(fd, sc->id.lib, sclip->clip);
 
                                                sclip->scopes.track_preview = NULL;
+                                               sclip->draw_context = NULL;
                                                sclip->scopes.ok = 0;
                                        }
                                }
index dfd0f258fc08300831bbbf77782c12b9269a8f67..1a890b533ce9d2fd70c9443ed7f629900d19ce50 100644 (file)
@@ -61,6 +61,11 @@ void ED_clip_point_undistorted_pos(SpaceClip *sc, float co[2], float nco[2]);
 void ED_clip_point_stable_pos(struct bContext *C, float x, float y, float *xr, float *yr);
 void ED_clip_mouse_pos(struct bContext *C, struct wmEvent *event, float co[2]);
 
+int ED_space_clip_texture_buffer_supported(struct SpaceClip *sc);
+int ED_space_clip_load_movieclip_buffer(struct SpaceClip *sc, struct ImBuf *ibuf);
+void ED_space_clip_unload_movieclip_buffer(struct SpaceClip *sc);
+void ED_space_clip_free_texture_buffer(struct SpaceClip *sc);
+
 int ED_space_clip_show_trackedit(struct SpaceClip *sc);
 
 /* clip_ops.c */
index 4f9819e8e777a4cb1b1cebf90362359a307a910e..30d2fe57c1006e6e7b56e44a91ce9c38e621ab9c 100644 (file)
@@ -31,6 +31,7 @@ set(INC
        ../../makesdna
        ../../makesrna
        ../../windowmanager
+       ../../gpu
        ../../../../intern/guardedalloc
        ${GLEW_INCLUDE_PATH}
 )
index 70331b0ec4aeea8a8b2119b428355dd61ff59ad3..c9c82aea68e571421280846bbd123a918f1b40f4 100644 (file)
@@ -4,6 +4,6 @@ Import ('env')
 sources = env.Glob('*.c')
 defs = []
 incs = '../include ../../blenkernel ../../blenloader ../../blenfont ../../blenlib ../../imbuf ../../makesdna'
-incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc #/extern/glew/include'
+incs += ' ../../makesrna ../../windowmanager #/intern/guardedalloc #/extern/glew/include ../../gpu'
 
 env.BlenderLib ( 'bf_editors_space_clip', sources, Split(incs), defs, libtype=['core'], priority=[95] )
index 2f9956fc14375d381814a0015935a0b358abb9be..0d519f36ba318994b4dfebfb874c04a4c050e9c7 100644 (file)
@@ -229,9 +229,6 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
        int x, y;
        MovieClip *clip = ED_space_clip(sc);
 
-       /* set zoom */
-       glPixelZoom(zoomx*width/ibuf->x, zoomy*height/ibuf->y);
-
        /* find window pixel coordinates of origin */
        UI_view2d_to_region_no_clip(&ar->v2d, 0.0f, 0.0f, &x, &y);
 
@@ -242,8 +239,42 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
        else {
                verify_buffer_float(ibuf);
 
-               if (ibuf->rect)
-                       glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+               if (ibuf->rect) {
+                       int need_fallback = 1;
+
+                       if (ED_space_clip_texture_buffer_supported(sc)) {
+                               if (ED_space_clip_load_movieclip_buffer(sc, ibuf)) {
+                                       glPushMatrix();
+                                       glTranslatef(x, y, 0.0f);
+                                       glScalef(zoomx, zoomy, 1.0f);
+
+                                       glBegin(GL_QUADS);
+                                               glTexCoord2f(0.0f, 0.0f); glVertex2f(0.0f,  0.0f);
+                                               glTexCoord2f(1.0f, 0.0f); glVertex2f(width, 0.0f);
+                                               glTexCoord2f(1.0f, 1.0f); glVertex2f(width, height);
+                                               glTexCoord2f(0.0f, 1.0f); glVertex2f(0.0f,  height);
+                                       glEnd();
+
+                                       glPopMatrix();
+
+                                       ED_space_clip_unload_movieclip_buffer(sc);
+
+                                       need_fallback = 0;
+                               }
+                       }
+
+                       /* if texture buffers aren't efifciently supported or texture is too large to
+                        * be binder fallback to simple draw pixels solution */
+                       if (need_fallback) {
+                               /* set zoom */
+                               glPixelZoom(zoomx*width/ibuf->x, zoomy*height/ibuf->y);
+
+                               glaDrawPixelsSafe(x, y, ibuf->x, ibuf->y, ibuf->x, GL_RGBA, GL_UNSIGNED_BYTE, ibuf->rect);
+
+                               /* reset zoom */
+                               glPixelZoom(1.0f, 1.0f);
+                       }
+               }
        }
 
        /* draw boundary border for frame if stabilization is enabled */
@@ -255,9 +286,9 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
                glLogicOp(GL_NOR);
 
                glPushMatrix();
-               glTranslatef(x, y, 0);
+               glTranslatef(x, y, 0.0f);
 
-               glScalef(zoomx, zoomy, 0);
+               glScalef(zoomx, zoomy, 1.0f);
                glMultMatrixf(sc->stabmat);
 
                glBegin(GL_LINE_LOOP);
@@ -272,10 +303,6 @@ static void draw_movieclip_buffer(SpaceClip *sc, ARegion *ar, ImBuf *ibuf,
                glDisable(GL_COLOR_LOGIC_OP);
                glDisable(GL_LINE_STIPPLE);
        }
-
-
-       /* reset zoom */
-       glPixelZoom(1.0f, 1.0f);
 }
 
 static void draw_track_path(SpaceClip *sc, MovieClip *UNUSED(clip), MovieTrackingTrack *track)
index 885357a100d9c5ac98435467c0318a88a8bbba1f..cd50366f8541ce26a445ca247670293b2949cc54 100644 (file)
@@ -31,6 +31,8 @@
 
 #include <stddef.h>
 
+#include "MEM_guardedalloc.h"
+
 #include "BKE_main.h"
 #include "BKE_movieclip.h"
 #include "BKE_context.h"
@@ -41,6 +43,8 @@
 #include "BLI_utildefines.h"
 #include "BLI_math.h"
 
+#include "GPU_extensions.h"
+
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
@@ -48,6 +52,7 @@
 #include "ED_clip.h"
 
 #include "BIF_gl.h"
+#include "BIF_glutil.h"
 
 #include "WM_api.h"
 #include "WM_types.h"
@@ -363,6 +368,146 @@ void ED_clip_mouse_pos(bContext *C, wmEvent *event, float co[2])
        ED_clip_point_stable_pos(C, event->mval[0], event->mval[1], &co[0], &co[1]);
 }
 
+/* OpenGL draw context */
+
+typedef struct SpaceClipDrawContext {
+       int support_checked, buffers_supported;
+
+       GLuint texture;                 /* OGL texture ID */
+       short texture_allocated;        /* flag if texture was allocated by glGenTextures */
+       struct ImBuf *texture_ibuf;     /* image buffer for which texture was created */
+       int image_width, image_height;  /* image width and height for which texture was created */
+       unsigned last_texture;          /* ID of previously used texture, so it'll be restored after clip drawing */
+       int framenr;
+} SpaceClipDrawContext;
+
+int ED_space_clip_texture_buffer_supported(SpaceClip *sc)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+
+       if (!context) {
+               context = MEM_callocN(sizeof(SpaceClipDrawContext), "SpaceClipDrawContext");
+               sc->draw_context = context;
+       }
+
+       if (!context->support_checked) {
+               context->support_checked = TRUE;
+               if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) {
+                       context->buffers_supported = FALSE;
+               }
+               else {
+                       context->buffers_supported = GPU_non_power_of_two_support();
+               }
+       }
+
+       return context->buffers_supported;
+}
+
+int ED_space_clip_load_movieclip_buffer(SpaceClip *sc, ImBuf *ibuf)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+       MovieClip *clip = ED_space_clip(sc);
+       int need_rebind = 0;
+
+       context->last_texture = glaGetOneInteger(GL_TEXTURE_2D);
+
+       /* image texture need to be rebinded if displaying another image buffer
+        * assuming displaying happens of footage frames only on which painting doesn't heppen.
+        * so not changed image buffer pointer means unchanged image content */
+       need_rebind |= context->texture_ibuf != ibuf;
+       need_rebind |= context->framenr != sc->user.framenr;
+
+       if (need_rebind) {
+               int width = ibuf->x, height = ibuf->y;
+               float *frect = NULL, *fscalerect = NULL;
+               unsigned int *rect = NULL, *scalerect = NULL;
+               int need_recreate = 0;
+
+               if (width > GL_MAX_TEXTURE_SIZE || height > GL_MAX_TEXTURE_SIZE)
+                       return 0;
+
+               rect = ibuf->rect;
+               frect = ibuf->rect_float;
+
+               /* if image resolution changed (e.g. switched to proxy display) texture need to be recreated */
+               need_recreate = context->image_width != ibuf->x || context->image_height != ibuf->y;
+
+               if (context->texture_ibuf && need_recreate) {
+                       glDeleteTextures(1, &context->texture);
+                       context->texture_allocated = 0;
+               }
+
+               if (need_recreate || !context->texture_allocated) {
+                       /* texture doesn't exist yet or need to be re-allocated because of changed dimensions */
+                       int filter = GL_LINEAR;
+
+                       /* non-scaled proxy shouldn;t use diltering */
+                       if ((clip->flag & MCLIP_USE_PROXY) == 0 ||
+                           ELEM(sc->user.render_size, MCLIP_PROXY_RENDER_SIZE_FULL, MCLIP_PROXY_RENDER_SIZE_100))
+                       {
+                               filter = GL_NEAREST;
+                       }
+
+                       glGenTextures(1, &context->texture);
+                       glBindTexture(GL_TEXTURE_2D, context->texture);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+                       glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+               }
+               else {
+                       /* if texture doesn't need to be reallocated itself, just bind it so
+                        * loading of image will happen to a proper texture */
+                       glBindTexture(GL_TEXTURE_2D, context->texture);
+               }
+
+               if (frect)
+                       glTexImage2D(GL_TEXTURE_2D, 0,  GL_RGBA16,  width, height, 0, GL_RGBA, GL_FLOAT, frect);
+               else
+                       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, rect);
+
+               /* store settings */
+               context->texture_allocated = 1;
+               context->texture_ibuf = ibuf;
+               context->image_width = ibuf->x;
+               context->image_height = ibuf->y;
+               context->framenr = sc->user.framenr;
+
+               if (fscalerect)
+                       MEM_freeN(fscalerect);
+               if (scalerect)
+                       MEM_freeN(scalerect);
+       }
+       else {
+               /* displaying exactly the same image which was loaded t oa texture,
+                * just bint texture in this case */
+               glBindTexture(GL_TEXTURE_2D, context->texture);
+       }
+
+       glEnable(GL_TEXTURE_2D);
+
+       return TRUE;
+}
+
+void ED_space_clip_unload_movieclip_buffer(SpaceClip *sc)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+
+       glBindTexture(GL_TEXTURE_2D, context->last_texture);
+       glDisable(GL_TEXTURE_2D);
+}
+
+void ED_space_clip_free_texture_buffer(SpaceClip *sc)
+{
+       SpaceClipDrawContext *context = sc->draw_context;
+
+       if (context) {
+               glDeleteTextures(1, &context->texture);
+
+               MEM_freeN(context);
+       }
+}
+
 int ED_space_clip_show_trackedit(SpaceClip *sc)
 {
        if (sc) {
index 2356c1945b9a402b4e09fbb1c128bae51fdbc4bb..947bf48386668d1b7aca71745f9d2e778d0bfc68 100644 (file)
@@ -523,6 +523,8 @@ typedef struct SpaceClip {
        int postproc_flag;
 
        int runtime_flag;                       /* different runtime flags */
+
+       void *draw_context;
 } SpaceClip;
 
 /* view3d  Now in DNA_view3d_types.h */