diff options
Diffstat (limited to 'source/blender/gpu/intern/gpu_viewport.c')
-rw-r--r-- | source/blender/gpu/intern/gpu_viewport.c | 265 |
1 files changed, 216 insertions, 49 deletions
diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index e4fd5d3f122..750db39d908 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -40,6 +40,7 @@ #include "GPU_framebuffer.h" #include "GPU_glew.h" #include "GPU_immediate.h" +#include "GPU_matrix.h" #include "GPU_texture.h" #include "GPU_viewport.h" #include "GPU_uniformbuffer.h" @@ -68,7 +69,10 @@ struct GPUViewport { int size[2]; int flag; - /* If engine_handles mismatch we free all ViewportEngineData in this viewport */ + /* Set the active view (for stereoscoptic viewport rendering). */ + int active_view; + + /* If engine_handles mismatch we free all ViewportEngineData in this viewport. */ struct { void *handle; ViewportEngineData *data; @@ -80,9 +84,10 @@ struct GPUViewport { ViewportMemoryPool vmempool; /* Used for rendering data structure. */ struct DRWInstanceDataList *idatalist; /* Used for rendering data structure. */ - ListBase tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines */ + ListBase + tex_pool; /* ViewportTempTexture list : Temporary textures shared across draw engines. */ - /* Profiling data */ + /* Profiling data. */ double cache_time; /* Color management. */ @@ -96,12 +101,11 @@ struct GPUViewport { enum { DO_UPDATE = (1 << 0), + GPU_VIEWPORT_STEREO = (1 << 1), }; -static void gpu_viewport_buffers_free(FramebufferList *fbl, - int fbl_len, - TextureList *txl, - int txl_len); +static void gpu_viewport_buffers_free( + FramebufferList *fbl, int fbl_len, TextureList *txl, TextureList *txl_stereo, int txl_len); static void gpu_viewport_storage_free(StorageList *stl, int stl_len); static void gpu_viewport_passes_free(PassList *psl, int psl_len); static void gpu_viewport_texture_pool_free(GPUViewport *viewport); @@ -125,12 +129,89 @@ GPUViewport *GPU_viewport_create(void) viewport->txl = MEM_callocN(sizeof(DefaultTextureList), "TextureList"); viewport->idatalist = DRW_instance_data_list_create(); viewport->do_color_management = false; - viewport->size[0] = viewport->size[1] = -1; + viewport->active_view = -1; + return viewport; +} +GPUViewport *GPU_viewport_stereo_create(void) +{ + GPUViewport *viewport = GPU_viewport_create(); + viewport->flag = GPU_VIEWPORT_STEREO; return viewport; } +static void gpu_viewport_framebuffer_view_set(GPUViewport *viewport, int view) +{ + /* Early check if the view is the latest requested. */ + if (viewport->active_view == view) { + return; + } + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + + /* Only swap the texture when this is a Stereo Viewport. */ + if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) { + SWAP(GPUTexture *, dtxl->color, dtxl->color_stereo); + SWAP(GPUTexture *, dtxl->color_overlay, dtxl->color_overlay_stereo); + + for (int i = 0; i < MAX_ENABLE_ENGINE; i++) { + if (viewport->engine_data[i].handle != NULL) { + ViewportEngineData *data = viewport->engine_data[i].data; + SWAP(StorageList *, data->stl, data->stl_stereo); + SWAP(TextureList *, data->txl, data->txl_stereo); + } + else { + break; + } + } + } + + GPU_framebuffer_ensure_config(&dfbl->default_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(dtxl->color), + }); + + GPU_framebuffer_ensure_config(&dfbl->overlay_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); + + GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_NONE, + }); + + GPU_framebuffer_ensure_config(&dfbl->color_only_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color), + }); + + GPU_framebuffer_ensure_config(&dfbl->overlay_only_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); + + if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) { + GPU_framebuffer_ensure_config(&dfbl->stereo_comp_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(dtxl->color), + GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), + }); + } + else { + dfbl->stereo_comp_fb = NULL; + } + + viewport->active_view = view; +} + void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type) { ViewportEngineData *data = MEM_callocN(sizeof(ViewportEngineData), "ViewportEngineData"); @@ -145,6 +226,13 @@ void *GPU_viewport_engine_data_create(GPUViewport *viewport, void *engine_type) data->psl = MEM_callocN((sizeof(void *) * psl_len) + sizeof(PassList), "PassList"); data->stl = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), "StorageList"); + if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0) { + data->txl_stereo = MEM_callocN((sizeof(void *) * txl_len) + sizeof(TextureList), + "TextureList"); + data->stl_stereo = MEM_callocN((sizeof(void *) * stl_len) + sizeof(StorageList), + "StorageList"); + } + for (int i = 0; i < MAX_ENABLE_ENGINE; i++) { if (viewport->engine_data[i].handle == NULL) { viewport->engine_data[i].handle = engine_type; @@ -166,7 +254,7 @@ static void gpu_viewport_engines_data_free(GPUViewport *viewport) DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, &psl_len, &stl_len); - gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); + gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, data->txl_stereo, txl_len); gpu_viewport_passes_free(data->psl, psl_len); gpu_viewport_storage_free(data->stl, stl_len); @@ -175,6 +263,11 @@ static void gpu_viewport_engines_data_free(GPUViewport *viewport) MEM_freeN(data->psl); MEM_freeN(data->stl); + if ((viewport->flag & GPU_VIEWPORT_STEREO) != 0) { + gpu_viewport_storage_free(data->stl_stereo, stl_len); + MEM_freeN(data->txl_stereo); + MEM_freeN(data->stl_stereo); + } /* We could handle this in the DRW module */ if (data->text_draw_cache) { extern void DRW_text_cache_destroy(struct DRWTextStore * dt); @@ -213,6 +306,16 @@ struct DRWInstanceDataList *GPU_viewport_instance_data_list_get(GPUViewport *vie return viewport->idatalist; } +/* Note this function is only allowed to be called from `DRW_notify_view_update`. The rest + * should bind the correct viewport. + * + * The reason is that DRW_notify_view_update can be called from a different thread, but needs + * access to the engine data. */ +void GPU_viewport_active_view_set(GPUViewport *viewport, int view) +{ + gpu_viewport_framebuffer_view_set(viewport, view); +} + void *GPU_viewport_framebuffer_list_get(GPUViewport *viewport) { return viewport->fbl; @@ -347,6 +450,10 @@ static void gpu_viewport_default_fb_create(GPUViewport *viewport) dtxl->color = GPU_texture_create_2d(size[0], size[1], GPU_RGBA16F, NULL, NULL); dtxl->color_overlay = GPU_texture_create_2d(size[0], size[1], GPU_SRGB8_A8, NULL, NULL); + if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) { + dtxl->color_stereo = GPU_texture_create_2d(size[0], size[1], GPU_RGBA16F, NULL, NULL); + dtxl->color_overlay_stereo = GPU_texture_create_2d(size[0], size[1], GPU_SRGB8_A8, NULL, NULL); + } /* Can be shared with GPUOffscreen. */ if (dtxl->depth == NULL) { @@ -358,42 +465,16 @@ static void gpu_viewport_default_fb_create(GPUViewport *viewport) goto cleanup; } - GPU_framebuffer_ensure_config(&dfbl->default_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(dtxl->color), - }); - - GPU_framebuffer_ensure_config(&dfbl->overlay_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), - }); - - GPU_framebuffer_ensure_config(&dfbl->depth_only_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_NONE, - }); - - GPU_framebuffer_ensure_config(&dfbl->color_only_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(dtxl->color), - }); - - GPU_framebuffer_ensure_config(&dfbl->overlay_only_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(dtxl->color_overlay), - }); + gpu_viewport_framebuffer_view_set(viewport, 0); ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->overlay_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL); ok = ok && GPU_framebuffer_check_valid(dfbl->overlay_only_fb, NULL); - + if (((viewport->flag & GPU_VIEWPORT_STEREO) != 0)) { + ok = ok && GPU_framebuffer_check_valid(dfbl->stereo_comp_fb, NULL); + } cleanup: if (!ok) { GPU_viewport_free(viewport); @@ -404,7 +485,7 @@ cleanup: GPU_framebuffer_restore(); } -void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) +void GPU_viewport_bind(GPUViewport *viewport, int view, const rcti *rect) { DefaultFramebufferList *dfbl = viewport->fbl; int fbl_len, txl_len; @@ -421,15 +502,17 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) gpu_viewport_buffers_free((FramebufferList *)viewport->fbl, default_fbl_len, (TextureList *)viewport->txl, + NULL, default_txl_len); for (int i = 0; i < MAX_ENABLE_ENGINE && viewport->engine_data[i].handle; i++) { ViewportEngineData *data = viewport->engine_data[i].data; DRW_engine_viewport_data_size_get(data->engine_type, &fbl_len, &txl_len, NULL, NULL); - gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, txl_len); + gpu_viewport_buffers_free(data->fbl, fbl_len, data->txl, data->txl_stereo, txl_len); } gpu_viewport_texture_pool_free(viewport); + viewport->active_view = -1; } } @@ -440,6 +523,7 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) if (!dfbl->default_fb) { gpu_viewport_default_fb_create(viewport); } + gpu_viewport_framebuffer_view_set(viewport, view); } void GPU_viewport_bind_from_offscreen(GPUViewport *viewport, struct GPUOffScreen *ofs) @@ -474,6 +558,74 @@ void GPU_viewport_colorspace_set(GPUViewport *viewport, viewport->do_color_management = true; } +/* Merge the stereo textures. `color` and `overlay` texture will be modified. */ +void GPU_viewport_stereo_composite(GPUViewport *viewport, Stereo3dFormat *stereo_format) +{ + if (!ELEM(stereo_format->display_mode, S3D_DISPLAY_ANAGLYPH, S3D_DISPLAY_INTERLACE)) { + /* Early Exit: the other display modes need access to the full screen and cannot be + * done from a single viewport. See `wm_stereo.c` */ + return; + } + gpu_viewport_framebuffer_view_set(viewport, 0); + DefaultTextureList *dtxl = viewport->txl; + DefaultFramebufferList *dfbl = viewport->fbl; + + GPUVertFormat *vert_format = immVertexFormat(); + uint pos = GPU_vertformat_attr_add(vert_format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); + GPU_framebuffer_bind(dfbl->stereo_comp_fb); + GPU_matrix_push(); + GPU_matrix_push_projection(); + GPU_matrix_identity_set(); + GPU_matrix_identity_projection_set(); + immBindBuiltinProgram(GPU_SHADER_2D_IMAGE_OVERLAYS_STEREO_MERGE); + immUniform1i("imageTexture", 0); + immUniform1i("overlayTexture", 1); + int settings = stereo_format->display_mode; + if (settings == S3D_DISPLAY_ANAGLYPH) { + switch (stereo_format->anaglyph_type) { + case S3D_ANAGLYPH_REDCYAN: + glColorMask(GL_FALSE, GL_TRUE, GL_TRUE, GL_TRUE); + break; + case S3D_ANAGLYPH_GREENMAGENTA: + glColorMask(GL_TRUE, GL_FALSE, GL_TRUE, GL_TRUE); + break; + case S3D_ANAGLYPH_YELLOWBLUE: + glColorMask(GL_FALSE, GL_FALSE, GL_TRUE, GL_TRUE); + break; + } + } + else if (settings == S3D_DISPLAY_INTERLACE) { + settings |= stereo_format->interlace_type << 3; + SET_FLAG_FROM_TEST(settings, stereo_format->flag & S3D_INTERLACE_SWAP, 1 << 6); + } + immUniform1i("stereoDisplaySettings", settings); + + GPU_texture_bind(dtxl->color_stereo, 0); + GPU_texture_bind(dtxl->color_overlay_stereo, 1); + + immBegin(GPU_PRIM_TRI_STRIP, 4); + + immVertex2f(pos, -1.0f, -1.0f); + immVertex2f(pos, 1.0f, -1.0f); + immVertex2f(pos, -1.0f, 1.0f); + immVertex2f(pos, 1.0f, 1.0f); + + immEnd(); + + GPU_texture_unbind(dtxl->color_stereo); + GPU_texture_unbind(dtxl->color_overlay_stereo); + + immUnbindProgram(); + GPU_matrix_pop_projection(); + GPU_matrix_pop(); + + if (settings == S3D_DISPLAY_ANAGLYPH) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + + GPU_framebuffer_restore(); +} + static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, const rctf *rect_pos, const rctf *rect_uv, @@ -537,9 +689,11 @@ static void gpu_viewport_draw_colormanaged(GPUViewport *viewport, * transform should be performed. */ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, + int view, const rcti *rect, bool display_colorspace) { + gpu_viewport_framebuffer_view_set(viewport, view); DefaultFramebufferList *dfbl = viewport->fbl; DefaultTextureList *dtxl = viewport->txl; GPUTexture *color = dtxl->color; @@ -594,9 +748,9 @@ void GPU_viewport_draw_to_screen_ex(GPUViewport *viewport, * \param rect: Coordinates to draw into. By swapping min and max values, drawing can be done with * inversed axis coordinates (upside down or sideways). */ -void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect) +void GPU_viewport_draw_to_screen(GPUViewport *viewport, int view, const rcti *rect) { - GPU_viewport_draw_to_screen_ex(viewport, rect, true); + GPU_viewport_draw_to_screen_ex(viewport, view, rect, true); } /** @@ -642,22 +796,25 @@ void GPU_viewport_unbind(GPUViewport *UNUSED(viewport)) DRW_opengl_context_disable(); } -GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport) +GPUTexture *GPU_viewport_color_texture(GPUViewport *viewport, int view) { DefaultFramebufferList *dfbl = viewport->fbl; if (dfbl->default_fb) { DefaultTextureList *dtxl = viewport->txl; - return dtxl->color; + if (viewport->active_view == view) { + return dtxl->color; + } + else { + return dtxl->color_stereo; + } } return NULL; } -static void gpu_viewport_buffers_free(FramebufferList *fbl, - int fbl_len, - TextureList *txl, - int txl_len) +static void gpu_viewport_buffers_free( + FramebufferList *fbl, int fbl_len, TextureList *txl, TextureList *txl_stereo, int txl_len) { for (int i = 0; i < fbl_len; i++) { GPUFrameBuffer *fb = fbl->framebuffers[i]; @@ -673,6 +830,15 @@ static void gpu_viewport_buffers_free(FramebufferList *fbl, txl->textures[i] = NULL; } } + if (txl_stereo != NULL) { + for (int i = 0; i < txl_len; i++) { + GPUTexture *tex = txl_stereo->textures[i]; + if (tex) { + GPU_texture_free(tex); + txl_stereo->textures[i] = NULL; + } + } + } } static void gpu_viewport_storage_free(StorageList *stl, int stl_len) @@ -699,6 +865,7 @@ void GPU_viewport_free(GPUViewport *viewport) gpu_viewport_buffers_free((FramebufferList *)viewport->fbl, default_fbl_len, (TextureList *)viewport->txl, + NULL, default_txl_len); gpu_viewport_texture_pool_free(viewport); |