diff options
author | Julian Eisel <eiseljulian@gmail.com> | 2019-07-21 02:10:18 +0300 |
---|---|---|
committer | Julian Eisel <eiseljulian@gmail.com> | 2019-07-21 02:10:18 +0300 |
commit | 55362436d9bd9b41ae9ae29d9b9c7d75134e83a7 (patch) | |
tree | b2a2a87c4b2a4e8b42738c45e27ebac9573be547 /source/blender/windowmanager/intern/wm_xr.c | |
parent | c1d164070b131f97d5adf2f580b106431599f9c4 (diff) |
Fix troubling memory leak in offscreen viewport drawing
I'm not really sure why the leak happened - draw manager kept allocating
certain buffers - but I figured I could avoid it by not recreating
GPU_offscreen/GPU_viewport on every redraw.
This should also improve performance a bit.
Diffstat (limited to 'source/blender/windowmanager/intern/wm_xr.c')
-rw-r--r-- | source/blender/windowmanager/intern/wm_xr.c | 76 |
1 files changed, 59 insertions, 17 deletions
diff --git a/source/blender/windowmanager/intern/wm_xr.c b/source/blender/windowmanager/intern/wm_xr.c index 0fa543d4872..cba3ec3bbdf 100644 --- a/source/blender/windowmanager/intern/wm_xr.c +++ b/source/blender/windowmanager/intern/wm_xr.c @@ -65,6 +65,8 @@ static wmSurface *g_xr_surface = NULL; typedef struct { GHOST_TXrGraphicsBinding gpu_binding_type; + GPUOffScreen *offscreen; + GPUViewport *viewport; } wmXrSurfaceData; typedef struct { @@ -134,17 +136,26 @@ static void wm_xr_session_surface_draw(bContext *C) static void wm_xr_session_free_data(wmSurface *surface) { + wmXrSurfaceData *data = surface->customdata; + WM_opengl_context_dispose(surface->ghost_ctx); if (surface->secondary_ghost_ctx) { #ifdef WIN32 - wmXrSurfaceData *data = surface->customdata; if (data->gpu_binding_type == GHOST_kXrGraphicsD3D11) { WM_directx_context_dispose(surface->secondary_ghost_ctx); } #endif } GPU_context_active_set(surface->gpu_ctx); + if (data->viewport) { + GPU_viewport_clear_from_offscreen(data->viewport); + GPU_viewport_free(data->viewport); + } + if (data->offscreen) { + GPU_offscreen_free(data->offscreen); + } GPU_context_discard(surface->gpu_ctx); + MEM_freeN(surface->customdata); g_xr_surface = NULL; @@ -227,31 +238,68 @@ static void wm_xr_draw_matrices_create(const Scene *scene, } } +static bool wm_xr_session_surface_offscreen_ensure(const GHOST_XrDrawViewInfo *draw_view) +{ + wmXrSurfaceData *surface_data = g_xr_surface->customdata; + char err_out[256] = "unknown"; + bool failure = false; + + if (surface_data->offscreen && + (GPU_offscreen_width(surface_data->offscreen) == draw_view->width) && + (GPU_offscreen_height(surface_data->offscreen) == draw_view->height)) { + BLI_assert(surface_data->viewport); + return true; + } + + if (surface_data->offscreen) { + GPU_viewport_clear_from_offscreen(surface_data->viewport); + GPU_viewport_free(surface_data->viewport); + GPU_offscreen_free(surface_data->offscreen); + } + + if (!(surface_data->offscreen = GPU_offscreen_create( + draw_view->width, draw_view->height, 0, true, false, err_out))) { + failure = true; + } + if ((failure == false) && + !(surface_data->viewport = GPU_viewport_create_from_offscreen(surface_data->offscreen))) { + GPU_offscreen_free(surface_data->offscreen); + failure = true; + } + + if (failure) { + fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); + return false; + } + + return true; +} + static GHOST_ContextHandle wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) { bContext *C = customdata; + wmXrSurfaceData *surface_data = g_xr_surface->customdata; const float clip_start = 0.01, clip_end = 500.0f; const float lens = 50.0f; /* TODO get from OpenXR */ + const rcti rect = { + .xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1}; GPUOffScreen *offscreen; GPUViewport *viewport; View3DShading shading; float viewmat[4][4], winmat[4][4]; - char err_out[256] = "unknown"; wm_xr_draw_matrices_create(CTX_data_scene(C), draw_view, clip_start, clip_end, viewmat, winmat); DRW_opengl_context_enable(); - offscreen = GPU_offscreen_create(draw_view->width, draw_view->height, 0, true, false, err_out); - if (offscreen == NULL) { - fprintf(stderr, "%s: failed to get buffer, %s\n", __func__, err_out); - DRW_opengl_context_disable(); + if (!wm_xr_session_surface_offscreen_ensure(draw_view)) { return NULL; } - GPU_offscreen_bind(offscreen, true); - viewport = GPU_viewport_create_from_offscreen(offscreen); + DRW_opengl_context_disable(); - glViewport(draw_view->ofsx, draw_view->ofsy, draw_view->width, draw_view->height); + offscreen = surface_data->offscreen; + viewport = surface_data->viewport; + GPU_viewport_bind(viewport, &rect); BKE_screen_view3d_shading_init(&shading); ED_view3d_draw_offscreen_simple(CTX_data_depsgraph(C), @@ -279,14 +327,12 @@ static GHOST_ContextHandle wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view // GHOST_ContextBlitOpenGLOffscreenContext( // g_xr_surface->ghost_ctx, DRW_opengl_context_get(), draw_view->width, draw_view->height); - GPU_offscreen_unbind(offscreen, true); + GPU_viewport_unbind(viewport); GPU_framebuffer_restore(); - DRW_opengl_context_disable_ex(true); GPUTexture *texture = GPU_offscreen_color_texture(offscreen); - rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1}; - GHOST_ActivateOpenGLContext(g_xr_surface->ghost_ctx); + WM_opengl_context_activate(g_xr_surface->ghost_ctx); wm_draw_offscreen_texture_parameters(offscreen); wmViewport(&rect); @@ -298,10 +344,6 @@ static GHOST_ContextHandle wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view GPU_texture_unbind(texture); } - GPU_viewport_clear_from_offscreen(viewport); - GPU_viewport_free(viewport); - GPU_offscreen_free(offscreen); - return g_xr_surface->ghost_ctx; } |