XR: Fix for Viewport Denoising Artifacts
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
This commit is contained in:
parent
eb43477851
commit
c41b93bda5
|
@ -683,6 +683,10 @@ typedef struct GHOST_XrDrawViewInfo {
|
|||
|
||||
/** Set if the buffer should be submitted with a SRGB transfer applied. */
|
||||
char expects_srgb_buffer;
|
||||
|
||||
/** The view that this info represents. Not necessarily the "eye index" (e.g. for quad view
|
||||
* systems, etc). */
|
||||
char view_idx;
|
||||
} GHOST_XrDrawViewInfo;
|
||||
|
||||
typedef struct GHOST_XrError {
|
||||
|
|
|
@ -409,6 +409,7 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain,
|
|||
XrCompositionLayerProjectionView &r_proj_layer_view,
|
||||
XrSpaceLocation &view_location,
|
||||
XrView &view,
|
||||
uint32_t view_idx,
|
||||
void *draw_customdata)
|
||||
{
|
||||
XrSwapchainImageBaseHeader *swapchain_image = swapchain.acquireDrawableSwapchainImage();
|
||||
|
@ -419,6 +420,8 @@ void GHOST_XrSession::drawView(GHOST_XrSwapchain &swapchain,
|
|||
r_proj_layer_view.fov = view.fov;
|
||||
swapchain.updateCompositionLayerProjectViewSubImage(r_proj_layer_view.subImage);
|
||||
|
||||
assert(view_idx < 256);
|
||||
draw_view_info.view_idx = (char)view_idx;
|
||||
draw_view_info.expects_srgb_buffer = swapchain.isBufferSRGB();
|
||||
draw_view_info.ofsx = r_proj_layer_view.subImage.imageRect.offset.x;
|
||||
draw_view_info.ofsy = r_proj_layer_view.subImage.imageRect.offset.y;
|
||||
|
@ -468,6 +471,7 @@ XrCompositionLayerProjection GHOST_XrSession::drawLayer(
|
|||
r_proj_layer_views[view_idx],
|
||||
view_location,
|
||||
m_oxr->views[view_idx],
|
||||
view_idx,
|
||||
draw_customdata);
|
||||
}
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ class GHOST_XrSession {
|
|||
XrCompositionLayerProjectionView &r_proj_layer_view,
|
||||
XrSpaceLocation &view_location,
|
||||
XrView &view,
|
||||
uint32_t view_idx,
|
||||
void *draw_customdata);
|
||||
void beginFrameDrawing();
|
||||
void endFrameDrawing(std::vector<XrCompositionLayerBaseHeader *> &layers);
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
|
||||
#include <string.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
GPU_viewport_free(viewport);
|
||||
GPU_offscreen_free(offscreen);
|
||||
}
|
||||
|
||||
if (!(surface_data->offscreen = GPU_offscreen_create(
|
||||
draw_view->width, draw_view->height, true, false, err_out))) {
|
||||
failure = true;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (failure) {
|
||||
/* Pass. */
|
||||
}
|
||||
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);
|
||||
|
|
Loading…
Reference in New Issue