From c41b93bda5328ce13faf7048dfd38708e6486b6a Mon Sep 17 00:00:00 2001 From: Peter Kim Date: Sat, 24 Jul 2021 00:11:22 +0900 Subject: XR: Fix for Viewport Denoising Artifacts MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses T76003. When using VR with Eevee and viewport denoising, scene geometry could sometimes be occluded for one eye. Solution is to use a separate GPUViewport/GPUOffscreen for each VR view instead of reusing a single one for rendering. Reviewed By: Julian Eisel, Clément Foucault Differential Revision: http://developer.blender.org/D11858 --- .../blender/windowmanager/xr/intern/wm_xr_draw.c | 16 ++++-- .../blender/windowmanager/xr/intern/wm_xr_intern.h | 8 ++- .../windowmanager/xr/intern/wm_xr_session.c | 66 ++++++++++++++-------- 3 files changed, 59 insertions(+), 31 deletions(-) (limited to 'source/blender/windowmanager') diff --git a/source/blender/windowmanager/xr/intern/wm_xr_draw.c b/source/blender/windowmanager/xr/intern/wm_xr_draw.c index bef88505488..4ac05e339b9 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_draw.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_draw.c @@ -24,6 +24,7 @@ #include +#include "BLI_listbase.h" #include "BLI_math.h" #include "ED_view3d_offscreen.h" @@ -91,6 +92,9 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( const wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view) { + const wmXrViewportPair *vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx); + BLI_assert(vp && vp->viewport); + const bool is_upside_down = GHOST_XrSessionNeedsUpsideDownDrawing(runtime_data->context); rcti rect = {.xmin = 0, .ymin = 0, .xmax = draw_view->width - 1, .ymax = draw_view->height - 1}; @@ -100,8 +104,7 @@ static void wm_xr_draw_viewport_buffers_to_active_framebuffer( if (is_upside_down) { SWAP(int, rect.ymin, rect.ymax); } - GPU_viewport_draw_to_screen_ex( - surface_data->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); + GPU_viewport_draw_to_screen_ex(vp->viewport, 0, &rect, draw_view->expects_srgb_buffer, true); } /** @@ -132,6 +135,9 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) return; } + const wmXrViewportPair *vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx); + BLI_assert(vp && vp->offscreen && vp->viewport); + /* In case a framebuffer is still bound from drawing the last eye. */ GPU_framebuffer_restore(); /* Some systems have drawing glitches without this. */ @@ -153,8 +159,8 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) true, NULL, false, - surface_data->offscreen, - surface_data->viewport); + vp->offscreen, + vp->viewport); /* The draw-manager uses both GPUOffscreen and GPUViewport to manage frame and texture buffers. A * call to GPU_viewport_draw_to_screen() is still needed to get the final result from the @@ -164,7 +170,7 @@ void wm_xr_draw_view(const GHOST_XrDrawViewInfo *draw_view, void *customdata) * In a next step, Ghost-XR will use the currently bound frame-buffer to retrieve the image * to be submitted to the OpenXR swap-chain. So do not un-bind the off-screen yet! */ - GPU_offscreen_bind(surface_data->offscreen, false); + GPU_offscreen_bind(vp->offscreen, false); wm_xr_draw_viewport_buffers_to_active_framebuffer(xr_data->runtime, surface_data, draw_view); } diff --git a/source/blender/windowmanager/xr/intern/wm_xr_intern.h b/source/blender/windowmanager/xr/intern/wm_xr_intern.h index 9bf63be61dd..24582388228 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_intern.h +++ b/source/blender/windowmanager/xr/intern/wm_xr_intern.h @@ -85,9 +85,15 @@ typedef struct wmXrRuntimeData { wmXrSessionExitFn exit_fn; } wmXrRuntimeData; -typedef struct { +typedef struct wmXrViewportPair { + struct wmXrViewportPair *next, *prev; struct GPUOffScreen *offscreen; struct GPUViewport *viewport; +} wmXrViewportPair; + +typedef struct { + /* Offscreen buffers/viewports for each view. */ + ListBase viewports; /* wmXrViewportPair */ } wmXrSurfaceData; typedef struct wmXrDrawData { diff --git a/source/blender/windowmanager/xr/intern/wm_xr_session.c b/source/blender/windowmanager/xr/intern/wm_xr_session.c index b740cb27471..4439f2fe479 100644 --- a/source/blender/windowmanager/xr/intern/wm_xr_session.c +++ b/source/blender/windowmanager/xr/intern/wm_xr_session.c @@ -546,7 +546,6 @@ void wm_xr_session_controller_data_clear(wmXrSessionState *state) */ static void wm_xr_session_surface_draw(bContext *C) { - wmXrSurfaceData *surface_data = g_xr_surface->customdata; wmWindowManager *wm = CTX_wm_manager(C); Main *bmain = CTX_data_main(C); wmXrDrawData draw_data; @@ -562,38 +561,50 @@ static void wm_xr_session_surface_draw(bContext *C) GHOST_XrSessionDrawViews(wm->xr.runtime->context, &draw_data); - GPU_offscreen_unbind(surface_data->offscreen, false); + GPU_framebuffer_restore(); } bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, const GHOST_XrDrawViewInfo *draw_view) { - const bool size_changed = surface_data->offscreen && - (GPU_offscreen_width(surface_data->offscreen) != draw_view->width) && - (GPU_offscreen_height(surface_data->offscreen) != draw_view->height); + wmXrViewportPair *vp = NULL; + if (draw_view->view_idx >= BLI_listbase_count(&surface_data->viewports)) { + vp = MEM_callocN(sizeof(*vp), __func__); + BLI_addtail(&surface_data->viewports, vp); + } + else { + vp = BLI_findlink(&surface_data->viewports, draw_view->view_idx); + } + BLI_assert(vp); + + GPUOffScreen *offscreen = vp->offscreen; + GPUViewport *viewport = vp->viewport; + const bool size_changed = offscreen && (GPU_offscreen_width(offscreen) != draw_view->width) && + (GPU_offscreen_height(offscreen) != draw_view->height); char err_out[256] = "unknown"; bool failure = false; - if (surface_data->offscreen) { - BLI_assert(surface_data->viewport); + if (offscreen) { + BLI_assert(viewport); if (!size_changed) { return true; } - 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, true, false, err_out))) { - failure = true; - } - - if (failure) { - /* Pass. */ + GPU_viewport_free(viewport); + GPU_offscreen_free(offscreen); + } + + offscreen = vp->offscreen = GPU_offscreen_create( + draw_view->width, draw_view->height, true, false, err_out); + if (offscreen) { + viewport = vp->viewport = GPU_viewport_create(); + if (!viewport) { + GPU_offscreen_free(offscreen); + offscreen = vp->offscreen = NULL; + failure = true; + } } - else if (!(surface_data->viewport = GPU_viewport_create())) { - GPU_offscreen_free(surface_data->offscreen); + else { failure = true; } @@ -608,12 +619,17 @@ bool wm_xr_session_surface_offscreen_ensure(wmXrSurfaceData *surface_data, static void wm_xr_session_surface_free_data(wmSurface *surface) { wmXrSurfaceData *data = surface->customdata; + ListBase *lb = &data->viewports; + wmXrViewportPair *vp; - if (data->viewport) { - GPU_viewport_free(data->viewport); - } - if (data->offscreen) { - GPU_offscreen_free(data->offscreen); + while (vp = BLI_pophead(lb)) { + if (vp->viewport) { + GPU_viewport_free(vp->viewport); + } + if (vp->offscreen) { + GPU_offscreen_free(vp->offscreen); + } + BLI_freelinkN(lb, vp); } MEM_freeN(surface->customdata); -- cgit v1.2.3