diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index f7d3a37246e..eb66e9c20ea 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -66,7 +66,6 @@ set(SRC intern/draw_manager.c intern/draw_manager_data.c intern/draw_manager_exec.c - intern/draw_manager_framebuffer.c intern/draw_manager_shader.c intern/draw_manager_text.c intern/draw_manager_texture.c diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index cc4c0ed10e8..e42b5a49d64 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -58,6 +58,8 @@ struct WorkSpace; /* Buffer and textures used by the viewport by default */ typedef struct DefaultFramebufferList { struct GPUFrameBuffer *default_fb; + struct GPUFrameBuffer *color_only_fb; + struct GPUFrameBuffer *depth_only_fb; struct GPUFrameBuffer *multisample_fb; } DefaultFramebufferList; diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index 382551b16e4..86ff52045db 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -148,14 +148,11 @@ typedef struct CLAY_PassList { struct DRWPass *hair_pass; } CLAY_PassList; -typedef struct CLAY_TextureList { - struct GPUTexture *color_copy; /* only used if fxaa */ -} CLAY_TextureList; typedef struct CLAY_Data { void *engine_type; CLAY_FramebufferList *fbl; - CLAY_TextureList *txl; + DRWViewportEmptyList *txl; CLAY_PassList *psl; CLAY_StorageList *stl; } CLAY_Data; @@ -201,6 +198,7 @@ typedef struct CLAY_PrivateData { struct GPUTexture *depth_tx; /* ref only, not alloced */ struct GPUTexture *normal_tx; /* ref only, not alloced */ struct GPUTexture *id_tx; /* ref only, not alloced */ + struct GPUTexture *color_copy; /* ref only, not alloced */ bool enable_deferred_path; /* Ssao */ float winmat[4][4]; @@ -351,9 +349,9 @@ static struct GPUTexture *create_jitter_texture(int num_samples) static void clay_engine_init(void *vedata) { CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); /* Create Texture Array */ if (!e_data.matcap_array) { @@ -463,19 +461,29 @@ static void clay_engine_init(void *vedata) } } - if (DRW_state_is_fbo()) { + /* FBO setup */ + { const float *viewport_size = DRW_viewport_size_get(); - DRWFboTexture texs[2] = {{&g_data->normal_tx, DRW_TEX_RG_8, DRW_TEX_TEMP}, - {&g_data->id_tx, DRW_TEX_R_16I, DRW_TEX_TEMP}}; - DRW_framebuffer_init(&fbl->prepass_fb, &draw_engine_clay_type, - (int)viewport_size[0], (int)viewport_size[1], - texs, 2); + const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; + + g_data->normal_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RG_8, &draw_engine_clay_type); + g_data->id_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_R_16I, &draw_engine_clay_type); + + GPU_framebuffer_ensure_config(&fbl->prepass_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(g_data->normal_tx), + GPU_ATTACHMENT_TEXTURE(g_data->id_tx) + }); /* For FXAA */ - DRWFboTexture tex = {&txl->color_copy, DRW_TEX_RGBA_8, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->antialias_fb, &draw_engine_clay_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + /* TODO(fclem): OPTI: we could merge normal_tx and id_tx into a DRW_TEX_RGBA_8 + * and reuse it for the fxaa target. */ + g_data->color_copy = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RGBA_8, &draw_engine_clay_type); + + GPU_framebuffer_ensure_config(&fbl->antialias_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(g_data->color_copy) + }); } /* SSAO setup */ @@ -809,7 +817,6 @@ static void clay_cache_init(void *vedata) DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - CLAY_TextureList *txl = ((CLAY_Data *)vedata)->txl; /* Disable AO unless a material needs it. */ stl->g_data->enable_deferred_path = false; @@ -854,7 +861,7 @@ static void clay_cache_init(void *vedata) psl->copy_ps = DRW_pass_create("Copy", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.copy_sh, psl->copy_ps); - DRW_shgroup_uniform_buffer(grp, "colortex", &txl->color_copy); + DRW_shgroup_uniform_buffer(grp, "colortex", &stl->g_data->color_copy); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -956,37 +963,25 @@ static void clay_draw_scene(void *vedata) DRW_draw_pass(psl->hair_pass); if (stl->g_data->enable_deferred_path) { - if (DRW_state_is_fbo()) { - DRW_framebuffer_texture_detach(dtxl->depth); - DRW_framebuffer_texture_attach(fbl->prepass_fb, dtxl->depth, 0, 0); - DRW_framebuffer_texture_attach(fbl->prepass_fb, stl->g_data->normal_tx, 0, 0); - DRW_framebuffer_texture_attach(fbl->prepass_fb, stl->g_data->id_tx, 1, 0); - DRW_framebuffer_bind(fbl->prepass_fb); - /* We need to clear the id texture unfortunately. */ - DRW_framebuffer_clear(true, false, false, (float[4]){0.0f, 0.0f, 0.0f, 0.0f}, 0.0f); - } + GPU_framebuffer_bind(fbl->prepass_fb); + /* We need to clear the id texture unfortunately. */ + const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_clear_color(fbl->prepass_fb, clear_col); DRW_draw_pass(psl->clay_pre_cull_ps); DRW_draw_pass(psl->clay_flat_pre_cull_ps); DRW_draw_pass(psl->clay_pre_ps); DRW_draw_pass(psl->clay_flat_pre_ps); - if (DRW_state_is_fbo()) { - DRW_framebuffer_texture_detach(dtxl->depth); - DRW_framebuffer_bind(dfbl->default_fb); - - DRW_draw_pass(psl->clay_deferred_ps); - - DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); - DRW_framebuffer_bind(dfbl->default_fb); - } + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->clay_deferred_ps); } if (true) { /* Always on for now. We might want a parameter for this. */ - DRW_framebuffer_bind(fbl->antialias_fb); + GPU_framebuffer_bind(fbl->antialias_fb); DRW_draw_pass(psl->fxaa_ps); - DRW_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->copy_ps); } } diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl index f2c6cd5f780..1939e4b735d 100644 --- a/source/blender/draw/engines/clay/shaders/clay_frag.glsl +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -225,14 +225,15 @@ void main() vec2 screenco = vec2(gl_FragCoord.xy) * invscreenres; #ifdef DEFERRED_SHADING - mat_id = texture(idtex, screenco).r; + ivec2 texel = ivec2(gl_FragCoord.xy); + mat_id = texelFetch(idtex, texel, 0).r; /* early out (manual stencil test) */ if (mat_id == 0) discard; - float depth = texture(depthtex, screenco).r; - vec3 N = normal_decode(texture(normaltex, screenco).rg); + float depth = texelFetch(depthtex, texel, 0).r; + vec3 N = normal_decode(texelFetch(normaltex, texel, 0).rg); /* see the prepass for explanations. */ if (mat_id < 0) { N = -N; diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c index c62f35a70e7..29f6ca3988c 100644 --- a/source/blender/draw/engines/eevee/eevee_bloom.c +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -84,7 +84,6 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -112,10 +111,13 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) effects->blit_texel_size[0] = 1.0f / (float)blitsize[0]; effects->blit_texel_size[1] = 1.0f / (float)blitsize[1]; - DRWFboTexture tex_blit = {&txl->bloom_blit, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->bloom_blit_fb, &draw_engine_eevee_type, - (int)blitsize[0], (int)blitsize[1], - &tex_blit, 1); + effects->bloom_blit = DRW_texture_pool_query_2D(blitsize[0], blitsize[1], DRW_TEX_RGB_11_11_10, + &draw_engine_eevee_type); + + GPU_framebuffer_ensure_config(&fbl->bloom_blit_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->bloom_blit) + }); /* Parameters */ float threshold = BKE_collection_engine_property_value_get_float(props, "bloom_threshold"); @@ -151,10 +153,12 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) effects->downsamp_texel_size[i][0] = 1.0f / (float)texsize[0]; effects->downsamp_texel_size[i][1] = 1.0f / (float)texsize[1]; - DRWFboTexture tex_bloom = {&txl->bloom_downsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->bloom_down_fb[i], &draw_engine_eevee_type, - (int)texsize[0], (int)texsize[1], - &tex_bloom, 1); + effects->bloom_downsample[i] = DRW_texture_pool_query_2D(texsize[0], texsize[1], DRW_TEX_RGB_11_11_10, + &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->bloom_down_fb[i], { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->bloom_downsample[i]) + }); } /* Upsample buffers */ @@ -165,30 +169,23 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) texsize[0] = MAX2(texsize[0], 2); texsize[1] = MAX2(texsize[1], 2); - DRWFboTexture tex_bloom = {&txl->bloom_upsample[i], DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->bloom_accum_fb[i], &draw_engine_eevee_type, - (int)texsize[0], (int)texsize[1], - &tex_bloom, 1); + effects->bloom_upsample[i] = DRW_texture_pool_query_2D(texsize[0], texsize[1], DRW_TEX_RGB_11_11_10, + &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->bloom_accum_fb[i], { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->bloom_upsample[i]) + }); } return EFFECT_BLOOM | EFFECT_POST_BUFFER; } /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->bloom_blit); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->bloom_blit_fb); - - /* Bloom and dof share this buffer. This - * tells dof to reconfigure it's framebuffer. */ - if (txl->bloom_downsample[0] != NULL) { - DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_down_fb); - } + GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_blit_fb); for (int i = 0; i < MAX_BLOOM_STEP - 1; ++i) { - DRW_TEXTURE_FREE_SAFE(txl->bloom_downsample[i]); - DRW_TEXTURE_FREE_SAFE(txl->bloom_upsample[i]); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->bloom_down_fb[i]); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->bloom_accum_fb[i]); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_down_fb[i]); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->bloom_accum_fb[i]); } return 0; @@ -280,39 +277,39 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata) copy_v2_v2(effects->unf_source_texel_size, effects->source_texel_size); effects->unf_source_buffer = effects->source_buffer; - DRW_framebuffer_bind(fbl->bloom_blit_fb); + GPU_framebuffer_bind(fbl->bloom_blit_fb); DRW_draw_pass(psl->bloom_blit); /* Downsample */ copy_v2_v2(effects->unf_source_texel_size, effects->blit_texel_size); - effects->unf_source_buffer = txl->bloom_blit; + effects->unf_source_buffer = effects->bloom_blit; - DRW_framebuffer_bind(fbl->bloom_down_fb[0]); + GPU_framebuffer_bind(fbl->bloom_down_fb[0]); DRW_draw_pass(psl->bloom_downsample_first); - last = txl->bloom_downsample[0]; + last = effects->bloom_downsample[0]; for (int i = 1; i < effects->bloom_iteration_ct; ++i) { copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i - 1]); effects->unf_source_buffer = last; - DRW_framebuffer_bind(fbl->bloom_down_fb[i]); + GPU_framebuffer_bind(fbl->bloom_down_fb[i]); DRW_draw_pass(psl->bloom_downsample); /* Used in next loop */ - last = txl->bloom_downsample[i]; + last = effects->bloom_downsample[i]; } /* Upsample and accumulate */ for (int i = effects->bloom_iteration_ct - 2; i >= 0; --i) { copy_v2_v2(effects->unf_source_texel_size, effects->downsamp_texel_size[i]); - effects->unf_source_buffer = txl->bloom_downsample[i]; + effects->unf_source_buffer = effects->bloom_downsample[i]; effects->unf_base_buffer = last; - DRW_framebuffer_bind(fbl->bloom_accum_fb[i]); + GPU_framebuffer_bind(fbl->bloom_accum_fb[i]); DRW_draw_pass(psl->bloom_upsample); - last = txl->bloom_upsample[i]; + last = effects->bloom_upsample[i]; } /* Resolve */ @@ -320,7 +317,7 @@ void EEVEE_bloom_draw(EEVEE_Data *vedata) effects->unf_source_buffer = last; effects->unf_base_buffer = effects->source_buffer; - DRW_framebuffer_bind(effects->target_buffer); + GPU_framebuffer_bind(effects->target_buffer); DRW_draw_pass(psl->bloom_resolve); SWAP_BUFFERS(); } diff --git a/source/blender/draw/engines/eevee/eevee_data.c b/source/blender/draw/engines/eevee/eevee_data.c index 0b6ab905e32..5adcf9e9ffb 100644 --- a/source/blender/draw/engines/eevee/eevee_data.c +++ b/source/blender/draw/engines/eevee/eevee_data.c @@ -38,8 +38,9 @@ static void eevee_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->light_ubo); DRW_UBO_FREE_SAFE(sldata->shadow_ubo); DRW_UBO_FREE_SAFE(sldata->shadow_render_ubo); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_target_fb); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->shadow_store_fb); + GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cube_target_fb); + GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_cascade_target_fb); + GPU_FRAMEBUFFER_FREE_SAFE(sldata->shadow_store_fb); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_target); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cube_blur); DRW_TEXTURE_FREE_SAFE(sldata->shadow_cascade_target); @@ -57,8 +58,10 @@ static void eevee_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->planar_ubo); DRW_UBO_FREE_SAFE(sldata->common_ubo); DRW_UBO_FREE_SAFE(sldata->clip_ubo); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); + GPU_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); + for (int i = 0; i < 6; ++i) { + GPU_FRAMEBUFFER_FREE_SAFE(sldata->probe_face_fb[i]); + } DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); diff --git a/source/blender/draw/engines/eevee/eevee_depth_of_field.c b/source/blender/draw/engines/eevee/eevee_depth_of_field.c index dcd45e27337..c137aa8da24 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -79,7 +79,6 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v { EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); @@ -104,39 +103,36 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v int buffer_size[2] = {(int)viewport_size[0] / 2, (int)viewport_size[1] / 2}; - /* Reuse buffer from Bloom if available */ - /* WATCH IT : must have the same size */ - struct GPUTexture **dof_down_near; + effects->dof_down_near = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], DRW_TEX_RGB_11_11_10, + &draw_engine_eevee_type); + effects->dof_down_far = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], DRW_TEX_RGB_11_11_10, + &draw_engine_eevee_type); + effects->dof_coc = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], DRW_TEX_RG_16, + &draw_engine_eevee_type); - if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { - dof_down_near = &txl->bloom_downsample[0]; - } - else { - dof_down_near = &txl->dof_down_near; - } - - /* Setup buffers */ - DRWFboTexture tex_down[3] = { - {dof_down_near, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, /* filter to not interfeer with bloom */ - {&txl->dof_down_far, DRW_TEX_RGB_11_11_10, 0}, - {&txl->dof_coc, DRW_TEX_RG_16, 0}, - }; - DRW_framebuffer_init( - &fbl->dof_down_fb, &draw_engine_eevee_type, - buffer_size[0], buffer_size[1], tex_down, 3); + GPU_framebuffer_ensure_config(&fbl->dof_down_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->dof_down_near), + GPU_ATTACHMENT_TEXTURE(effects->dof_down_far), + GPU_ATTACHMENT_TEXTURE(effects->dof_coc) + }); /* Go full 32bits for rendering and reduce the color artifacts. */ DRWTextureFormat fb_format = DRW_state_is_image_render() ? DRW_TEX_RGBA_32 : DRW_TEX_RGBA_16; - DRWFboTexture tex_scatter_far = {&txl->dof_far_blur, fb_format, DRW_TEX_FILTER}; - DRW_framebuffer_init( - &fbl->dof_scatter_far_fb, &draw_engine_eevee_type, - buffer_size[0], buffer_size[1], &tex_scatter_far, 1); + effects->dof_far_blur = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], fb_format, + &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->dof_scatter_far_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->dof_far_blur), + }); - DRWFboTexture tex_scatter_near = {&txl->dof_near_blur, fb_format, DRW_TEX_FILTER}; - DRW_framebuffer_init( - &fbl->dof_scatter_near_fb, &draw_engine_eevee_type, - buffer_size[0], buffer_size[1], &tex_scatter_near, 1); + effects->dof_near_blur = DRW_texture_pool_query_2D(buffer_size[0], buffer_size[1], fb_format, + &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->dof_scatter_near_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->dof_near_blur), + }); /* Parameters */ /* TODO UI Options */ @@ -178,14 +174,9 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v } /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->dof_down_near); - DRW_TEXTURE_FREE_SAFE(txl->dof_down_far); - DRW_TEXTURE_FREE_SAFE(txl->dof_coc); - DRW_TEXTURE_FREE_SAFE(txl->dof_far_blur); - DRW_TEXTURE_FREE_SAFE(txl->dof_near_blur); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_down_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_far_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_near_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->dof_down_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_far_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->dof_scatter_near_fb); return 0; } @@ -194,7 +185,6 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ { EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects = stl->effects; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); @@ -229,7 +219,7 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ grp = DRW_shgroup_empty_tri_batch_create(e_data.dof_scatter_sh, psl->dof_scatter, sprite_ct); DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->unf_source_buffer); - DRW_shgroup_uniform_buffer(grp, "cocBuffer", &txl->dof_coc); + DRW_shgroup_uniform_buffer(grp, "cocBuffer", &effects->dof_coc); DRW_shgroup_uniform_vec2(grp, "layerSelection", effects->dof_layer_select, 1); DRW_shgroup_uniform_vec4(grp, "bokehParams", effects->dof_bokeh, 1); @@ -237,8 +227,8 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ grp = DRW_shgroup_create(e_data.dof_resolve_sh, psl->dof_resolve); DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer); - DRW_shgroup_uniform_buffer(grp, "nearBuffer", &txl->dof_near_blur); - DRW_shgroup_uniform_buffer(grp, "farBuffer", &txl->dof_far_blur); + DRW_shgroup_uniform_buffer(grp, "nearBuffer", &effects->dof_near_blur); + DRW_shgroup_uniform_buffer(grp, "farBuffer", &effects->dof_far_blur); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_uniform_vec2(grp, "nearFar", effects->dof_near_far, 1); DRW_shgroup_uniform_vec3(grp, "dofParams", effects->dof_params, 1); @@ -259,31 +249,25 @@ void EEVEE_depth_of_field_draw(EEVEE_Data *vedata) float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; /* Downsample */ - DRW_framebuffer_bind(fbl->dof_down_fb); + GPU_framebuffer_bind(fbl->dof_down_fb); DRW_draw_pass(psl->dof_down); /* Scatter Far */ - effects->unf_source_buffer = txl->dof_down_far; + effects->unf_source_buffer = effects->dof_down_far; copy_v2_fl2(effects->dof_layer_select, 0.0f, 1.0f); - DRW_framebuffer_bind(fbl->dof_scatter_far_fb); - DRW_framebuffer_clear(true, false, false, clear_col, 0.0f); + GPU_framebuffer_bind(fbl->dof_scatter_far_fb); + GPU_framebuffer_clear_color(fbl->dof_scatter_far_fb, clear_col); DRW_draw_pass(psl->dof_scatter); /* Scatter Near */ - if ((effects->enabled_effects & EFFECT_BLOOM) != 0) { - /* Reuse bloom half res buffer */ - effects->unf_source_buffer = txl->bloom_downsample[0]; - } - else { - effects->unf_source_buffer = txl->dof_down_near; - } + effects->unf_source_buffer = effects->dof_down_near; copy_v2_fl2(effects->dof_layer_select, 1.0f, 0.0f); - DRW_framebuffer_bind(fbl->dof_scatter_near_fb); - DRW_framebuffer_clear(true, false, false, clear_col, 0.0f); + GPU_framebuffer_bind(fbl->dof_scatter_near_fb); + GPU_framebuffer_clear_color(fbl->dof_scatter_near_fb, clear_col); DRW_draw_pass(psl->dof_scatter); /* Resolve */ - DRW_framebuffer_bind(effects->target_buffer); + GPU_framebuffer_bind(effects->target_buffer); DRW_draw_pass(psl->dof_resolve); SWAP_BUFFERS(); } diff --git a/source/blender/draw/engines/eevee/eevee_effects.c b/source/blender/draw/engines/eevee/eevee_effects.c index 1030fe1ce3a..d7fa9e76370 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -105,6 +105,7 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_EffectsInfo *effects; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -141,31 +142,45 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object * Ping Pong buffer */ if ((effects->enabled_effects & EFFECT_POST_BUFFER) != 0) { - DRWFboTexture tex = {&txl->color_post, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - DRW_framebuffer_init(&fbl->effect_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + DRW_texture_ensure_fullscreen_2D(&txl->color_post, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP); + + GPU_framebuffer_ensure_config(&fbl->effect_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->color_post), + }); + + GPU_framebuffer_ensure_config(&fbl->effect_color_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->color_post), + }); } else { /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->color_post); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->effect_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->effect_fb); } /** * MinMax Pyramid */ - DRWFboTexture texmax = {&txl->maxzbuffer, DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP}; + int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; + size[0] = max_ii(size[0] / 2, 1); + size[1] = max_ii(size[1] / 2, 1); if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_ANY, GPU_DRIVER_ANY)) { /* Intel gpu seems to have problem rendering to only depth format */ - texmax.format = DRW_TEX_R_32; + DRW_texture_ensure_2D(&txl->maxzbuffer, size[0], size[1], DRW_TEX_R_32, DRW_TEX_MIPMAP); + GPU_framebuffer_ensure_config(&fbl->downsample_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer) + }); + } + else { + DRW_texture_ensure_2D(&txl->maxzbuffer, size[0], size[1], DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP); + GPU_framebuffer_ensure_config(&fbl->downsample_fb, { + GPU_ATTACHMENT_TEXTURE(txl->maxzbuffer) + }); } - - DRW_framebuffer_init(&fbl->downsample_fb, &draw_engine_eevee_type, - max_ii((int)viewport_size[0] / 2, 1), max_ii((int)viewport_size[1] / 2, 1), - &texmax, 1); - /** * Compute Mipmap texel alignement. @@ -185,34 +200,37 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object * Normal buffer for deferred passes. */ if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - if (txl->ssr_normal_input == NULL) { - DRWTextureFormat nor_format = DRW_TEX_RG_16; - txl->ssr_normal_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], nor_format, 0, NULL); - } + int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - /* Reattach textures to the right buffer (because we are alternating between buffers) */ - /* TODO multiple FBO per texture!!!! */ - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); + effects->ssr_normal_input = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], DRW_TEX_RG_16, + &draw_engine_eevee_type); + + GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_normal_input, 1, 0); } else { - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->ssr_normal_input); + effects->ssr_normal_input = NULL; } /** * Setup double buffer so we can access last frame as it was before post processes. */ if ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0) { - DRWFboTexture tex_double_buffer = {&txl->color_double_buffer, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - DRW_framebuffer_init(&fbl->double_buffer, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex_double_buffer, 1); + DRW_texture_ensure_fullscreen_2D(&txl->color_double_buffer, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP); + + GPU_framebuffer_ensure_config(&fbl->double_buffer_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->color_double_buffer) + }); + + GPU_framebuffer_ensure_config(&fbl->double_buffer_color_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->color_double_buffer) + }); } else { /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->color_double_buffer); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer_fb); } } @@ -253,53 +271,24 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) /* Perform min/max downsample */ DRWShadingGroup *grp; -#if 0 /* Not used for now */ - psl->minz_downlevel_ps = DRW_pass_create("HiZ Min Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(e_data.minz_downlevel_sh, psl->minz_downlevel_ps); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &stl->g_data->minzbuffer); - DRW_shgroup_call_add(grp, quad, NULL); -#endif - psl->maxz_downlevel_ps = DRW_pass_create("HiZ Max Down Level", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downlevel_sh, psl->maxz_downlevel_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &txl->maxzbuffer); DRW_shgroup_call_add(grp, quad, NULL); /* Copy depth buffer to halfres top level of HiZ */ -#if 0 /* Not used for now */ - psl->minz_downdepth_ps = DRW_pass_create("HiZ Min Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(e_data.minz_downdepth_sh, psl->minz_downdepth_ps); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_call_add(grp, quad, NULL); -#endif psl->maxz_downdepth_ps = DRW_pass_create("HiZ Max Copy Depth Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_sh, psl->maxz_downdepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); -#if 0 /* Not used for now */ - psl->minz_downdepth_layer_ps = DRW_pass_create("HiZ Min Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(e_data.minz_downdepth_layer_sh, psl->minz_downdepth_layer_ps); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); - DRW_shgroup_call_add(grp, quad, NULL); -#endif - psl->maxz_downdepth_layer_ps = DRW_pass_create("HiZ Max Copy DepthLayer Halfres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_downdepth_layer_sh, psl->maxz_downdepth_layer_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_uniform_int(grp, "depthLayer", &e_data.depth_src_layer, 1); DRW_shgroup_call_add(grp, quad, NULL); - /* Copy depth buffer to halfres top level of HiZ */ -#if 0 /* Not used for now */ - psl->minz_copydepth_ps = DRW_pass_create("HiZ Min Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(e_data.minz_copydepth_sh, psl->minz_copydepth_ps); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_call_add(grp, quad, NULL); -#endif - psl->maxz_copydepth_ps = DRW_pass_create("HiZ Max Copy Depth Fullres", downsample_write | DRW_STATE_DEPTH_ALWAYS); grp = DRW_shgroup_create(e_data.maxz_copydepth_sh, psl->maxz_copydepth_ps); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); @@ -346,64 +335,67 @@ void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, GPUTexture *depth_src, int l #if 0 /* Not required for now */ DRW_stats_group_start("Min buffer"); /* Copy depth buffer to min texture top level */ - DRW_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0); - DRW_framebuffer_bind(fbl->downsample_fb); + GPU_framebuffer_texture_attach(fbl->downsample_fb, stl->g_data->minzbuffer, 0, 0); + GPU_framebuffer_bind(fbl->downsample_fb); if (layer >= 0) { DRW_draw_pass(psl->minz_downdepth_layer_ps); } else { DRW_draw_pass(psl->minz_downdepth_ps); } - DRW_framebuffer_texture_detach(stl->g_data->minzbuffer); + GPU_framebuffer_texture_detach(stl->g_data->minzbuffer); /* Create lower levels */ - DRW_framebuffer_recursive_downsample(fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata); + GPU_framebuffer_recursive_downsample(fbl->downsample_fb, stl->g_data->minzbuffer, 8, &min_downsample_cb, vedata); DRW_stats_group_end(); #endif DRW_stats_group_start("Max buffer"); /* Copy depth buffer to max texture top level */ - DRW_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0); - DRW_framebuffer_bind(fbl->downsample_fb); + GPU_framebuffer_texture_attach(fbl->downsample_fb, txl->maxzbuffer, 0, 0); + GPU_framebuffer_bind(fbl->downsample_fb); if (layer >= 0) { DRW_draw_pass(psl->maxz_downdepth_layer_ps); } else { DRW_draw_pass(psl->maxz_downdepth_ps); } - DRW_framebuffer_texture_detach(txl->maxzbuffer); /* Create lower levels */ - DRW_framebuffer_recursive_downsample(fbl->downsample_fb, txl->maxzbuffer, 8, &max_downsample_cb, vedata); + GPU_framebuffer_recursive_downsample(fbl->downsample_fb, 8, &max_downsample_cb, vedata); DRW_stats_group_end(); /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); } /** * Simple downsampling algorithm. Reconstruct mip chain up to mip level. **/ -void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, GPUTexture *texture_src, int level) +void EEVEE_downsample_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level) { + EEVEE_FramebufferList *fbl = vedata->fbl; e_data.color_src = texture_src; - DRW_stats_group_start("Downsample buffer"); /* Create lower levels */ - DRW_framebuffer_recursive_downsample(fb_src, texture_src, level, &simple_downsample_cb, vedata); + DRW_stats_group_start("Downsample buffer"); + GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0); + GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cb, vedata); DRW_stats_group_end(); } /** * Simple downsampling algorithm for cubemap. Reconstruct mip chain up to mip level. **/ -void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, GPUTexture *texture_src, int level) +void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, GPUTexture *texture_src, int level) { + EEVEE_FramebufferList *fbl = vedata->fbl; e_data.color_src = texture_src; - DRW_stats_group_start("Downsample Cube buffer"); /* Create lower levels */ - DRW_framebuffer_recursive_downsample(fb_src, texture_src, level, &simple_downsample_cube_cb, vedata); + DRW_stats_group_start("Downsample Cube buffer"); + GPU_framebuffer_texture_attach(fbl->downsample_fb, texture_src, 0, 0); + GPU_framebuffer_recursive_downsample(fbl->downsample_fb, level, &simple_downsample_cube_cb, vedata); DRW_stats_group_end(); } @@ -413,21 +405,17 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); /* only once per frame after the first post process */ effects->swap_double_buffer = ((effects->enabled_effects & EFFECT_DOUBLE_BUFFER) != 0); /* Init pointers */ effects->source_buffer = txl->color; /* latest updated texture */ - effects->target_buffer = fbl->effect_fb; /* next target to render to */ + effects->target_buffer = fbl->effect_color_fb; /* next target to render to */ /* Temporal Anti-Aliasing MUST come first */ EEVEE_temporal_sampling_draw(vedata); - /* Detach depth for effects to use it */ - DRW_framebuffer_texture_detach(dtxl->depth); - /* Post process stack (order matters) */ EEVEE_motion_blur_draw(vedata); EEVEE_depth_of_field_draw(vedata); @@ -435,7 +423,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) /* Save the final texture and framebuffer for final transformation or read. */ effects->final_tx = effects->source_buffer; - effects->final_fb = (effects->target_buffer != fbl->main) ? fbl->main : fbl->effect_fb; + effects->final_fb = (effects->target_buffer != fbl->main_fb) ? fbl->main_fb : fbl->effect_fb; /* If no post processes is enabled, buffers are still not swapped, do it now. */ SWAP_DOUBLE_BUFFERS(); diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index 6cfecd0a226..276f23c7cf7 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -55,6 +55,7 @@ static void eevee_engine_init(void *ved) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; @@ -68,12 +69,22 @@ static void eevee_engine_init(void *ved) stl->g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f; stl->g_data->valid_double_buffer = (txl->color_double_buffer != NULL); - DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; + /* Main Buffer */ + DRW_texture_ensure_fullscreen_2D(&txl->color, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP); - const float *viewport_size = DRW_viewport_size_get(); - DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + GPU_framebuffer_ensure_config(&fbl->main_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->color), + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE + }); + + GPU_framebuffer_ensure_config(&fbl->main_color_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->color) + }); if (sldata->common_ubo == NULL) { sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); @@ -170,6 +181,7 @@ static void eevee_draw_background(void *vedata) EEVEE_TextureList *txl = ((EEVEE_Data *)vedata)->txl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; EEVEE_FramebufferList *fbl = ((EEVEE_Data *)vedata)->fbl; + EEVEE_EffectsInfo *effects = stl->effects; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); /* Default framebuffer and texture */ @@ -185,6 +197,9 @@ static void eevee_draw_background(void *vedata) (stl->effects->enabled_effects & (EFFECT_VOLUMETRIC | EFFECT_SSR)) != 0) ? 4 : 1; while (loop_ct--) { + float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float clear_depth = 1.0f; + unsigned int clear_stencil = 0xFF; unsigned int primes[3] = {2, 3, 7}; double offset[3] = {0.0, 0.0, 0.0}; double r[3]; @@ -228,18 +243,11 @@ static void eevee_draw_background(void *vedata) EEVEE_draw_shadows(sldata, psl); DRW_stats_group_end(); - /* Attach depth to the hdr buffer and bind it */ - DRW_framebuffer_texture_detach(dtxl->depth); - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); - DRW_framebuffer_bind(fbl->main); - if (DRW_state_draw_background()) { - DRW_framebuffer_clear(false, true, true, NULL, 1.0f); - } - else { - /* We need to clear the alpha chanel in this case. */ - float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - DRW_framebuffer_clear(true, true, true, clear_col, 1.0f); - } + GPU_framebuffer_bind(fbl->main_fb); + GPUFrameBufferBits clear_bits = GPU_DEPTH_BIT; + clear_bits |= (DRW_state_draw_background()) ? 0 : GPU_COLOR_BIT; + clear_bits |= ((stl->effects->enabled_effects & EFFECT_SSS) != 0) ? GPU_STENCIL_BIT : 0; + GPU_framebuffer_clear(fbl->main_fb, clear_bits, clear_col, clear_depth, clear_stencil); /* Depth prepass */ DRW_stats_group_start("Prepass"); @@ -295,11 +303,8 @@ static void eevee_draw_background(void *vedata) } } - /* Restore default framebuffer */ - DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); - DRW_framebuffer_bind(dfbl->default_fb); - - /* Tonemapping */ + /* Tonemapping and transfer result to default framebuffer. */ + GPU_framebuffer_bind(dfbl->default_fb); DRW_transform_to_display(stl->effects->final_tx); /* Debug : Ouput buffer to view. */ @@ -308,25 +313,25 @@ static void eevee_draw_background(void *vedata) if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer); break; case 2: - if (stl->g_data->ssr_pdf_output) DRW_transform_to_display(stl->g_data->ssr_pdf_output); + if (effects->ssr_pdf_output) DRW_transform_to_display(effects->ssr_pdf_output); break; case 3: - if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input); + if (effects->ssr_normal_input) DRW_transform_to_display(effects->ssr_normal_input); break; case 4: - if (txl->ssr_specrough_input) DRW_transform_to_display(txl->ssr_specrough_input); + if (effects->ssr_specrough_input) DRW_transform_to_display(effects->ssr_specrough_input); break; case 5: if (txl->color_double_buffer) DRW_transform_to_display(txl->color_double_buffer); break; case 6: - if (stl->g_data->gtao_horizons_debug) DRW_transform_to_display(stl->g_data->gtao_horizons_debug); + if (effects->gtao_horizons_debug) DRW_transform_to_display(effects->gtao_horizons_debug); break; case 7: - if (txl->gtao_horizons) DRW_transform_to_display(txl->gtao_horizons); + if (effects->gtao_horizons) DRW_transform_to_display(effects->gtao_horizons); break; case 8: - if (txl->sss_data) DRW_transform_to_display(txl->sss_data); + if (effects->sss_data) DRW_transform_to_display(effects->sss_data); break; default: break; diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index e751f2dd6b4..daab8deda7c 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -155,7 +155,6 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) /* XXX TODO OPTIMISATION : This is a complete waist of texture memory. * Instead of allocating each planar probe for each viewport, * only alloc them once using the biggest viewport resolution. */ - EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; const float *viewport_size = DRW_viewport_size_get(); @@ -182,15 +181,6 @@ static void planar_pool_ensure_alloc(EEVEE_Data *vedata, int num_planar_ref) txl->planar_depth = DRW_texture_create_2D_array(1, 1, 1, DRW_TEX_DEPTH_24, 0, NULL); } } - - if (num_planar_ref > 0) { - /* NOTE : Depth buffer is 2D but the planar_pool tex is 2D array. - * DRW_framebuffer_init binds the whole texture making the framebuffer invalid. - * To overcome this, we bind the planar pool ourselves later */ - - /* XXX Do this one first so it gets it's mipmap done. */ - DRW_framebuffer_init(&fbl->planarref_fb, &draw_engine_eevee_type, 1, 1, NULL, 0); - } } static void lightprobe_shaders_init(void) @@ -349,7 +339,6 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); } int visibility_res = BKE_collection_engine_property_value_get_int(props, "gi_visibility_resolution"); @@ -370,13 +359,12 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda sldata->probe_rt = DRW_texture_create_cube(sldata->probes->target_size, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); } - DRWFboTexture tex_probe[2] = {{&sldata->probe_depth_rt, DRW_TEX_DEPTH_24, 0}, - {&sldata->probe_rt, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}}; - DRW_framebuffer_init(&sldata->probe_fb, &draw_engine_eevee_type, sldata->probes->target_size, sldata->probes->target_size, tex_probe, 2); - - /* Minmaxz Pyramid */ - // DRWFboTexture tex_minmaxz = {&e_data.cube_face_minmaxz, DRW_TEX_RG_32, DRW_TEX_MIPMAP | DRW_TEX_TEMP}; - // DRW_framebuffer_init(&vedata->fbl->downsample_fb, &draw_engine_eevee_type, PROBE_RT_SIZE / 2, PROBE_RT_SIZE / 2, &tex_minmaxz, 1); + for (int i = 0; i < 6; ++i) { + GPU_framebuffer_ensure_config(&sldata->probe_face_fb[i], { + GPU_ATTACHMENT_TEXTURE_CUBEFACE(sldata->probe_depth_rt, i), + GPU_ATTACHMENT_TEXTURE_CUBEFACE(sldata->probe_rt, i) + }); + } /* Placeholder planar pool: used when rendering planar reflections (avoid dependency loop). */ if (!e_data.planar_pool_placeholder) { @@ -957,7 +945,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved sldata->probe_pool = DRW_texture_create_2D_array(pinfo->cubemap_res, pinfo->cubemap_res, max_ff(1, pinfo->num_cube), DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); if (sldata->probe_filter_fb) { - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); } /* Tag probes to refresh */ pinfo->update_world |= PROBE_UPDATE_CUBE; @@ -973,11 +961,6 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } } - DRWFboTexture tex_filter = {&sldata->probe_pool, DRW_TEX_RGBA_16, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - - DRW_framebuffer_init(&sldata->probe_filter_fb, &draw_engine_eevee_type, pinfo->cubemap_res, pinfo->cubemap_res, &tex_filter, 1); - - #ifdef IRRADIANCE_SH_L2 /* we need a signed format for Spherical Harmonics */ int irradiance_format = DRW_TEX_RGBA_16; @@ -1051,14 +1034,17 @@ static void glossy_filter_probe( /* Max lod used from the render target probe */ pinfo->lod_rt_max = floorf(log2f(pinfo->target_size)) - 2.0f; + /* Start fresh */ + GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); + /* 2 - Let gpu create Mipmaps for Filtered Importance Sampling. */ /* Bind next framebuffer to be able to gen. mips for probe_rt. */ - DRW_framebuffer_bind(sldata->probe_filter_fb); - EEVEE_downsample_cube_buffer(vedata, sldata->probe_filter_fb, sldata->probe_rt, (int)(pinfo->lod_rt_max)); + EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max)); /* 3 - Render to probe array to the specified layer, do prefiltering. */ - /* Detach to rebind the right mipmap. */ - DRW_framebuffer_texture_detach(sldata->probe_pool); float mipsize = pinfo->cubemap_res; const int maxlevel = (int)floorf(log2f(pinfo->cubemap_res)); const int min_lod_level = 3; @@ -1101,19 +1087,19 @@ static void glossy_filter_probe( pinfo->invsamples_ct = 1.0f / pinfo->samples_ct; pinfo->lodfactor = bias + 0.5f * log((float)(pinfo->target_size * pinfo->target_size) * pinfo->invsamples_ct) / log(2); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, i); - DRW_framebuffer_viewport_size(sldata->probe_filter_fb, 0, 0, mipsize, mipsize); + GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_MIP(sldata->probe_pool, i) + }); + GPU_framebuffer_bind(sldata->probe_filter_fb); + GPU_framebuffer_viewport_set(sldata->probe_filter_fb, 0, 0, mipsize, mipsize); DRW_draw_pass(psl->probe_glossy_compute); - DRW_framebuffer_texture_detach(sldata->probe_pool); mipsize /= 2; CLAMP_MIN(mipsize, 1); } /* For shading, save max level of the octahedron map */ sldata->common_data.prb_lod_cube_max = (float)(maxlevel - min_lod_level) - 1.0f; - - /* reattach to have a valid framebuffer. */ - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); } /* Diffuse filter probe_rt to irradiance_pool at index probe_idx */ @@ -1156,14 +1142,21 @@ static void diffuse_filter_probe( pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */ #endif + /* Start fresh */ + GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); + /* 4 - Compute spherical harmonics */ - DRW_framebuffer_bind(sldata->probe_filter_fb); - EEVEE_downsample_cube_buffer(vedata, sldata->probe_filter_fb, sldata->probe_rt, (int)(pinfo->lod_rt_max)); + EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max)); - DRW_framebuffer_texture_detach(sldata->probe_pool); - DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0, 0); - - DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]); + GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, 0) + }); + GPU_framebuffer_bind(sldata->probe_filter_fb); + GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, size[0], size[1]); DRW_draw_pass(psl->probe_diffuse_compute); /* World irradiance have no visibility */ @@ -1183,18 +1176,16 @@ static void diffuse_filter_probe( x = common_data->prb_irradiance_vis_size * (offset % cell_per_row); y = common_data->prb_irradiance_vis_size * ((offset / cell_per_row) % cell_per_col); int layer = 1 + ((offset / cell_per_row) / cell_per_col); + const int vis_size = common_data->prb_irradiance_vis_size; - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, layer, 0); - - DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, common_data->prb_irradiance_vis_size, - common_data->prb_irradiance_vis_size); + GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_LAYER(sldata->irradiance_rt, layer) + }); + GPU_framebuffer_bind(sldata->probe_filter_fb); + GPU_framebuffer_viewport_set(sldata->probe_filter_fb, x, y, vis_size, vis_size); DRW_draw_pass(psl->probe_visibility_compute); } - - /* reattach to have a valid framebuffer. */ - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); } /* Render the scene to the probe_rt texture. */ @@ -1204,7 +1195,6 @@ static void render_scene_to_probe( { EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; - EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; DRWMatrixState matstate; @@ -1230,19 +1220,13 @@ static void render_scene_to_probe( /* Avoid using the texture attached to framebuffer when rendering. */ /* XXX */ GPUTexture *tmp_planar_pool = txl->planar_pool; - GPUTexture *tmp_minz = stl->g_data->minzbuffer; GPUTexture *tmp_maxz = txl->maxzbuffer; txl->planar_pool = e_data.planar_pool_placeholder; - stl->g_data->minzbuffer = e_data.depth_placeholder; txl->maxzbuffer = e_data.depth_placeholder; /* Update common uniforms */ DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); - /* Detach to rebind the right cubeface. */ - DRW_framebuffer_bind(sldata->probe_fb); - DRW_framebuffer_texture_detach(sldata->probe_rt); - DRW_framebuffer_texture_detach(sldata->probe_depth_rt); for (int i = 0; i < 6; ++i) { /* Setup custom matrices */ mul_m4_m4m4(viewmat, cubefacemat[i], posmat); @@ -1256,11 +1240,8 @@ static void render_scene_to_probe( /* Be sure that cascaded shadow maps are updated. */ EEVEE_draw_shadows(sldata, psl); - DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0); - DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, i, 0); - DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size); - - DRW_framebuffer_clear(false, true, false, NULL, 1.0); + GPU_framebuffer_bind(sldata->probe_face_fb[i]); + GPU_framebuffer_clear_depth(sldata->probe_face_fb[i], 1.0); /* Depth prepass */ DRW_draw_pass(psl->depth_pass); @@ -1270,23 +1251,17 @@ static void render_scene_to_probe( // EEVEE_create_minmax_buffer(vedata, sldata->probe_depth_rt); - /* Rebind Planar FB */ - DRW_framebuffer_bind(sldata->probe_fb); + /* Rebind Target FB */ + GPU_framebuffer_bind(sldata->probe_face_fb[i]); /* Shading pass */ EEVEE_draw_default_passes(psl); DRW_draw_pass(psl->material_pass); DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ - - DRW_framebuffer_texture_detach(sldata->probe_rt); - DRW_framebuffer_texture_detach(sldata->probe_depth_rt); } - DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); - DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0); /* Restore */ txl->planar_pool = tmp_planar_pool; - stl->g_data->minzbuffer = tmp_minz; txl->maxzbuffer = tmp_maxz; } @@ -1322,12 +1297,13 @@ static void render_scene_to_planar( DRW_uniformbuffer_update(sldata->clip_ubo, &sldata->clip_data); DRW_state_clip_planes_count_set(1); - /* Attach depth here since it's a DRW_TEX_TEMP */ - DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_depth, 0, layer, 0); - DRW_framebuffer_texture_layer_attach(fbl->planarref_fb, txl->planar_pool, 0, layer, 0); - DRW_framebuffer_bind(fbl->planarref_fb); + GPU_framebuffer_ensure_config(&fbl->planarref_fb, { + GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_depth, layer), + GPU_ATTACHMENT_TEXTURE_LAYER(txl->planar_pool, layer) + }); - DRW_framebuffer_clear(false, true, false, NULL, 1.0); + GPU_framebuffer_bind(fbl->planarref_fb); + GPU_framebuffer_clear_depth(fbl->planarref_fb, 1.0); /* Avoid using the texture attached to framebuffer when rendering. */ /* XXX */ @@ -1354,7 +1330,7 @@ static void render_scene_to_planar( EEVEE_occlusion_compute(sldata, vedata, tmp_planar_depth, layer); /* Rebind Planar FB */ - DRW_framebuffer_bind(fbl->planarref_fb); + GPU_framebuffer_bind(fbl->planarref_fb); /* Shading pass */ EEVEE_draw_default_passes(psl); @@ -1375,9 +1351,6 @@ static void render_scene_to_planar( /* Restore */ txl->planar_pool = tmp_planar_pool; txl->planar_depth = tmp_planar_depth; - - DRW_framebuffer_texture_detach(txl->planar_pool); - DRW_framebuffer_texture_detach(txl->planar_depth); } static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) @@ -1397,10 +1370,6 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p perspective_m4(winmat, -0.1f, 0.1f, -0.1f, 0.1f, 0.1f, 1.0f); invert_m4_m4(wininv, winmat); - /* Detach to rebind the right cubeface. */ - DRW_framebuffer_bind(sldata->probe_fb); - DRW_framebuffer_texture_detach(sldata->probe_rt); - DRW_framebuffer_texture_detach(sldata->probe_depth_rt); for (int i = 0; i < 6; ++i) { /* Setup custom matrices */ copy_m4_m4(viewmat, cubefacemat[i]); @@ -1409,15 +1378,10 @@ static void render_world_to_probe(EEVEE_ViewLayerData *sldata, EEVEE_PassList *p invert_m4_m4(viewinv, viewmat); DRW_viewport_matrix_override_set_all(&matstate); - DRW_framebuffer_cubeface_attach(sldata->probe_fb, sldata->probe_rt, 0, i, 0); - DRW_framebuffer_viewport_size(sldata->probe_fb, 0, 0, pinfo->target_size, pinfo->target_size); - + GPU_framebuffer_bind(sldata->probe_face_fb[i]); + GPU_framebuffer_clear_depth(sldata->probe_face_fb[i], 1.0f); DRW_draw_pass(psl->probe_background); - - DRW_framebuffer_texture_detach(sldata->probe_rt); } - DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_rt, 0, 0); - DRW_framebuffer_texture_attach(sldata->probe_fb, sldata->probe_depth_rt, 0, 0); } static void lightprobe_cell_grid_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_local_cell[3]) @@ -1459,12 +1423,13 @@ static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *v } if (pinfo->update_world & PROBE_UPDATE_GRID) { diffuse_filter_probe(sldata, vedata, psl, 0, 0.0, 0.0, 0.0, 0.0, 1.0); + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - DRW_framebuffer_texture_detach(sldata->probe_pool); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + + GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + GPU_framebuffer_bind(sldata->probe_filter_fb); DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + common_data->prb_num_render_grid = 1; /* Reset volume history. */ stl->effects->volume_current_sample = -1; @@ -1486,27 +1451,26 @@ static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEV /* Grid is already initialized, nothing to do. */ return; } - DRW_framebuffer_texture_detach(sldata->probe_pool); /* Flood fill with world irradiance. */ - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - DRW_framebuffer_bind(sldata->probe_filter_fb); - DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - - SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + GPU_framebuffer_bind(sldata->probe_filter_fb); DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); - /* Reattach to have a valid framebuffer. */ - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + + GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + GPU_framebuffer_bind(sldata->probe_filter_fb); + DRW_draw_pass(psl->probe_grid_fill); + + SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); + pinfo->grid_initialized = true; } void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; Object *ob; EEVEE_LightProbesInfo *pinfo = sldata->probes; @@ -1547,7 +1511,12 @@ void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *v if ((vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { const int max_lod = 9; DRW_stats_group_start("Planar Probe Downsample"); - DRW_framebuffer_recursive_downsample(vedata->fbl->downsample_fb, txl->planar_pool, max_lod, &downsample_planar, vedata); + + GPU_framebuffer_ensure_config(&fbl->planar_downsample_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->planar_pool) + }); + GPU_framebuffer_recursive_downsample(fbl->planar_downsample_fb, max_lod, &downsample_planar, vedata); /* For shading, save max level of the planar map */ common_data->prb_lod_planar_max = (float)(max_lod); DRW_stats_group_end(); @@ -1738,12 +1707,11 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ } /* Reset the next buffer so we can see the progress. */ /* irradiance_rt is already the next rt because of the previous SWAP */ - DRW_framebuffer_texture_detach(sldata->probe_pool); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); - DRW_framebuffer_bind(sldata->probe_filter_fb); + GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0); + GPU_framebuffer_bind(sldata->probe_filter_fb); DRW_draw_pass(psl->probe_grid_fill); - DRW_framebuffer_texture_detach(sldata->irradiance_rt); - DRW_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); + + GPU_framebuffer_texture_attach(sldata->probe_filter_fb, sldata->probe_pool, 0, 0); /* Swap AFTER */ SWAP(GPUTexture *, sldata->irradiance_pool, sldata->irradiance_rt); } diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index b4afb8bb555..443fdff15e3 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -505,7 +505,6 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) linfo->shadow_size, linfo->shadow_size, MAX_CASCADE_NUM, shadow_pool_format, DRW_TEX_FILTER, NULL); } - /* Initialize Textures Array first so DRW_framebuffer_init just bind them. */ if (!sldata->shadow_pool) { /* All shadows fit in this array */ sldata->shadow_pool = DRW_texture_create_2D_array( @@ -514,19 +513,18 @@ void EEVEE_lights_cache_finish(EEVEE_ViewLayerData *sldata) } /* Render FB */ - DRWFboTexture tex_cascade = {&sldata->shadow_cube_target, DRW_TEX_DEPTH_24, 0}; - DRW_framebuffer_init(&sldata->shadow_target_fb, &draw_engine_eevee_type, - linfo->shadow_size, linfo->shadow_size, - &tex_cascade, 1); + GPU_framebuffer_ensure_config(&sldata->shadow_cube_target_fb, { + GPU_ATTACHMENT_TEXTURE(sldata->shadow_cube_target) + }); + GPU_framebuffer_ensure_config(&sldata->shadow_cascade_target_fb, { + GPU_ATTACHMENT_TEXTURE(sldata->shadow_cascade_target) + }); /* Storage FB */ - DRWFboTexture tex_pool = {&sldata->shadow_pool, shadow_pool_format, DRW_TEX_FILTER}; - DRW_framebuffer_init(&sldata->shadow_store_fb, &draw_engine_eevee_type, - linfo->shadow_size, linfo->shadow_size, - &tex_pool, 1); - - /* Restore */ - DRW_framebuffer_texture_detach(sldata->shadow_cube_target); + GPU_framebuffer_ensure_config(&sldata->shadow_store_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(sldata->shadow_pool) + }); /* Update Lamps UBOs. */ EEVEE_lights_update(sldata); @@ -1033,7 +1031,6 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) EEVEE_LampsInfo *linfo = sldata->lamps; Object *ob; int i; - float clear_col[4] = {FLT_MAX}; DRWMatrixState saved_mats; @@ -1042,7 +1039,6 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) /* Cube Shadow Maps */ DRW_stats_group_start("Cube Shadow Maps"); - DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cube_target, 0, 0); /* Render each shadow to one layer of the array */ for (i = 0; (ob = linfo->shadow_cube_ref[i]) && (i < MAX_SHADOW_CUBE); i++) { EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); @@ -1073,11 +1069,10 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) eevee_shadows_cube_culling_frustum(srd); - DRW_framebuffer_bind(sldata->shadow_target_fb); - DRW_framebuffer_clear(true, true, false, clear_col, 1.0f); - /* Render shadow cube */ linfo->shadow_instance_count = 6; + GPU_framebuffer_bind(sldata->shadow_cube_target_fb); + GPU_framebuffer_clear_depth(sldata->shadow_cube_target_fb, 1.0f); DRW_draw_pass(psl->shadow_pass); /* 0.001f is arbitrary, but it should be relatively small so that filter size is not too big. */ @@ -1091,10 +1086,10 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) linfo->current_shadow_face++) { /* Copy using a small 3x3 box filter */ - DRW_framebuffer_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, linfo->current_shadow_face, 0); - DRW_framebuffer_bind(sldata->shadow_store_fb); + GPU_framebuffer_texture_cubeface_attach(sldata->shadow_store_fb, sldata->shadow_cube_blur, 0, + linfo->current_shadow_face, 0); + GPU_framebuffer_bind(sldata->shadow_store_fb); DRW_draw_pass(psl->shadow_cube_copy_pass); - DRW_framebuffer_texture_detach(sldata->shadow_cube_blur); } /* Push it to shadowmap array */ @@ -1118,22 +1113,19 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) srd->shadow_inv_samples_ct = 1.0f / (float)srd->shadow_samples_ct; DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0); - DRW_framebuffer_bind(sldata->shadow_store_fb); + GPU_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, evscd->layer_id, 0); + GPU_framebuffer_bind(sldata->shadow_store_fb); DRW_draw_pass(psl->shadow_cube_store_pass); led->need_update = false; } linfo->update_flag &= ~LIGHT_UPDATE_SHADOW_CUBE; - - DRW_framebuffer_texture_detach(sldata->shadow_cube_target); DRW_stats_group_end(); DRW_viewport_matrix_override_set_all(&saved_mats); /* Cascaded Shadow Maps */ DRW_stats_group_start("Cascaded Shadow Maps"); - DRW_framebuffer_texture_attach(sldata->shadow_target_fb, sldata->shadow_cascade_target, 0, 0); for (i = 0; (ob = linfo->shadow_cascade_ref[i]) && (i < MAX_SHADOW_CASCADE); i++) { EEVEE_LampEngineData *led = EEVEE_lamp_data_ensure(ob); Lamp *la = (Lamp *)ob->data; @@ -1150,13 +1142,12 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) } DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); - DRW_framebuffer_bind(sldata->shadow_target_fb); - DRW_framebuffer_clear(false, true, false, NULL, 1.0); - eevee_shadows_cascade_culling_frustum(evscd); /* Render shadow cascades */ linfo->shadow_instance_count = la->cascade_count; + GPU_framebuffer_bind(sldata->shadow_cascade_target_fb); + GPU_framebuffer_clear_depth(sldata->shadow_cascade_target_fb, 1.0); DRW_draw_pass(psl->shadow_pass); /* TODO: OPTI: Filter all cascade in one/two draw call */ @@ -1170,11 +1161,10 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) /* Copy using a small 3x3 box filter */ linfo->filter_size = linfo->shadow_render_data.stored_texel_size * ((filter_pixel_size > 1.0f) ? 1.0f : 0.0f); - DRW_framebuffer_texture_layer_attach( + GPU_framebuffer_texture_layer_attach( sldata->shadow_store_fb, sldata->shadow_cascade_blur, 0, linfo->current_shadow_cascade, 0); - DRW_framebuffer_bind(sldata->shadow_store_fb); + GPU_framebuffer_bind(sldata->shadow_store_fb); DRW_draw_pass(psl->shadow_cascade_copy_pass); - DRW_framebuffer_texture_detach(sldata->shadow_cascade_blur); /* Push it to shadowmap array and blur more */ @@ -1198,13 +1188,12 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRW_uniformbuffer_update(sldata->shadow_render_ubo, &linfo->shadow_render_data); int layer = evscd->layer_id + linfo->current_shadow_cascade; - DRW_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, layer, 0); - DRW_framebuffer_bind(sldata->shadow_store_fb); + GPU_framebuffer_texture_layer_attach(sldata->shadow_store_fb, sldata->shadow_pool, 0, layer, 0); + GPU_framebuffer_bind(sldata->shadow_store_fb); DRW_draw_pass(psl->shadow_cascade_store_pass); } } - DRW_framebuffer_texture_detach(sldata->shadow_cascade_target); DRW_stats_group_end(); DRW_viewport_matrix_override_set_all(&saved_mats); diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index 6215445e113..a7cc645f738 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -138,9 +138,9 @@ static struct GPUTexture *create_ggx_lut_texture(int UNUSED(w), int UNUSED(h)) tex = DRW_texture_create_2D(w, h, DRW_TEX_RG_16, DRW_TEX_FILTER, (float *)texels); DRWFboTexture tex_filter = {&tex, DRW_TEX_RG_16, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); + GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - DRW_framebuffer_bind(fb); + GPU_framebuffer_bind(fb); DRW_draw_pass(pass); float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); @@ -200,9 +200,9 @@ static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) tex = DRW_texture_create_2D(w, h, DRW_TEX_R_16, DRW_TEX_FILTER, (float *)texels); DRWFboTexture tex_filter = {&tex, DRW_TEX_R_16, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); + GPU_framebuffer_init(&fb, &draw_engine_eevee_type, w, h, &tex_filter, 1); - DRW_framebuffer_bind(fb); + GPU_framebuffer_bind(fb); float *data = MEM_mallocN(sizeof(float[3]) * w * h, "lut"); @@ -216,7 +216,7 @@ static struct GPUTexture *create_ggx_refraction_lut_texture(int w, int h) a2 = powf(roughness, 4.0f); DRW_draw_pass(pass); - DRW_framebuffer_read_data(0, 0, w, h, 3, 0, data); + GPU_framebuffer_read_data(0, 0, w, h, 3, 0, data); #if 1 fprintf(f, "\t{\n\t\t"); @@ -374,7 +374,7 @@ static void add_standard_uniforms( DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); if ((vedata->stl->effects->enabled_effects & EFFECT_GTAO) != 0) { - DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->gtao_horizons); + DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->stl->effects->gtao_horizons); } else { /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */ @@ -482,10 +482,8 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const d /* Attach & detach because we don't currently support multiple FB per texture, * and this would be the case for multiple viewport. */ - DRW_framebuffer_texture_layer_attach(fbl->update_noise_fb, e_data.util_tex, 0, 2, 0); - DRW_framebuffer_bind(fbl->update_noise_fb); + GPU_framebuffer_bind(fbl->update_noise_fb); DRW_draw_pass(psl->update_noise_pass); - DRW_framebuffer_texture_detach(e_data.util_tex); } static void EEVEE_update_viewvecs(float invproj[4][4], float winmat[4][4], float (*r_viewvecs)[4]) @@ -623,9 +621,10 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E { /* Update noise Framebuffer. */ - if (fbl->update_noise_fb == NULL) { - fbl->update_noise_fb = DRW_framebuffer_create(); - } + GPU_framebuffer_ensure_config(&fbl->update_noise_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE_LAYER(e_data.util_tex, 2) + }); } } diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c index e221ed865b5..eaef3121a3f 100644 --- a/source/blender/draw/engines/eevee/eevee_mist.c +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -55,7 +55,6 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_PrivateData *g_data = stl->g_data; Scene *scene = draw_ctx->scene; - const float *viewport_size = DRW_viewport_size_get(); float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; if (e_data.mist_sh == NULL) { @@ -71,13 +70,16 @@ void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } /* Create FrameBuffer. */ - DRWFboTexture tex_data = {&txl->mist_accum, DRW_TEX_R_32, 0}; /* Should be enough precision for many samples. */ - DRW_framebuffer_init(&fbl->mist_accum_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], - &tex_data, 1); + DRW_texture_ensure_fullscreen_2D(&txl->mist_accum, DRW_TEX_R_32, 0); /* Should be enough precision for many samples. */ + + GPU_framebuffer_ensure_config(&fbl->mist_accum_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->mist_accum) + }); /* Clear texture. */ - DRW_framebuffer_bind(fbl->mist_accum_fb); - DRW_framebuffer_clear(true, false, false, clear, 0.0f); + GPU_framebuffer_bind(fbl->mist_accum_fb); + GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); /* Mist settings. */ if (scene && scene->world) { @@ -123,11 +125,11 @@ void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat EEVEE_PassList *psl = vedata->psl; if (fbl->mist_accum_fb != NULL) { - DRW_framebuffer_bind(fbl->mist_accum_fb); + GPU_framebuffer_bind(fbl->mist_accum_fb); DRW_draw_pass(psl->mist_accum_ps); /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); } } diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index 53fff5de50e..3278b288d6b 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -217,7 +217,7 @@ void EEVEE_motion_blur_draw(EEVEE_Data *vedata) /* Motion Blur */ if ((effects->enabled_effects & EFFECT_MOTION_BLUR) != 0) { - DRW_framebuffer_bind(effects->target_buffer); + GPU_framebuffer_bind(effects->target_buffer); DRW_draw_pass(psl->motion_blur); SWAP_BUFFERS(); } diff --git a/source/blender/draw/engines/eevee/eevee_occlusion.c b/source/blender/draw/engines/eevee/eevee_occlusion.c index d7d022e9b98..9c5cb09148a 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -68,9 +68,9 @@ static void eevee_create_shader_occlusion(void) int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_StorageList *stl = vedata->stl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -80,6 +80,7 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if (BKE_collection_engine_property_value_get_bool(props, "gtao_enable")) { const float *viewport_size = DRW_viewport_size_get(); + const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; /* Shaders */ if (!e_data.gtao_sh) { @@ -100,26 +101,31 @@ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ao_bounce_fac = (float)BKE_collection_engine_property_value_get_bool(props, "gtao_bounce"); - DRWFboTexture tex = {&txl->gtao_horizons, DRW_TEX_RGBA_8, 0}; - - DRW_framebuffer_init(&fbl->gtao_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + effects->gtao_horizons = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], DRW_TEX_RGBA_8, + &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->gtao_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->gtao_horizons) + }); if (G.debug_value == 6) { - DRWFboTexture tex_debug = {&stl->g_data->gtao_horizons_debug, DRW_TEX_RGBA_8, DRW_TEX_TEMP}; - - DRW_framebuffer_init(&fbl->gtao_debug_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex_debug, 1); + effects->gtao_horizons_debug = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], DRW_TEX_RGBA_8, + &draw_engine_eevee_type); + GPU_framebuffer_ensure_config(&fbl->gtao_debug_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->gtao_horizons_debug) + }); + } + else { + effects->gtao_horizons_debug = NULL; } return EFFECT_GTAO | EFFECT_NORMAL_BUFFER; } /* Cleanup */ - DRW_TEXTURE_FREE_SAFE(txl->gtao_horizons); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); + effects->gtao_horizons = NULL; + GPU_FRAMEBUFFER_FREE_SAFE(fbl->gtao_fb); common_data->ao_settings = 0.0f; return 0; @@ -129,8 +135,9 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; EEVEE_PassList *psl = vedata->psl; - const float *viewport_size = DRW_viewport_size_get(); + EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -140,13 +147,16 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - DRWFboTexture tex_data = {&txl->ao_accum, DRW_TEX_R_32, 0}; - DRW_framebuffer_init(&fbl->ao_accum_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], - &tex_data, 1); + DRW_texture_ensure_fullscreen_2D(&txl->ao_accum, DRW_TEX_R_32, 0); /* Should be enough precision for many samples. */ + + GPU_framebuffer_ensure_config(&fbl->ao_accum_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->ao_accum) + }); /* Clear texture. */ - DRW_framebuffer_bind(fbl->ao_accum_fb); - DRW_framebuffer_clear(true, false, false, clear, 0.0f); + GPU_framebuffer_bind(fbl->ao_accum_fb); + GPU_framebuffer_clear_color(fbl->ao_accum_fb, clear); /* Accumulation pass */ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE; @@ -155,15 +165,15 @@ void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } else { /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->ao_accum); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->ao_accum_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->ao_accum_fb); } } @@ -212,8 +222,8 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &txl->gtao_horizons); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, quad, NULL); } @@ -233,7 +243,7 @@ void EEVEE_occlusion_compute( effects->ao_src_depth = depth_src; effects->ao_depth_layer = layer; - DRW_framebuffer_bind(fbl->gtao_fb); + GPU_framebuffer_bind(fbl->gtao_fb); if (layer >= 0) { DRW_draw_pass(psl->ao_horizon_search_layer); @@ -243,7 +253,7 @@ void EEVEE_occlusion_compute( } /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } @@ -259,14 +269,11 @@ void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data if (((effects->enabled_effects & EFFECT_GTAO) != 0) && (G.debug_value == 6)) { DRW_stats_group_start("GTAO Debug"); - DRW_framebuffer_texture_attach(fbl->gtao_debug_fb, stl->g_data->gtao_horizons_debug, 0, 0); - DRW_framebuffer_bind(fbl->gtao_debug_fb); - + GPU_framebuffer_bind(fbl->gtao_debug_fb); DRW_draw_pass(psl->ao_horizon_debug); /* Restore */ - DRW_framebuffer_texture_detach(stl->g_data->gtao_horizons_debug); - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } @@ -284,11 +291,11 @@ void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data * EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); - DRW_framebuffer_bind(fbl->ao_accum_fb); + GPU_framebuffer_bind(fbl->ao_accum_fb); DRW_draw_pass(psl->ao_accum_ps); /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); } } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 88fb55cfbdf..b000cad6601 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -72,22 +72,23 @@ extern struct DrawEngineType draw_engine_eevee_type; #define SWAP_DOUBLE_BUFFERS() { \ if (effects->swap_double_buffer) { \ - SWAP(struct GPUFrameBuffer *, fbl->main, fbl->double_buffer); \ + SWAP(struct GPUFrameBuffer *, fbl->main_fb, fbl->double_buffer_fb); \ + SWAP(struct GPUFrameBuffer *, fbl->main_color_fb, fbl->double_buffer_color_fb); \ SWAP(GPUTexture *, txl->color, txl->color_double_buffer); \ effects->swap_double_buffer = false; \ } \ } ((void)0) #define SWAP_BUFFERS() { \ - if (effects->target_buffer != fbl->main) { \ + if (effects->target_buffer == fbl->effect_color_fb) { \ SWAP_DOUBLE_BUFFERS(); \ effects->source_buffer = txl->color_post; \ - effects->target_buffer = fbl->main; \ + effects->target_buffer = fbl->main_color_fb; \ } \ else { \ SWAP_DOUBLE_BUFFERS(); \ effects->source_buffer = txl->color; \ - effects->target_buffer = fbl->effect_fb; \ + effects->target_buffer = fbl->effect_color_fb; \ } \ } ((void)0) @@ -217,11 +218,11 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *gtao_fb; struct GPUFrameBuffer *gtao_debug_fb; struct GPUFrameBuffer *downsample_fb; - struct GPUFrameBuffer *effect_fb; struct GPUFrameBuffer *bloom_blit_fb; struct GPUFrameBuffer *bloom_down_fb[MAX_BLOOM_STEP]; struct GPUFrameBuffer *bloom_accum_fb[MAX_BLOOM_STEP - 1]; struct GPUFrameBuffer *sss_blur_fb; + struct GPUFrameBuffer *sss_resolve_fb; struct GPUFrameBuffer *sss_clear_fb; struct GPUFrameBuffer *sss_accum_fb; struct GPUFrameBuffer *dof_down_fb; @@ -238,30 +239,24 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *update_noise_fb; struct GPUFrameBuffer *planarref_fb; + struct GPUFrameBuffer *planar_downsample_fb; - struct GPUFrameBuffer *main; - struct GPUFrameBuffer *double_buffer; - struct GPUFrameBuffer *depth_double_buffer_fb; + struct GPUFrameBuffer *main_fb; + struct GPUFrameBuffer *main_color_fb; + struct GPUFrameBuffer *effect_fb; + struct GPUFrameBuffer *effect_color_fb; + struct GPUFrameBuffer *double_buffer_fb; + struct GPUFrameBuffer *double_buffer_color_fb; + struct GPUFrameBuffer *double_buffer_depth_fb; } EEVEE_FramebufferList; typedef struct EEVEE_TextureList { /* Effects */ struct GPUTexture *color_post; /* R16_G16_B16 */ - struct GPUTexture *dof_down_near; /* R16_G16_B16_A16 */ - struct GPUTexture *dof_down_far; /* R16_G16_B16_A16 */ - struct GPUTexture *dof_coc; /* R16_G16 */ - struct GPUTexture *dof_near_blur; /* R16_G16_B16_A16 */ - struct GPUTexture *dof_far_blur; /* R16_G16_B16_A16 */ - struct GPUTexture *bloom_blit; /* R16_G16_B16 */ - struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; /* R16_G16_B16 */ - struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; /* R16_G16_B16 */ struct GPUTexture *mist_accum; struct GPUTexture *ao_accum; struct GPUTexture *sss_dir_accum; struct GPUTexture *sss_col_accum; - struct GPUTexture *ssr_normal_input; - struct GPUTexture *ssr_specrough_input; - struct GPUTexture *ssr_hit_output; struct GPUTexture *refract_color; struct GPUTexture *volume_prop_scattering; @@ -276,13 +271,6 @@ typedef struct EEVEE_TextureList { struct GPUTexture *planar_pool; struct GPUTexture *planar_depth; - struct GPUTexture *gtao_horizons; - - struct GPUTexture *sss_data; - struct GPUTexture *sss_albedo; - struct GPUTexture *sss_blur; - struct GPUTexture *sss_stencil; - struct GPUTexture *maxzbuffer; struct GPUTexture *color; /* R16_G16_B16 */ @@ -486,12 +474,20 @@ typedef struct EEVEE_EffectsInfo { /* SSSS */ int sss_sample_count; bool sss_separate_albedo; + struct GPUTexture *sss_data; /* Textures from pool */ + struct GPUTexture *sss_albedo; + struct GPUTexture *sss_blur; + struct GPUTexture *sss_stencil; /* Volumetrics */ int volume_current_sample; /* SSR */ bool reflection_trace_full; int ssr_neighbor_ofs; int ssr_halfres_ofs[2]; + struct GPUTexture *ssr_normal_input; /* Textures from pool */ + struct GPUTexture *ssr_specrough_input; + struct GPUTexture *ssr_hit_output; + struct GPUTexture *ssr_pdf_output; /* Temporal Anti Aliasing */ int taa_current_sample; int taa_render_sample; @@ -506,6 +502,8 @@ typedef struct EEVEE_EffectsInfo { /* Ambient Occlusion */ int ao_depth_layer; struct GPUTexture *ao_src_depth; /* pointer copy */ + struct GPUTexture *gtao_horizons; /* Textures from pool */ + struct GPUTexture *gtao_horizons_debug; /* Motion Blur */ float current_ndc_to_world[4][4]; float past_world_to_ndc[4][4]; @@ -516,6 +514,11 @@ typedef struct EEVEE_EffectsInfo { float dof_bokeh[4]; float dof_layer_select[2]; int dof_target_size[2]; + struct GPUTexture *dof_down_near; /* Textures from pool */ + struct GPUTexture *dof_down_far; + struct GPUTexture *dof_coc; + struct GPUTexture *dof_near_blur; + struct GPUTexture *dof_far_blur; /* Other */ float prev_persmat[4][4]; /* Bloom */ @@ -528,6 +531,9 @@ typedef struct EEVEE_EffectsInfo { float bloom_sample_scale; float bloom_curve_threshold[4]; float unf_source_texel_size[2]; + struct GPUTexture *bloom_blit; /* Textures from pool */ + struct GPUTexture *bloom_downsample[MAX_BLOOM_STEP]; + struct GPUTexture *bloom_upsample[MAX_BLOOM_STEP - 1]; struct GPUTexture *unf_source_buffer; /* pointer copy */ struct GPUTexture *unf_base_buffer; /* pointer copy */ /* Not alloced, just a copy of a *GPUtexture in EEVEE_TextureList. */ @@ -620,7 +626,8 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuffer *shadow_render_ubo; struct GPUUniformBuffer *shadow_samples_ubo; - struct GPUFrameBuffer *shadow_target_fb; + struct GPUFrameBuffer *shadow_cube_target_fb; + struct GPUFrameBuffer *shadow_cascade_target_fb; struct GPUFrameBuffer *shadow_store_fb; struct GPUTexture *shadow_cube_target; @@ -638,8 +645,8 @@ typedef struct EEVEE_ViewLayerData { struct GPUUniformBuffer *grid_ubo; struct GPUUniformBuffer *planar_ubo; - struct GPUFrameBuffer *probe_fb; struct GPUFrameBuffer *probe_filter_fb; + struct GPUFrameBuffer *probe_face_fb[6]; struct GPUTexture *probe_rt; struct GPUTexture *probe_depth_rt; @@ -746,9 +753,6 @@ typedef struct EEVEE_PrivateData { struct DRWShadingGroup *planar_display_shgrp; struct GHash *material_hash; struct GHash *hair_material_hash; - struct GPUTexture *minzbuffer; - struct GPUTexture *ssr_pdf_output; - struct GPUTexture *gtao_horizons_debug; float background_alpha; /* TODO find a better place for this. */ /* For planar probes */ float planar_texel_size[2]; @@ -890,8 +894,8 @@ void EEVEE_volumes_free(void); void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_create_minmax_buffer(EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); -void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); -void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUFrameBuffer *fb_src, struct GPUTexture *texture_src, int level); +void EEVEE_downsample_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); +void EEVEE_downsample_cube_buffer(EEVEE_Data *vedata, struct GPUTexture *texture_src, int level); void EEVEE_effects_do_gtao(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_effects_free(void); diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c index 52d45e2ef04..130999adb39 100644 --- a/source/blender/draw/engines/eevee/eevee_render.c +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -53,7 +53,6 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); Scene *scene = DEG_get_evaluated_scene(depsgraph); - const float *viewport_size = DRW_viewport_size_get(); /* Init default FB and render targets: * In render mode the default framebuffer is not generated @@ -62,16 +61,22 @@ void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph * DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - /* NOTE : use 32 bit format for precision in render mode. */ - DRWFboTexture dtex = {&dtxl->depth, DRW_TEX_DEPTH_24_STENCIL_8, 0}; - DRW_framebuffer_init(&dfbl->default_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &dtex, 1); + /* TODO 32 bit depth */ + DRW_texture_ensure_fullscreen_2D(&dtxl->depth, DRW_TEX_DEPTH_24_STENCIL_8, 0); + DRW_texture_ensure_fullscreen_2D(&txl->color, DRW_TEX_RGBA_32, DRW_TEX_FILTER | DRW_TEX_MIPMAP); - DRWFboTexture tex = {&txl->color, DRW_TEX_RGBA_32, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; - DRW_framebuffer_init(&fbl->main, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + GPU_framebuffer_ensure_config(&dfbl->default_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->color) + }); + GPU_framebuffer_ensure_config(&fbl->main_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(txl->color) + }); + GPU_framebuffer_ensure_config(&fbl->main_color_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->color) + }); /* Alloc transient data. */ if (!stl->g_data) { @@ -166,8 +171,11 @@ static void eevee_render_result_combined( { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); - DRW_framebuffer_bind(vedata->stl->effects->final_fb); - DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 4, 0, rp->rect); + GPU_framebuffer_bind(vedata->stl->effects->final_fb); + GPU_framebuffer_read_color(vedata->stl->effects->final_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + 4, 0, rp->rect); } static void eevee_render_result_subsurface( @@ -185,8 +193,11 @@ static void eevee_render_result_subsurface( if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname); - DRW_framebuffer_bind(vedata->fbl->sss_accum_fb); - DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 1, rp->rect); + GPU_framebuffer_bind(vedata->fbl->sss_accum_fb); + GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + 3, 1, rp->rect); /* This is the accumulated color. Divide by the number of samples. */ for (int i = 0; i < rp->rectx * rp->recty * 3; i++) { @@ -197,8 +208,11 @@ static void eevee_render_result_subsurface( if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname); - DRW_framebuffer_bind(vedata->fbl->sss_accum_fb); - DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 0, rp->rect); + GPU_framebuffer_bind(vedata->fbl->sss_accum_fb); + GPU_framebuffer_read_color(vedata->fbl->sss_accum_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + 3, 0, rp->rect); /* This is the accumulated color. Divide by the number of samples. */ for (int i = 0; i < rp->rectx * rp->recty * 3; i++) { @@ -228,7 +242,11 @@ static void eevee_render_result_normal( if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname); - DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 1, rp->rect); + GPU_framebuffer_bind(vedata->fbl->main_fb); + GPU_framebuffer_read_color(vedata->fbl->main_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + 3, 1, rp->rect); /* Convert Eevee encoded normals to Blender normals. */ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) { @@ -270,7 +288,10 @@ static void eevee_render_result_z( if ((view_layer->passflag & SCE_PASS_Z) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); - DRW_framebuffer_read_depth(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), rp->rect); + GPU_framebuffer_read_depth(vedata->fbl->main_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + rp->rect); bool is_persp = DRW_viewport_is_persp_get(); @@ -302,8 +323,11 @@ static void eevee_render_result_mist( if ((view_layer->passflag & SCE_PASS_MIST) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname); - DRW_framebuffer_bind(vedata->fbl->mist_accum_fb); - DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 1, 0, rp->rect); + GPU_framebuffer_bind(vedata->fbl->mist_accum_fb); + GPU_framebuffer_read_color(vedata->fbl->mist_accum_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + 1, 0, rp->rect); /* This is the accumulated color. Divide by the number of samples. */ for (int i = 0; i < rp->rectx * rp->recty; i++) { @@ -327,8 +351,11 @@ static void eevee_render_result_occlusion( if ((view_layer->passflag & SCE_PASS_AO) != 0) { RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname); - DRW_framebuffer_bind(vedata->fbl->ao_accum_fb); - DRW_framebuffer_read_data(rect->xmin, rect->ymin, BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), 3, 0, rp->rect); + GPU_framebuffer_bind(vedata->fbl->ao_accum_fb); + GPU_framebuffer_read_color(vedata->fbl->ao_accum_fb, + rect->xmin, rect->ymin, + BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), + 3, 0, rp->rect); /* This is the accumulated color. Divide by the number of samples. */ for (int i = 0; i < rp->rectx * rp->recty * 3; i += 3) { @@ -339,30 +366,34 @@ static void eevee_render_result_occlusion( static void eevee_render_draw_background(EEVEE_Data *vedata) { - EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_StorageList *stl = vedata->stl; EEVEE_PassList *psl = vedata->psl; /* Prevent background to write to data buffers. * NOTE : This also make sure the textures are bound * to the right double buffer. */ - if (txl->ssr_normal_input != NULL) { - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - } - if (txl->ssr_specrough_input != NULL) { - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - } - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_ensure_config(&fbl->main_fb, { + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); + GPU_framebuffer_bind(fbl->main_fb); DRW_draw_pass(psl->background_pass); - if (txl->ssr_normal_input != NULL) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); - } - if (txl->ssr_specrough_input != NULL) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); - } - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_ensure_config(&fbl->main_fb, { + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_normal_input), + GPU_ATTACHMENT_TEXTURE(stl->effects->ssr_specrough_input), + GPU_ATTACHMENT_TEXTURE(stl->effects->sss_data), + GPU_ATTACHMENT_TEXTURE(stl->effects->sss_albedo) + }); + GPU_framebuffer_bind(fbl->main_fb); } void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl, const rcti *rect) @@ -413,6 +444,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl while (render_samples < tot_sample && !RE_engine_test_break(engine)) { float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float clear_depth = 1.0f; + unsigned int clear_stencil = 0xFF; unsigned int primes[3] = {2, 3, 7}; double offset[3] = {0.0, 0.0, 0.0}; double r[3]; @@ -455,10 +488,8 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl /* Refresh Shadows */ EEVEE_draw_shadows(sldata, psl); - DRW_framebuffer_texture_detach(dtxl->depth); - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); - DRW_framebuffer_bind(fbl->main); - DRW_framebuffer_clear(true, true, true, clear_col, 1.0f); + GPU_framebuffer_bind(fbl->main_fb); + GPU_framebuffer_clear_color_depth_stencil(fbl->main_fb, clear_col, clear_depth, clear_stencil); /* Depth prepass */ DRW_draw_pass(psl->depth_pass); DRW_draw_pass(psl->depth_pass_cull); @@ -468,7 +499,7 @@ void EEVEE_render_draw(EEVEE_Data *vedata, RenderEngine *engine, RenderLayer *rl EEVEE_volumes_compute(sldata, vedata); /* Shading pass */ eevee_render_draw_background(vedata); - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); EEVEE_draw_default_passes(psl); DRW_draw_pass(psl->material_pass); EEVEE_subsurface_data_render(sldata, vedata); diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 96d560688f3..7a856870eb3 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -124,14 +124,15 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) const bool use_refraction = BKE_collection_engine_property_value_get_bool(props, "ssr_refraction"); if (use_refraction) { - DRWFboTexture tex = {&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP}; + /* TODO: Opti: Could be shared. */ + DRW_texture_ensure_fullscreen_2D(&txl->refract_color, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER | DRW_TEX_MIPMAP); - DRW_framebuffer_init(&fbl->refract_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + GPU_framebuffer_ensure_config(&fbl->refract_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->refract_color) + }); } - bool prev_trace_full = effects->reflection_trace_full; effects->reflection_trace_full = !BKE_collection_engine_property_value_get_bool(props, "ssr_halfres"); common_data->ssr_thickness = BKE_collection_engine_property_value_get_float(props, "ssr_thickness"); common_data->ssr_border_fac = BKE_collection_engine_property_value_get_float(props, "ssr_border_fade"); @@ -144,47 +145,39 @@ int EEVEE_screen_raytrace_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ssr_firefly_fac = FLT_MAX; } - if (prev_trace_full != effects->reflection_trace_full) { - DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output); - } - const int divisor = (effects->reflection_trace_full) ? 1 : 2; int tracing_res[2] = {(int)viewport_size[0] / divisor, (int)viewport_size[1] / divisor}; + int size_fs[2] = {(int)viewport_size[0], (int)viewport_size[1]}; const bool high_qual_input = true; /* TODO dither low quality input */ + const DRWTextureFormat format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8; /* MRT for the shading pass in order to output needed data for the SSR pass. */ - /* TODO create one texture layer per lobe */ - if (txl->ssr_specrough_input == NULL) { - DRWTextureFormat specrough_format = (high_qual_input) ? DRW_TEX_RGBA_16 : DRW_TEX_RGBA_8; - txl->ssr_specrough_input = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], - specrough_format, 0, NULL); - } + effects->ssr_specrough_input = DRW_texture_pool_query_2D(size_fs[0], size_fs[1], format, + &draw_engine_eevee_type); - /* Reattach textures to the right buffer (because we are alternating between buffers) */ - /* TODO multiple FBO per texture!!!! */ - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); + GPU_framebuffer_texture_attach(fbl->main_fb, effects->ssr_specrough_input, 2, 0); /* Raytracing output */ - /* (AMD or Intel) For some reason DRW_TEX_TEMP with DRW_TEX_RG_16I - * creates problems when toggling ssr_halfres. Texture is not read correctly (black output). - * So using a persistent buffer instead. */ - DRWFboTexture tex_output[2] = {{&txl->ssr_hit_output, DRW_TEX_RG_16I, 0}, - {&stl->g_data->ssr_pdf_output, DRW_TEX_R_16, DRW_TEX_TEMP}}; + effects->ssr_hit_output = DRW_texture_pool_query_2D(tracing_res[0], tracing_res[1], DRW_TEX_RG_16I, + &draw_engine_eevee_type); + effects->ssr_pdf_output = DRW_texture_pool_query_2D(tracing_res[0], tracing_res[1], DRW_TEX_R_16, + &draw_engine_eevee_type); - DRW_framebuffer_init(&fbl->screen_tracing_fb, &draw_engine_eevee_type, - tracing_res[0], tracing_res[1], - tex_output, 2); + GPU_framebuffer_ensure_config(&fbl->screen_tracing_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->ssr_hit_output), + GPU_ATTACHMENT_TEXTURE(effects->ssr_pdf_output) + }); /* Enable double buffering to be able to read previous frame color */ return EFFECT_SSR | EFFECT_NORMAL_BUFFER | EFFECT_DOUBLE_BUFFER | ((use_refraction) ? EFFECT_REFRACT : 0); } /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->ssr_specrough_input); - DRW_TEXTURE_FREE_SAFE(txl->ssr_hit_output); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); - stl->g_data->ssr_pdf_output = NULL; + GPU_FRAMEBUFFER_FREE_SAFE(fbl->screen_tracing_fb); + effects->ssr_specrough_input = NULL; + effects->ssr_hit_output = NULL; + effects->ssr_pdf_output = NULL; return 0; } @@ -221,8 +214,8 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v psl->ssr_raytrace = DRW_pass_create("SSR Raytrace", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(trace_shader, psl->ssr_raytrace); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &effects->ssr_specrough_input); DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); @@ -236,13 +229,13 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v psl->ssr_resolve = DRW_pass_create("SSR Resolve", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); grp = DRW_shgroup_create(resolve_shader, psl->ssr_resolve); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &e_data.depth_src); - DRW_shgroup_uniform_buffer(grp, "normalBuffer", &txl->ssr_normal_input); - DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &txl->ssr_specrough_input); + DRW_shgroup_uniform_buffer(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_buffer(grp, "specroughBuffer", &effects->ssr_specrough_input); DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_buffer(grp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); - DRW_shgroup_uniform_buffer(grp, "hitBuffer", &vedata->txl->ssr_hit_output); - DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &stl->g_data->ssr_pdf_output); + DRW_shgroup_uniform_buffer(grp, "hitBuffer", &effects->ssr_hit_output); + DRW_shgroup_uniform_buffer(grp, "pdfBuffer", &effects->ssr_pdf_output); DRW_shgroup_uniform_buffer(grp, "prevColorBuffer", &txl->color_double_buffer); DRW_shgroup_uniform_block(grp, "probe_block", sldata->probe_ubo); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); @@ -250,7 +243,7 @@ void EEVEE_screen_raytrace_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *v DRW_shgroup_uniform_int(grp, "neighborOffset", &effects->ssr_neighbor_ofs, 1); if ((effects->enabled_effects & EFFECT_GTAO) != 0) { DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &vedata->txl->gtao_horizons); + DRW_shgroup_uniform_buffer(grp, "horizonBuffer", &effects->gtao_horizons); } DRW_shgroup_call_add(grp, quad, NULL); @@ -265,12 +258,11 @@ void EEVEE_refraction_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v EEVEE_EffectsInfo *effects = stl->effects; if ((effects->enabled_effects & EFFECT_REFRACT) != 0) { - DRW_framebuffer_texture_attach(fbl->refract_fb, txl->refract_color, 0, 0); - DRW_framebuffer_blit(fbl->main, fbl->refract_fb, false, false); - EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->refract_color, 9); + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->refract_fb, 0, GPU_COLOR_BIT); + EEVEE_downsample_buffer(vedata, txl->refract_color, 9); /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); } } @@ -287,15 +279,12 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v e_data.depth_src = dtxl->depth; DRW_stats_group_start("SSR"); - DRW_framebuffer_texture_attach(fbl->screen_tracing_fb, stl->g_data->ssr_pdf_output, 1, 0); - DRW_framebuffer_bind(fbl->screen_tracing_fb); /* Raytrace. */ + GPU_framebuffer_bind(fbl->screen_tracing_fb); DRW_draw_pass(psl->ssr_raytrace); - DRW_framebuffer_texture_detach(stl->g_data->ssr_pdf_output); - - EEVEE_downsample_buffer(vedata, fbl->downsample_fb, txl->color_double_buffer, 9); + EEVEE_downsample_buffer(vedata, txl->color_double_buffer, 9); /* Resolve at fullres */ int sample = (DRW_state_is_image_render()) ? effects->taa_render_sample : effects->taa_current_sample; @@ -320,18 +309,11 @@ void EEVEE_reflection_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v effects->ssr_halfres_ofs[1] = 1; break; } - DRW_framebuffer_texture_detach(dtxl->depth); - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_color_fb); DRW_draw_pass(psl->ssr_resolve); /* Restore */ - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); - DRW_framebuffer_bind(fbl->main); - + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } } diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 12a70cc2fe7..510f1e8fdb6 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -66,6 +66,7 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; const float *viewport_size = DRW_viewport_size_get(); + const int fs_size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; @@ -90,36 +91,45 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * as the depth buffer we are sampling from. This could be avoided if the stencil is * a separate texture but that needs OpenGL 4.4 or ARB_texture_stencil8. * OR OpenGL 4.3 / ARB_ES3_compatibility if using a renderbuffer instead */ - DRWFboTexture texs[2] = {{&txl->sss_stencil, DRW_TEX_DEPTH_24_STENCIL_8, 0}, - {&txl->sss_blur, DRW_TEX_RGBA_16, DRW_TEX_FILTER}}; + effects->sss_stencil = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], DRW_TEX_DEPTH_24_STENCIL_8, + &draw_engine_eevee_type); + effects->sss_blur = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], DRW_TEX_RGBA_16, + &draw_engine_eevee_type); + effects->sss_data = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], DRW_TEX_RGBA_16, + &draw_engine_eevee_type); - DRW_framebuffer_init(&fbl->sss_blur_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], - texs, 2); + GPU_framebuffer_ensure_config(&fbl->sss_blur_fb, { + GPU_ATTACHMENT_TEXTURE(effects->sss_stencil), + GPU_ATTACHMENT_TEXTURE(effects->sss_blur) + }); - DRWFboTexture tex_data = {&txl->sss_data, DRW_TEX_RGBA_16, DRW_TEX_FILTER}; - DRW_framebuffer_init(&fbl->sss_clear_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], - &tex_data, 1); + GPU_framebuffer_ensure_config(&fbl->sss_resolve_fb, { + GPU_ATTACHMENT_TEXTURE(effects->sss_stencil), + GPU_ATTACHMENT_TEXTURE(txl->color) + }); + + GPU_framebuffer_ensure_config(&fbl->sss_clear_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(effects->sss_data) + }); if (effects->sss_separate_albedo) { - if (txl->sss_albedo == NULL) { - txl->sss_albedo = DRW_texture_create_2D((int)viewport_size[0], (int)viewport_size[1], - DRW_TEX_RGB_11_11_10, 0, NULL); - } + effects->sss_albedo = DRW_texture_pool_query_2D(fs_size[0], fs_size[1], DRW_TEX_RGB_11_11_10, + &draw_engine_eevee_type); } else { - /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->sss_albedo); + effects->sss_albedo = NULL; } return EFFECT_SSS; } /* Cleanup to release memory */ - DRW_TEXTURE_FREE_SAFE(txl->sss_albedo); - DRW_TEXTURE_FREE_SAFE(txl->sss_data); - DRW_TEXTURE_FREE_SAFE(txl->sss_blur); - DRW_TEXTURE_FREE_SAFE(txl->sss_stencil); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->sss_blur_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_blur_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_resolve_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_clear_fb); + effects->sss_stencil = NULL; + effects->sss_blur = NULL; + effects->sss_data = NULL; return 0; } @@ -133,23 +143,27 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; - const float *viewport_size = DRW_viewport_size_get(); + EEVEE_StorageList *stl = vedata->stl; + EEVEE_EffectsInfo *effects = stl->effects; const DRWContextState *draw_ctx = DRW_context_state_get(); ViewLayer *view_layer = draw_ctx->view_layer; IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); if (BKE_collection_engine_property_value_get_bool(props, "sss_enable")) { - float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + DRW_texture_ensure_fullscreen_2D(&txl->sss_dir_accum, DRW_TEX_RGBA_16, 0); + DRW_texture_ensure_fullscreen_2D(&txl->sss_col_accum, DRW_TEX_RGBA_16, 0); - DRWFboTexture tex_data[2] = {{&txl->sss_dir_accum, DRW_TEX_RGBA_16, 0}, - {&txl->sss_col_accum, DRW_TEX_RGBA_16, 0}}; - DRW_framebuffer_init(&fbl->sss_accum_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], - tex_data, 2); + GPU_framebuffer_ensure_config(&fbl->sss_accum_fb, { + GPU_ATTACHMENT_TEXTURE(effects->sss_stencil), + GPU_ATTACHMENT_TEXTURE(txl->sss_dir_accum), + GPU_ATTACHMENT_TEXTURE(txl->sss_col_accum) + }); /* Clear texture. */ - DRW_framebuffer_bind(fbl->sss_accum_fb); - DRW_framebuffer_clear(true, false, false, clear, 0.0f); + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_framebuffer_bind(fbl->sss_accum_fb); + GPU_framebuffer_clear_color(fbl->sss_accum_fb, clear); /* Make the opaque refraction pass mask the sss. */ DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL | DRW_STATE_CLIP_PLANES | @@ -161,7 +175,7 @@ void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->sss_dir_accum); DRW_TEXTURE_FREE_SAFE(txl->sss_col_accum); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); } } @@ -187,7 +201,6 @@ void EEVEE_subsurface_add_pass( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile) { DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; @@ -196,7 +209,7 @@ void EEVEE_subsurface_add_pass( DRWShadingGroup *grp = DRW_shgroup_create(e_data.sss_sh[0], psl->sss_blur_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_data); + DRW_shgroup_uniform_buffer(grp, "sssData", &effects->sss_data); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); @@ -206,22 +219,22 @@ void EEVEE_subsurface_add_pass( grp = DRW_shgroup_create(sh, psl->sss_resolve_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur); + DRW_shgroup_uniform_buffer(grp, "sssData", &effects->sss_blur); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); DRW_shgroup_call_add(grp, quad, NULL); if (effects->sss_separate_albedo) { - DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &txl->sss_albedo); + DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &effects->sss_albedo); } if (DRW_state_is_image_render()) { grp = DRW_shgroup_create(e_data.sss_sh[3], psl->sss_accum_ps); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_buffer(grp, "sssData", &txl->sss_blur); - DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &txl->sss_albedo); + DRW_shgroup_uniform_buffer(grp, "sssData", &effects->sss_blur); + DRW_shgroup_uniform_buffer(grp, "sssAlbedo", &effects->sss_albedo); DRW_shgroup_uniform_block(grp, "sssProfile", sss_profile); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_stencil_mask(grp, sss_id); @@ -232,7 +245,6 @@ void EEVEE_subsurface_add_pass( void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; @@ -240,103 +252,60 @@ void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat if ((effects->enabled_effects & EFFECT_SSS) != 0) { float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; /* Clear sss_data texture only... can this be done in a more clever way? */ - DRW_framebuffer_bind(fbl->sss_clear_fb); - DRW_framebuffer_clear(true, false, false, clear, 0.0f); + GPU_framebuffer_bind(fbl->sss_clear_fb); + GPU_framebuffer_clear_color(fbl->sss_clear_fb, clear); + GPU_framebuffer_ensure_config(&fbl->main_fb, { + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_TEXTURE(effects->sss_data), + GPU_ATTACHMENT_TEXTURE(effects->sss_albedo) + }); - DRW_framebuffer_texture_detach(txl->sss_data); - if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - } - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - } - - /* Start at slot 1 because slot 0 is txl->color */ - int tex_slot = 1; - DRW_framebuffer_texture_attach(fbl->main, txl->sss_data, tex_slot++, 0); - if (effects->sss_separate_albedo) { - DRW_framebuffer_texture_attach(fbl->main, txl->sss_albedo, tex_slot++, 0); - } - if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, tex_slot++, 0); - } - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, tex_slot++, 0); - } - DRW_framebuffer_bind(fbl->main); - + GPU_framebuffer_bind(fbl->main_fb); DRW_draw_pass(psl->sss_pass); /* Restore */ - DRW_framebuffer_texture_detach(txl->sss_data); - if (effects->sss_separate_albedo) { - DRW_framebuffer_texture_detach(txl->sss_albedo); - } - if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - } - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - } - - DRW_framebuffer_texture_attach(fbl->sss_clear_fb, txl->sss_data, 0, 0); - if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); - } - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); - } + GPU_framebuffer_ensure_config(&fbl->main_fb, { + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_LEAVE, + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); } } void EEVEE_subsurface_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; - EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_EffectsInfo *effects = stl->effects; if ((effects->enabled_effects & EFFECT_SSS) != 0) { float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DRW_stats_group_start("SSS"); /* Copy stencil channel, could be avoided (see EEVEE_subsurface_init) */ - DRW_framebuffer_blit(fbl->main, fbl->sss_blur_fb, false, true); - - DRW_framebuffer_texture_detach(dtxl->depth); + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT); /* 1. horizontal pass */ - DRW_framebuffer_bind(fbl->sss_blur_fb); - DRW_framebuffer_clear(true, false, false, clear, 0.0f); + GPU_framebuffer_bind(fbl->sss_blur_fb); + GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear); DRW_draw_pass(psl->sss_blur_ps); /* 2. vertical pass + Resolve */ - DRW_framebuffer_texture_detach(txl->sss_stencil); - if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - DRW_framebuffer_texture_detach(txl->ssr_normal_input); - } - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - DRW_framebuffer_texture_detach(txl->ssr_specrough_input); - } - DRW_framebuffer_texture_attach(fbl->main, txl->sss_stencil, 0, 0); - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_texture_attach(fbl->sss_resolve_fb, txl->color, 0, 0); + GPU_framebuffer_bind(fbl->sss_resolve_fb); DRW_draw_pass(psl->sss_resolve_ps); - /* Restore */ - DRW_framebuffer_texture_detach(txl->sss_stencil); - DRW_framebuffer_texture_attach(fbl->sss_blur_fb, txl->sss_stencil, 0, 0); - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); - if ((effects->enabled_effects & EFFECT_NORMAL_BUFFER) != 0) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_normal_input, 1, 0); - } - if ((effects->enabled_effects & EFFECT_SSR) != 0) { - DRW_framebuffer_texture_attach(fbl->main, txl->ssr_specrough_input, 2, 0); - } - + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } } @@ -345,24 +314,19 @@ void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEV { EEVEE_PassList *psl = vedata->psl; EEVEE_FramebufferList *fbl = vedata->fbl; - EEVEE_TextureList *txl = vedata->txl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; if (((effects->enabled_effects & EFFECT_SSS) != 0) && (fbl->sss_accum_fb != NULL)) { /* Copy stencil channel, could be avoided (see EEVEE_subsurface_init) */ - DRW_framebuffer_blit(fbl->main, fbl->sss_blur_fb, false, true); + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT); /* Only do vertical pass + Resolve */ - DRW_framebuffer_texture_detach(txl->sss_stencil); - DRW_framebuffer_texture_attach(fbl->sss_accum_fb, txl->sss_stencil, 0, 0); - DRW_framebuffer_bind(fbl->sss_accum_fb); + GPU_framebuffer_bind(fbl->sss_accum_fb); DRW_draw_pass(psl->sss_accum_ps); /* Restore */ - DRW_framebuffer_texture_detach(txl->sss_stencil); - DRW_framebuffer_texture_attach(fbl->sss_blur_fb, txl->sss_stencil, 0, 0); - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); } } diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index a417a9bdf56..25dbf4d4802 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -179,7 +179,6 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data (effects->enabled_effects & EFFECT_MOTION_BLUR) == 0) || DRW_state_is_image_render()) { - const float *viewport_size = DRW_viewport_size_get(); float persmat[4][4], viewmat[4][4]; if (!e_data.taa_resolve_sh) { @@ -239,11 +238,11 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data effects->taa_current_sample = 1; } - DRWFboTexture tex_double_buffer = {&txl->depth_double_buffer, DRW_TEX_DEPTH_24_STENCIL_8, 0}; + DRW_texture_ensure_fullscreen_2D(&txl->depth_double_buffer, DRW_TEX_DEPTH_24_STENCIL_8, 0); - DRW_framebuffer_init(&fbl->depth_double_buffer_fb, &draw_engine_eevee_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex_double_buffer, 1); + GPU_framebuffer_ensure_config(&fbl->double_buffer_depth_fb, { + GPU_ATTACHMENT_TEXTURE(txl->depth_double_buffer) + }); return EFFECT_TAA | EFFECT_DOUBLE_BUFFER | EFFECT_POST_BUFFER; } @@ -252,7 +251,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data /* Cleanup to release memory */ DRW_TEXTURE_FREE_SAFE(txl->depth_double_buffer); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->depth_double_buffer_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->double_buffer_depth_fb); return 0; } @@ -293,27 +292,28 @@ void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata) effects->taa_alpha = 1.0f / (float)(effects->taa_current_sample); } - DRW_framebuffer_bind(fbl->effect_fb); + GPU_framebuffer_bind(fbl->effect_color_fb); DRW_draw_pass(psl->taa_resolve); /* Restore the depth from sample 1. */ if (!DRW_state_is_image_render()) { - DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true, false); + GPU_framebuffer_blit(fbl->double_buffer_depth_fb, 0, fbl->main_fb, 0, GPU_DEPTH_BIT); } /* Special Swap */ - SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer); + SWAP(struct GPUFrameBuffer *, fbl->effect_fb, fbl->double_buffer_fb); + SWAP(struct GPUFrameBuffer *, fbl->effect_color_fb, fbl->double_buffer_color_fb); SWAP(GPUTexture *, txl->color_post, txl->color_double_buffer); effects->swap_double_buffer = false; effects->source_buffer = txl->color_double_buffer; - effects->target_buffer = fbl->main; + effects->target_buffer = fbl->main_fb; } else { /* Save the depth buffer for the next frame. * This saves us from doing anything special * in the other mode engines. */ if (!DRW_state_is_image_render()) { - DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true, false); + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->double_buffer_depth_fb, 0, GPU_DEPTH_BIT); } } diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index 85b168d1075..11ad4cae398 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -195,9 +195,9 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); common_data->vol_tex_size[0] = tex_size[0]; common_data->vol_tex_size[1] = tex_size[1]; common_data->vol_tex_size[2] = tex_size[2]; @@ -268,28 +268,23 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) EEVEE_volumes_set_jitter(sldata, current_sample); /* Framebuffer setup */ - DRWFboTexture tex_vol[4] = {{&txl->volume_prop_scattering, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_prop_extinction, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_prop_emission, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_prop_phase, DRW_TEX_RG_16, DRW_TEX_FILTER}}; - - DRW_framebuffer_init(&fbl->volumetric_fb, &draw_engine_eevee_type, - (int)tex_size[0], (int)tex_size[1], - tex_vol, 4); - - DRWFboTexture tex_vol_scat[2] = {{&txl->volume_scatter, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_transmittance, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; - - DRW_framebuffer_init(&fbl->volumetric_scat_fb, &draw_engine_eevee_type, - (int)tex_size[0], (int)tex_size[1], - tex_vol_scat, 2); - - DRWFboTexture tex_vol_integ[2] = {{&txl->volume_scatter_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}, - {&txl->volume_transmittance_history, DRW_TEX_RGB_11_11_10, DRW_TEX_FILTER}}; - - DRW_framebuffer_init(&fbl->volumetric_integ_fb, &draw_engine_eevee_type, - (int)tex_size[0], (int)tex_size[1], - tex_vol_integ, 2); + GPU_framebuffer_ensure_config(&fbl->volumetric_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_scattering), + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_extinction), + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_emission), + GPU_ATTACHMENT_TEXTURE(txl->volume_prop_phase) + }); + GPU_framebuffer_ensure_config(&fbl->volumetric_scat_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_scatter), + GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance) + }); + GPU_framebuffer_ensure_config(&fbl->volumetric_integ_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(txl->volume_scatter_history), + GPU_ATTACHMENT_TEXTURE(txl->volume_transmittance_history) + }); float integration_start = BKE_collection_engine_property_value_get_float(props, "volumetric_start"); float integration_end = BKE_collection_engine_property_value_get_float(props, "volumetric_end"); @@ -345,9 +340,9 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance); DRW_TEXTURE_FREE_SAFE(txl->volume_scatter_history); DRW_TEXTURE_FREE_SAFE(txl->volume_transmittance_history); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); - DRW_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_scat_fb); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->volumetric_integ_fb); return 0; } @@ -530,16 +525,16 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda DRW_stats_group_start("Volumetrics"); /* Step 1: Participating Media Properties */ - DRW_framebuffer_bind(fbl->volumetric_fb); + GPU_framebuffer_bind(fbl->volumetric_fb); DRW_draw_pass(psl->volumetric_world_ps); DRW_draw_pass(psl->volumetric_objects_ps); /* Step 2: Scatter Light */ - DRW_framebuffer_bind(fbl->volumetric_scat_fb); + GPU_framebuffer_bind(fbl->volumetric_scat_fb); DRW_draw_pass(psl->volumetric_scatter_ps); /* Step 3: Integration */ - DRW_framebuffer_bind(fbl->volumetric_integ_fb); + GPU_framebuffer_bind(fbl->volumetric_integ_fb); DRW_draw_pass(psl->volumetric_integration_ps); /* Swap volume history buffers */ @@ -548,7 +543,7 @@ void EEVEE_volumes_compute(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda SWAP(GPUTexture *, txl->volume_transmittance, txl->volume_transmittance_history); /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } @@ -569,14 +564,14 @@ void EEVEE_volumes_resolve(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda e_data.depth_src = dtxl->depth; /* Step 4: Apply for opaque */ - DRW_framebuffer_bind(fbl->effect_fb); + GPU_framebuffer_bind(fbl->effect_color_fb); DRW_draw_pass(psl->volumetric_resolve_ps); /* Swap the buffers and rebind depth to the current buffer */ - DRW_framebuffer_texture_detach(dtxl->depth); - SWAP(struct GPUFrameBuffer *, fbl->main, fbl->effect_fb); + SWAP(GPUFrameBuffer *, fbl->main_fb, fbl->effect_fb); + SWAP(GPUFrameBuffer *, fbl->main_color_fb, fbl->effect_color_fb); SWAP(GPUTexture *, txl->color, txl->color_post); - DRW_framebuffer_texture_attach(fbl->main, dtxl->depth, 0, 0); + GPU_framebuffer_texture_attach(fbl->main_fb, dtxl->depth, 0, 0); } } diff --git a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl index 23487e66a17..1fba69ffa51 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -760,20 +760,13 @@ Closure closure_add(Closure cl1, Closure cl2) # if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY) layout(location = 0) out vec4 fragColor; -# ifdef USE_SSS -# ifdef USE_SSS_ALBEDO -layout(location = 1) out vec4 sssData; -layout(location = 2) out vec4 sssAlbedo; -layout(location = 3) out vec4 ssrNormals; -layout(location = 4) out vec4 ssrData; -# else -layout(location = 1) out vec4 sssData; -layout(location = 2) out vec4 ssrNormals; -layout(location = 3) out vec4 ssrData; -# endif /* USE_SSS_ALBEDO */ -# else layout(location = 1) out vec4 ssrNormals; layout(location = 2) out vec4 ssrData; +# ifdef USE_SSS +layout(location = 3) out vec4 sssData; +# ifdef USE_SSS_ALBEDO +layout(location = 4) out vec4 sssAlbedo; +# endif /* USE_SSS_ALBEDO */ # endif /* USE_SSS */ Closure nodetree_exec(void); /* Prototype */ diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 3334579a7cd..e60ce6c391b 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -45,6 +45,8 @@ #include "DNA_material_types.h" #include "DNA_scene_types.h" +#include "GPU_framebuffer.h" + #include "draw_common.h" #include "draw_cache.h" #include "draw_view.h" @@ -100,9 +102,8 @@ typedef char DRWViewportEmptyList; #define MULTISAMPLE_SYNC_ENABLE(dfbl) { \ if (dfbl->multisample_fb != NULL) { \ DRW_stats_query_start("Multisample Blit"); \ - DRW_framebuffer_blit(dfbl->default_fb, dfbl->multisample_fb, false, false); \ - DRW_framebuffer_blit(dfbl->default_fb, dfbl->multisample_fb, true, false); \ - DRW_framebuffer_bind(dfbl->multisample_fb); \ + GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_COLOR_BIT | GPU_DEPTH_BIT); \ + GPU_framebuffer_bind(dfbl->multisample_fb); \ DRW_stats_query_end(); \ } \ } @@ -110,9 +111,8 @@ typedef char DRWViewportEmptyList; #define MULTISAMPLE_SYNC_DISABLE(dfbl) { \ if (dfbl->multisample_fb != NULL) { \ DRW_stats_query_start("Multisample Resolve"); \ - DRW_framebuffer_blit(dfbl->multisample_fb, dfbl->default_fb, false, false); \ - DRW_framebuffer_blit(dfbl->multisample_fb, dfbl->default_fb, true, false); \ - DRW_framebuffer_bind(dfbl->default_fb); \ + GPU_framebuffer_blit(dfbl->multisample_fb, 0, dfbl->default_fb, 0, GPU_COLOR_BIT | GPU_DEPTH_BIT); \ + GPU_framebuffer_bind(dfbl->default_fb); \ DRW_stats_query_end(); \ } \ } @@ -153,6 +153,8 @@ typedef struct DrawEngineType { /* Buffer and textures used by the viewport by default */ typedef struct DefaultFramebufferList { struct GPUFrameBuffer *default_fb; + struct GPUFrameBuffer *color_only_fb; + struct GPUFrameBuffer *depth_only_fb; struct GPUFrameBuffer *multisample_fb; } DefaultFramebufferList; @@ -195,9 +197,13 @@ typedef enum { DRW_TEX_WRAP = (1 << 1), DRW_TEX_COMPARE = (1 << 2), DRW_TEX_MIPMAP = (1 << 3), - DRW_TEX_TEMP = (1 << 4), } DRWTextureFlag; +/* Textures from DRW_texture_pool_query_* have the options + * DRW_TEX_FILTER for color float textures, and no options + * for depth textures and integer textures. */ +struct GPUTexture *DRW_texture_pool_query_2D(int w, int h, DRWTextureFormat format, DrawEngineType *engine_type); + struct GPUTexture *DRW_texture_create_1D( int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); struct GPUTexture *DRW_texture_create_2D( @@ -208,6 +214,12 @@ struct GPUTexture *DRW_texture_create_3D( int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); struct GPUTexture *DRW_texture_create_cube( int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels); + +void DRW_texture_ensure_fullscreen_2D( + struct GPUTexture **tex, DRWTextureFormat format, DRWTextureFlag flags); +void DRW_texture_ensure_2D( + struct GPUTexture **tex, int w, int h, DRWTextureFormat format, DRWTextureFlag flags); + void DRW_texture_generate_mipmaps(struct GPUTexture *tex); void DRW_texture_free(struct GPUTexture *tex); #define DRW_TEXTURE_FREE_SAFE(tex) do { \ @@ -228,40 +240,6 @@ void DRW_uniformbuffer_free(struct GPUUniformBuffer *ubo); } \ } while (0) -/* Buffers */ -#define MAX_FBO_TEX 5 - -typedef struct DRWFboTexture { - struct GPUTexture **tex; - int format; - DRWTextureFlag flag; -} DRWFboTexture; - -struct GPUFrameBuffer *DRW_framebuffer_create(void); -void DRW_framebuffer_init( - struct GPUFrameBuffer **fb, void *engine_type, int width, int height, - DRWFboTexture textures[MAX_FBO_TEX], int textures_len); -void DRW_framebuffer_bind(struct GPUFrameBuffer *fb); -void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth); -void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data); -void DRW_framebuffer_read_depth(int x, int y, int w, int h, float *data); -void DRW_framebuffer_texture_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); -void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); -void DRW_framebuffer_cubeface_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); -void DRW_framebuffer_texture_detach(struct GPUTexture *tex); -void DRW_framebuffer_blit(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth, bool stencil); -void DRW_framebuffer_recursive_downsample( - struct GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, - void (*callback)(void *userData, int level), void *userData); -void DRW_framebuffer_viewport_size(struct GPUFrameBuffer *fb_read, int x, int y, int w, int h); -void DRW_framebuffer_free(struct GPUFrameBuffer *fb); -#define DRW_FRAMEBUFFER_FREE_SAFE(fb) do { \ - if (fb != NULL) { \ - DRW_framebuffer_free(fb); \ - fb = NULL; \ - } \ -} while (0) - void DRW_transform_to_display(struct GPUTexture *tex); /* Shaders */ diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 8377d212788..2b64eabe332 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -744,6 +744,10 @@ static void drw_engines_draw_scene(void) if (engine->draw_scene) { DRW_stats_group_start(engine->idname); engine->draw_scene(data); + /* Restore for next engine */ + if (DRW_state_is_fbo()) { + GPU_framebuffer_bind(DST.default_framebuffer); + } DRW_stats_group_end(); } @@ -1126,6 +1130,9 @@ void DRW_draw_render_loop_ex( /* Update ubos */ DRW_globals_update(); + /* No framebuffer allowed before drawing. */ + BLI_assert(GPU_framebuffer_current_get() == 0); + /* Init engines */ drw_engines_init(); @@ -1152,6 +1159,8 @@ void DRW_draw_render_loop_ex( DRW_stats_begin(); + GPU_framebuffer_bind(DST.default_framebuffer); + /* Start Drawing */ DRW_state_reset(); @@ -1217,6 +1226,8 @@ void DRW_draw_render_loop_ex( glEnable(GL_DEPTH_TEST); } + GPU_framebuffer_restore(); + DRW_state_reset(); drw_engines_disable(); @@ -1262,6 +1273,8 @@ void DRW_draw_render_loop_offscreen( } } + GPU_framebuffer_restore(); + /* Reset before using it. */ memset(&DST, 0x0, offsetof(DRWManager, ogl_context)); DST.options.is_image_render = true; @@ -1461,11 +1474,6 @@ void DRW_draw_select_loop( DST.viewport = viewport; v3d->zbuf = true; - /* Setup framebuffer */ - draw_select_framebuffer_setup(rect); - GPU_framebuffer_bind(g_select_buffer.framebuffer); - DRW_framebuffer_clear(false, true, false, NULL, 1.0f); - DST.options.is_select = true; /* Get list of enabled engines */ @@ -1519,6 +1527,11 @@ void DRW_draw_select_loop( DRW_render_instance_buffer_finish(); } + /* Setup framebuffer */ + draw_select_framebuffer_setup(rect); + GPU_framebuffer_bind(g_select_buffer.framebuffer); + GPU_framebuffer_clear_depth(g_select_buffer.framebuffer, 1.0f); + /* Start Drawing */ DRW_state_reset(); DRW_draw_callbacks_pre_scene(); @@ -1628,7 +1641,7 @@ void DRW_draw_depth_loop( /* Setup framebuffer */ draw_select_framebuffer_setup(&ar->winrct); GPU_framebuffer_bind(g_select_buffer.framebuffer); - DRW_framebuffer_clear(false, true, false, NULL, 1.0f); + GPU_framebuffer_clear_depth(g_select_buffer.framebuffer, 1.0f); bool cache_is_dirty; DST.viewport = viewport; @@ -1918,7 +1931,7 @@ void DRW_engines_free(void) DRW_opengl_context_enable(); DRW_TEXTURE_FREE_SAFE(g_select_buffer.texture_depth); - DRW_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer); + GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer); DRW_shape_cache_free(); DRW_stats_free(); diff --git a/source/blender/draw/intern/draw_manager_framebuffer.c b/source/blender/draw/intern/draw_manager_framebuffer.c deleted file mode 100644 index a76b1c42a53..00000000000 --- a/source/blender/draw/intern/draw_manager_framebuffer.c +++ /dev/null @@ -1,189 +0,0 @@ -/* - * Copyright 2016, Blender Foundation. - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * Contributor(s): Blender Institute - * - */ - -/** \file blender/draw/intern/draw_manager_framebuffer.c - * \ingroup draw - */ - -#include "draw_manager.h" - -GPUFrameBuffer *DRW_framebuffer_create(void) -{ - return GPU_framebuffer_create(); -} - -void DRW_framebuffer_init( - GPUFrameBuffer **fb, void *engine_type, int width, int height, - DRWFboTexture textures[MAX_FBO_TEX], int textures_len) -{ - BLI_assert(textures_len <= MAX_FBO_TEX); - BLI_assert(width > 0 && height > 0); - - bool create_fb = false; - int color_attachment = -1; - - if (!*fb) { - *fb = GPU_framebuffer_create(); - create_fb = true; - } - - for (int i = 0; i < textures_len; ++i) { - int channels; - bool is_depth; - bool create_tex = false; - GPUTextureFormat gpu_format; - - DRWFboTexture fbotex = textures[i]; - bool is_temp = (fbotex.flag & DRW_TEX_TEMP) != 0; - - drw_texture_get_format(fbotex.format, true, &gpu_format, &channels, &is_depth); - - if (!*fbotex.tex || is_temp) { - /* Temp textures need to be queried each frame, others not. */ - if (is_temp) { - *fbotex.tex = GPU_viewport_texture_pool_query( - DST.viewport, engine_type, width, height, channels, gpu_format); - } - else { - *fbotex.tex = GPU_texture_create_2D_custom( - width, height, channels, gpu_format, NULL, NULL); - create_tex = true; - } - } - - if (!is_depth) { - ++color_attachment; - } - - if (create_fb || create_tex) { - drw_texture_set_parameters(*fbotex.tex, fbotex.flag); - GPU_framebuffer_texture_attach(*fb, *fbotex.tex, color_attachment, 0); - } - } - - if (create_fb && (textures_len > 0)) { - if (!GPU_framebuffer_check_valid(*fb, NULL)) { - printf("Error invalid framebuffer\n"); - } - - /* Detach temp textures */ - for (int i = 0; i < textures_len; ++i) { - DRWFboTexture fbotex = textures[i]; - - if ((fbotex.flag & DRW_TEX_TEMP) != 0) { - GPU_framebuffer_texture_detach(*fbotex.tex); - } - } - - if (DST.default_framebuffer != NULL) { - GPU_framebuffer_bind(DST.default_framebuffer); - } - } -} - -void DRW_framebuffer_free(GPUFrameBuffer *fb) -{ - GPU_framebuffer_free(fb); -} - -void DRW_framebuffer_bind(GPUFrameBuffer *fb) -{ - GPU_framebuffer_bind(fb); -} - -void DRW_framebuffer_clear(bool color, bool depth, bool stencil, float clear_col[4], float clear_depth) -{ - if (color) { - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - glClearColor(clear_col[0], clear_col[1], clear_col[2], clear_col[3]); - } - if (depth) { - glDepthMask(GL_TRUE); - glClearDepth(clear_depth); - } - if (stencil) { - glStencilMask(0xFF); - } - glClear(((color) ? GL_COLOR_BUFFER_BIT : 0) | - ((depth) ? GL_DEPTH_BUFFER_BIT : 0) | - ((stencil) ? GL_STENCIL_BUFFER_BIT : 0)); -} - -void DRW_framebuffer_read_data(int x, int y, int w, int h, int channels, int slot, float *data) -{ - GLenum type; - switch (channels) { - case 1: type = GL_RED; break; - case 2: type = GL_RG; break; - case 3: type = GL_RGB; break; - case 4: type = GL_RGBA; break; - default: - BLI_assert(false && "wrong number of read channels"); - return; - } - glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); - glReadPixels(x, y, w, h, type, GL_FLOAT, data); -} - -void DRW_framebuffer_read_depth(int x, int y, int w, int h, float *data) -{ - GLenum type = GL_DEPTH_COMPONENT; - - glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ - glReadPixels(x, y, w, h, type, GL_FLOAT, data); -} - -void DRW_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) -{ - GPU_framebuffer_texture_attach(fb, tex, slot, mip); -} - -void DRW_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) -{ - GPU_framebuffer_texture_layer_attach(fb, tex, slot, layer, mip); -} - -void DRW_framebuffer_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) -{ - GPU_framebuffer_texture_cubeface_attach(fb, tex, slot, face, mip); -} - -void DRW_framebuffer_texture_detach(GPUTexture *tex) -{ - GPU_framebuffer_texture_detach(tex); -} - -void DRW_framebuffer_blit(GPUFrameBuffer *fb_read, GPUFrameBuffer *fb_write, bool depth, bool stencil) -{ - GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth, stencil); -} - -void DRW_framebuffer_recursive_downsample( - GPUFrameBuffer *fb, GPUTexture *tex, int num_iter, - void (*callback)(void *userData, int level), void *userData) -{ - GPU_framebuffer_recursive_downsample(fb, tex, num_iter, callback, userData); -} - -void DRW_framebuffer_viewport_size(GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h) -{ - glViewport(x, y, w, h); -} diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 3a258954dbd..65856a6bf5c 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -197,6 +197,33 @@ GPUTexture *DRW_texture_create_cube(int w, DRWTextureFormat format, DRWTextureFl return tex; } +GPUTexture *DRW_texture_pool_query_2D(int w, int h, DRWTextureFormat format, DrawEngineType *engine_type) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, true, &data_type, &channels, NULL); + tex = GPU_viewport_texture_pool_query(DST.viewport, engine_type, w, h, channels, data_type); + + return tex; +} + +void DRW_texture_ensure_fullscreen_2D(GPUTexture **tex, DRWTextureFormat format, DRWTextureFlag flags) +{ + if (*(tex) == NULL) { + const float *size = DRW_viewport_size_get(); + *(tex) = DRW_texture_create_2D((int)size[0], (int)size[1], format, flags, NULL); + } +} + +void DRW_texture_ensure_2D(GPUTexture **tex, int w, int h, DRWTextureFormat format, DRWTextureFlag flags) +{ + if (*(tex) == NULL) { + *(tex) = DRW_texture_create_2D(w, h, format, flags, NULL); + } +} + void DRW_texture_generate_mipmaps(GPUTexture *tex) { GPU_texture_bind(tex, 0); diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index cc1373dc29f..51b8eca9148 100644 --- a/source/blender/draw/modes/edit_mesh_mode.c +++ b/source/blender/draw/modes/edit_mesh_mode.c @@ -137,15 +137,17 @@ static void EDIT_MESH_engine_init(void *vedata) EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl; const float *viewport_size = DRW_viewport_size_get(); + const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - DRWFboTexture tex[2] = {{ - &e_data.occlude_wire_depth_tx, DRW_TEX_DEPTH_24, DRW_TEX_TEMP}, - {&e_data.occlude_wire_color_tx, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_TEMP} - }; - DRW_framebuffer_init( - &fbl->occlude_wire_fb, &draw_engine_edit_mesh_type, - (int)viewport_size[0], (int)viewport_size[1], - tex, ARRAY_SIZE(tex)); + e_data.occlude_wire_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_DEPTH_24, + &draw_engine_edit_mesh_type); + e_data.occlude_wire_color_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RGBA_8, + &draw_engine_edit_mesh_type); + + GPU_framebuffer_ensure_config(&fbl->occlude_wire_fb, { + GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_depth_tx), + GPU_ATTACHMENT_TEXTURE(e_data.occlude_wire_color_tx) + }); if (!e_data.vcolor_face_shader) { e_data.vcolor_face_shader = GPU_shader_get_builtin_shader(GPU_SHADER_SIMPLE_LIGHTING_SMOOTH_COLOR_ALPHA); @@ -523,7 +525,6 @@ static void EDIT_MESH_draw_scene(void *vedata) EDIT_MESH_PassList *psl = ((EDIT_MESH_Data *)vedata)->psl; EDIT_MESH_FramebufferList *fbl = ((EDIT_MESH_Data *)vedata)->fbl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DRW_draw_pass(psl->vcolor_faces); @@ -534,29 +535,15 @@ static void EDIT_MESH_draw_scene(void *vedata) /* render facefill */ DRW_draw_pass(psl->facefill_occlude); - /* attach temp textures */ - DRW_framebuffer_texture_attach(fbl->occlude_wire_fb, e_data.occlude_wire_depth_tx, 0, 0); - DRW_framebuffer_texture_attach(fbl->occlude_wire_fb, e_data.occlude_wire_color_tx, 0, 0); - /* Render wires on a separate framebuffer */ - DRW_framebuffer_bind(fbl->occlude_wire_fb); - DRW_framebuffer_clear(true, true, false, clearcol, 1.0f); + GPU_framebuffer_bind(fbl->occlude_wire_fb); + GPU_framebuffer_clear_color_depth(fbl->occlude_wire_fb, clearcol, 1.0f); DRW_draw_pass(psl->normals); DRW_draw_pass(psl->edit_face_occluded); - /* detach textures */ - DRW_framebuffer_texture_detach(dtxl->depth); - /* Combine with scene buffer */ - DRW_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->mix_occlude); - - /* detach temp textures */ - DRW_framebuffer_texture_detach(e_data.occlude_wire_depth_tx); - DRW_framebuffer_texture_detach(e_data.occlude_wire_color_tx); - - /* reattach */ - DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); } else { DRW_draw_pass(psl->normals); diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index b5127ca634d..2947c64d91b 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -106,8 +106,9 @@ typedef struct OBJECT_PassList { } OBJECT_PassList; typedef struct OBJECT_FramebufferList { - struct GPUFrameBuffer *outlines; - struct GPUFrameBuffer *blur; + struct GPUFrameBuffer *outlines_fb; + struct GPUFrameBuffer *blur_fb; + struct GPUFrameBuffer *expand_fb; } OBJECT_FramebufferList; typedef struct OBJECT_StorageList { @@ -282,23 +283,31 @@ static void OBJECT_engine_init(void *vedata) OBJECT_FramebufferList *fbl = ((OBJECT_Data *)vedata)->fbl; const float *viewport_size = DRW_viewport_size_get(); + const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; if (DRW_state_is_fbo()) { - DRWFboTexture tex[2] = { - {&e_data.outlines_depth_tx, DRW_TEX_DEPTH_24, DRW_TEX_TEMP}, - {&e_data.outlines_color_tx, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_TEMP}, - }; + e_data.outlines_depth_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_DEPTH_24, + &draw_engine_object_type); + e_data.outlines_color_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RGBA_8, + &draw_engine_object_type); - DRW_framebuffer_init( - &fbl->outlines, &draw_engine_object_type, - (int)viewport_size[0], (int)viewport_size[1], - tex, 2); + GPU_framebuffer_ensure_config(&fbl->outlines_fb, { + GPU_ATTACHMENT_TEXTURE(e_data.outlines_depth_tx), + GPU_ATTACHMENT_TEXTURE(e_data.outlines_color_tx) + }); - DRWFboTexture blur_tex = {&e_data.outlines_blur_tx, DRW_TEX_RGBA_8, DRW_TEX_FILTER | DRW_TEX_TEMP}; - DRW_framebuffer_init( - &fbl->blur, &draw_engine_object_type, - (int)viewport_size[0], (int)viewport_size[1], - &blur_tex, 1); + GPU_framebuffer_ensure_config(&fbl->expand_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(e_data.outlines_color_tx) + }); + + e_data.outlines_blur_tx = DRW_texture_pool_query_2D(size[0], size[1], DRW_TEX_RGBA_8, + &draw_engine_object_type); + + GPU_framebuffer_ensure_config(&fbl->blur_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(e_data.outlines_blur_tx) + }); } if (!e_data.outline_resolve_sh) { @@ -2036,38 +2045,27 @@ static void OBJECT_draw_scene(void *vedata) if (DRW_state_is_fbo()) { DRW_stats_group_start("Outlines"); - /* attach temp textures */ - DRW_framebuffer_texture_attach(fbl->outlines, e_data.outlines_depth_tx, 0, 0); - DRW_framebuffer_texture_attach(fbl->outlines, e_data.outlines_color_tx, 0, 0); - DRW_framebuffer_texture_attach(fbl->blur, e_data.outlines_blur_tx, 0, 0); /* Render filled polygon on a separate framebuffer */ - DRW_framebuffer_bind(fbl->outlines); - DRW_framebuffer_clear(true, true, false, clearcol, 1.0f); + GPU_framebuffer_bind(fbl->outlines_fb); + GPU_framebuffer_clear_color_depth(fbl->outlines_fb, clearcol, 1.0f); DRW_draw_pass(psl->outlines); DRW_draw_pass(psl->lightprobes); - /* detach textures */ - DRW_framebuffer_texture_detach(e_data.outlines_depth_tx); - /* Search outline pixels */ - DRW_framebuffer_bind(fbl->blur); + GPU_framebuffer_bind(fbl->blur_fb); DRW_draw_pass(psl->outlines_search); /* Expand outline to form a 3px wide line */ - DRW_framebuffer_bind(fbl->outlines); + GPU_framebuffer_bind(fbl->expand_fb); DRW_draw_pass(psl->outlines_expand); /* Bleed color so the AA can do it's stuff */ - DRW_framebuffer_bind(fbl->blur); + GPU_framebuffer_bind(fbl->blur_fb); DRW_draw_pass(psl->outlines_bleed); - /* detach temp textures */ - DRW_framebuffer_texture_detach(e_data.outlines_color_tx); - DRW_framebuffer_texture_detach(e_data.outlines_blur_tx); - /* restore main framebuffer */ - DRW_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_bind(dfbl->default_fb); DRW_stats_group_end(); } else if (DRW_state_is_select()) { @@ -2091,9 +2089,9 @@ static void OBJECT_draw_scene(void *vedata) if (DRW_state_is_fbo()) { if (e_data.draw_grid) { - DRW_framebuffer_texture_detach(dtxl->depth); + GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->grid); - DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); + GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); } /* Combine with scene buffer last */ diff --git a/source/blender/gpu/GPU_framebuffer.h b/source/blender/gpu/GPU_framebuffer.h index 93f16b342d1..0ab15a4ea47 100644 --- a/source/blender/gpu/GPU_framebuffer.h +++ b/source/blender/gpu/GPU_framebuffer.h @@ -36,6 +36,13 @@ extern "C" { #endif +struct GPUTexture; + +typedef struct GPUAttachment { + struct GPUTexture *tex; + int mip, layer; +} GPUAttachment; + typedef enum GPUFrameBufferBits{ GPU_COLOR_BIT = (1 << 0), GPU_DEPTH_BIT = (1 << 1), @@ -44,40 +51,95 @@ typedef enum GPUFrameBufferBits{ typedef struct GPUFrameBuffer GPUFrameBuffer; typedef struct GPUOffScreen GPUOffScreen; -struct GPUTexture; /* GPU Framebuffer * - this is a wrapper for an OpenGL framebuffer object (FBO). in practice * multiple FBO's may be created, to get around limitations on the number * of attached textures and the dimension requirements. - * - after any of the GPU_framebuffer_* functions, GPU_framebuffer_restore must - * be called before rendering to the window framebuffer again */ - -void GPU_texture_bind_as_framebuffer(struct GPUTexture *tex); + * - actual FBO creation & config is deferred until GPU_framebuffer_bind or + * GPU_framebuffer_check_valid to allow creation & config while another + * opengl context is bound (since FBOs are not shared between ogl contexts). + */ GPUFrameBuffer *GPU_framebuffer_create(void); -bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); -bool GPU_framebuffer_texture_layer_attach( - GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); -bool GPU_framebuffer_texture_cubeface_attach( - GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); -void GPU_framebuffer_texture_detach(struct GPUTexture *tex); -void GPU_framebuffer_bind(GPUFrameBuffer *fb); -void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot); -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *fb, struct GPUTexture *tex); void GPU_framebuffer_free(GPUFrameBuffer *fb); +void GPU_framebuffer_bind(GPUFrameBuffer *fb); +void GPU_framebuffer_restore(void); + +bool GPU_framebuffer_bound(GPUFrameBuffer *fb); bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]); /* internal use only */ unsigned int GPU_framebuffer_current_get(void); -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot); -bool GPU_framebuffer_bound(GPUFrameBuffer *fb); +#define GPU_FRAMEBUFFER_FREE_SAFE(fb) do { \ + if (fb != NULL) { \ + GPU_framebuffer_free(fb); \ + fb = NULL; \ + } \ +} while (0) + +/* Framebuffer setup : You need to call GPU_framebuffer_bind for theses + * to be effective. */ + +void GPU_framebuffer_texture_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int mip); +void GPU_framebuffer_texture_layer_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip); +void GPU_framebuffer_texture_cubeface_attach( + GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int face, int mip); +void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, struct GPUTexture *tex); +void GPU_framebuffer_texture_detach_slot( + GPUFrameBuffer *fb, struct GPUTexture *tex, int type); + +/** + * How to use GPU_framebuffer_ensure_config(). + * + * Example : + * GPU_framebuffer_ensure_config(&fb, { + * GPU_ATTACHMENT_TEXTURE(depth), // must be depth buffer + * GPU_ATTACHMENT_TEXTURE(tex1), + * GPU_ATTACHMENT_TEXTURE_CUBEFACE(tex2, 0), + * GPU_ATTACHMENT_TEXTURE_LAYER_MIP(tex2, 0, 0) + * }) + * + * Note : Unspecified attachements (i.e: those beyond the last + * GPU_ATTACHMENT_* in GPU_framebuffer_ensure_config list) + * are left unchanged. + * Note : Make sure that the dimensions of your textures matches + * otherwise you will have an invalid framebuffer error. + **/ +#define GPU_framebuffer_ensure_config(_fb, ...) do { \ + if (*(_fb) == NULL) { \ + *(_fb) = GPU_framebuffer_create(); \ + } \ + GPUAttachment config[] = __VA_ARGS__; \ + GPU_framebuffer_config_array(*(_fb), config, (sizeof(config) / sizeof(GPUAttachment))); \ +} while (0) + +void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_ct); + +#define GPU_ATTACHMENT_NONE \ + {.tex = NULL, .layer = -1, .mip = 0} +#define GPU_ATTACHMENT_LEAVE \ + {.tex = NULL, .layer = -1, .mip = -1} +#define GPU_ATTACHMENT_TEXTURE(_tex) \ + {.tex = _tex, .layer = -1, .mip = 0} +#define GPU_ATTACHMENT_TEXTURE_MIP(_tex, _mip) \ + {.tex = _tex, .layer = -1, .mip = _mip} +#define GPU_ATTACHMENT_TEXTURE_LAYER(_tex, _layer) \ + {.tex = _tex, .layer = _layer, .mip = 0} +#define GPU_ATTACHMENT_TEXTURE_LAYER_MIP(_tex, _layer, _mip) \ + {.tex = _tex, .layer = _layer, .mip = _mip} +#define GPU_ATTACHMENT_TEXTURE_CUBEFACE(_tex, _face) \ + {.tex = _tex, .layer = _face, .mip = 0} +#define GPU_ATTACHMENT_TEXTURE_CUBEFACE_MIP(_tex, _face, _mip) \ + {.tex = _tex, .layer = _face, .mip = _mip} + /* Framebuffer operations */ void GPU_framebuffer_viewport_set(GPUFrameBuffer *fb, int x, int y, int w, int h); -void GPU_framebuffer_restore(void); void GPU_framebuffer_clear( GPUFrameBuffer *fb, GPUFrameBufferBits buffers, const float clear_col[4], float clear_depth, unsigned int clear_stencil); @@ -100,18 +162,22 @@ void GPU_framebuffer_clear( #define GPU_framebuffer_clear_color_depth_stencil(fb, col, depth, stencil) \ GPU_framebuffer_clear(fb, GPU_COLOR_BIT | GPU_DEPTH_BIT | GPU_STENCIL_BIT, col, depth, stencil) +void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data); +void GPU_framebuffer_read_color( + GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data); void GPU_framebuffer_blit( GPUFrameBuffer *fb_read, int read_slot, - GPUFrameBuffer *fb_write, int write_slot, bool use_depth, bool use_stencil); + GPUFrameBuffer *fb_write, int write_slot, + GPUFrameBufferBits blit_buffers); void GPU_framebuffer_recursive_downsample( - GPUFrameBuffer *fb, struct GPUTexture *tex, int num_iter, + GPUFrameBuffer *fb, int max_lvl, void (*callback)(void *userData, int level), void *userData); /* GPU OffScreen * - wrapper around framebuffer and texture for simple offscreen drawing - * - changes size if graphics card can't support it */ + */ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool depth, bool high_bitdepth, char err_out[256]); diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 72e3859a5a8..57185d2f39e 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -189,9 +189,8 @@ void GPU_texture_filter_mode(GPUTexture *tex, bool use_filter); void GPU_texture_mipmap_mode(GPUTexture *tex, bool use_mipmap, bool use_filter); void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat); -struct GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex); -int GPU_texture_framebuffer_attachment(GPUTexture *tex); -void GPU_texture_framebuffer_set(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment); +void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment); +int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb); int GPU_texture_target(const GPUTexture *tex); int GPU_texture_width(const GPUTexture *tex); diff --git a/source/blender/gpu/intern/gpu_framebuffer.c b/source/blender/gpu/intern/gpu_framebuffer.c index dbcf0dc4568..0e27e3e0f8f 100644 --- a/source/blender/gpu/intern/gpu_framebuffer.c +++ b/source/blender/gpu/intern/gpu_framebuffer.c @@ -30,6 +30,7 @@ #include "BLI_blenlib.h" #include "BLI_threads.h" #include "BLI_utildefines.h" +#include "BLI_math_base.h" #include "BKE_global.h" @@ -43,16 +44,67 @@ static ThreadLocal(GLuint) g_currentfb; -/* Number of maximum output slots. - * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate) */ -#define GPU_FB_MAX_SLOTS 5 +typedef enum { + GPU_FB_DEPTH_ATTACHMENT = 0, + GPU_FB_DEPTH_STENCIL_ATTACHMENT, + GPU_FB_COLOR_ATTACHMENT0, + GPU_FB_COLOR_ATTACHMENT1, + GPU_FB_COLOR_ATTACHMENT2, + GPU_FB_COLOR_ATTACHMENT3, + GPU_FB_COLOR_ATTACHMENT4, + /* Number of maximum output slots. + * We support 5 outputs for now (usually we wouldn't need more to preserve fill rate). */ + /* Keep in mind that GL max is GL_MAX_DRAW_BUFFERS and is at least 8, corresponding to + * the maximum number of COLOR attachments specified by glDrawBuffers. */ + GPU_FB_MAX_ATTACHEMENT +} GPUAttachmentType; + +#define GPU_FB_MAX_COLOR_ATTACHMENT (GPU_FB_MAX_ATTACHEMENT - GPU_FB_COLOR_ATTACHMENT0) + +#define GPU_FB_DIRTY_DRAWBUFFER (1 << 15) + +#define GPU_FB_ATTACHEMENT_IS_DIRTY(flag, type) ((flag & (1 << type)) != 0) +#define GPU_FB_ATTACHEMENT_SET_DIRTY(flag, type) (flag |= (1 << type)) struct GPUFrameBuffer { GLuint object; - GPUTexture *colortex[GPU_FB_MAX_SLOTS]; - GPUTexture *depthtex; + GPUAttachment attachments[GPU_FB_MAX_ATTACHEMENT]; + uint16_t dirty_flag; + int width, height; + bool multisample; + /* TODO Check that we always use the right context when binding + * (FBOs are not shared accross ogl contexts). */ + // void *ctx; }; +static GLenum convert_attachment_type_to_gl(GPUAttachmentType type) +{ + static const GLenum table[] = { + [GPU_FB_DEPTH_ATTACHMENT] = GL_DEPTH_ATTACHMENT, + [GPU_FB_DEPTH_STENCIL_ATTACHMENT] = GL_DEPTH_STENCIL_ATTACHMENT, + [GPU_FB_COLOR_ATTACHMENT0] = GL_COLOR_ATTACHMENT0, + [GPU_FB_COLOR_ATTACHMENT1] = GL_COLOR_ATTACHMENT1, + [GPU_FB_COLOR_ATTACHMENT2] = GL_COLOR_ATTACHMENT2, + [GPU_FB_COLOR_ATTACHMENT3] = GL_COLOR_ATTACHMENT3, + [GPU_FB_COLOR_ATTACHMENT4] = GL_COLOR_ATTACHMENT4 + }; + return table[type]; +} + +static GPUAttachmentType attachment_type_from_tex(GPUTexture *tex, int slot) +{ + switch (GPU_texture_format(tex)) { + case GPU_DEPTH_COMPONENT32F: + case GPU_DEPTH_COMPONENT24: + case GPU_DEPTH_COMPONENT16: + return GPU_FB_DEPTH_ATTACHMENT; + case GPU_DEPTH24_STENCIL8: + return GPU_FB_DEPTH_STENCIL_ATTACHMENT; + default: + return GPU_FB_COLOR_ATTACHMENT0 + slot; + } +} + static GLenum convert_buffer_bits_to_gl(GPUFrameBufferBits bits) { GLbitfield mask = 0; @@ -62,6 +114,19 @@ static GLenum convert_buffer_bits_to_gl(GPUFrameBufferBits bits) return mask; } +static GPUTexture *framebuffer_get_depth_tex(GPUFrameBuffer *fb) +{ + if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex) + return fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex; + else + return fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex;; +} + +static GPUTexture *framebuffer_get_color_tex(GPUFrameBuffer *fb, int slot) +{ + return fb->attachments[GPU_FB_COLOR_ATTACHMENT0 + slot].tex; +} + static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) { const char *format = "GPUFrameBuffer: framebuffer status %s\n"; @@ -102,303 +167,268 @@ static void gpu_print_framebuffer_error(GLenum status, char err_out[256]) GPUFrameBuffer *GPU_framebuffer_create(void) { - GPUFrameBuffer *fb; + /* We generate the FB object later at first use in order to + * create the framebuffer in the right opengl context. */ + return MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer");; +} - fb = MEM_callocN(sizeof(GPUFrameBuffer), "GPUFrameBuffer"); +static void gpu_framebuffer_init(GPUFrameBuffer *fb) +{ glGenFramebuffers(1, &fb->object); - - if (!fb->object) { - fprintf(stderr, "GPUFFrameBuffer: framebuffer gen failed.\n"); - GPU_framebuffer_free(fb); - return NULL; - } - - /* make sure no read buffer is enabled, so completeness check will not fail. We set those at binding time */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - glReadBuffer(GL_NONE); - glDrawBuffer(GL_NONE); - glBindFramebuffer(GL_FRAMEBUFFER, 0); - - return fb; } -bool GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) +void GPU_framebuffer_free(GPUFrameBuffer *fb) { - GLenum attachment; - - if (slot >= GPU_FB_MAX_SLOTS) { - fprintf(stderr, - "Attaching to index %d framebuffer slot unsupported. " - "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return false; - } - - if ((G.debug & G_DEBUG)) { - if (GPU_texture_bound_number(tex) != -1) { - fprintf(stderr, - "Feedback loop warning!: " - "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; type++) { + if (fb->attachments[type].tex != NULL) { + GPU_framebuffer_texture_detach(fb, fb->attachments[type].tex); } } - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - g_currentfb = fb->object; + /* This restores the framebuffer if it was bound */ + glDeleteFramebuffers(1, &fb->object); - if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) - attachment = GL_DEPTH_STENCIL_ATTACHMENT; - else if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT; - else - attachment = GL_COLOR_ATTACHMENT0 + slot; + if (g_currentfb == fb->object) { + g_currentfb = 0; + } - glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip); - - if (GPU_texture_depth(tex)) - fb->depthtex = tex; - else - fb->colortex[slot] = tex; - - GPU_texture_framebuffer_set(tex, fb, slot); - - return true; + MEM_freeN(fb); } -static bool gpu_framebuffer_texture_layer_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip, bool cubemap) -{ - GLenum attachment; - GLenum facetarget; +/* ---------- Attach ----------- */ - if (slot >= GPU_FB_MAX_SLOTS) { +static void gpu_framebuffer_texture_attach_ex(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +{ + if (slot >= GPU_FB_MAX_COLOR_ATTACHMENT) { fprintf(stderr, "Attaching to index %d framebuffer slot unsupported. " - "Use at most %d\n", slot, GPU_FB_MAX_SLOTS); - return false; + "Use at most %d\n", slot, GPU_FB_MAX_COLOR_ATTACHMENT); + return; } - if ((G.debug & G_DEBUG)) { - if (GPU_texture_bound_number(tex) != -1) { - fprintf(stderr, - "Feedback loop warning!: " - "Attempting to attach texture to framebuffer while still bound to texture unit for drawing!\n"); + GPUAttachmentType type = attachment_type_from_tex(tex, slot); + GPUAttachment *attachment = &fb->attachments[type]; + + if ((attachment->tex == tex) && + (attachment->mip == mip) && + (attachment->layer == layer)) + { + return; /* Exact same texture already bound here. */ + } + else if (attachment->tex != NULL) { + GPU_framebuffer_texture_detach(fb, attachment->tex); + } + + if (attachment->tex == NULL) { + GPU_texture_attach_framebuffer(tex, fb, type); + } + + attachment->tex = tex; + attachment->mip = mip; + attachment->layer = layer; + GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); +} + +void GPU_framebuffer_texture_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) +{ + return gpu_framebuffer_texture_attach_ex(fb, tex, slot, -1, mip); +} + +void GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +{ + /* NOTE: We could support 1D ARRAY texture. */ + BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_2D_ARRAY); + return gpu_framebuffer_texture_attach_ex(fb, tex, slot, layer, mip); +} + +void GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) +{ + BLI_assert(GPU_texture_cube(tex)); + return gpu_framebuffer_texture_attach_ex(fb, tex, slot, face, mip); +} + +/* ---------- Detach ----------- */ + +void GPU_framebuffer_texture_detach_slot(GPUFrameBuffer *fb, GPUTexture *tex, int type) +{ + GPUAttachment *attachment = &fb->attachments[type]; + + if (attachment->tex != tex) { + fprintf(stderr, + "Warning, attempting to detach Texture %p from framebuffer %p " + "but texture is not attached.\n", tex, fb); + return; + } + + attachment->tex = NULL; + GPU_FB_ATTACHEMENT_SET_DIRTY(fb->dirty_flag, type); +} + +void GPU_framebuffer_texture_detach(GPUFrameBuffer *fb, GPUTexture *tex) +{ + GPUAttachmentType type = GPU_texture_detach_framebuffer(tex, fb); + GPU_framebuffer_texture_detach_slot(fb, tex, type); +} + +/* ---------- Config (Attach & Detach) ----------- */ + +/** + * First GPUAttachment in *config is always the depth/depth_stencil buffer. + * Following GPUAttachments are color buffers. + * Setting GPUAttachment.mip to -1 will leave the texture in this slot. + * Setting GPUAttachment.tex to NULL will detach the texture in this slot. + **/ +void GPU_framebuffer_config_array(GPUFrameBuffer *fb, const GPUAttachment *config, int config_ct) +{ + if (config[0].tex) { + BLI_assert(GPU_texture_depth(config[0].tex)); + gpu_framebuffer_texture_attach_ex(fb, config[0].tex, 0, config[0].layer, config[0].mip); + } + else if (config[0].mip == -1) { + /* Leave texture attached */ + } + else if (fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex != NULL) { + GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_ATTACHMENT].tex); + } + else if (fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex != NULL) { + GPU_framebuffer_texture_detach(fb, fb->attachments[GPU_FB_DEPTH_STENCIL_ATTACHMENT].tex); + } + + int slot = 0; + for (int i = 1; i < config_ct; ++i, ++slot) { + if (config[i].tex != NULL) { + BLI_assert(GPU_texture_depth(config[i].tex) == false); + gpu_framebuffer_texture_attach_ex(fb, config[i].tex, slot, config[i].layer, config[i].mip); + } + else if (config[i].mip != -1) { + GPUTexture *tex = framebuffer_get_color_tex(fb, slot); + if (tex != NULL) { + GPU_framebuffer_texture_detach(fb, tex); + } } } +} - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - g_currentfb = fb->object; +/* ---------- Bind / Restore ----------- */ - if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) - attachment = GL_DEPTH_STENCIL_ATTACHMENT; - else if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT; - else - attachment = GL_COLOR_ATTACHMENT0 + slot; +static void gpu_framebuffer_attachment_attach(GPUAttachment *attach, GPUAttachmentType attach_type) +{ + int tex_bind = GPU_texture_opengl_bindcode(attach->tex); + GLenum gl_attachment = convert_attachment_type_to_gl(attach_type); - if (cubemap) { - facetarget = GL_TEXTURE_CUBE_MAP_POSITIVE_X + layer; - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment, facetarget, GPU_texture_opengl_bindcode(tex), mip); + if (attach->layer > -1) { + if (GPU_texture_cube(attach->tex)) { + glFramebufferTexture2D(GL_FRAMEBUFFER, gl_attachment, GL_TEXTURE_CUBE_MAP_POSITIVE_X + attach->layer, + tex_bind, attach->mip); + } + else { + glFramebufferTextureLayer(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip, attach->layer); + } } else { - glFramebufferTextureLayer(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), mip, layer); + glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, tex_bind, attach->mip); } - - if (GPU_texture_depth(tex)) - fb->depthtex = tex; - else - fb->colortex[slot] = tex; - - GPU_texture_framebuffer_set(tex, fb, slot); - - return true; } -bool GPU_framebuffer_texture_layer_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int layer, int mip) +static void gpu_framebuffer_attachment_detach(GPUAttachment *UNUSED(attachment), GPUAttachmentType attach_type) { - return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, layer, mip, false); + GLenum gl_attachment = convert_attachment_type_to_gl(attach_type); + glFramebufferTexture(GL_FRAMEBUFFER, gl_attachment, 0, 0); } -bool GPU_framebuffer_texture_cubeface_attach(GPUFrameBuffer *fb, GPUTexture *tex, int slot, int face, int mip) +static void gpu_framebuffer_update_attachments(GPUFrameBuffer *fb) { - BLI_assert(GPU_texture_target(tex) == GL_TEXTURE_CUBE_MAP); - return gpu_framebuffer_texture_layer_attach_ex(fb, tex, slot, face, mip, true); -} + GLenum gl_attachments[GPU_FB_MAX_COLOR_ATTACHMENT]; + int numslots = 0; -void GPU_framebuffer_texture_detach(GPUTexture *tex) -{ - GLenum attachment; - GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); - int fb_attachment = GPU_texture_framebuffer_attachment(tex); + BLI_assert(g_currentfb == fb->object); - if (!fb) - return; + /* Update attachments */ + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { - if (g_currentfb != fb->object) { - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - g_currentfb = fb->object; - } - - if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) { - fb->depthtex = NULL; - attachment = GL_DEPTH_STENCIL_ATTACHMENT; - } - else if (GPU_texture_depth(tex)) { - fb->depthtex = NULL; - attachment = GL_DEPTH_ATTACHMENT; - } - else { - BLI_assert(fb->colortex[fb_attachment] == tex); - fb->colortex[fb_attachment] = NULL; - attachment = GL_COLOR_ATTACHMENT0 + fb_attachment; - } - - glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); - - GPU_texture_framebuffer_set(tex, NULL, -1); -} - -void GPU_texture_bind_as_framebuffer(GPUTexture *tex) -{ - GPUFrameBuffer *fb = GPU_texture_framebuffer(tex); - int fb_attachment = GPU_texture_framebuffer_attachment(tex); - - if (!fb) { - fprintf(stderr, "Error, texture not bound to framebuffer!\n"); - return; - } - - /* push attributes */ - gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); - - /* bind framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - - if (GPU_texture_depth(tex)) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - else { - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); - glReadBuffer(GL_COLOR_ATTACHMENT0 + fb_attachment); - } - - if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { - glEnable(GL_MULTISAMPLE); - } - - /* set default viewport */ - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - g_currentfb = fb->object; -} - -void GPU_framebuffer_slots_bind(GPUFrameBuffer *fb, int slot) -{ - int numslots = 0, i; - GLenum attachments[GPU_FB_MAX_SLOTS]; - - if (!fb->colortex[slot]) { - fprintf(stderr, "Error, framebuffer slot empty!\n"); - return; - } - - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; + if (type >= GPU_FB_COLOR_ATTACHMENT0) { + if (fb->attachments[type].tex) { + gl_attachments[numslots] = convert_attachment_type_to_gl(type); + } + else { + gl_attachments[numslots] = GL_NONE; + } numslots++; } + + if (GPU_FB_ATTACHEMENT_IS_DIRTY(fb->dirty_flag, type) == false) { + continue; + } + else if (fb->attachments[type].tex != NULL) { + gpu_framebuffer_attachment_attach(&fb->attachments[type], type); + + fb->multisample = (GPU_texture_samples(fb->attachments[type].tex) > 0); + fb->width = GPU_texture_width(fb->attachments[type].tex); + fb->height = GPU_texture_height(fb->attachments[type].tex); + } + else { + gpu_framebuffer_attachment_detach(&fb->attachments[type], type); + } } - - /* push attributes */ - gpuPushAttrib(GPU_ENABLE_BIT | GPU_VIEWPORT_BIT); - glDisable(GL_SCISSOR_TEST); + fb->dirty_flag = 0; - /* bind framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffers(numslots, attachments); - glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); - - /* set default viewport */ - glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); - g_currentfb = fb->object; + /* Update draw buffers (color targets) + * This state is saved in the FBO */ + if (numslots) + glDrawBuffers(numslots, gl_attachments); + else + glDrawBuffer(GL_NONE); } void GPU_framebuffer_bind(GPUFrameBuffer *fb) { - int numslots = 0, i; - GLenum attachments[GPU_FB_MAX_SLOTS]; - GLenum readattachement = 0; - GPUTexture *tex; + if (fb->object == 0) + gpu_framebuffer_init(fb); - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - attachments[numslots] = GL_COLOR_ATTACHMENT0 + i; - tex = fb->colortex[i]; + if (g_currentfb != fb->object) + glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - if (!readattachement) - readattachement = GL_COLOR_ATTACHMENT0 + i; + g_currentfb = fb->object; - numslots++; - } + if (fb->dirty_flag != 0) + gpu_framebuffer_update_attachments(fb); + + /* TODO manually check for errors? */ +#if 0 + char err_out[256]; + if (!GPU_framebuffer_check_valid(fb, err_out)) { + printf("Invalid %s\n", err_out); } +#endif - /* bind framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - - if (numslots == 0) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - tex = fb->depthtex; - } - else { - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffers(numslots, attachments); - glReadBuffer(readattachement); - } - - if (GPU_texture_target(tex) == GL_TEXTURE_2D_MULTISAMPLE) { + if (fb->multisample) glEnable(GL_MULTISAMPLE); + + glViewport(0, 0, fb->width, fb->height); +} + +void GPU_framebuffer_restore(void) +{ + if (g_currentfb != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, 0); + g_currentfb = 0; } - - glViewport(0, 0, GPU_texture_width(tex), GPU_texture_height(tex)); - g_currentfb = fb->object; -} - -void GPU_framebuffer_texture_unbind(GPUFrameBuffer *UNUSED(fb), GPUTexture *UNUSED(tex)) -{ - /* Restore attributes. */ - gpuPopAttrib(); -} - -void GPU_framebuffer_bind_no_save(GPUFrameBuffer *fb, int slot) -{ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - /* last bound prevails here, better allow explicit control here too */ - glDrawBuffer(GL_COLOR_ATTACHMENT0 + slot); - glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); - - /* push matrices and set default viewport and matrix */ - glViewport(0, 0, GPU_texture_width(fb->colortex[slot]), GPU_texture_height(fb->colortex[slot])); - g_currentfb = fb->object; } bool GPU_framebuffer_bound(GPUFrameBuffer *fb) { - return fb->object == g_currentfb; + return (fb->object == g_currentfb) && (fb->object != 0); +} + +unsigned int GPU_framebuffer_current_get(void) +{ + return g_currentfb; } bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) { - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - g_currentfb = fb->object; - - /* On macOS glDrawBuffer must be set when checking completeness, - * otherwise it will return GL_FRAMEBUFFER_UNSUPPORTED when only a - * color buffer without depth is used. */ - if (fb->colortex[0]) { - glDrawBuffer(GL_COLOR_ATTACHMENT0); - } + if (g_currentfb != fb->object) + GPU_framebuffer_bind(fb); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -411,42 +441,7 @@ bool GPU_framebuffer_check_valid(GPUFrameBuffer *fb, char err_out[256]) return true; } -void GPU_framebuffer_free(GPUFrameBuffer *fb) -{ - int i; - if (fb->depthtex) - GPU_framebuffer_texture_detach(fb->depthtex); - - for (i = 0; i < GPU_FB_MAX_SLOTS; i++) { - if (fb->colortex[i]) { - GPU_framebuffer_texture_detach(fb->colortex[i]); - } - } - - if (fb->object) { - glDeleteFramebuffers(1, &fb->object); - - if (g_currentfb == fb->object) { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - g_currentfb = 0; - } - } - - MEM_freeN(fb); -} - -unsigned int GPU_framebuffer_current_get(void) -{ - return g_currentfb; -} - -void GPU_framebuffer_restore(void) -{ - if (g_currentfb != 0) { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - g_currentfb = 0; - } -} +/* ---------- Framebuffer Operations ----------- */ #define CHECK_FRAMEBUFFER_IS_BOUND(_fb) \ BLI_assert(GPU_framebuffer_bound(_fb)); \ @@ -482,61 +477,104 @@ void GPU_framebuffer_clear( glClear(mask); } -void GPU_framebuffer_blit( - GPUFrameBuffer *fb_read, int read_slot, GPUFrameBuffer *fb_write, - int write_slot, bool use_depth, bool use_stencil) +void GPU_framebuffer_read_depth(GPUFrameBuffer *fb, int x, int y, int w, int h, float *data) { - GPUTexture *read_tex = (use_depth || use_stencil) ? fb_read->depthtex : fb_read->colortex[read_slot]; - GPUTexture *write_tex = (use_depth || use_stencil) ? fb_write->depthtex : fb_write->colortex[write_slot]; - int read_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : - (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : - GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(read_tex); - int write_attach = (use_depth) ? GL_DEPTH_ATTACHMENT : - (use_stencil) ? GL_DEPTH_STENCIL_ATTACHMENT : - GL_COLOR_ATTACHMENT0 + GPU_texture_framebuffer_attachment(write_tex); - int read_bind = GPU_texture_opengl_bindcode(read_tex); - int write_bind = GPU_texture_opengl_bindcode(write_tex); - const int read_w = GPU_texture_width(read_tex); - const int read_h = GPU_texture_height(read_tex); - const int write_w = GPU_texture_width(write_tex); - const int write_h = GPU_texture_height(write_tex); + CHECK_FRAMEBUFFER_IS_BOUND(fb); + GLenum type = GL_DEPTH_COMPONENT; + glReadBuffer(GL_COLOR_ATTACHMENT0); /* This is OK! */ + glReadPixels(x, y, w, h, type, GL_FLOAT, data); +} - /* Never both! */ - BLI_assert(!(use_depth && use_stencil)); +void GPU_framebuffer_read_color( + GPUFrameBuffer *fb, int x, int y, int w, int h, int channels, int slot, float *data) +{ + CHECK_FRAMEBUFFER_IS_BOUND(fb); - if (use_depth) { + GLenum type; + switch (channels) { + case 1: type = GL_RED; break; + case 2: type = GL_RG; break; + case 3: type = GL_RGB; break; + case 4: type = GL_RGBA; break; + default: + BLI_assert(false && "wrong number of read channels"); + return; + } + glReadBuffer(GL_COLOR_ATTACHMENT0 + slot); + glReadPixels(x, y, w, h, type, GL_FLOAT, data); +} + +/* read_slot and write_slot are only used for color buffers. */ +void GPU_framebuffer_blit( + GPUFrameBuffer *fb_read, int read_slot, + GPUFrameBuffer *fb_write, int write_slot, + GPUFrameBufferBits blit_buffers) +{ + BLI_assert(blit_buffers != 0); + + GLuint prev_fb = g_currentfb; + + /* Framebuffers must be up to date. This simplify this function. */ + if (fb_read->dirty_flag != 0 || fb_read->object == 0) { + GPU_framebuffer_bind(fb_read); + } + if (fb_write->dirty_flag != 0 || fb_write->object == 0) { + GPU_framebuffer_bind(fb_write); + } + + const bool do_color = (blit_buffers & GPU_COLOR_BIT); + const bool do_depth = (blit_buffers & GPU_DEPTH_BIT); + const bool do_stencil = (blit_buffers & GPU_STENCIL_BIT); + + GPUTexture *read_tex = (do_depth || do_stencil) + ? framebuffer_get_depth_tex(fb_read) + : framebuffer_get_color_tex(fb_read, read_slot); + GPUTexture *write_tex = (do_depth || do_stencil) + ? framebuffer_get_depth_tex(fb_write) + : framebuffer_get_color_tex(fb_write, read_slot); + + if (do_depth) { BLI_assert(GPU_texture_depth(read_tex) && GPU_texture_depth(write_tex)); BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); } - else if (use_stencil) { + if (do_stencil) { BLI_assert(GPU_texture_stencil(read_tex) && GPU_texture_stencil(write_tex)); BLI_assert(GPU_texture_format(read_tex) == GPU_texture_format(write_tex)); } + if (GPU_texture_samples(write_tex) != 0 || + GPU_texture_samples(read_tex) != 0) + { + /* Can only blit multisample textures to another texture of the same size. */ + BLI_assert((fb_read->width == fb_write->width) && + (fb_read->height == fb_write->height)); + } - /* read from multi-sample buffer */ glBindFramebuffer(GL_READ_FRAMEBUFFER, fb_read->object); - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, read_attach, - GPU_texture_target(read_tex), read_bind, 0); - BLI_assert(glCheckFramebufferStatus(GL_READ_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); - - /* write into new single-sample buffer */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fb_write->object); - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, write_attach, - GPU_texture_target(write_tex), write_bind, 0); - BLI_assert(glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE); - glDrawBuffer((use_depth || use_stencil) ? GL_COLOR_ATTACHMENT0 : read_attach); - glBlitFramebuffer(0, 0, read_w, read_h, 0, 0, write_w, write_h, - (use_depth) ? GL_DEPTH_BUFFER_BIT : - (use_stencil) ? GL_STENCIL_BUFFER_BIT : - GL_COLOR_BUFFER_BIT, GL_NEAREST); + if (do_color) { + glReadBuffer(GL_COLOR_ATTACHMENT0 + read_slot); + glDrawBuffer(GL_COLOR_ATTACHMENT0 + write_slot); + /* XXX we messed with the glDrawBuffer, this will reset the + * glDrawBuffers the next time we bind fb_write. */ + fb_write->dirty_flag = GPU_FB_DIRTY_DRAWBUFFER; + } + + GLbitfield mask = convert_buffer_bits_to_gl(blit_buffers); + + glBlitFramebuffer(0, 0, fb_read->width, fb_read->height, + 0, 0, fb_write->width, fb_write->height, + mask, GL_NEAREST); /* Restore previous framebuffer */ - glBindFramebuffer(GL_FRAMEBUFFER, g_currentfb); - glDrawBuffer(GL_COLOR_ATTACHMENT0); + if (fb_write->object == prev_fb) { + GPU_framebuffer_bind(fb_write); /* To update drawbuffers */ + } + else { + glBindFramebuffer(GL_FRAMEBUFFER, prev_fb); + g_currentfb = prev_fb; + } } /** @@ -544,68 +582,63 @@ void GPU_framebuffer_blit( * This function only takes care of the correct texture handling. It execute the callback for each texture level. **/ void GPU_framebuffer_recursive_downsample( - GPUFrameBuffer *fb, GPUTexture *tex, int num_iter, void (*callback)(void *userData, int level), void *userData) + GPUFrameBuffer *fb, int max_lvl, + void (*callback)(void *userData, int level), void *userData) { + /* Framebuffer must be up to date and bound. This simplify this function. */ + if (g_currentfb != fb->object || fb->dirty_flag != 0 || fb->object == 0) { + GPU_framebuffer_bind(fb); + } + /* HACK: We make the framebuffer appear not bound in order to + * not trigger any error in GPU_texture_bind(). */ + GLuint prev_fb = g_currentfb; + g_currentfb = 0; + int i; - int current_dim[2] = {GPU_texture_width(tex), GPU_texture_height(tex)}; - GLenum attachment; - - /* Manually setup framebuffer to not use GPU_texture_framebuffer_set() */ - glBindFramebuffer(GL_FRAMEBUFFER, fb->object); - g_currentfb = fb->object; - - if (GPU_texture_stencil(tex) && GPU_texture_depth(tex)) - attachment = GL_DEPTH_STENCIL_ATTACHMENT; - else if (GPU_texture_depth(tex)) - attachment = GL_DEPTH_ATTACHMENT; - else - attachment = GL_COLOR_ATTACHMENT0; - - /* last bound prevails here, better allow explicit control here too */ - if (GPU_texture_depth(tex)) { - glDrawBuffer(GL_NONE); - glReadBuffer(GL_NONE); - } - else { - glDrawBuffer(GL_COLOR_ATTACHMENT0); - glReadBuffer(GL_COLOR_ATTACHMENT0); - } - - for (i = 1; i < num_iter + 1; i++) { - + int current_dim[2] = {fb->width, fb->height}; + for (i = 1; i < max_lvl + 1; i++) { /* calculate next viewport size */ - current_dim[0] /= 2; - current_dim[1] /= 2; + current_dim[0] = max_ii(current_dim[0] / 2, 1); + current_dim[1] = max_ii(current_dim[1] / 2, 1); - if (current_dim[0] <= 2 && current_dim[1] <= 2) { - /* Cannot reduce further. */ - break; + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { + if (fb->attachments[type].tex != NULL) { + /* bind next level for rendering but first restrict fetches only to previous level */ + GPUTexture *tex = fb->attachments[type].tex; + GPU_texture_bind(tex, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); + GPU_texture_unbind(tex); + /* copy attachment and replace miplevel. */ + GPUAttachment attachment = fb->attachments[type]; + attachment.mip = i; + gpu_framebuffer_attachment_attach(&attachment, type); + } } - /* ensure that the viewport size is always at least 1x1 */ - CLAMP_MIN(current_dim[0], 1); - CLAMP_MIN(current_dim[1], 1); - glViewport(0, 0, current_dim[0], current_dim[1]); - - /* bind next level for rendering but first restrict fetches only to previous level */ - GPU_texture_bind(tex, 0); - glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, i - 1); - glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); - GPU_texture_unbind(tex); - - glFramebufferTexture(GL_FRAMEBUFFER, attachment, GPU_texture_opengl_bindcode(tex), i); - callback(userData, i); + + if (current_dim[0] == 1 && current_dim[1] == 1) + break; } - glFramebufferTexture(GL_FRAMEBUFFER, attachment, 0, 0); + for (GPUAttachmentType type = 0; type < GPU_FB_MAX_ATTACHEMENT; ++type) { + if (fb->attachments[type].tex != NULL) { + /* reset mipmap level range */ + GPUTexture *tex = fb->attachments[type].tex; + GPU_texture_bind(tex, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); + GPU_texture_unbind(tex); + /* Reattach original level */ + /* NOTE: This is not necessary but this makes the FBO config + * remain in sync with the GPUFrameBuffer config. */ + gpu_framebuffer_attachment_attach(&fb->attachments[type], type); + } + } - /* reset mipmap level range for the depth image */ - GPU_texture_bind(tex, 0); - glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_BASE_LEVEL, 0); - glTexParameteri(GPU_texture_target(tex), GL_TEXTURE_MAX_LEVEL, i - 1); - GPU_texture_unbind(tex); + g_currentfb = prev_fb; } /* GPUOffScreen */ @@ -622,51 +655,23 @@ GPUOffScreen *GPU_offscreen_create(int width, int height, int samples, bool dept ofs = MEM_callocN(sizeof(GPUOffScreen), "GPUOffScreen"); - ofs->fb = GPU_framebuffer_create(); - if (!ofs->fb) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (samples) { - if (!GLEW_ARB_texture_multisample || - /* This is required when blitting from a multi-sampled buffers, - * even though we're not scaling. */ - !GLEW_EXT_framebuffer_multisample_blit_scaled) - { - samples = 0; - } - } + ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, + (high_bitdepth) ? GPU_RGBA16F : GPU_RGBA8, NULL, samples, err_out); if (depth) { ofs->depth = GPU_texture_create_depth_with_stencil_multisample(width, height, samples, err_out); - if (!ofs->depth) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->depth, 0, 0)) { - GPU_offscreen_free(ofs); - return NULL; - } } - if (high_bitdepth) { - ofs->color = GPU_texture_create_2D_custom_multisample(width, height, 4, GPU_RGBA16F, NULL, samples, err_out); - } - else { - ofs->color = GPU_texture_create_2D_multisample(width, height, NULL, samples, err_out); - } - if (!ofs->color) { - GPU_offscreen_free(ofs); - return NULL; - } - - if (!GPU_framebuffer_texture_attach(ofs->fb, ofs->color, 0, 0)) { + if (!ofs->depth || !ofs->color) { GPU_offscreen_free(ofs); return NULL; } + GPU_framebuffer_ensure_config(&ofs->fb, { + GPU_ATTACHMENT_TEXTURE(ofs->depth), + GPU_ATTACHMENT_TEXTURE(ofs->color) + }); + /* check validity at the very end! */ if (!GPU_framebuffer_check_valid(ofs->fb, err_out)) { GPU_offscreen_free(ofs); @@ -692,68 +697,48 @@ void GPU_offscreen_free(GPUOffScreen *ofs) void GPU_offscreen_bind(GPUOffScreen *ofs, bool save) { + if (save) { + gpuPushAttrib(GPU_SCISSOR_BIT | GPU_VIEWPORT_BIT); + } glDisable(GL_SCISSOR_TEST); - if (save) - GPU_texture_bind_as_framebuffer(ofs->color); - else { - GPU_framebuffer_bind_no_save(ofs->fb, 0); + GPU_framebuffer_bind(ofs->fb); +} + +void GPU_offscreen_unbind(GPUOffScreen *UNUSED(ofs), bool restore) +{ + GPU_framebuffer_restore(); + if (restore) { + gpuPopAttrib(); } } -void GPU_offscreen_unbind(GPUOffScreen *ofs, bool restore) -{ - if (restore) - GPU_framebuffer_texture_unbind(ofs->fb, ofs->color); - GPU_framebuffer_restore(); - glEnable(GL_SCISSOR_TEST); -} - - void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) { const int w = GPU_texture_width(ofs->color); const int h = GPU_texture_height(ofs->color); + BLI_assert(type == GL_UNSIGNED_BYTE || type == GL_FLOAT); + if (GPU_texture_target(ofs->color) == GL_TEXTURE_2D_MULTISAMPLE) { /* For a multi-sample texture, * we need to create an intermediate buffer to blit to, * before its copied using 'glReadPixels' */ - - /* not needed since 'ofs' needs to be bound to the framebuffer already */ -// #define USE_FBO_CTX_SWITCH - GLuint fbo_blit = 0; GLuint tex_blit = 0; - GLenum status; /* create texture for new 'fbo_blit' */ glGenTextures(1, &tex_blit); - if (!tex_blit) { - goto finally; - } - glBindTexture(GL_TEXTURE_2D, tex_blit); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, w, h, 0, GL_RGBA, type, 0); - -#ifdef USE_FBO_CTX_SWITCH - /* read from multi-sample buffer */ - glBindFramebuffer(GL_READ_FRAMEBUFFER, ofs->color->fb->object); - glFramebufferTexture2D( - GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + ofs->color->fb_attachment, - GL_TEXTURE_2D_MULTISAMPLE, ofs->color->bindcode, 0); - status = glCheckFramebufferStatus(GL_READ_FRAMEBUFFER); - if (status != GL_FRAMEBUFFER_COMPLETE) { - goto finally; - } -#endif + glTexImage2D(GL_TEXTURE_2D, 0, (type == GL_FLOAT) ? GL_RGBA16F : GL_RGBA8, + w, h, 0, GL_RGBA, type, 0); /* write into new single-sample buffer */ glGenFramebuffers(1, &fbo_blit); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo_blit); - glFramebufferTexture2D( - GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, tex_blit, 0); - status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); + glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, tex_blit, 0); + + GLenum status = glCheckFramebufferStatus(GL_DRAW_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { goto finally; } @@ -765,21 +750,13 @@ void GPU_offscreen_read_pixels(GPUOffScreen *ofs, int type, void *pixels) glBindFramebuffer(GL_READ_FRAMEBUFFER, fbo_blit); glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); -#ifdef USE_FBO_CTX_SWITCH /* restore the original frame-bufer */ - glBindFramebuffer(GL_FRAMEBUFFER, ofs->color->fb->object); -#undef USE_FBO_CTX_SWITCH -#endif - + glBindFramebuffer(GL_FRAMEBUFFER, ofs->fb->object); finally: /* cleanup */ - if (tex_blit) { - glDeleteTextures(1, &tex_blit); - } - if (fbo_blit) { - glDeleteFramebuffers(1, &fbo_blit); - } + glDeleteTextures(1, &tex_blit); + glDeleteFramebuffers(1, &fbo_blit); } else { glReadPixels(0, 0, w, h, GL_RGBA, type, pixels); diff --git a/source/blender/gpu/intern/gpu_lamp.c b/source/blender/gpu/intern/gpu_lamp.c index ffdb433bacf..8968521060d 100644 --- a/source/blender/gpu/intern/gpu_lamp.c +++ b/source/blender/gpu/intern/gpu_lamp.c @@ -267,89 +267,35 @@ GPULamp *GPU_lamp_from_blender(Scene *scene, Object *ob, Object *par) if ((la->type == LA_SPOT && (la->mode & (LA_SHAD_BUF | LA_SHAD_RAY))) || (la->type == LA_SUN && (la->mode & LA_SHAD_RAY))) { - /* opengl */ - lamp->fb = GPU_framebuffer_create(); - if (!lamp->fb) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) { - /* Shadow depth map */ lamp->depthtex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->depthtex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - GPU_texture_bind(lamp->depthtex, 0); - GPU_texture_compare_mode(lamp->depthtex, true); - GPU_texture_unbind(lamp->depthtex); - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* Shadow color map */ lamp->tex = gpu_lamp_create_vsm_shadow_map(lamp->size); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* FBO and texture for blurring */ - lamp->blurfb = GPU_framebuffer_create(); - if (!lamp->blurfb) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - lamp->blurtex = gpu_lamp_create_vsm_shadow_map(lamp->size * 0.5); - if (!lamp->blurtex) { + + lamp->fb = GPU_framebuffer_create(); + GPU_framebuffer_texture_attach(lamp->fb, lamp->depthtex, 0, 0); + GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0); + + lamp->blurfb = GPU_framebuffer_create(); + GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0); + + if (!GPU_framebuffer_check_valid(lamp->fb, NULL) || + !GPU_framebuffer_check_valid(lamp->blurfb, NULL)) + { gpu_lamp_shadow_free(lamp); return lamp; } - - if (!GPU_framebuffer_texture_attach(lamp->blurfb, lamp->blurtex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - - /* we need to properly bind to test for completeness */ - GPU_texture_bind_as_framebuffer(lamp->blurtex); - - if (!GPU_framebuffer_check_valid(lamp->blurfb, NULL)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } - } else { lamp->tex = GPU_texture_create_depth(lamp->size, lamp->size, NULL); - if (!lamp->tex) { - gpu_lamp_shadow_free(lamp); - return lamp; - } GPU_texture_bind(lamp->tex, 0); GPU_texture_compare_mode(lamp->tex, true); + GPU_texture_filter_mode(lamp->tex, true); GPU_texture_unbind(lamp->tex); - if (!GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0)) { - gpu_lamp_shadow_free(lamp); - return lamp; - } + lamp->fb = GPU_framebuffer_create(); + GPU_framebuffer_texture_attach(lamp->fb, lamp->tex, 0, 0); if (!GPU_framebuffer_check_valid(lamp->fb, NULL)) { gpu_lamp_shadow_free(lamp); @@ -437,7 +383,7 @@ void GPU_lamp_shadow_buffer_bind(GPULamp *lamp, float viewmat[4][4], int *winsiz /* opengl */ glDisable(GL_SCISSOR_TEST); - GPU_texture_bind_as_framebuffer(lamp->tex); + GPU_framebuffer_bind(lamp->fb); if (lamp->la->shadowmap_type == LA_SHADMAP_VARIANCE) GPU_shader_bind(GPU_shader_get_builtin_shader(GPU_SHADER_VSM_STORE)); @@ -486,7 +432,6 @@ void GPU_lamp_shadow_buffer_unbind(GPULamp *lamp) gpu_lamp_shadow_blur(lamp); } - GPU_framebuffer_texture_unbind(lamp->fb, lamp->tex); GPU_framebuffer_restore(); glEnable(GL_SCISSOR_TEST); } diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index b8368343a88..2ccc9ce7ca7 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -48,6 +48,9 @@ static struct GPUTextureGlobal { GPUTexture *invalid_tex_3D; } GG = {NULL, NULL, NULL}; +/* Maximum number of FBOs a texture can be attached to. */ +#define GPU_TEX_MAX_FBO_ATTACHED 8 + typedef enum GPUTextureFormatFlag{ GPU_FORMAT_DEPTH = (1 << 0), GPU_FORMAT_STENCIL = (1 << 1), @@ -72,14 +75,15 @@ struct GPUTexture { GLuint bindcode; /* opengl identifier for texture */ int fromblender; /* we got the texture from Blender */ + GPUTextureFormat format; GPUTextureFormatFlag format_flag; - GPUFrameBuffer *fb; /* GPUFramebuffer this texture is attached to */ - int fb_attachment; /* slot the texture is attached to */ unsigned int bytesize; /* number of byte for one pixel */ - GPUTextureFormat format; int components; /* number of color/alpha channels */ int samples; /* number of samples for multisamples textures. 0 if not multisample target */ + + int fb_attachment[GPU_TEX_MAX_FBO_ATTACHED]; + GPUFrameBuffer *fb[GPU_TEX_MAX_FBO_ATTACHED]; }; /* ------ Memory Management ------- */ @@ -355,7 +359,6 @@ static GPUTexture *GPU_texture_create_nD( tex->samples = samples; tex->number = -1; tex->refcount = 1; - tex->fb_attachment = -1; tex->format = data_type; tex->components = components; tex->format_flag = 0; @@ -506,7 +509,6 @@ static GPUTexture *GPU_texture_cube_create( tex->samples = 0; tex->number = -1; tex->refcount = 1; - tex->fb_attachment = -1; tex->format = data_type; tex->components = components; tex->format_flag = GPU_FORMAT_CUBE; @@ -847,8 +849,13 @@ void GPU_texture_bind(GPUTexture *tex, int number) } if ((G.debug & G_DEBUG)) { - if (tex->fb && GPU_framebuffer_bound(tex->fb)) { - fprintf(stderr, "Feedback loop warning!: Attempting to bind texture attached to current framebuffer!\n"); + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] && GPU_framebuffer_bound(tex->fb[i])) { + fprintf(stderr, "Feedback loop warning!: Attempting to bind " + "texture attached to current framebuffer!\n"); + BLI_assert(0); /* Should never happen! */ + break; + } } } @@ -961,8 +968,12 @@ void GPU_texture_free(GPUTexture *tex) fprintf(stderr, "GPUTexture: negative refcount\n"); if (tex->refcount == 0) { - if (tex->fb) - GPU_framebuffer_texture_detach(tex); + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] != NULL) { + GPU_framebuffer_texture_detach_slot(tex->fb[i], tex, tex->fb_attachment[i]); + } + } + if (tex->bindcode && !tex->fromblender) glDeleteTextures(1, &tex->bindcode); @@ -1027,19 +1038,28 @@ int GPU_texture_opengl_bindcode(const GPUTexture *tex) return tex->bindcode; } -GPUFrameBuffer *GPU_texture_framebuffer(GPUTexture *tex) +void GPU_texture_attach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) { - return tex->fb; + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] == NULL) { + tex->fb[i] = fb; + tex->fb_attachment[i] = attachment; + return; + } + } + + BLI_assert(!"Error: Texture: Not enough Framebuffer slots"); } -int GPU_texture_framebuffer_attachment(GPUTexture *tex) +/* Return previous attachment point */ +int GPU_texture_detach_framebuffer(GPUTexture *tex, GPUFrameBuffer *fb) { - return tex->fb_attachment; -} + for (int i = 0; i < GPU_TEX_MAX_FBO_ATTACHED; ++i) { + if (tex->fb[i] == fb) { + tex->fb[i] = NULL; + return tex->fb_attachment[i]; + } + } -void GPU_texture_framebuffer_set(GPUTexture *tex, GPUFrameBuffer *fb, int attachment) -{ - tex->fb = fb; - tex->fb_attachment = attachment; + BLI_assert(!"Error: Texture: Framebuffer is not attached"); } - diff --git a/source/blender/gpu/intern/gpu_viewport.c b/source/blender/gpu/intern/gpu_viewport.c index 0f061f1c791..e635174eca2 100644 --- a/source/blender/gpu/intern/gpu_viewport.c +++ b/source/blender/gpu/intern/gpu_viewport.c @@ -48,6 +48,7 @@ #include "GPU_immediate.h" #include "GPU_texture.h" #include "GPU_viewport.h" +#include "GPU_draw.h" #include "DRW_engine.h" @@ -69,7 +70,6 @@ typedef struct ViewportTempTexture { struct GPUViewport { int size[2]; - int samples; int flag; @@ -137,12 +137,19 @@ GPUViewport *GPU_viewport_create_from_offscreen(struct GPUOffScreen *ofs) viewport->txl->multisample_depth = depth; viewport->fbl->multisample_fb = fb; gpu_viewport_default_fb_create(viewport); - GPU_framebuffer_slots_bind(viewport->fbl->default_fb, 0); } else { viewport->fbl->default_fb = fb; viewport->txl->color = color; viewport->txl->depth = depth; + GPU_framebuffer_ensure_config(&viewport->fbl->color_only_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(viewport->txl->color) + }); + GPU_framebuffer_ensure_config(&viewport->fbl->depth_only_fb, { + GPU_ATTACHMENT_TEXTURE(viewport->txl->depth), + GPU_ATTACHMENT_NONE + }); } return viewport; @@ -158,8 +165,7 @@ void GPU_viewport_clear_from_offscreen(GPUViewport *viewport) if (dfbl->multisample_fb) { /* GPUViewport expect the final result to be in default_fb but * GPUOffscreen wants it in its multisample_fb, so we sync it back. */ - GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, false, false); - GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, true, false); + GPU_framebuffer_blit(dfbl->default_fb, 0, dfbl->multisample_fb, 0, GPU_COLOR_BIT | GPU_DEPTH_BIT); dfbl->multisample_fb = NULL; dtxl->multisample_color = NULL; dtxl->multisample_depth = NULL; @@ -288,9 +294,9 @@ GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, GPUTexture *tex; for (ViewportTempTexture *tmp_tex = viewport->tex_pool.first; tmp_tex; tmp_tex = tmp_tex->next) { - if ((GPU_texture_width(tmp_tex->texture) == width) && - (GPU_texture_height(tmp_tex->texture) == height) && - (GPU_texture_format(tmp_tex->texture) == format)) + if ((GPU_texture_format(tmp_tex->texture) == format) && + (GPU_texture_width(tmp_tex->texture) == width) && + (GPU_texture_height(tmp_tex->texture) == height)) { /* Search if the engine is not already using this texture */ for (int i = 0; i < MAX_ENGINE_BUFFER_SHARING; ++i) { @@ -307,11 +313,16 @@ GPUTexture *GPU_viewport_texture_pool_query(GPUViewport *viewport, void *engine, } tex = GPU_texture_create_2D_custom(width, height, channels, format, NULL, NULL); + GPU_texture_bind(tex, 0); + /* Doing filtering for depth does not make sense when not doing shadow mapping, + * and enabling texture filtering on integer texture make them unreadable. */ + bool do_filter = !GPU_texture_depth(tex) && !GPU_texture_integer(tex); + GPU_texture_filter_mode(tex, do_filter); + GPU_texture_unbind(tex); ViewportTempTexture *tmp_tex = MEM_callocN(sizeof(ViewportTempTexture), "ViewportTempTexture"); tmp_tex->texture = tex; tmp_tex->user[0] = engine; - BLI_addtail(&viewport->tex_pool, tmp_tex); return tex; @@ -378,48 +389,66 @@ static void gpu_viewport_default_fb_create(GPUViewport *viewport) int *size = viewport->size; bool ok = true; - dfbl->default_fb = GPU_framebuffer_create(); - if (!dfbl->default_fb) { - ok = false; - goto cleanup; - } - - /* Color */ dtxl->color = GPU_texture_create_2D(size[0], size[1], NULL, NULL); - if (!dtxl->color) { - ok = false; - goto cleanup; - } - - if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->color, 0, 0)) { - ok = false; - goto cleanup; - } - - /* Depth */ dtxl->depth = GPU_texture_create_depth_with_stencil(size[0], size[1], NULL); - if (dtxl->depth) { - /* Define texture parameters */ - GPU_texture_bind(dtxl->depth, 0); - GPU_texture_compare_mode(dtxl->depth, false); - GPU_texture_filter_mode(dtxl->depth, false); - GPU_texture_unbind(dtxl->depth); - } - else { + if (!(dtxl->depth && dtxl->color)) { ok = false; goto cleanup; } - if (!GPU_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0)) { - ok = false; - goto cleanup; - } - else if (!GPU_framebuffer_check_valid(dfbl->default_fb, NULL)) { + GPU_framebuffer_ensure_config(&dfbl->default_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(dtxl->color) + }); + + 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) + }); + + ok = ok && GPU_framebuffer_check_valid(dfbl->default_fb, NULL); + ok = ok && GPU_framebuffer_check_valid(dfbl->color_only_fb, NULL); + ok = ok && GPU_framebuffer_check_valid(dfbl->depth_only_fb, NULL); + +cleanup: + if (!ok) { + GPU_viewport_free(viewport); + DRW_opengl_context_disable(); + return; + } + + GPU_framebuffer_restore(); +} + +static void gpu_viewport_default_multisample_fb_create(GPUViewport *viewport) +{ + DefaultFramebufferList *dfbl = viewport->fbl; + DefaultTextureList *dtxl = viewport->txl; + int *size = viewport->size; + int samples = viewport->samples; + bool ok = true; + + dtxl->multisample_color = GPU_texture_create_2D_multisample(size[0], size[1], NULL, samples, NULL); + dtxl->multisample_depth = GPU_texture_create_depth_with_stencil_multisample(size[0], size[1], samples, NULL); + + if (!(dtxl->multisample_depth && dtxl->multisample_color)) { ok = false; goto cleanup; } + GPU_framebuffer_ensure_config(&dfbl->multisample_fb, { + GPU_ATTACHMENT_TEXTURE(dtxl->multisample_depth), + GPU_ATTACHMENT_TEXTURE(dtxl->multisample_color) + }); + + ok = ok && GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL); + cleanup: if (!ok) { GPU_viewport_free(viewport); @@ -433,7 +462,6 @@ cleanup: void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) { DefaultFramebufferList *dfbl = viewport->fbl; - DefaultTextureList *dtxl = viewport->txl; int fbl_len, txl_len; /* add one pixel because of scissor test */ @@ -460,64 +488,20 @@ void GPU_viewport_bind(GPUViewport *viewport, const rcti *rect) viewport->size[0] = rect_w; viewport->size[1] = rect_h; + viewport->samples = U.ogl_multisamples; gpu_viewport_texture_pool_clear_users(viewport); /* Multisample Buffer */ - if (U.ogl_multisamples > 0) { + if (viewport->samples > 0) { if (!dfbl->default_fb) { - bool ok = true; - viewport->samples = U.ogl_multisamples; - - dfbl->multisample_fb = GPU_framebuffer_create(); - if (!dfbl->multisample_fb) { - ok = false; - goto cleanup_multisample; - } - - /* Color */ - dtxl->multisample_color = GPU_texture_create_2D_multisample(rect_w, rect_h, NULL, U.ogl_multisamples, NULL); - if (!dtxl->multisample_color) { - ok = false; - goto cleanup_multisample; - } - - if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_color, 0, 0)) { - ok = false; - goto cleanup_multisample; - } - - /* Depth */ - dtxl->multisample_depth = GPU_texture_create_depth_with_stencil_multisample(rect_w, rect_h, - U.ogl_multisamples, NULL); - - if (!dtxl->multisample_depth) { - ok = false; - goto cleanup_multisample; - } - - if (!GPU_framebuffer_texture_attach(dfbl->multisample_fb, dtxl->multisample_depth, 0, 0)) { - ok = false; - goto cleanup_multisample; - } - else if (!GPU_framebuffer_check_valid(dfbl->multisample_fb, NULL)) { - ok = false; - goto cleanup_multisample; - } - -cleanup_multisample: - if (!ok) { - GPU_viewport_free(viewport); - return; - } + gpu_viewport_default_multisample_fb_create(viewport); } } if (!dfbl->default_fb) { gpu_viewport_default_fb_create(viewport); } - - GPU_framebuffer_slots_bind(dfbl->default_fb, 0); } void GPU_viewport_draw_to_screen(GPUViewport *viewport, const rcti *rect) diff --git a/source/blender/windowmanager/intern/wm_window.c b/source/blender/windowmanager/intern/wm_window.c index 4c3a89f76fa..84a4c3786e6 100644 --- a/source/blender/windowmanager/intern/wm_window.c +++ b/source/blender/windowmanager/intern/wm_window.c @@ -82,6 +82,7 @@ #include "GPU_batch.h" #include "GPU_draw.h" #include "GPU_extensions.h" +#include "GPU_framebuffer.h" #include "GPU_init_exit.h" #include "GPU_immediate.h" #include "BLF_api.h" @@ -1157,6 +1158,8 @@ static int query_qual(modifierKeyType qual) void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) { + BLI_assert(GPU_framebuffer_current_get() == 0); + if (win != wm->windrawable && win->ghostwin) { // win->lmbut = 0; /* keeps hanging when mousepressed while other window opened */ @@ -1180,6 +1183,7 @@ void wm_window_make_drawable(wmWindowManager *wm, wmWindow *win) void wm_window_reset_drawable(void) { BLI_assert(BLI_thread_is_main()); + BLI_assert(GPU_framebuffer_current_get() == 0); wmWindowManager *wm = G.main->wm.first; if (wm == NULL) @@ -2211,20 +2215,24 @@ void *WM_opengl_context_create(void) * So we should call this function only on the main thread. */ BLI_assert(BLI_thread_is_main()); + BLI_assert(GPU_framebuffer_current_get() == 0); return GHOST_CreateOpenGLContext(g_system); } void WM_opengl_context_dispose(void *context) { + BLI_assert(GPU_framebuffer_current_get() == 0); GHOST_DisposeOpenGLContext(g_system, (GHOST_ContextHandle)context); } void WM_opengl_context_activate(void *context) { + BLI_assert(GPU_framebuffer_current_get() == 0); GHOST_ActivateOpenGLContext((GHOST_ContextHandle)context); } void WM_opengl_context_release(void *context) { + BLI_assert(GPU_framebuffer_current_get() == 0); GHOST_ReleaseOpenGLContext((GHOST_ContextHandle)context); }