diff options
Diffstat (limited to 'source/blender/draw')
79 files changed, 8489 insertions, 4967 deletions
diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 4dcc8dc081c..1529ee7022e 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -67,7 +67,11 @@ set(SRC intern/draw_hair.c intern/draw_instance_data.c intern/draw_manager.c + intern/draw_manager_data.c + intern/draw_manager_exec.c + intern/draw_manager_shader.c intern/draw_manager_text.c + intern/draw_manager_texture.c intern/draw_manager_profiling.c intern/draw_view.c modes/edit_armature_mode.c @@ -96,8 +100,10 @@ set(SRC engines/eevee/eevee_lightprobes.c engines/eevee/eevee_lights.c engines/eevee/eevee_materials.c + engines/eevee/eevee_mist.c engines/eevee/eevee_motion_blur.c engines/eevee/eevee_occlusion.c + engines/eevee/eevee_render.c engines/eevee/eevee_screen_raytrace.c engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c @@ -110,6 +116,7 @@ set(SRC intern/draw_cache_impl.h intern/draw_common.h intern/draw_instance_data.h + intern/draw_manager.h intern/draw_manager_text.h intern/draw_manager_profiling.h intern/draw_view.h @@ -128,6 +135,9 @@ if(WITH_CLAY_ENGINE) endif() data_to_c_simple(engines/clay/shaders/clay_frag.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_fxaa.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_copy.glsl SRC) +data_to_c_simple(engines/clay/shaders/clay_prepass_frag.glsl SRC) data_to_c_simple(engines/clay/shaders/clay_vert.glsl SRC) data_to_c_simple(engines/clay/shaders/clay_particle_vert.glsl SRC) data_to_c_simple(engines/clay/shaders/clay_particle_strand_frag.glsl SRC) @@ -165,6 +175,7 @@ data_to_c_simple(engines/eevee/shaders/effect_downsample_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_downsample_cube_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_gtao_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_minmaxz_frag.glsl SRC) +data_to_c_simple(engines/eevee/shaders/effect_mist_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_motion_blur_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_ssr_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/effect_subsurface_frag.glsl SRC) @@ -199,7 +210,9 @@ data_to_c_simple(engines/eevee/shaders/volumetric_scatter_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/volumetric_integration_frag.glsl SRC) data_to_c_simple(modes/shaders/common_globals_lib.glsl SRC) +data_to_c_simple(modes/shaders/common_view_lib.glsl SRC) data_to_c_simple(modes/shaders/common_fxaa_lib.glsl SRC) +data_to_c_simple(modes/shaders/common_fullscreen_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_frag.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_vert.glsl SRC) data_to_c_simple(modes/shaders/edit_mesh_overlay_geom_tri.glsl SRC) @@ -228,7 +241,6 @@ data_to_c_simple(modes/shaders/object_grid_frag.glsl SRC) data_to_c_simple(modes/shaders/object_grid_vert.glsl SRC) data_to_c_simple(modes/shaders/object_lightprobe_grid_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_prim_vert.glsl SRC) -data_to_c_simple(modes/shaders/object_particle_prim_frag.glsl SRC) data_to_c_simple(modes/shaders/object_particle_dot_vert.glsl SRC) data_to_c_simple(modes/shaders/object_particle_dot_frag.glsl SRC) data_to_c_simple(modes/shaders/paint_texture_frag.glsl SRC) diff --git a/source/blender/draw/DRW_engine.h b/source/blender/draw/DRW_engine.h index 0cfa1fe7d6a..cf76bfdeef5 100644 --- a/source/blender/draw/DRW_engine.h +++ b/source/blender/draw/DRW_engine.h @@ -26,6 +26,8 @@ #ifndef __DRW_ENGINE_H__ #define __DRW_ENGINE_H__ +#include "BLI_sys_types.h" /* for bool */ + struct ARegion; struct CollectionEngineSettings; struct Depsgraph; @@ -44,16 +46,20 @@ struct ViewContext; struct ViewportEngineData; struct View3D; struct rcti; +struct GPUMaterial; struct GPUOffScreen; struct GPUViewport; +struct RenderEngine; struct RenderEngineType; struct WorkSpace; -#include "BLI_sys_types.h" /* for bool */ +#include "DNA_object_enums.h" /* 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; @@ -67,6 +73,7 @@ typedef struct DefaultTextureList { void DRW_engines_register(void); void DRW_engines_free(void); +bool DRW_engine_render_support(struct DrawEngineType *draw_engine_type); void DRW_engine_register(struct DrawEngineType *draw_engine_type); void DRW_engine_viewport_data_size_get( const void *engine_type, @@ -84,6 +91,11 @@ typedef struct DRWUpdateContext { void DRW_notify_view_update(const DRWUpdateContext *update_ctx); void DRW_notify_id_update(const DRWUpdateContext *update_ctx, struct ID *id); + +typedef enum eDRWSelectStage { DRW_SELECT_PASS_PRE = 1, DRW_SELECT_PASS_POST, } eDRWSelectStage; +typedef bool (*DRW_SelectPassFn)( + eDRWSelectStage stage, void *user_data); + void DRW_draw_view(const struct bContext *C); void DRW_draw_render_loop_ex( @@ -104,7 +116,8 @@ void DRW_draw_render_loop_offscreen( void DRW_draw_select_loop( struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d, - bool use_obedit_skip, bool use_nearest, const struct rcti *rect); + bool use_obedit_skip, bool use_nearest, const struct rcti *rect, + DRW_SelectPassFn select_pass_fn, void *select_pass_user_data); void DRW_draw_depth_loop( struct Depsgraph *depsgraph, struct ARegion *ar, struct View3D *v3d); @@ -121,4 +134,11 @@ void EDIT_ARMATURE_collection_settings_create(struct IDProperty *properties); void PAINT_WEIGHT_collection_settings_create(struct IDProperty *properties); void PAINT_VERTEX_collection_settings_create(struct IDProperty *properties); +void DRW_opengl_context_create(void); +void DRW_opengl_context_destroy(void); +void DRW_opengl_context_enable(void); +void DRW_opengl_context_disable(void); + +void DRW_deferred_shader_remove(struct GPUMaterial *mat); + #endif /* __DRW_ENGINE_H__ */ diff --git a/source/blender/draw/engines/basic/basic_engine.c b/source/blender/draw/engines/basic/basic_engine.c index 10dfe7b5996..171b9111bac 100644 --- a/source/blender/draw/engines/basic/basic_engine.c +++ b/source/blender/draw/engines/basic/basic_engine.c @@ -46,34 +46,10 @@ /* GPUViewport.storage * Is freed everytime the viewport engine changes */ -typedef struct BASIC_Storage { - int dummy; -} BASIC_Storage; - typedef struct BASIC_StorageList { - struct BASIC_Storage *storage; struct BASIC_PrivateData *g_data; } BASIC_StorageList; -typedef struct BASIC_FramebufferList { - /* default */ - struct GPUFrameBuffer *default_fb; - /* engine specific */ -#ifdef USE_DEPTH - struct GPUFrameBuffer *dupli_depth; -#endif -} BASIC_FramebufferList; - -typedef struct BASIC_TextureList { - /* default */ - struct GPUTexture *color; -#ifdef USE_DEPTH - struct GPUTexture *depth; - /* engine specific */ - struct GPUTexture *depth_dup; -#endif -} BASIC_TextureList; - typedef struct BASIC_PassList { #ifdef USE_DEPTH struct DRWPass *depth_pass; @@ -84,8 +60,8 @@ typedef struct BASIC_PassList { typedef struct BASIC_Data { void *engine_type; - BASIC_FramebufferList *fbl; - BASIC_TextureList *txl; + DRWViewportEmptyList *fbl; + DRWViewportEmptyList *txl; BASIC_PassList *psl; BASIC_StorageList *stl; } BASIC_Data; @@ -111,12 +87,8 @@ typedef struct BASIC_PrivateData { /* Functions */ -static void basic_engine_init(void *vedata) +static void basic_engine_init(void *UNUSED(vedata)) { - BASIC_StorageList *stl = ((BASIC_Data *)vedata)->stl; - BASIC_TextureList *txl = ((BASIC_Data *)vedata)->txl; - BASIC_FramebufferList *fbl = ((BASIC_Data *)vedata)->fbl; - #ifdef USE_DEPTH /* Depth prepass */ if (!e_data.depth_sh) { @@ -128,20 +100,6 @@ static void basic_engine_init(void *vedata) if (!e_data.color_sh) { e_data.color_sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); } - - if (!stl->storage) { - stl->storage = MEM_callocN(sizeof(BASIC_Storage), "BASIC_Storage"); - } - -#ifdef USE_DEPTH - if (DRW_state_is_fbo()) { - const float *viewport_size = DRW_viewport_size_get(); - DRWFboTexture tex = {&txl->depth_dup, DRW_TEX_DEPTH_24_STENCIL_8, 0}; - DRW_framebuffer_init(&fbl->dupli_depth, &draw_engine_basic_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); - } -#endif } static void basic_cache_init(void *vedata) @@ -204,8 +162,6 @@ static void basic_draw_scene(void *vedata) { BASIC_PassList *psl = ((BASIC_Data *)vedata)->psl; - BASIC_FramebufferList *fbl = ((BASIC_Data *)vedata)->fbl; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); const bool is_select = DRW_state_is_select(); bool use_color = true; @@ -228,14 +184,6 @@ static void basic_draw_scene(void *vedata) if (use_depth_cull) { DRW_draw_pass(psl->depth_pass_cull); } - - /* Pass 2 : Duplicate depth */ - if (use_depth || use_depth_cull) { - /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */ - if (DRW_state_is_fbo()) { - DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true, false); - } - } #endif /* Pass 3 : Shading */ @@ -264,6 +212,7 @@ DrawEngineType draw_engine_basic_type = { &basic_draw_scene, NULL, NULL, + NULL, }; /* Note: currently unused, we may want to register so we can see this when debugging the view. */ diff --git a/source/blender/draw/engines/clay/clay_engine.c b/source/blender/draw/engines/clay/clay_engine.c index a9a919f7ac2..4976cd01d11 100644 --- a/source/blender/draw/engines/clay/clay_engine.c +++ b/source/blender/draw/engines/clay/clay_engine.c @@ -20,7 +20,7 @@ */ #include "BLI_utildefines.h" -#include "BLI_dynstr.h" +#include "BLI_string_utils.h" #include "BLI_rand.h" #include "DNA_particle_types.h" @@ -51,17 +51,24 @@ #define MAX_CLAY_MAT 512 /* 512 = 9 bit material id */ -#define SHADER_DEFINES \ +#define SHADER_DEFINES_NO_AO \ "#define MAX_MATERIAL " STRINGIFY(MAX_CLAY_MAT) "\n" \ "#define USE_ROTATION\n" \ - "#define USE_AO\n" \ "#define USE_HSV\n" +#define SHADER_DEFINES \ + SHADER_DEFINES_NO_AO \ + "#define USE_AO\n" + extern char datatoc_clay_frag_glsl[]; +extern char datatoc_clay_prepass_frag_glsl[]; +extern char datatoc_clay_copy_glsl[]; extern char datatoc_clay_vert_glsl[]; +extern char datatoc_clay_fxaa_glsl[]; extern char datatoc_clay_particle_vert_glsl[]; extern char datatoc_clay_particle_strand_frag_glsl[]; extern char datatoc_ssao_alchemy_glsl[]; +extern char datatoc_common_fxaa_lib_glsl[]; /* *********** LISTS *********** */ @@ -111,31 +118,37 @@ typedef struct CLAY_Storage { int hair_ubo_current_id; DRWShadingGroup *shgrps[MAX_CLAY_MAT]; DRWShadingGroup *shgrps_flat[MAX_CLAY_MAT]; + DRWShadingGroup *shgrps_pre[MAX_CLAY_MAT]; + DRWShadingGroup *shgrps_pre_flat[MAX_CLAY_MAT]; DRWShadingGroup *hair_shgrps[MAX_CLAY_MAT]; } CLAY_Storage; typedef struct CLAY_StorageList { struct CLAY_Storage *storage; - struct GPUUniformBuffer *mat_ubo; - struct GPUUniformBuffer *hair_mat_ubo; struct CLAY_PrivateData *g_data; } CLAY_StorageList; typedef struct CLAY_FramebufferList { - /* default */ - struct GPUFrameBuffer *default_fb; - /* engine specific */ - struct GPUFrameBuffer *dupli_depth; + struct GPUFrameBuffer *antialias_fb; + struct GPUFrameBuffer *prepass_fb; } CLAY_FramebufferList; typedef struct CLAY_PassList { - struct DRWPass *depth_pass; - struct DRWPass *depth_pass_cull; - struct DRWPass *clay_pass; - struct DRWPass *clay_pass_flat; + struct DRWPass *clay_ps; + struct DRWPass *clay_cull_ps; + struct DRWPass *clay_flat_ps; + struct DRWPass *clay_flat_cull_ps; + struct DRWPass *clay_pre_ps; + struct DRWPass *clay_pre_cull_ps; + struct DRWPass *clay_flat_pre_ps; + struct DRWPass *clay_flat_pre_cull_ps; + struct DRWPass *clay_deferred_ps; + struct DRWPass *fxaa_ps; + struct DRWPass *copy_ps; struct DRWPass *hair_pass; } CLAY_PassList; + typedef struct CLAY_Data { void *engine_type; CLAY_FramebufferList *fbl; @@ -146,6 +159,9 @@ typedef struct CLAY_Data { typedef struct CLAY_ViewLayerData { struct GPUTexture *jitter_tx; + struct GPUUniformBuffer *mat_ubo; + struct GPUUniformBuffer *matcaps_ubo; + struct GPUUniformBuffer *hair_mat_ubo; struct GPUUniformBuffer *sampling_ubo; int cached_sample_num; } CLAY_ViewLayerData; @@ -153,27 +169,22 @@ typedef struct CLAY_ViewLayerData { /* *********** STATIC *********** */ static struct { - /* Depth Pre Pass */ - struct GPUShader *depth_sh; /* Shading Pass */ struct GPUShader *clay_sh; struct GPUShader *clay_flat_sh; + struct GPUShader *clay_prepass_flat_sh; + struct GPUShader *clay_prepass_sh; + struct GPUShader *clay_deferred_shading_sh; + struct GPUShader *fxaa_sh; + struct GPUShader *copy_sh; struct GPUShader *hair_sh; - /* Matcap textures */ struct GPUTexture *matcap_array; - float matcap_colors[24][3]; - - /* Ssao */ - float winmat[4][4]; - float viewvecs[3][4]; - float ssao_params[4]; - + float matcap_colors[24][4]; /* Just a serie of int from 0 to MAX_CLAY_MAT-1 */ int ubo_mat_idxs[MAX_CLAY_MAT]; - - /* engine specific */ - struct GPUTexture *depth_dup; + /* To avoid useless texture and ubo binds. */ + bool first_shgrp; } e_data = {NULL}; /* Engine data */ typedef struct CLAY_PrivateData { @@ -183,7 +194,16 @@ typedef struct CLAY_PrivateData { DRWShadingGroup *depth_shgrp_cull; DRWShadingGroup *depth_shgrp_cull_select; DRWShadingGroup *depth_shgrp_cull_active; - bool enable_ao; + /* Deferred shading */ + 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]; + float viewvecs[3][4]; + float ssao_params[4]; } CLAY_PrivateData; /* Transient data */ /* Functions */ @@ -192,6 +212,9 @@ static void clay_view_layer_data_free(void *storage) { CLAY_ViewLayerData *sldata = (CLAY_ViewLayerData *)storage; + DRW_UBO_FREE_SAFE(sldata->mat_ubo); + DRW_UBO_FREE_SAFE(sldata->matcaps_ubo); + DRW_UBO_FREE_SAFE(sldata->hair_mat_ubo); DRW_UBO_FREE_SAFE(sldata->sampling_ubo); DRW_TEXTURE_FREE_SAFE(sldata->jitter_tx); } @@ -328,6 +351,7 @@ static void clay_engine_init(void *vedata) CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; 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) { @@ -362,49 +386,66 @@ static void clay_engine_init(void *vedata) e_data.matcap_array = load_matcaps(prv, 24); } - /* Depth prepass */ - if (!e_data.depth_sh) { - e_data.depth_sh = DRW_shader_create_3D_depth_only(); - } - /* Shading pass */ if (!e_data.clay_sh) { - DynStr *ds = BLI_dynstr_new(); - char *matcap_with_ao; - - BLI_dynstr_append(ds, datatoc_clay_frag_glsl); - BLI_dynstr_append(ds, datatoc_ssao_alchemy_glsl); - - matcap_with_ao = BLI_dynstr_get_cstring(ds); + char *matcap_with_ao = BLI_string_joinN( + datatoc_clay_frag_glsl, + datatoc_ssao_alchemy_glsl); e_data.clay_sh = DRW_shader_create( - datatoc_clay_vert_glsl, NULL, matcap_with_ao, - SHADER_DEFINES); + datatoc_clay_vert_glsl, NULL, datatoc_clay_frag_glsl, + SHADER_DEFINES_NO_AO); e_data.clay_flat_sh = DRW_shader_create( - datatoc_clay_vert_glsl, NULL, matcap_with_ao, + datatoc_clay_vert_glsl, NULL, datatoc_clay_frag_glsl, + SHADER_DEFINES_NO_AO + "#define USE_FLAT_NORMAL\n"); + + e_data.clay_prepass_sh = DRW_shader_create( + datatoc_clay_vert_glsl, NULL, datatoc_clay_prepass_frag_glsl, + SHADER_DEFINES); + e_data.clay_prepass_flat_sh = DRW_shader_create( + datatoc_clay_vert_glsl, NULL, datatoc_clay_prepass_frag_glsl, SHADER_DEFINES "#define USE_FLAT_NORMAL\n"); - BLI_dynstr_free(ds); + e_data.clay_deferred_shading_sh = DRW_shader_create_fullscreen( + matcap_with_ao, + SHADER_DEFINES + "#define DEFERRED_SHADING\n"); + MEM_freeN(matcap_with_ao); - } - if (!e_data.hair_sh) { - e_data.hair_sh = DRW_shader_create( - datatoc_clay_particle_vert_glsl, NULL, datatoc_clay_particle_strand_frag_glsl, - "#define MAX_MATERIAL 512\n"); + char *fxaa_str = BLI_string_joinN( + datatoc_common_fxaa_lib_glsl, + datatoc_clay_fxaa_glsl); + + e_data.fxaa_sh = DRW_shader_create_fullscreen(fxaa_str, NULL); + + MEM_freeN(fxaa_str); + + e_data.copy_sh = DRW_shader_create_fullscreen(datatoc_clay_copy_glsl, NULL); } if (!stl->storage) { stl->storage = MEM_callocN(sizeof(CLAY_Storage), "CLAY_Storage"); } - if (!stl->mat_ubo) { - stl->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL); + if (!stl->g_data) { + stl->g_data = MEM_mallocN(sizeof(*stl->g_data), "CLAY_PrivateStorage"); } - if (!stl->hair_mat_ubo) { - stl->hair_mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_HAIR_UBO_Storage), NULL); + CLAY_PrivateData *g_data = stl->g_data; + + if (!sldata->mat_ubo) { + sldata->mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_UBO_Storage), NULL); + } + + if (!sldata->hair_mat_ubo) { + sldata->hair_mat_ubo = DRW_uniformbuffer_create(sizeof(CLAY_HAIR_UBO_Storage), NULL); + } + + if (!sldata->matcaps_ubo) { + sldata->matcaps_ubo = DRW_uniformbuffer_create(sizeof(e_data.matcap_colors), e_data.matcap_colors); } if (e_data.ubo_mat_idxs[1] == 0) { @@ -414,12 +455,29 @@ static void clay_engine_init(void *vedata) } } - if (DRW_state_is_fbo()) { + /* FBO setup */ + { const float *viewport_size = DRW_viewport_size_get(); - DRWFboTexture tex = {&e_data.depth_dup, DRW_TEX_DEPTH_24_STENCIL_8, DRW_TEX_TEMP}; - DRW_framebuffer_init(&fbl->dupli_depth, &draw_engine_clay_type, - (int)viewport_size[0], (int)viewport_size[1], - &tex, 1); + 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 */ + /* 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 */ @@ -445,14 +503,14 @@ static void clay_engine_init(void *vedata) DRW_state_dfdy_factors_get(dfdyfacs); - e_data.ssao_params[0] = ssao_samples; - e_data.ssao_params[1] = size[0] / 64.0; - e_data.ssao_params[2] = size[1] / 64.0; - e_data.ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ + g_data->ssao_params[0] = ssao_samples; + g_data->ssao_params[1] = size[0] / 64.0; + g_data->ssao_params[2] = size[1] / 64.0; + g_data->ssao_params[3] = dfdyfacs[1]; /* dfdy sign for offscreen */ /* invert the view matrix */ - DRW_viewport_matrix_get(e_data.winmat, DRW_MAT_WIN); - invert_m4_m4(invproj, e_data.winmat); + DRW_viewport_matrix_get(g_data->winmat, DRW_MAT_WIN); + invert_m4_m4(invproj, g_data->winmat); /* convert the view vectors to view space */ for (i = 0; i < 3; i++) { @@ -464,19 +522,19 @@ static void clay_engine_init(void *vedata) mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); viewvecs[i][3] = 1.0; - copy_v4_v4(e_data.viewvecs[i], viewvecs[i]); + copy_v4_v4(g_data->viewvecs[i], viewvecs[i]); } /* we need to store the differences */ - e_data.viewvecs[1][0] -= e_data.viewvecs[0][0]; - e_data.viewvecs[1][1] = e_data.viewvecs[2][1] - e_data.viewvecs[0][1]; + g_data->viewvecs[1][0] -= g_data->viewvecs[0][0]; + g_data->viewvecs[1][1] = g_data->viewvecs[2][1] - g_data->viewvecs[0][1]; /* calculate a depth offset as well */ if (!is_persp) { float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; mul_m4_v4(invproj, vec_far); mul_v3_fl(vec_far, 1.0f / vec_far[3]); - e_data.viewvecs[1][2] = vec_far[2] - e_data.viewvecs[0][2]; + g_data->viewvecs[1][2] = vec_far[2] - g_data->viewvecs[0][2]; } /* AO Samples Tex */ @@ -495,37 +553,61 @@ static void clay_engine_init(void *vedata) } } -static DRWShadingGroup *CLAY_shgroup_create(CLAY_Data *vedata, DRWPass *pass, int *material_id, bool use_flat) +static DRWShadingGroup *CLAY_shgroup_create(DRWPass *pass, GPUShader *sh, int id) { - CLAY_StorageList *stl = vedata->stl; CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); - DRWShadingGroup *grp = DRW_shgroup_create(use_flat ? e_data.clay_flat_sh : e_data.clay_sh, pass); + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1); + if (e_data.first_shgrp) { + DRW_shgroup_uniform_texture_persistent(grp, "matcaps", e_data.matcap_array); + DRW_shgroup_uniform_block_persistent(grp, "material_block", sldata->mat_ubo); + DRW_shgroup_uniform_block_persistent(grp, "matcaps_block", sldata->matcaps_ubo); + } + return grp; +} - DRW_shgroup_uniform_vec2(grp, "screenres", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_buffer(grp, "depthtex", &e_data.depth_dup); - DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array); - DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)e_data.winmat); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)e_data.viewvecs, 3); - DRW_shgroup_uniform_vec4(grp, "ssao_params", e_data.ssao_params, 1); - DRW_shgroup_uniform_vec3(grp, "matcaps_color[0]", (float *)e_data.matcap_colors, 24); +static DRWShadingGroup *CLAY_shgroup_deferred_prepass_create(DRWPass *pass, GPUShader *sh, int id) +{ + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1); - DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1); + return grp; +} +static DRWShadingGroup *CLAY_shgroup_deferred_shading_create(DRWPass *pass, CLAY_PrivateData *g_data) +{ + CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.clay_deferred_shading_sh, pass); + DRW_shgroup_uniform_texture_ref(grp, "depthtex", &g_data->depth_tx); + DRW_shgroup_uniform_texture_ref(grp, "normaltex", &g_data->normal_tx); + DRW_shgroup_uniform_texture_ref(grp, "idtex", &g_data->id_tx); + DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array); DRW_shgroup_uniform_texture(grp, "ssao_jitter", sldata->jitter_tx); DRW_shgroup_uniform_block(grp, "samples_block", sldata->sampling_ubo); - DRW_shgroup_uniform_block(grp, "material_block", stl->mat_ubo); - + DRW_shgroup_uniform_block(grp, "material_block", sldata->mat_ubo); + DRW_shgroup_uniform_block(grp, "matcaps_block", sldata->matcaps_ubo); + /* TODO put in ubo */ + DRW_shgroup_uniform_mat4(grp, "WinMatrix", (float *)g_data->winmat); + DRW_shgroup_uniform_vec2(grp, "invscreenres", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)g_data->viewvecs, 3); + DRW_shgroup_uniform_vec4(grp, "ssao_params", g_data->ssao_params, 1); return grp; } -static DRWShadingGroup *CLAY_hair_shgroup_create(CLAY_Data *vedata, DRWPass *pass, int *material_id) +static DRWShadingGroup *CLAY_hair_shgroup_create(DRWPass *pass, int id) { - CLAY_StorageList *stl = vedata->stl; - DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass); + CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); + + if (!e_data.hair_sh) { + e_data.hair_sh = DRW_shader_create( + datatoc_clay_particle_vert_glsl, NULL, datatoc_clay_particle_strand_frag_glsl, + "#define MAX_MATERIAL 512\n"); + } + DRWShadingGroup *grp = DRW_shgroup_create(e_data.hair_sh, pass); DRW_shgroup_uniform_texture(grp, "matcaps", e_data.matcap_array); - DRW_shgroup_uniform_int(grp, "mat_id", material_id, 1); - DRW_shgroup_uniform_block(grp, "material_block", stl->mat_ubo); + DRW_shgroup_uniform_block(grp, "material_block", sldata->mat_ubo); + DRW_shgroup_uniform_int(grp, "mat_id", &e_data.ubo_mat_idxs[id], 1); return grp; } @@ -560,25 +642,17 @@ static int search_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Mat static int push_mat_to_ubo(CLAY_Storage *storage, const CLAY_UBO_Material *mat_ubo_test) { - int id = storage->ubo_current_id; - CLAY_UBO_Material *ubo = &storage->mat_storage.materials[id]; - - *ubo = *mat_ubo_test; - - storage->ubo_current_id++; - + int id = storage->ubo_current_id++; + id = min_ii(MAX_CLAY_MAT, id); + storage->mat_storage.materials[id] = *mat_ubo_test; return id; } static int push_hair_mat_to_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material *hair_mat_ubo_test) { - int id = storage->hair_ubo_current_id; - CLAY_HAIR_UBO_Material *ubo = &storage->hair_mat_storage.materials[id]; - - *ubo = *hair_mat_ubo_test; - - storage->hair_ubo_current_id++; - + int id = storage->hair_ubo_current_id++; + id = min_ii(MAX_CLAY_MAT, id); + storage->hair_mat_storage.materials[id] = *hair_mat_ubo_test; return id; } @@ -608,11 +682,11 @@ static int hair_mat_in_ubo(CLAY_Storage *storage, const CLAY_HAIR_UBO_Material * return id; } -static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_needs_ao) +static void ubo_mat_from_object(CLAY_Storage *storage, Object *ob, bool *r_needs_ao, int *r_id) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); - /* Default Settings */ + int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation"); float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue"); float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation"); @@ -621,41 +695,45 @@ static void ubo_mat_from_object(Object *ob, CLAY_UBO_Material *r_ubo, bool *r_ne float ssao_factor_cavity = BKE_collection_engine_property_value_get_float(props, "ssao_factor_cavity"); float ssao_factor_edge = BKE_collection_engine_property_value_get_float(props, "ssao_factor_edge"); float ssao_attenuation = BKE_collection_engine_property_value_get_float(props, "ssao_attenuation"); - int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); + + CLAY_UBO_Material r_ubo = {{0.0f}}; if (((ssao_factor_cavity > 0.0) || (ssao_factor_edge > 0.0)) && (ssao_distance > 0.0)) { *r_needs_ao = true; + + r_ubo.ssao_params_var[0] = ssao_distance; + r_ubo.ssao_params_var[1] = ssao_factor_cavity; + r_ubo.ssao_params_var[2] = ssao_factor_edge; + r_ubo.ssao_params_var[3] = ssao_attenuation; + } + else { + *r_needs_ao = false; } - memset(r_ubo, 0x0, sizeof(*r_ubo)); + r_ubo.matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); + r_ubo.matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f); - r_ubo->matcap_rot[0] = cosf(matcap_rot * 3.14159f * 2.0f); - r_ubo->matcap_rot[1] = sinf(matcap_rot * 3.14159f * 2.0f); + r_ubo.matcap_hsv[0] = matcap_hue + 0.5f; + r_ubo.matcap_hsv[1] = matcap_sat * 2.0f; + r_ubo.matcap_hsv[2] = matcap_val * 2.0f; - r_ubo->matcap_hsv[0] = matcap_hue + 0.5f; - r_ubo->matcap_hsv[1] = matcap_sat * 2.0f; - r_ubo->matcap_hsv[2] = matcap_val * 2.0f; + r_ubo.matcap_id = matcap_to_index(matcap_icon); - r_ubo->ssao_params_var[0] = ssao_distance; - r_ubo->ssao_params_var[1] = ssao_factor_cavity; - r_ubo->ssao_params_var[2] = ssao_factor_edge; - r_ubo->ssao_params_var[3] = ssao_attenuation; - r_ubo->matcap_id = matcap_to_index(matcap_icon); + *r_id = mat_in_ubo(storage, &r_ubo); } -static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo) +static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_CLAY); - /* Default Settings */ + int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); float matcap_rot = BKE_collection_engine_property_value_get_float(props, "matcap_rotation"); float matcap_hue = BKE_collection_engine_property_value_get_float(props, "matcap_hue"); float matcap_sat = BKE_collection_engine_property_value_get_float(props, "matcap_saturation"); float matcap_val = BKE_collection_engine_property_value_get_float(props, "matcap_value"); float hair_randomness = BKE_collection_engine_property_value_get_float(props, "hair_brightness_randomness"); - int matcap_icon = BKE_collection_engine_property_value_get_int(props, "matcap_icon"); memset(r_ubo, 0x0, sizeof(*r_ubo)); @@ -668,25 +746,56 @@ static void hair_ubo_mat_from_object(Object *ob, CLAY_HAIR_UBO_Material *r_ubo) r_ubo->matcap_id = matcap_to_index(matcap_icon); } -static DRWShadingGroup *CLAY_object_shgrp_get( - CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl, bool use_flat) +static DRWShadingGroup *CLAY_object_shgrp_get(CLAY_Data *vedata, Object *ob, bool use_flat, bool cull) { - DRWShadingGroup **shgrps = use_flat ? stl->storage->shgrps_flat : stl->storage->shgrps; - CLAY_UBO_Material mat_ubo_test; + bool prepass; int id; + CLAY_PassList *psl = vedata->psl; + CLAY_Storage *storage = vedata->stl->storage; + DRWShadingGroup **shgrps; + DRWPass *pass; GPUShader *sh; + + ubo_mat_from_object(storage, ob, &prepass, &id); + + if (prepass) { + if (use_flat) { + shgrps = storage->shgrps_pre_flat; + pass = (cull) ? psl->clay_flat_pre_cull_ps : psl->clay_flat_pre_ps; + sh = e_data.clay_prepass_flat_sh; + } + else { + shgrps = storage->shgrps_pre; + pass = (cull) ? psl->clay_pre_cull_ps : psl->clay_pre_ps; + sh = e_data.clay_prepass_sh; + } - ubo_mat_from_object(ob, &mat_ubo_test, &stl->g_data->enable_ao); + if (shgrps[id] == NULL) { + shgrps[id] = CLAY_shgroup_deferred_prepass_create(pass, sh, id); + } - int id = mat_in_ubo(stl->storage, &mat_ubo_test); + vedata->stl->g_data->enable_deferred_path = true; + } + else { + if (use_flat) { + shgrps = storage->shgrps_flat; + pass = (cull) ? psl->clay_flat_cull_ps : psl->clay_flat_ps; + sh = e_data.clay_flat_sh; + } + else { + shgrps = storage->shgrps; + pass = (cull) ? psl->clay_cull_ps : psl->clay_ps; + sh = e_data.clay_sh; + } - if (shgrps[id] == NULL) { - shgrps[id] = CLAY_shgroup_create( - vedata, use_flat ? psl->clay_pass_flat : psl->clay_pass, &e_data.ubo_mat_idxs[id], use_flat); + if (shgrps[id] == NULL) { + shgrps[id] = CLAY_shgroup_create(pass, sh, id); + e_data.first_shgrp = false; + } } return shgrps[id]; } -static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) +static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *UNUSED(vedata), Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) { DRWShadingGroup **hair_shgrps = stl->storage->hair_shgrps; @@ -696,54 +805,43 @@ static DRWShadingGroup *CLAY_hair_shgrp_get(CLAY_Data *vedata, Object *ob, CLAY_ int hair_id = hair_mat_in_ubo(stl->storage, &hair_mat_ubo_test); if (hair_shgrps[hair_id] == NULL) { - hair_shgrps[hair_id] = CLAY_hair_shgroup_create(vedata, psl->hair_pass, &e_data.ubo_mat_idxs[hair_id]); + hair_shgrps[hair_id] = CLAY_hair_shgroup_create(psl->hair_pass, hair_id); } return hair_shgrps[hair_id]; } -static DRWShadingGroup *CLAY_object_shgrp_default_mode_get( - CLAY_Data *vedata, Object *ob, CLAY_StorageList *stl, CLAY_PassList *psl) -{ - bool use_flat = DRW_object_is_flat_normal(ob); - return CLAY_object_shgrp_get(vedata, ob, stl, psl, use_flat); -} - 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; - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_mallocN(sizeof(*stl->g_data), __func__); - } - /* Disable AO unless a material needs it. */ - stl->g_data->enable_ao = false; + stl->g_data->enable_deferred_path = false; - /* Depth Pass */ - { - psl->depth_pass = DRW_pass_create("Depth Pass", DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); - stl->g_data->depth_shgrp = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass); - - psl->depth_pass_cull = DRW_pass_create( - "Depth Pass Cull", - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK); - stl->g_data->depth_shgrp_cull = DRW_shgroup_create(e_data.depth_sh, psl->depth_pass_cull); - } + /* Reset UBO datas, shgrp pointers and material id counters. */ + memset(stl->storage, 0, sizeof(*stl->storage)); + e_data.first_shgrp = true; - /* Clay Pass */ + /* Solid Passes */ { - psl->clay_pass = DRW_pass_create("Clay Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); - stl->storage->ubo_current_id = 0; - memset(stl->storage->shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); - } - - /* Clay Pass (Flat) */ - { - psl->clay_pass_flat = DRW_pass_create("Clay Pass Flat", DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL); - memset(stl->storage->shgrps_flat, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + psl->clay_ps = DRW_pass_create("Clay", state); + psl->clay_cull_ps = DRW_pass_create("Clay Culled", state | DRW_STATE_CULL_BACK); + psl->clay_flat_ps = DRW_pass_create("Clay Flat", state); + psl->clay_flat_cull_ps = DRW_pass_create("Clay Flat Culled", state | DRW_STATE_CULL_BACK); + + DRWState prepass_state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + DRWState prepass_cull_state = prepass_state | DRW_STATE_CULL_BACK; + psl->clay_pre_ps = DRW_pass_create("Clay Deferred Pre", prepass_state); + psl->clay_pre_cull_ps = DRW_pass_create("Clay Deferred Pre Culled", prepass_cull_state); + psl->clay_flat_pre_ps = DRW_pass_create("Clay Deferred Flat Pre", prepass_state); + psl->clay_flat_pre_cull_ps = DRW_pass_create("Clay Deferred Flat Pre Culled", prepass_cull_state); + + psl->clay_deferred_ps = DRW_pass_create("Clay Deferred Shading", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = CLAY_shgroup_deferred_shading_create(psl->clay_deferred_ps, stl->g_data); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } /* Hair Pass */ @@ -751,8 +849,19 @@ static void clay_cache_init(void *vedata) psl->hair_pass = DRW_pass_create( "Hair Pass", DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_WIRE); - stl->storage->hair_ubo_current_id = 0; - memset(stl->storage->hair_shgrps, 0, sizeof(DRWShadingGroup *) * MAX_CLAY_MAT); + } + + { + psl->fxaa_ps = DRW_pass_create("Fxaa", DRW_STATE_WRITE_COLOR); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.fxaa_sh, psl->fxaa_ps); + DRW_shgroup_uniform_texture_ref(grp, "colortex", &dtxl->color); + DRW_shgroup_uniform_vec2(grp, "invscreenres", DRW_viewport_invert_size_get(), 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); + + 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_texture_ref(grp, "colortex", &stl->g_data->color_copy); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } } @@ -762,11 +871,7 @@ static void clay_cache_populate_particles(void *vedata, Object *ob) CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; - - if (ob != obedit) { + if (ob != draw_ctx->object_edit) { for (ParticleSystem *psys = ob->particlesystem.first; psys; psys = psys->next) { if (psys_check_enabled(ob, psys, false)) { ParticleSettings *part = psys->part; @@ -791,9 +896,6 @@ static void clay_cache_populate_particles(void *vedata, Object *ob) static void clay_cache_populate(void *vedata, Object *ob) { - CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; - CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - DRWShadingGroup *clay_shgrp; if (!DRW_object_is_renderable(ob)) @@ -820,43 +922,27 @@ static void clay_cache_populate(void *vedata, Object *ob) if (geom) { IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, ""); const bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling"); - const bool is_sculpt_mode = is_active && (ob->mode & OB_MODE_SCULPT) != 0; - const bool is_default_mode_shader = is_sculpt_mode; - - /* Depth Prepass */ - { - DRWShadingGroup *depth_shgrp = do_cull ? stl->g_data->depth_shgrp_cull : stl->g_data->depth_shgrp; - if (is_sculpt_mode) { - DRW_shgroup_call_sculpt_add(depth_shgrp, ob, ob->obmat); - } - else { - DRW_shgroup_call_object_add(depth_shgrp, geom, ob); - } - } + const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; + const bool use_flat = is_sculpt_mode && DRW_object_is_flat_normal(ob); - /* Shading */ - if (is_default_mode_shader) { - clay_shgrp = CLAY_object_shgrp_default_mode_get(vedata, ob, stl, psl); - } - else { - clay_shgrp = CLAY_object_shgrp_get(vedata, ob, stl, psl, false); - } + clay_shgrp = CLAY_object_shgrp_get(vedata, ob, use_flat, do_cull); if (is_sculpt_mode) { DRW_shgroup_call_sculpt_add(clay_shgrp, ob, ob->obmat); } else { - DRW_shgroup_call_add(clay_shgrp, geom, ob->obmat); + DRW_shgroup_call_object_add(clay_shgrp, geom, ob); } } } static void clay_cache_finish(void *vedata) { + CLAY_ViewLayerData *sldata = CLAY_view_layer_data_get(); CLAY_StorageList *stl = ((CLAY_Data *)vedata)->stl; - DRW_uniformbuffer_update(stl->mat_ubo, &stl->storage->mat_storage); - DRW_uniformbuffer_update(stl->hair_mat_ubo, &stl->storage->hair_mat_storage); + DRW_uniformbuffer_update(sldata->mat_ubo, &stl->storage->mat_storage); + DRW_uniformbuffer_update(sldata->hair_mat_ubo, &stl->storage->hair_mat_storage); } static void clay_draw_scene(void *vedata) @@ -865,37 +951,38 @@ static void clay_draw_scene(void *vedata) CLAY_PassList *psl = ((CLAY_Data *)vedata)->psl; CLAY_FramebufferList *fbl = ((CLAY_Data *)vedata)->fbl; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + stl->g_data->depth_tx = dtxl->depth; + + /* Passes are ordered to have less _potential_ overdraw */ + DRW_draw_pass(psl->clay_cull_ps); + DRW_draw_pass(psl->clay_flat_cull_ps); + DRW_draw_pass(psl->clay_ps); + DRW_draw_pass(psl->clay_flat_ps); + DRW_draw_pass(psl->hair_pass); - /* Pass 1 : Depth pre-pass */ - if (stl->g_data->enable_ao) { - DRW_draw_pass(psl->depth_pass); - DRW_draw_pass(psl->depth_pass_cull); - } - else { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; - DRW_pass_state_set(psl->clay_pass, state); - DRW_pass_state_set(psl->clay_pass_flat, state); - } + if (stl->g_data->enable_deferred_path) { + 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); - /* Pass 2 : Duplicate depth */ - /* Unless we go for deferred shading we need this to avoid manual depth test and artifacts */ - if (DRW_state_is_fbo() && stl->g_data->enable_ao) { - /* attach temp textures */ - DRW_framebuffer_texture_attach(fbl->dupli_depth, e_data.depth_dup, 0, 0); + 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); - DRW_framebuffer_blit(dfbl->default_fb, fbl->dupli_depth, true, false); + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->clay_deferred_ps); + } - /* detach temp textures */ - DRW_framebuffer_texture_detach(e_data.depth_dup); + if (true) { /* Always on for now. We might want a parameter for this. */ + GPU_framebuffer_bind(fbl->antialias_fb); + DRW_draw_pass(psl->fxaa_ps); - /* restore default fb */ - DRW_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->copy_ps); } - - /* Pass 3 : Shading */ - DRW_draw_pass(psl->clay_pass); - DRW_draw_pass(psl->clay_pass_flat); - DRW_draw_pass(psl->hair_pass); } static void clay_layer_collection_settings_create(RenderEngine *UNUSED(engine), IDProperty *props) @@ -930,6 +1017,11 @@ static void clay_engine_free(void) { DRW_SHADER_FREE_SAFE(e_data.clay_sh); DRW_SHADER_FREE_SAFE(e_data.clay_flat_sh); + DRW_SHADER_FREE_SAFE(e_data.clay_prepass_flat_sh); + DRW_SHADER_FREE_SAFE(e_data.clay_prepass_sh); + DRW_SHADER_FREE_SAFE(e_data.clay_deferred_shading_sh); + DRW_SHADER_FREE_SAFE(e_data.fxaa_sh); + DRW_SHADER_FREE_SAFE(e_data.copy_sh); DRW_SHADER_FREE_SAFE(e_data.hair_sh); DRW_TEXTURE_FREE_SAFE(e_data.matcap_array); } @@ -949,6 +1041,7 @@ DrawEngineType draw_engine_clay_type = { &clay_draw_scene, NULL, NULL, + NULL, }; RenderEngineType DRW_engine_viewport_clay_type = { diff --git a/source/blender/draw/engines/clay/shaders/clay_copy.glsl b/source/blender/draw/engines/clay/shaders/clay_copy.glsl new file mode 100644 index 00000000000..ec462978e67 --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_copy.glsl @@ -0,0 +1,10 @@ + +in vec4 uvcoordsvar; +out vec4 fragColor; + +uniform sampler2D colortex; + +void main() +{ + fragColor = texture(colortex, uvcoordsvar.st); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_frag.glsl index 9c8c90bd5b6..1939e4b735d 100644 --- a/source/blender/draw/engines/clay/shaders/clay_frag.glsl +++ b/source/blender/draw/engines/clay/shaders/clay_frag.glsl @@ -1,10 +1,8 @@ -uniform vec2 screenres; -uniform sampler2D depthtex; +uniform vec2 invscreenres; uniform mat4 WinMatrix; /* Matcap */ uniform sampler2DArray matcaps; -uniform vec3 matcaps_color[24]; /* Screen Space Occlusion */ /* store the view space vectors for the corners of the view frustum here. @@ -26,11 +24,22 @@ layout(std140) uniform samples_block { vec4 ssao_samples[500]; }; +layout(std140) uniform matcaps_block { + vec4 matcaps_color[24]; +}; + layout(std140) uniform material_block { Material matcaps_param[MAX_MATERIAL]; }; +#ifdef DEFERRED_SHADING +uniform sampler2D depthtex; +uniform sampler2D normaltex; +uniform isampler2D idtex; +int mat_id; /* global */ +#else uniform int mat_id; +#endif /* Aliases */ #define ssao_samples_num ssao_params.x @@ -41,10 +50,12 @@ uniform int mat_id; #define matcap_index matcaps_param[mat_id].matcap_hsv_id.w #define matcap_rotation matcaps_param[mat_id].matcap_rot.xy -#ifdef USE_FLAT_NORMAL +#ifndef DEFERRED_SHADING +# ifdef USE_FLAT_NORMAL flat in vec3 normal; -#else +# else in vec3 normal; +# endif #endif out vec4 fragColor; @@ -166,26 +177,35 @@ void ssao_factors( out float cavities, out float edges); #endif -void main() { - vec2 screenco = vec2(gl_FragCoord.xy) / screenres; - float depth = texture(depthtex, screenco).r; - - vec3 position = get_view_space_from_depth(screenco, depth); +/* From http://aras-p.info/texts/CompactNormalStorage.html + * Using Method #4: Spheremap Transform */ +vec3 normal_decode(vec2 enc) +{ + vec2 fenc = enc * 4.0 - 2.0; + float f = dot(fenc, fenc); + float g = sqrt(1.0 - f / 4.0); + vec3 n; + n.xy = fenc*g; + n.z = 1 - f / 2; + return n; +} +vec3 shade(vec3 N, vec3 position, float depth, vec2 screenco) +{ #ifdef USE_ROTATION /* Rotate texture coordinates */ vec2 rotY = vec2(-matcap_rotation.y, matcap_rotation.x); - vec2 texco = abs(vec2(dot(normal.xy, matcap_rotation), dot(normal.xy, rotY)) * .49 + 0.5); + vec2 texco = abs(vec2(dot(N.xy, matcap_rotation), dot(N.xy, rotY)) * .49 + 0.5); #else - vec2 texco = abs(normal.xy * .49 + 0.5); + vec2 texco = abs(N.xy * .49 + 0.5); #endif vec3 col = texture(matcaps, vec3(texco, matcap_index)).rgb; #ifdef USE_AO - float cavity, edges; - ssao_factors(depth, normal, position, screenco, cavity, edges); + float cavity = 0.0, edges = 0.0; + ssao_factors(depth, N, position, screenco, cavity, edges); - col *= mix(vec3(1.0), matcaps_color[int(matcap_index)], cavity); + col *= mix(vec3(1.0), matcaps_color[int(matcap_index)].rgb, cavity); #endif #ifdef USE_HSV @@ -197,5 +217,36 @@ void main() { col *= edges + 1.0; #endif + return col; +} + +void main() +{ + vec2 screenco = vec2(gl_FragCoord.xy) * invscreenres; + +#ifdef DEFERRED_SHADING + 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 = 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; + } + mat_id = abs(mat_id) - 1; +#else + float depth = gl_FragCoord.z; + vec3 N = normal; +#endif + + vec3 position = get_view_space_from_depth(screenco, depth); + + vec3 col = shade(N, position, depth, screenco); + fragColor = vec4(col, 1.0); } diff --git a/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl b/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl new file mode 100644 index 00000000000..924e51421aa --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_fxaa.glsl @@ -0,0 +1,18 @@ + +in vec4 uvcoordsvar; +out vec4 fragColor; + +uniform vec2 invscreenres; +uniform sampler2D colortex; + +void main() +{ + fragColor = vec4(FxaaPixelShader( + uvcoordsvar.st, + colortex, + invscreenres, + 1.0, + 0.166, + 0.0833 + ).rgb, 1.0); +} diff --git a/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl b/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl new file mode 100644 index 00000000000..f30322bc9fe --- /dev/null +++ b/source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl @@ -0,0 +1,44 @@ +uniform int mat_id; + +#ifdef USE_FLAT_NORMAL +flat in vec3 normal; +#else +in vec3 normal; +#endif + +layout(location = 0) out vec2 outNormals; +layout(location = 1) out int outIndex; + +/* From http://aras-p.info/texts/CompactNormalStorage.html + * Using Method #4: Spheremap Transform */ +vec2 normal_encode(vec3 n) +{ + float p = sqrt(n.z * 8.0 + 8.0); + return n.xy / p + 0.5; +} + +/* 4x4 bayer matrix prepared for 8bit UNORM precision error. */ +#define P(x) (((x + 0.5) * (1.0 / 16.0) - 0.5) * (1.0 / 255.0)) +const vec4 dither_mat[4] = vec4[4]( + vec4( P(0.0), P(8.0), P(2.0), P(10.0)), + vec4(P(12.0), P(4.0), P(14.0), P(6.0)), + vec4( P(3.0), P(11.0), P(1.0), P(9.0)), + vec4(P(15.0), P(7.0), P(13.0), P(5.0)) +); + +void main() { + outIndex = (mat_id + 1); /* 0 is clear color */ + /** + * To fix the normal buffer precision issue for backfaces, + * we invert normals and use the sign of the index buffer + * to tag them, and re-invert in deferred pass. + **/ + vec3 N = (gl_FrontFacing) ? normal : -normal; + outIndex = (gl_FrontFacing) ? outIndex : -outIndex; + + outNormals = normal_encode(N); + + /* Dither the output to fight low quality. */ + ivec2 tx = ivec2(gl_FragCoord.xy) % 4; + outNormals += dither_mat[tx.x][tx.y]; +} diff --git a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl index 48c117c3d8d..94e2d6f3c7b 100644 --- a/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl +++ b/source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl @@ -10,6 +10,11 @@ void ssao_factors( in float depth, in vec3 normal, in vec3 position, in vec2 screenco, out float cavities, out float edges) { + cavities = edges = 0.0; + /* early out if there is no need for SSAO */ + if (ssao_factor_cavity == 0.0 && ssao_factor_edge == 0.0) + return; + /* take the normalized ray direction here */ vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb; @@ -22,7 +27,6 @@ void ssao_factors( /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ offset *= 0.5; - cavities = edges = 0.0; int num_samples = int(ssao_samples_num); /* Note. Putting noise usage here to put some ALU after texture fetch. */ diff --git a/source/blender/draw/engines/eevee/eevee_bloom.c b/source/blender/draw/engines/eevee/eevee_bloom.c index 63c030a574f..89a7aeab4b2 100644 --- a/source/blender/draw/engines/eevee/eevee_bloom.c +++ b/source/blender/draw/engines/eevee/eevee_bloom.c @@ -41,7 +41,7 @@ static struct { struct GPUShader *bloom_downsample_sh[2]; struct GPUShader *bloom_upsample_sh[2]; struct GPUShader *bloom_resolve_sh[2]; -} e_data = {NULL}; /* Engine data */ +} e_data = {{NULL}}; /* Engine data */ extern char datatoc_effect_bloom_frag_glsl[]; @@ -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"); @@ -145,22 +147,18 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) for (int i = 0; i < effects->bloom_iteration_ct; ++i) { texsize[0] /= 2; texsize[1] /= 2; - if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { - texsize[0] = MAX2(texsize[0], 17); - texsize[1] = MAX2(texsize[1], 17); - } - else { - texsize[0] = MAX2(texsize[0], 2); - texsize[1] = MAX2(texsize[1], 2); - } + texsize[0] = MAX2(texsize[0], 2); + texsize[1] = MAX2(texsize[1], 2); 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 */ @@ -168,39 +166,26 @@ int EEVEE_bloom_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) for (int i = 0; i < effects->bloom_iteration_ct - 1; ++i) { texsize[0] /= 2; texsize[1] /= 2; - if (GPU_type_matches(GPU_DEVICE_AMD_VEGA, GPU_OS_UNIX, GPU_DRIVER_OPENSOURCE)) { - texsize[0] = MAX2(texsize[0], 17); - texsize[1] = MAX2(texsize[1], 17); - } - else { - 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); + texsize[0] = MAX2(texsize[0], 2); + texsize[1] = MAX2(texsize[1], 2); + + 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; @@ -215,10 +200,10 @@ static DRWShadingGroup *eevee_create_bloom_pass( DRWShadingGroup *grp = DRW_shgroup_create(sh, *pass); DRW_shgroup_call_add(grp, quad, NULL); - DRW_shgroup_uniform_buffer(grp, "sourceBuffer", &effects->unf_source_buffer); + DRW_shgroup_uniform_texture_ref(grp, "sourceBuffer", &effects->unf_source_buffer); DRW_shgroup_uniform_vec2(grp, "sourceBufferTexelSize", effects->unf_source_texel_size, 1); if (upsample) { - DRW_shgroup_uniform_buffer(grp, "baseBuffer", &effects->unf_base_buffer); + DRW_shgroup_uniform_texture_ref(grp, "baseBuffer", &effects->unf_base_buffer); DRW_shgroup_uniform_float(grp, "sampleScale", &effects->bloom_sample_scale, 1); } @@ -292,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 */ @@ -332,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 0a052b12e93..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); @@ -56,8 +57,11 @@ static void eevee_view_layer_data_free(void *storage) DRW_UBO_FREE_SAFE(sldata->grid_ubo); DRW_UBO_FREE_SAFE(sldata->planar_ubo); DRW_UBO_FREE_SAFE(sldata->common_ubo); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_fb); - DRW_FRAMEBUFFER_FREE_SAFE(sldata->probe_filter_fb); + DRW_UBO_FREE_SAFE(sldata->clip_ubo); + 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); @@ -65,13 +69,6 @@ static void eevee_view_layer_data_free(void *storage) DRW_TEXTURE_FREE_SAFE(sldata->irradiance_rt); } -static void eevee_lightprobe_data_free(void *storage) -{ - EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)storage; - - BLI_freelistN(&ped->captured_object_list); -} - EEVEE_ViewLayerData *EEVEE_view_layer_data_get(void) { return (EEVEE_ViewLayerData *)DRW_view_layer_engine_data_get( @@ -90,61 +87,95 @@ EEVEE_ViewLayerData *EEVEE_view_layer_data_ensure(void) return *sldata; } +/* Object data. */ + +static void eevee_object_data_init(ObjectEngineData *engine_data) +{ + EEVEE_ObjectEngineData *eevee_data = (EEVEE_ObjectEngineData *)engine_data; + eevee_data->shadow_caster_id = -1; +} + EEVEE_ObjectEngineData *EEVEE_object_data_get(Object *ob) { + if (ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)) { + return NULL; + } return (EEVEE_ObjectEngineData *)DRW_object_engine_data_get( ob, &draw_engine_eevee_type); } EEVEE_ObjectEngineData *EEVEE_object_data_ensure(Object *ob) { - EEVEE_ObjectEngineData **oedata = (EEVEE_ObjectEngineData **)DRW_object_engine_data_ensure( - ob, &draw_engine_eevee_type, NULL); + BLI_assert(!ELEM(ob->type, OB_LIGHTPROBE, OB_LAMP)); + return (EEVEE_ObjectEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_eevee_type, + sizeof(EEVEE_ObjectEngineData), + eevee_object_data_init, + NULL); +} - if (*oedata == NULL) { - *oedata = MEM_callocN(sizeof(**oedata), "EEVEE_ObjectEngineData"); - (*oedata)->shadow_caster_id = -1; - } +/* Light probe data. */ - return *oedata; +static void eevee_lightprobe_data_init(ObjectEngineData *engine_data) +{ + EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data; + ped->need_full_update = true; + ped->need_update = true; +} + +static void eevee_lightprobe_data_free(ObjectEngineData *engine_data) +{ + EEVEE_LightProbeEngineData *ped = (EEVEE_LightProbeEngineData *)engine_data; + + BLI_freelistN(&ped->captured_object_list); } EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_get(Object *ob) { + if (ob->type != OB_LIGHTPROBE) { + return NULL; + } return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_get( ob, &draw_engine_eevee_type); } EEVEE_LightProbeEngineData *EEVEE_lightprobe_data_ensure(Object *ob) { - EEVEE_LightProbeEngineData **pedata = (EEVEE_LightProbeEngineData **)DRW_object_engine_data_ensure( - ob, &draw_engine_eevee_type, &eevee_lightprobe_data_free); + BLI_assert(ob->type == OB_LIGHTPROBE); + return (EEVEE_LightProbeEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_eevee_type, + sizeof(EEVEE_LightProbeEngineData), + eevee_lightprobe_data_init, + eevee_lightprobe_data_free); +} - if (*pedata == NULL) { - *pedata = MEM_callocN(sizeof(**pedata), "EEVEE_LightProbeEngineData"); - (*pedata)->need_full_update = true; - (*pedata)->need_update = true; - } +/* Lamp data. */ - return *pedata; +static void eevee_lamp_data_init(ObjectEngineData *engine_data) +{ + EEVEE_LampEngineData *led = (EEVEE_LampEngineData *)engine_data; + led->need_update = true; + led->prev_cube_shadow_id = -1; } EEVEE_LampEngineData *EEVEE_lamp_data_get(Object *ob) { + if (ob->type != OB_LAMP) { + return NULL; + } return (EEVEE_LampEngineData *)DRW_object_engine_data_get( ob, &draw_engine_eevee_type); } EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob) { - EEVEE_LampEngineData **ledata = (EEVEE_LampEngineData **)DRW_object_engine_data_ensure( - ob, &draw_engine_eevee_type, NULL); - - if (*ledata == NULL) { - *ledata = MEM_callocN(sizeof(**ledata), "EEVEE_LampEngineData"); - (*ledata)->need_update = true; - (*ledata)->prev_cube_shadow_id = -1; - } - - return *ledata; + BLI_assert(ob->type == OB_LAMP); + return (EEVEE_LampEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_eevee_type, + sizeof(EEVEE_LampEngineData), + eevee_lamp_data_init, + NULL); } 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 124873add96..c7a94a877a7 100644 --- a/source/blender/draw/engines/eevee/eevee_depth_of_field.c +++ b/source/blender/draw/engines/eevee/eevee_depth_of_field.c @@ -32,7 +32,7 @@ #include "DNA_anim_types.h" #include "DNA_camera_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_screen_types.h" #include "DNA_view3d_types.h" #include "DNA_world_types.h" @@ -75,11 +75,10 @@ static void eevee_create_shader_depth_of_field(void) datatoc_effect_dof_frag_glsl, "#define STEP_RESOLVE\n"); } -int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) { 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(); @@ -88,17 +87,15 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v if (BKE_collection_engine_property_value_get_bool(props, "dof_enable")) { Scene *scene = draw_ctx->scene; - View3D *v3d = draw_ctx->v3d; RegionView3D *rv3d = draw_ctx->rv3d; if (!e_data.dof_downsample_sh) { eevee_create_shader_depth_of_field(); } - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (camera) { const float *viewport_size = DRW_viewport_size_get(); - Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); - Camera *cam = (Camera *)camera_object->data; + Camera *cam = (Camera *)camera->data; /* Retreive Near and Far distance */ effects->dof_near_far[0] = -cam->clipsta; @@ -106,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 */ @@ -147,7 +141,7 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v float rotation = cam->gpu_dof.rotation; float ratio = 1.0f / cam->gpu_dof.ratio; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); - float focus_dist = BKE_camera_object_dof_distance(camera_object); + float focus_dist = BKE_camera_object_dof_distance(camera); float focal_len = cam->lens; UNUSED_VARS(rotation, ratio); @@ -163,9 +157,13 @@ int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *v float focal_len_scaled = scale_camera * focal_len; float sensor_scaled = scale_camera * sensor; + if (rv3d != NULL) { + sensor_scaled *= rv3d->viewcamtexcofac[0]; + } + effects->dof_params[0] = aperture * fabsf(focal_len_scaled / (focus_dist - focal_len_scaled)); effects->dof_params[1] = -focus_dist; - effects->dof_params[2] = viewport_size[0] / (rv3d->viewcamtexcofac[0] * sensor_scaled); + effects->dof_params[2] = viewport_size[0] / sensor_scaled; effects->dof_bokeh[0] = blades; effects->dof_bokeh[1] = rotation; effects->dof_bokeh[2] = ratio; @@ -176,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; } @@ -192,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(); @@ -212,8 +204,8 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ psl->dof_down = DRW_pass_create("DoF Downsample", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.dof_downsample_sh, psl->dof_down); - DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); + DRW_shgroup_uniform_texture_ref(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); DRW_shgroup_call_add(grp, quad, NULL); @@ -226,18 +218,18 @@ void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_ const int sprite_ct = ((int)viewport_size[0] / 2) * ((int)viewport_size[1] / 2); /* brackets matters */ 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_texture_ref(grp, "colorBuffer", &effects->unf_source_buffer); + DRW_shgroup_uniform_texture_ref(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); psl->dof_resolve = DRW_pass_create("DoF Resolve", DRW_STATE_WRITE_COLOR); 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, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); + DRW_shgroup_uniform_texture_ref(grp, "nearBuffer", &effects->dof_near_blur); + DRW_shgroup_uniform_texture_ref(grp, "farBuffer", &effects->dof_far_blur); + DRW_shgroup_uniform_texture_ref(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); DRW_shgroup_call_add(grp, quad, NULL); @@ -257,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 5821111c59d..977eb14a1bb 100644 --- a/source/blender/draw/engines/eevee/eevee_effects.c +++ b/source/blender/draw/engines/eevee/eevee_effects.c @@ -27,8 +27,6 @@ #include "DRW_render.h" -#include "BKE_global.h" /* for G.debug_value */ - #include "eevee_private.h" #include "GPU_texture.h" #include "GPU_extensions.h" @@ -100,16 +98,18 @@ static void eevee_create_shader_downsample(void) "#define COPY_DEPTH\n"); } -void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_StorageList *stl = vedata->stl; 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; const float *viewport_size = DRW_viewport_size_get(); - /* Shaders */ if (!e_data.downsample_sh) { eevee_create_shader_downsample(); @@ -122,44 +122,62 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects = stl->effects; effects->enabled_effects = 0; - effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata); + effects->enabled_effects |= EEVEE_motion_blur_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_bloom_init(sldata, vedata); - effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata); + effects->enabled_effects |= EEVEE_depth_of_field_init(sldata, vedata, camera); effects->enabled_effects |= EEVEE_temporal_sampling_init(sldata, vedata); effects->enabled_effects |= EEVEE_occlusion_init(sldata, vedata); effects->enabled_effects |= EEVEE_subsurface_init(sldata, vedata); effects->enabled_effects |= EEVEE_screen_raytrace_init(sldata, vedata); effects->enabled_effects |= EEVEE_volumes_init(sldata, vedata); + /* Force normal buffer creation. */ + if (DRW_state_is_image_render() && + (view_layer->passflag & SCE_PASS_NORMAL) != 0) + { + effects->enabled_effects |= EFFECT_NORMAL_BUFFER; + } + /** * 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); + } + else { + DRW_texture_ensure_2D(&txl->maxzbuffer, size[0], size[1], DRW_TEX_DEPTH_24, DRW_TEX_MIPMAP); } - 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); - + if (fbl->downsample_fb == NULL) { + fbl->downsample_fb = GPU_framebuffer_create(); + } /** * Compute Mipmap texel alignement. @@ -179,34 +197,37 @@ void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) * 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); } } @@ -227,75 +248,47 @@ void EEVEE_effects_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { psl->color_downsample_ps = DRW_pass_create("Downsample", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_sh, psl->color_downsample_ps); - DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src); + DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src); DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); DRW_shgroup_call_add(grp, quad, NULL); } { static int zero = 0; + static unsigned int six = 6; psl->color_downsample_cube_ps = DRW_pass_create("Downsample Cube", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.downsample_cube_sh, psl->color_downsample_cube_ps, quad); - DRW_shgroup_uniform_buffer(grp, "source", &e_data.color_src); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.downsample_cube_sh, psl->color_downsample_cube_ps); + DRW_shgroup_uniform_texture_ref(grp, "source", &e_data.color_src); DRW_shgroup_uniform_float(grp, "texelSize", &e_data.cube_texel_size, 1); DRW_shgroup_uniform_int(grp, "Layer", &zero, 1); - DRW_shgroup_set_instance_count(grp, 6); + DRW_shgroup_call_instances_add(grp, quad, NULL, &six); } { /* 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_uniform_texture_ref(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_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); 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_texture_ref(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); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); DRW_shgroup_call_add(grp, quad, NULL); } } @@ -339,130 +332,98 @@ 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); + GPU_framebuffer_texture_detach(fbl->downsample_fb, txl->maxzbuffer); 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); + GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src); 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); + GPU_framebuffer_texture_detach(fbl->downsample_fb, texture_src); DRW_stats_group_end(); } -void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +void EEVEE_draw_effects(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_TextureList *txl = vedata->txl; EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - 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); EEVEE_bloom_draw(vedata); - /* Restore default framebuffer */ - DRW_framebuffer_texture_attach(dfbl->default_fb, dtxl->depth, 0, 0); - DRW_framebuffer_bind(dfbl->default_fb); - - /* Tonemapping */ - DRW_transform_to_display(effects->source_buffer); - - /* Debug : Ouput buffer to view. */ - switch (G.debug_value) { - case 1: - 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); - break; - case 3: - if (txl->ssr_normal_input) DRW_transform_to_display(txl->ssr_normal_input); - break; - case 4: - if (txl->ssr_specrough_input) DRW_transform_to_display(txl->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); - break; - case 7: - if (txl->gtao_horizons) DRW_transform_to_display(txl->gtao_horizons); - break; - case 8: - if (txl->sss_data) DRW_transform_to_display(txl->sss_data); - break; - default: - break; - } + /* 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_fb) ? fbl->main_fb : fbl->effect_fb; /* If no post processes is enabled, buffers are still not swapped, do it now. */ SWAP_DOUBLE_BUFFERS(); @@ -477,7 +438,7 @@ void EEVEE_draw_effects(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } /* Record pers matrix for the next frame. */ - DRW_viewport_matrix_get(sldata->common_data.prev_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_get(stl->effects->prev_persmat, DRW_MAT_PERS); /* Update double buffer status if render mode. */ if (DRW_state_is_image_render()) { diff --git a/source/blender/draw/engines/eevee/eevee_engine.c b/source/blender/draw/engines/eevee/eevee_engine.c index fe2beb4b557..276f23c7cf7 100644 --- a/source/blender/draw/engines/eevee/eevee_engine.c +++ b/source/blender/draw/engines/eevee/eevee_engine.c @@ -29,9 +29,13 @@ #include "BLI_rand.h" #include "BKE_object.h" +#include "BKE_global.h" /* for G.debug_value */ +#include "BKE_screen.h" #include "DNA_world_types.h" +#include "ED_screen.h" + #include "GPU_material.h" #include "GPU_glew.h" @@ -51,6 +55,12 @@ 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; + RegionView3D *rv3d = draw_ctx->rv3d; + Object *camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; if (!stl->g_data) { /* Alloc transient pointers */ @@ -59,44 +69,52 @@ 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); } + if (sldata->clip_ubo == NULL) { + sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); + } /* EEVEE_effects_init needs to go first for TAA */ - EEVEE_effects_init(sldata, vedata); - + EEVEE_effects_init(sldata, vedata, camera); EEVEE_materials_init(sldata, stl, fbl); EEVEE_lights_init(sldata); EEVEE_lightprobes_init(sldata, vedata); if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { /* XXX otherwise it would break the other engines. */ - DRW_viewport_matrix_override_unset(DRW_MAT_PERS); - DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); - DRW_viewport_matrix_override_unset(DRW_MAT_WIN); - DRW_viewport_matrix_override_unset(DRW_MAT_WININV); + DRW_viewport_matrix_override_unset_all(); } } static void eevee_cache_init(void *vedata) { - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); EEVEE_bloom_cache_init(sldata, vedata); EEVEE_depth_of_field_cache_init(sldata, vedata); EEVEE_effects_cache_init(sldata, vedata); EEVEE_lightprobes_cache_init(sldata, vedata); - EEVEE_lights_cache_init(sldata, psl); - EEVEE_materials_cache_init(vedata); + EEVEE_lights_cache_init(sldata, vedata); + EEVEE_materials_cache_init(sldata, vedata); EEVEE_motion_blur_cache_init(sldata, vedata); EEVEE_occlusion_cache_init(sldata, vedata); EEVEE_screen_raytrace_cache_init(sldata, vedata); @@ -160,36 +178,61 @@ static void eevee_cache_finish(void *vedata) static void eevee_draw_background(void *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; + 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 */ DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + /* Sort transparents before the loop. */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); - /* Number of iteration: needed for all temporal effect (SSR, TAA) + /* Number of iteration: needed for all temporal effect (SSR, volumetrics) * when using opengl render. */ - int loop_ct = DRW_state_is_image_render() ? 4 : 1; + int loop_ct = (DRW_state_is_image_render() && + (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]; - if (DRW_state_is_image_render()) { + if (DRW_state_is_image_render() || + ((stl->effects->enabled_effects & EFFECT_TAA) != 0)) + { BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r); - /* Set jitter offset */ EEVEE_update_noise(psl, fbl, r); + EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1); + EEVEE_materials_init(sldata, stl, fbl); } - else if ((stl->effects->enabled_effects & EFFECT_TAA) != 0) { - BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r); - /* Set jitter offset */ - EEVEE_update_noise(psl, fbl, r); + /* Copy previous persmat to UBO data */ + copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); + + if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && + (stl->effects->taa_current_sample > 1) && + !DRW_state_is_image_render()) + { + DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV); } /* Refresh Probes */ DRW_stats_group_start("Probes Refresh"); EEVEE_lightprobes_refresh(sldata, vedata); + /* Probes refresh can have reset the current sample. */ + if (stl->effects->taa_current_sample == 1) { + DRW_viewport_matrix_override_unset_all(); + } + EEVEE_lightprobes_refresh_planar(sldata, vedata); DRW_stats_group_end(); /* Update common buffer after probe rendering. */ @@ -200,28 +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); - } - - if (((stl->effects->enabled_effects & EFFECT_TAA) != 0) && - (stl->effects->taa_current_sample > 1) && - !DRW_state_is_image_render()) - { - DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV); - } + 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"); @@ -265,7 +291,6 @@ static void eevee_draw_background(void *vedata) EEVEE_volumes_resolve(sldata, vedata); /* Transparent */ - DRW_pass_sort_shgroup_z(psl->transparent_pass); DRW_draw_pass(psl->transparent_pass); /* Post Process */ @@ -274,13 +299,44 @@ static void eevee_draw_background(void *vedata) DRW_stats_group_end(); if ((stl->effects->taa_current_sample > 1) && !DRW_state_is_image_render()) { - DRW_viewport_matrix_override_unset(DRW_MAT_PERS); - DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); - DRW_viewport_matrix_override_unset(DRW_MAT_WIN); - DRW_viewport_matrix_override_unset(DRW_MAT_WININV); + DRW_viewport_matrix_override_unset_all(); } } + /* 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. */ + switch (G.debug_value) { + case 1: + if (txl->maxzbuffer) DRW_transform_to_display(txl->maxzbuffer); + break; + case 2: + if (effects->ssr_pdf_output) DRW_transform_to_display(effects->ssr_pdf_output); + break; + case 3: + if (effects->ssr_normal_input) DRW_transform_to_display(effects->ssr_normal_input); + break; + case 4: + 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 (effects->gtao_horizons_debug) DRW_transform_to_display(effects->gtao_horizons_debug); + break; + case 7: + if (effects->gtao_horizons) DRW_transform_to_display(effects->gtao_horizons); + break; + case 8: + if (effects->sss_data) DRW_transform_to_display(effects->sss_data); + break; + default: + break; + } + EEVEE_volumes_free_smoke_textures(); stl->g_data->view_updated = false; @@ -294,33 +350,52 @@ static void eevee_view_update(void *vedata) } } -static void eevee_id_update(void *UNUSED(vedata), ID *id) +static void eevee_id_object_update(void *UNUSED(vedata), Object *object) { /* This is a bit mask of components which update is to be ignored. */ const int ignore_updates = ID_RECALC_COLLECTIONS; - /* Check whether we have to do anything here. */ - if ((id->recalc & ~ignore_updates) == 0) { - return; + const int allowed_updates = ~ignore_updates; + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); + if (ped != NULL && (ped->engine_data.recalc & allowed_updates) != 0) { + ped->need_full_update = true; + ped->engine_data.recalc = 0; + } + EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object); + if (led != NULL && (led->engine_data.recalc & allowed_updates) != 0) { + led->need_update = true; + led->engine_data.recalc = 0; + } + EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); + if (oedata != NULL && (oedata->engine_data.recalc & allowed_updates) != 0) { + oedata->need_update = true; + oedata->engine_data.recalc = 0; } +} + +static void eevee_id_update(void *vedata, ID *id) +{ /* Handle updates based on ID type. */ - const ID_Type id_type = GS(id->name); - if (id_type == ID_OB) { - Object *object = (Object *)id; - EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_get(object); - if (ped != NULL) { - ped->need_full_update = true; - } - EEVEE_LampEngineData *led = EEVEE_lamp_data_get(object); - if (led != NULL) { - led->need_update = true; - } - EEVEE_ObjectEngineData *oedata = EEVEE_object_data_get(object); - if (oedata != NULL) { - oedata->need_update = true; - } + switch (GS(id->name)) { + case ID_OB: + eevee_id_object_update(vedata, (Object *)id); + break; + default: + /* pass */ + break; } } +static void eevee_render_to_image(void *vedata, RenderEngine *engine, struct RenderLayer *render_layer, const rcti *rect) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + EEVEE_render_init(vedata, engine, draw_ctx->depsgraph); + + DRW_render_object_iter(vedata, engine, draw_ctx->depsgraph, EEVEE_render_cache); + + /* Actually do the rendering. */ + EEVEE_render_draw(vedata, engine, render_layer, rect); +} + static void eevee_engine_free(void) { EEVEE_bloom_free(); @@ -329,6 +404,7 @@ static void eevee_engine_free(void) EEVEE_lightprobes_free(); EEVEE_lights_free(); EEVEE_materials_free(); + EEVEE_mist_free(); EEVEE_motion_blur_free(); EEVEE_occlusion_free(); EEVEE_screen_raytrace_free(); @@ -356,7 +432,8 @@ static void eevee_view_layer_settings_create(RenderEngine *UNUSED(engine), IDPro BKE_collection_engine_property_add_int(props, "gi_cubemap_resolution", 512); BKE_collection_engine_property_add_int(props, "gi_visibility_resolution", 32); - BKE_collection_engine_property_add_int(props, "taa_samples", 8); + BKE_collection_engine_property_add_int(props, "taa_samples", 16); + BKE_collection_engine_property_add_int(props, "taa_render_samples", 64); BKE_collection_engine_property_add_bool(props, "sss_enable", false); BKE_collection_engine_property_add_int(props, "sss_samples", 7); @@ -428,12 +505,14 @@ DrawEngineType draw_engine_eevee_type = { NULL, /* Everything is drawn in the background pass (see comment on function) */ &eevee_view_update, &eevee_id_update, + &eevee_render_to_image, }; RenderEngineType DRW_engine_viewport_eevee_type = { NULL, NULL, - EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, + EEVEE_ENGINE, N_("Eevee"), RE_INTERNAL | RE_USE_SHADING_NODES | RE_USE_PREVIEW, + NULL, &DRW_render_to_image, NULL, NULL, NULL, NULL, + &EEVEE_render_update_passes, &eevee_layer_collection_settings_create, &eevee_view_layer_settings_create, &draw_engine_eevee_type, diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 7403da737dd..59e8e76bc52 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -36,6 +36,7 @@ #include "DNA_view3d_types.h" #include "BKE_object.h" +#include "MEM_guardedalloc.h" #include "GPU_material.h" #include "GPU_texture.h" @@ -82,7 +83,8 @@ static struct { struct GPUTexture *depth_array_placeholder; struct GPUTexture *cube_face_minmaxz; - int update_world; + struct Gwn_VertFormat *format_probe_display_cube; + struct Gwn_VertFormat *format_probe_display_planar; } e_data = {NULL}; /* Engine data */ extern char datatoc_background_vert_glsl[]; @@ -107,6 +109,7 @@ extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern GlobalsUboStorage ts; @@ -152,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(); @@ -179,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) @@ -203,8 +196,10 @@ static void lightprobe_shaders_init(void) "#define NOISE_SIZE 64\n"; char *shader_str = NULL; + char *vert_str = NULL; shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, @@ -219,6 +214,7 @@ static void lightprobe_shaders_init(void) MEM_freeN(shader_str); shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, @@ -229,6 +225,7 @@ static void lightprobe_shaders_init(void) MEM_freeN(shader_str); shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, @@ -240,15 +237,20 @@ static void lightprobe_shaders_init(void) shader_str = BLI_string_joinN( datatoc_octahedron_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_lightprobe_grid_display_frag_glsl); - e_data.probe_grid_display_sh = DRW_shader_create( - datatoc_lightprobe_grid_display_vert_glsl, NULL, shader_str, filter_defines); + vert_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_lightprobe_grid_display_vert_glsl); + + e_data.probe_grid_display_sh = DRW_shader_create(vert_str, NULL, shader_str, filter_defines); + MEM_freeN(vert_str); MEM_freeN(shader_str); e_data.probe_grid_fill_sh = DRW_shader_create_fullscreen( @@ -256,19 +258,33 @@ static void lightprobe_shaders_init(void) shader_str = BLI_string_joinN( datatoc_octahedron_lib_glsl, + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_lightprobe_cube_display_frag_glsl); - e_data.probe_cube_display_sh = DRW_shader_create( - datatoc_lightprobe_cube_display_vert_glsl, NULL, shader_str, NULL); + vert_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_lightprobe_cube_display_vert_glsl); + e_data.probe_cube_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL); + + MEM_freeN(vert_str); MEM_freeN(shader_str); - e_data.probe_planar_display_sh = DRW_shader_create( - datatoc_lightprobe_planar_display_vert_glsl, NULL, - datatoc_lightprobe_planar_display_frag_glsl, NULL); + vert_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_lightprobe_planar_display_vert_glsl); + + shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_lightprobe_planar_display_frag_glsl); + + e_data.probe_planar_display_sh = DRW_shader_create(vert_str, NULL, shader_str, NULL); + + MEM_freeN(vert_str); + MEM_freeN(shader_str); e_data.probe_planar_downsample_sh = DRW_shader_create( datatoc_lightprobe_planar_downsample_vert_glsl, @@ -300,6 +316,9 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda sldata->planar_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_PlanarReflection) * MAX_PLANAR, NULL); } + /* Only start doing probes if all materials have finished compiling. */ + sldata->probes->all_materials_updated = true; + common_data->spec_toggle = true; common_data->ssr_toggle = true; common_data->sss_toggle = true; @@ -317,6 +336,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda sldata->probes->target_size = prop_cubemap_res >> 1; + DRW_TEXTURE_FREE_SAFE(sldata->probe_depth_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_rt); DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); } @@ -328,7 +348,7 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(veda } if (update_all) { - e_data.update_world |= PROBE_UPDATE_ALL; + sldata->probes->update_world |= PROBE_UPDATE_ALL; sldata->probes->updated_bounce = 0; sldata->probes->grid_initialized = false; } @@ -339,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) { @@ -389,36 +408,47 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat float *col = ts.colorBackground; if (wo) { col = &wo->horr; - if (wo->update_flag != 0 || pinfo->prev_world != wo) { - e_data.update_world |= PROBE_UPDATE_ALL; - pinfo->updated_bounce = 0; - pinfo->grid_initialized = false; - } - wo->update_flag = 0; + bool wo_sh_compiled = true; if (wo->use_nodes && wo->nodetree) { + static float error_col[3] = {1.0f, 0.0f, 1.0f}; + static float compile_col[3] = {0.5f, 0.5f, 0.5f}; struct GPUMaterial *gpumat = EEVEE_material_world_lightprobe_get(scene, wo); - grp = DRW_shgroup_material_create(gpumat, psl->probe_background); - - if (grp) { - DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - DRW_shgroup_call_add(grp, geom, NULL); - } - else { - /* Shader failed : pink background */ - static float pink[3] = {1.0f, 0.0f, 1.0f}; - col = pink; + GPUMaterialStatus status = GPU_material_status(gpumat); + + switch (status) { + case GPU_MAT_SUCCESS: + grp = DRW_shgroup_material_create(gpumat, psl->probe_background); + DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + DRW_shgroup_call_add(grp, geom, NULL); + wo_sh_compiled = true; + break; + case GPU_MAT_QUEUED: + pinfo->all_materials_updated = false; + wo_sh_compiled = false; + /* TODO Bypass probe compilation. */ + col = compile_col; + break; + case GPU_MAT_FAILED: + default: + wo_sh_compiled = true; + col = error_col; + break; } } - pinfo->prev_world = wo; + if (wo->update_flag != 0 || pinfo->prev_world != wo || pinfo->prev_wo_sh_compiled != wo_sh_compiled) { + pinfo->update_world |= PROBE_UPDATE_ALL; + pinfo->prev_wo_sh_compiled = wo_sh_compiled; + pinfo->prev_world = wo; + } + wo->update_flag = 0; } else if (pinfo->prev_world) { + pinfo->update_world |= PROBE_UPDATE_ALL; + pinfo->prev_wo_sh_compiled = false; pinfo->prev_world = NULL; - e_data.update_world |= PROBE_UPDATE_ALL; - pinfo->updated_bounce = 0; - pinfo->grid_initialized = false; } /* Fallback if shader fails or if not using nodetree. */ @@ -433,9 +463,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat { psl->probe_glossy_compute = DRW_pass_create("LightProbe Glossy Compute", DRW_STATE_WRITE_COLOR); - struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); - - DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute, geom); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_filter_glossy_sh, psl->probe_glossy_compute); DRW_shgroup_uniform_float(grp, "intensityFac", &pinfo->intensity_fac, 1); DRW_shgroup_uniform_float(grp, "sampleCount", &pinfo->samples_ct, 1); DRW_shgroup_uniform_float(grp, "invSampleCount", &pinfo->invsamples_ct, 1); @@ -448,8 +476,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRW_shgroup_uniform_texture(grp, "texHammersley", e_data.hammersley); // DRW_shgroup_uniform_texture(grp, "texJitter", e_data.jitter); DRW_shgroup_uniform_texture(grp, "probeHdr", sldata->probe_rt); - - DRW_shgroup_set_instance_count(grp, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } { @@ -495,7 +522,7 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat psl->probe_grid_fill = DRW_pass_create("LightProbe Grid Floodfill", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_fill_sh, psl->probe_grid_fill); - DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool); struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); DRW_shgroup_call_add(grp, geom, NULL); @@ -505,28 +532,42 @@ void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedat DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CULL_BACK; psl->probe_display = DRW_pass_create("LightProbe Display", state); - struct Gwn_Batch *geom = DRW_cache_sphere_get(); - DRWShadingGroup *grp = stl->g_data->cube_display_shgrp = DRW_shgroup_instance_create(e_data.probe_cube_display_sh, psl->probe_display, geom); - DRW_shgroup_attrib_float(grp, "probe_id", 1); /* XXX this works because we are still uploading 4bytes and using the right stride */ - DRW_shgroup_attrib_float(grp, "probe_location", 3); - DRW_shgroup_attrib_float(grp, "sphere_size", 1); - DRW_shgroup_uniform_buffer(grp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_instance_format(e_data.format_probe_display_cube, { + {"probe_id", DRW_ATTRIB_INT, 1}, + {"probe_location", DRW_ATTRIB_FLOAT, 3}, + {"sphere_size", DRW_ATTRIB_FLOAT, 1}, + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create( + e_data.probe_cube_display_sh, + psl->probe_display, + DRW_cache_sphere_get(), + e_data.format_probe_display_cube); + stl->g_data->cube_display_shgrp = grp; + DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &sldata->probe_pool); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - geom = DRW_cache_quad_get(); - grp = stl->g_data->planar_display_shgrp = DRW_shgroup_instance_create(e_data.probe_planar_display_sh, psl->probe_display, geom); - DRW_shgroup_attrib_float(grp, "probe_id", 1); /* XXX this works because we are still uploading 4bytes and using the right stride */ - DRW_shgroup_attrib_float(grp, "probe_mat", 16); - DRW_shgroup_uniform_buffer(grp, "probePlanars", &txl->planar_pool); + DRW_shgroup_instance_format(e_data.format_probe_display_planar, { + {"probe_id", DRW_ATTRIB_INT, 1}, + {"probe_mat", DRW_ATTRIB_FLOAT, 16}, + }); + + grp = DRW_shgroup_instance_create( + e_data.probe_planar_display_sh, + psl->probe_display, + DRW_cache_quad_get(), + e_data.format_probe_display_planar); + stl->g_data->planar_display_shgrp = grp; + DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &txl->planar_pool); } { psl->probe_planar_downsample_ps = DRW_pass_create("LightProbe Planar Downsample", DRW_STATE_WRITE_COLOR); - struct Gwn_Batch *geom = DRW_cache_fullscreen_quad_get(); - DRWShadingGroup *grp = stl->g_data->planar_downsample = DRW_shgroup_instance_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps, geom); - DRW_shgroup_uniform_buffer(grp, "source", &txl->planar_pool); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_planar_downsample_sh, psl->probe_planar_downsample_ps); + DRW_shgroup_uniform_texture_ref(grp, "source", &txl->planar_pool); DRW_shgroup_uniform_float(grp, "fireflyFactor", &sldata->common_data.ssr_firefly_fac, 1); + DRW_shgroup_call_instances_add(grp, DRW_cache_fullscreen_quad_get(), NULL, (unsigned int *)&pinfo->num_planar); } } @@ -535,20 +576,40 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) EEVEE_LightProbesInfo *pinfo = sldata->probes; LightProbe *probe = (LightProbe *)ob->data; - /* Step 1 find all lamps in the scene and setup them */ if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) || - (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE)) + (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) || + (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_grid >= MAX_PLANAR)) { printf("Too much probes in the scene !!!\n"); return; } + if (probe->type == LIGHTPROBE_TYPE_PLANAR) { + /* See if this planar probe is inside the view frustum. If not, no need to update it. */ + /* NOTE: this could be bypassed if we want feedback loop mirrors for rendering. */ + BoundBox bbox; float tmp[4][4]; + const float min[3] = {-1.0f, -1.0f, -1.0f}; + const float max[3] = { 1.0f, 1.0f, 1.0f}; + BKE_boundbox_init_from_minmax(&bbox, min, max); + + copy_m4_m4(tmp, ob->obmat); + normalize_v3(tmp[2]); + mul_v3_fl(tmp[2], probe->distinf); + + for (int v = 0; v < 8; ++v) { + mul_m4_v3(tmp, bbox.vec[v]); + } + if (!DRW_culling_box_test(&bbox)) { + return; /* Culled */ + } + } + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); ped->num_cell = probe->grid_resolution_x * probe->grid_resolution_y * probe->grid_resolution_z; if ((probe->type == LIGHTPROBE_TYPE_GRID) && - ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES)) + ((pinfo->total_irradiance_samples + ped->num_cell) >= MAX_IRRADIANCE_SAMPLES)) { printf("Too much grid samples !!!\n"); return; @@ -567,7 +628,7 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) } } - if (e_data.update_world) { + if (pinfo->update_world) { ped->need_update = true; ped->updated_cells = 0; ped->updated_lvl = 0; @@ -576,18 +637,20 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) pinfo->do_cube_update |= ped->need_update; - if (probe->type == LIGHTPROBE_TYPE_CUBE) { - pinfo->probes_cube_ref[pinfo->num_cube] = ob; - pinfo->num_cube++; - } - else if (probe->type == LIGHTPROBE_TYPE_PLANAR) { - pinfo->probes_planar_ref[pinfo->num_planar] = ob; - pinfo->num_planar++; - } - else { /* GRID */ - pinfo->probes_grid_ref[pinfo->num_grid] = ob; - pinfo->num_grid++; - pinfo->total_irradiance_samples += ped->num_cell; + switch (probe->type) { + case LIGHTPROBE_TYPE_CUBE: + pinfo->probes_cube_ref[pinfo->num_cube] = ob; + pinfo->num_cube++; + break; + case LIGHTPROBE_TYPE_PLANAR: + pinfo->probes_planar_ref[pinfo->num_planar] = ob; + pinfo->num_planar++; + break; + case LIGHTPROBE_TYPE_GRID: + pinfo->probes_grid_ref[pinfo->num_grid] = ob; + pinfo->num_grid++; + pinfo->total_irradiance_samples += ped->num_cell; + break; } } @@ -598,15 +661,34 @@ static void scale_m4_v3(float R[4][4], float v[3]) mul_v3_v3(R[i], v); } -static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl) +static void EEVEE_planar_reflections_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl) +{ + EEVEE_LightProbesInfo *pinfo = sldata->probes; + Object *ob; + + for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { + LightProbe *probe = (LightProbe *)ob->data; + EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); + + ped->probe_id = i; + + /* Debug Display */ + if (DRW_state_draw_support() && + (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) + { + DRW_shgroup_call_dynamic_add(stl->g_data->planar_display_shgrp, &ped->probe_id, ob->obmat); + } + } +} + +static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata) { EEVEE_LightProbesInfo *pinfo = sldata->probes; Object *ob; float mtx[4][4], normat[4][4], imat[4][4], rangemat[4][4]; - float viewmat[4][4], winmat[4][4]; + float viewmat[4][4]; DRW_viewport_matrix_get(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); zero_m4(rangemat); rangemat[0][0] = rangemat[1][1] = rangemat[2][2] = 0.5f; @@ -618,36 +700,27 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_ LightProbe *probe = (LightProbe *)ob->data; EEVEE_PlanarReflection *eplanar = &pinfo->planar_data[i]; EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - /* Computing mtx : matrix that mirror position around object's XY plane. */ normalize_m4_m4(normat, ob->obmat); /* object > world */ invert_m4_m4(imat, normat); /* world > object */ - float reflect[3] = {1.0f, 1.0f, -1.0f}; /* XY reflection plane */ scale_m4_v3(imat, reflect); /* world > object > mirrored obj */ mul_m4_m4m4(mtx, normat, imat); /* world > object > mirrored obj > world */ - /* Reflect Camera Matrix. */ - mul_m4_m4m4(ped->viewmat, viewmat, mtx); - + mul_m4_m4m4(ped->mats.mat[DRW_MAT_VIEW], viewmat, mtx); /* TODO FOV margin */ - float winmat_fov[4][4]; - copy_m4_m4(winmat_fov, winmat); - - /* Apply Perspective Matrix. */ - mul_m4_m4m4(ped->persmat, winmat_fov, ped->viewmat); - + /* Temporal sampling jitter should be already applied to the DRW_MAT_WIN. */ + DRW_viewport_matrix_get(ped->mats.mat[DRW_MAT_WIN], DRW_MAT_WIN); + /* Apply Projection Matrix. */ + mul_m4_m4m4(ped->mats.mat[DRW_MAT_PERS], ped->mats.mat[DRW_MAT_WIN], ped->mats.mat[DRW_MAT_VIEW]); /* This is the matrix used to reconstruct texture coordinates. * We use the original view matrix because it does not create * visual artifacts if receiver is not perfectly aligned with * the planar reflection probe. */ - mul_m4_m4m4(eplanar->reflectionmat, winmat_fov, viewmat); /* TODO FOV margin */ + mul_m4_m4m4(eplanar->reflectionmat, ped->mats.mat[DRW_MAT_WIN], viewmat); /* TODO FOV margin */ /* Convert from [-1, 1] to [0, 1] (NDC to Texture coord). */ mul_m4_m4m4(eplanar->reflectionmat, rangemat, eplanar->reflectionmat); - /* TODO frustum check. */ - ped->need_update = true; - /* Compute clip plane equation / normal. */ float refpoint[3]; copy_v3_v3(eplanar->plane_equation, ob->obmat[2]); @@ -692,13 +765,6 @@ static void EEVEE_planar_reflections_updates(EEVEE_ViewLayerData *sldata, EEVEE_ float min_dist = min_ff(1.0f - 1e-8f, 1.0f - probe->falloff) * probe->distinf; eplanar->attenuation_scale = -1.0f / max_ff(1e-8f, max_dist - min_dist); eplanar->attenuation_bias = max_dist * -eplanar->attenuation_scale; - - /* Debug Display */ - if (DRW_state_draw_support() && - (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) - { - DRW_shgroup_call_dynamic_add(stl->g_data->planar_display_shgrp, &ped->probe_id, ob->obmat); - } } } @@ -818,25 +884,25 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis /* Visibility bias */ egrid->visibility_bias = 0.05f * probe->vis_bias; egrid->visibility_bleed = probe->vis_bleedbias; - egrid->visibility_range = max_ff(max_ff(len_v3(egrid->increment_x), - len_v3(egrid->increment_y)), - len_v3(egrid->increment_z)) + 1.0f; + egrid->visibility_range = ( + sqrtf(max_fff(len_squared_v3(egrid->increment_x), + len_squared_v3(egrid->increment_y), + len_squared_v3(egrid->increment_z))) + 1.0f); /* Debug Display */ if (DRW_state_draw_support() && (probe->flag & LIGHTPROBE_FLAG_SHOW_DATA)) { - struct Gwn_Batch *geom = DRW_cache_sphere_get(); - DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.probe_grid_display_sh, psl->probe_display, geom); - DRW_shgroup_set_instance_count(grp, ped->num_cell); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.probe_grid_display_sh, psl->probe_display); DRW_shgroup_uniform_int(grp, "offset", &egrid->offset, 1); DRW_shgroup_uniform_ivec3(grp, "grid_resolution", egrid->resolution, 1); DRW_shgroup_uniform_vec3(grp, "corner", egrid->corner, 1); DRW_shgroup_uniform_vec3(grp, "increment_x", egrid->increment_x, 1); DRW_shgroup_uniform_vec3(grp, "increment_y", egrid->increment_y, 1); DRW_shgroup_uniform_vec3(grp, "increment_z", egrid->increment_z, 1); - DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool); DRW_shgroup_uniform_float(grp, "sphere_size", &probe->data_draw_size, 1); + DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, (unsigned int *)&ped->num_cell); } } } @@ -844,7 +910,6 @@ static void EEVEE_lightprobes_updates(EEVEE_ViewLayerData *sldata, EEVEE_PassLis void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; - EEVEE_StorageList *stl = vedata->stl; EEVEE_LightProbesInfo *pinfo = sldata->probes; Object *ob; @@ -852,6 +917,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* Free textures if number mismatch. */ if (pinfo->num_cube != pinfo->cache_num_cube) { DRW_TEXTURE_FREE_SAFE(sldata->probe_pool); + pinfo->cache_num_cube = pinfo->num_cube; } if (pinfo->num_planar != pinfo->cache_num_planar) { @@ -875,21 +941,18 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved /* XXX this should be run each frame as it ensure planar_depth is set */ planar_pool_ensure_alloc(vedata, pinfo->num_planar); - /* Setup planar filtering pass */ - DRW_shgroup_set_instance_count(stl->g_data->planar_downsample, pinfo->num_planar); - if (!sldata->probe_pool) { 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 */ - e_data.update_world |= PROBE_UPDATE_CUBE; - common_data->prb_num_render_cube = 0; - pinfo->cache_num_cube = pinfo->num_cube; + pinfo->update_world |= PROBE_UPDATE_CUBE; + } + if ((pinfo->update_world & PROBE_UPDATE_CUBE) != 0) { + common_data->prb_num_render_cube = 0; for (int i = 1; (ob = pinfo->probes_cube_ref[i]) && (i < MAX_PROBE); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); ped->need_update = true; @@ -898,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; @@ -919,11 +977,14 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved sldata->irradiance_rt = DRW_texture_create_2D_array(irr_size[0], irr_size[1], irr_size[2], irradiance_format, DRW_TEX_FILTER, NULL); } - common_data->prb_num_render_grid = 0; - pinfo->updated_bounce = 0; + /* Tag probes to refresh */ + pinfo->update_world |= PROBE_UPDATE_GRID; pinfo->grid_initialized = false; - e_data.update_world |= PROBE_UPDATE_GRID; + } + if ((pinfo->update_world & PROBE_UPDATE_GRID) != 0) { + common_data->prb_num_render_grid = 0; + pinfo->updated_bounce = 0; for (int i = 1; (ob = pinfo->probes_grid_ref[i]) && (i < MAX_PROBE); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); ped->need_update = true; @@ -936,12 +997,12 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved common_data->prb_num_render_grid = pinfo->num_grid; } + EEVEE_planar_reflections_cache_finish(sldata, vedata->stl); + EEVEE_lightprobes_updates(sldata, vedata->psl, vedata->stl); - EEVEE_planar_reflections_updates(sldata, vedata->stl); DRW_uniformbuffer_update(sldata->probe_ubo, &sldata->probes->probe_data); DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); - DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data); } static void downsample_planar(void *vedata, int level) @@ -973,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; @@ -1023,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 */ @@ -1078,14 +1142,21 @@ static void diffuse_filter_probe( pinfo->lod_rt_max = 2.0f; /* Improve cache reuse */ #endif - /* 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)); - - DRW_framebuffer_texture_detach(sldata->probe_pool); - DRW_framebuffer_texture_layer_attach(sldata->probe_filter_fb, sldata->irradiance_rt, 0, 0, 0); + /* Start fresh */ + GPU_framebuffer_ensure_config(&sldata->probe_filter_fb, { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_NONE + }); - DRW_framebuffer_viewport_size(sldata->probe_filter_fb, x, y, size[0], size[1]); + /* 4 - Compute spherical harmonics */ + EEVEE_downsample_cube_buffer(vedata, sldata->probe_rt, (int)(pinfo->lod_rt_max)); + + 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 */ @@ -1105,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); - - 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); + const int 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. */ @@ -1126,11 +1195,17 @@ 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; - float winmat[4][4], wininv[4][4], posmat[4][4]; + DRWMatrixState matstate; + float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW]; + float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV]; + float (*persmat)[4] = matstate.mat[DRW_MAT_PERS]; + float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV]; + float (*winmat)[4] = matstate.mat[DRW_MAT_WIN]; + float (*wininv)[4] = matstate.mat[DRW_MAT_WININV]; + float posmat[4][4]; unit_m4(posmat); /* Move to capture position */ @@ -1145,23 +1220,14 @@ 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) { - float viewmat[4][4], persmat[4][4]; - float viewinv[4][4], persinv[4][4]; - /* Setup custom matrices */ mul_m4_m4m4(viewmat, cubefacemat[i], posmat); mul_m4_m4m4(persmat, winmat, viewmat); @@ -1169,21 +1235,13 @@ static void render_scene_to_probe( invert_m4_m4(viewinv, viewmat); invert_m4_m4(wininv, winmat); - DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV); - DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV); + DRW_viewport_matrix_override_set_all(&matstate); /* 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); @@ -1193,68 +1251,59 @@ 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); - - DRW_viewport_matrix_override_unset(DRW_MAT_PERS); - DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); - DRW_viewport_matrix_override_unset(DRW_MAT_VIEW); - DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV); - DRW_viewport_matrix_override_unset(DRW_MAT_WIN); - DRW_viewport_matrix_override_unset(DRW_MAT_WININV); /* Restore */ txl->planar_pool = tmp_planar_pool; - stl->g_data->minzbuffer = tmp_minz; txl->maxzbuffer = tmp_maxz; } static void render_scene_to_planar( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, int layer, - float (*viewmat)[4], float (*persmat)[4], - float clip_plane[4]) + EEVEE_LightProbeEngineData *ped) { EEVEE_FramebufferList *fbl = vedata->fbl; EEVEE_TextureList *txl = vedata->txl; EEVEE_PassList *psl = vedata->psl; - float viewinv[4][4]; - float persinv[4][4]; + float (*viewmat)[4] = ped->mats.mat[DRW_MAT_VIEW]; + float (*viewinv)[4] = ped->mats.mat[DRW_MAT_VIEWINV]; + float (*persmat)[4] = ped->mats.mat[DRW_MAT_PERS]; + float (*persinv)[4] = ped->mats.mat[DRW_MAT_PERSINV]; + float (*winmat)[4] = ped->mats.mat[DRW_MAT_WIN]; + float (*wininv)[4] = ped->mats.mat[DRW_MAT_WININV]; invert_m4_m4(viewinv, viewmat); invert_m4_m4(persinv, persmat); + invert_m4_m4(wininv, winmat); - DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV); - - /* Since we are rendering with an inverted view matrix, we need - * to invert the facing for backface culling to be the same. */ - DRW_state_invert_facing(); + DRW_viewport_matrix_override_set_all(&ped->mats); /* Be sure that cascaded shadow maps are updated. */ EEVEE_draw_shadows(sldata, psl); - DRW_state_clip_planes_add(clip_plane); + /* Since we are rendering with an inverted view matrix, we need + * to invert the facing for backface culling to be the same. */ + DRW_state_invert_facing(); + /* Set clipping plan */ + copy_v4_v4(sldata->clip_data.clip_planes[0], ped->planer_eq_offset); + 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 */ @@ -1263,9 +1312,14 @@ static void render_scene_to_planar( txl->planar_pool = e_data.planar_pool_placeholder; txl->planar_depth = e_data.depth_array_placeholder; + /* Slight modification: we handle refraction as normal + * shading and don't do SSRefraction. */ + /* Depth prepass */ DRW_draw_pass(psl->depth_pass_clip); DRW_draw_pass(psl->depth_pass_clip_cull); + DRW_draw_pass(psl->refract_depth_pass); + DRW_draw_pass(psl->refract_depth_pass_cull); /* Background */ DRW_draw_pass(psl->probe_background); @@ -1276,12 +1330,20 @@ 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); DRW_draw_pass(psl->material_pass); DRW_draw_pass(psl->sss_pass); /* Only output standard pass */ + DRW_draw_pass(psl->refract_pass); + + /* Transparent */ + if (DRW_state_is_image_render()) { + /* Do the reordering only for offline because it can be costly. */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); + } + DRW_draw_pass(psl->transparent_pass); DRW_state_invert_facing(); DRW_state_clip_planes_reset(); @@ -1289,64 +1351,37 @@ static void render_scene_to_planar( /* Restore */ txl->planar_pool = tmp_planar_pool; txl->planar_depth = tmp_planar_depth; - DRW_viewport_matrix_override_unset(DRW_MAT_PERS); - DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); - DRW_viewport_matrix_override_unset(DRW_MAT_VIEW); - DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV); - - 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) { EEVEE_LightProbesInfo *pinfo = sldata->probes; - float winmat[4][4], wininv[4][4]; + DRWMatrixState matstate; + float (*viewmat)[4] = matstate.mat[DRW_MAT_VIEW]; + float (*viewinv)[4] = matstate.mat[DRW_MAT_VIEWINV]; + float (*persmat)[4] = matstate.mat[DRW_MAT_PERS]; + float (*persinv)[4] = matstate.mat[DRW_MAT_PERSINV]; + float (*winmat)[4] = matstate.mat[DRW_MAT_WIN]; + float (*wininv)[4] = matstate.mat[DRW_MAT_WININV]; - /* 1 - Render to cubemap target using geometry shader. */ /* For world probe, we don't need to clear since we render the background directly. */ pinfo->layer = 0; 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) { - float viewmat[4][4], persmat[4][4]; - float viewinv[4][4], persinv[4][4]; - - 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); - /* Setup custom matrices */ copy_m4_m4(viewmat, cubefacemat[i]); mul_m4_m4m4(persmat, winmat, viewmat); invert_m4_m4(persinv, persmat); invert_m4_m4(viewinv, viewmat); + DRW_viewport_matrix_override_set_all(&matstate); - DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); - DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV); - DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW); - DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV); - DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); - DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV); - + 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); - - DRW_viewport_matrix_override_unset(DRW_MAT_PERS); - DRW_viewport_matrix_override_unset(DRW_MAT_PERSINV); - DRW_viewport_matrix_override_unset(DRW_MAT_VIEW); - DRW_viewport_matrix_override_unset(DRW_MAT_VIEWINV); - DRW_viewport_matrix_override_unset(DRW_MAT_WIN); - DRW_viewport_matrix_override_unset(DRW_MAT_WININV); } static void lightprobe_cell_grid_location_get(EEVEE_LightGrid *egrid, int cell_idx, float r_local_cell[3]) @@ -1373,25 +1408,39 @@ static void lightprobe_cell_world_location_get(EEVEE_LightGrid *egrid, float loc static void lightprobes_refresh_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_LightProbesInfo *pinfo = sldata->probes; EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + DRWMatrixState saved_mats; + + /* We need to save the Matrices before overidding them */ + DRW_viewport_matrix_get_all(&saved_mats); render_world_to_probe(sldata, psl); - if (e_data.update_world & PROBE_UPDATE_CUBE) { + if (pinfo->update_world & PROBE_UPDATE_CUBE) { glossy_filter_probe(sldata, vedata, psl, 0, 1.0); common_data->prb_num_render_cube = 1; } - if (e_data.update_world & PROBE_UPDATE_GRID) { + 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; + common_data->vol_history_alpha = 0.0f; } - e_data.update_world = 0; + pinfo->update_world = 0; DRW_viewport_request_redraw(); + /* Do not let this frame accumulate. */ + stl->effects->taa_current_sample = 1; + + DRW_viewport_matrix_override_set_all(&saved_mats); } static void lightprobes_refresh_initialize_grid(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -1402,39 +1451,47 @@ 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); + 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); - 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); + pinfo->grid_initialized = true; } -static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +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; + DRWMatrixState saved_mats; if (pinfo->num_planar == 0) { + /* Disable SSR if we cannot read previous frame */ + common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer; + common_data->prb_num_planar = 0; return; } + EEVEE_planar_reflections_updates(sldata); + DRW_uniformbuffer_update(sldata->planar_ubo, &sldata->probes->planar_data); + + /* We need to save the Matrices before overidding them */ + DRW_viewport_matrix_get_all(&saved_mats); + /* Temporary Remove all planar reflections (avoid lag effect). */ common_data->prb_num_planar = 0; /* Turn off ssr to avoid black specular */ - /* TODO : Enable SSR in planar reflections? (Would be very heavy) */ common_data->ssr_toggle = false; common_data->sss_toggle = false; @@ -1442,12 +1499,7 @@ static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data * for (int i = 0; (ob = pinfo->probes_planar_ref[i]) && (i < MAX_PLANAR); i++) { EEVEE_LightProbeEngineData *ped = EEVEE_lightprobe_data_ensure(ob); - if (!ped->need_update) { - continue; - } - render_scene_to_planar(sldata, vedata, i, ped->viewmat, ped->persmat, ped->planer_eq_offset); - ped->need_update = false; - ped->probe_id = i; + render_scene_to_planar(sldata, vedata, i, ped); } /* Restore */ @@ -1455,15 +1507,30 @@ static void lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data * common_data->ssr_toggle = true; common_data->sss_toggle = true; - /* If there is at least one planar probe */ - if (pinfo->num_planar > 0 && (vedata->stl->effects->enabled_effects & EFFECT_SSR) != 0) { + /* Prefilter for SSR */ + 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(); } + + DRW_viewport_matrix_override_set_all(&saved_mats); + + if (DRW_state_is_image_render()) { + /* Sort transparents because planar reflections could have re-sorted them. */ + DRW_pass_sort_shgroup_z(vedata->psl->transparent_pass); + } + + /* Disable SSR if we cannot read previous frame */ + common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer; } static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -1493,10 +1560,11 @@ static void lightprobes_refresh_cube(EEVEE_ViewLayerData *sldata, EEVEE_Data *ve DRW_viewport_request_redraw(); /* Do not let this frame accumulate. */ stl->effects->taa_current_sample = 1; - /* Only do one probe per frame */ return; } + + pinfo->do_cube_update = false; } static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) @@ -1516,6 +1584,9 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ return; } } + /* We need to save the Matrices before overidding them */ + DRWMatrixState saved_mats; + DRW_viewport_matrix_get_all(&saved_mats); /* Make sure grid is initialized. */ lightprobes_refresh_initialize_grid(sldata, vedata); /* Reflection probes depend on diffuse lighting thus on irradiance grid, @@ -1615,6 +1686,11 @@ static void lightprobes_refresh_all_no_world(EEVEE_ViewLayerData *sldata, EEVEE_ DRW_viewport_request_redraw(); /* Do not let this frame accumulate. */ stl->effects->taa_current_sample = 1; + /* Reset volume history. */ + stl->effects->volume_current_sample = -1; + common_data->vol_history_alpha = 0.0f; + /* Restore matrices */ + DRW_viewport_matrix_override_set_all(&saved_mats); return; } @@ -1631,25 +1707,36 @@ 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); } } /* Refresh cube probe when needed. */ lightprobes_refresh_cube(sldata, vedata); + /* Restore matrices */ + DRW_viewport_matrix_override_set_all(&saved_mats); } -void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data *UNUSED(vedata)) { EEVEE_LightProbesInfo *pinfo = sldata->probes; EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + return ((pinfo->do_cube_update == false) && + (pinfo->updated_bounce == pinfo->num_bounce) && + (common_data->prb_num_render_cube == pinfo->num_cube)); +} + +void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_LightProbesInfo *pinfo = sldata->probes; + /* Disable specular lighting when rendering probes to avoid feedback loops (looks bad). */ common_data->spec_toggle = false; common_data->ssr_toggle = false; @@ -1662,10 +1749,10 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->ao_dist = 0.0f; /* Render world in priority */ - if (e_data.update_world) { + if (pinfo->update_world) { lightprobes_refresh_world(sldata, vedata); } - else if (pinfo->do_cube_update || (pinfo->updated_bounce < pinfo->num_bounce)) { + else if (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false && pinfo->all_materials_updated) { lightprobes_refresh_all_no_world(sldata, vedata); } @@ -1675,15 +1762,12 @@ void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) common_data->sss_toggle = true; common_data->ao_dist = tmp_ao_dist; common_data->ao_settings = tmp_ao_settings; - - lightprobes_refresh_planar(sldata, vedata); - - /* Disable SSR if we cannot read previous frame */ - common_data->ssr_toggle = vedata->stl->g_data->valid_double_buffer; } void EEVEE_lightprobes_free(void) { + MEM_SAFE_FREE(e_data.format_probe_display_cube); + MEM_SAFE_FREE(e_data.format_probe_display_planar); DRW_SHADER_FREE_SAFE(e_data.probe_default_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_glossy_sh); DRW_SHADER_FREE_SAFE(e_data.probe_filter_diffuse_sh); diff --git a/source/blender/draw/engines/eevee/eevee_lights.c b/source/blender/draw/engines/eevee/eevee_lights.c index 69b58bf9670..7496142a26e 100644 --- a/source/blender/draw/engines/eevee/eevee_lights.c +++ b/source/blender/draw/engines/eevee/eevee_lights.c @@ -26,6 +26,7 @@ #include "DRW_render.h" #include "BLI_dynstr.h" +#include "BLI_rect.h" #include "BKE_object.h" @@ -106,50 +107,6 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) if (!e_data.shadow_sh) { e_data.shadow_sh = DRW_shader_create( datatoc_shadow_vert_glsl, datatoc_shadow_geom_glsl, datatoc_shadow_frag_glsl, NULL); - - DynStr *ds_frag = BLI_dynstr_new(); - BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl); - BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl); - char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag); - BLI_dynstr_free(ds_frag); - - e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define ESM\n"); - e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define ESM\n" - "#define CSM\n"); - - e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define VSM\n"); - e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - store_shadow_shader_str, - "#define VSM\n" - "#define CSM\n"); - - MEM_freeN(store_shadow_shader_str); - - e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define ESM\n" - "#define COPY\n"); - e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define ESM\n" - "#define COPY\n" - "#define CSM\n"); - - e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define VSM\n" - "#define COPY\n"); - e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( - datatoc_shadow_copy_frag_glsl, - "#define VSM\n" - "#define COPY\n" - "#define CSM\n"); } if (!sldata->lamps) { @@ -203,11 +160,67 @@ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata) linfo->shadow_cube_target_size = new_cube_target_size; linfo->shadow_render_data.cube_texel_size = 1.0 / (float)linfo->shadow_cube_target_size; } + + /* only compile the ones needed. reduce startup time. */ + if ((sh_method == SHADOW_ESM) && !e_data.shadow_store_cube_sh[SHADOW_ESM]) { + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl); + char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.shadow_store_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( + store_shadow_shader_str, + "#define ESM\n"); + e_data.shadow_store_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( + store_shadow_shader_str, + "#define ESM\n" + "#define CSM\n"); + MEM_freeN(store_shadow_shader_str); + + e_data.shadow_copy_cube_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define ESM\n" + "#define COPY\n"); + e_data.shadow_copy_cascade_sh[SHADOW_ESM] = DRW_shader_create_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define ESM\n" + "#define COPY\n" + "#define CSM\n"); + } + else if ((sh_method == SHADOW_VSM) && !e_data.shadow_store_cube_sh[SHADOW_VSM]) { + DynStr *ds_frag = BLI_dynstr_new(); + BLI_dynstr_append(ds_frag, datatoc_concentric_samples_lib_glsl); + BLI_dynstr_append(ds_frag, datatoc_shadow_store_frag_glsl); + char *store_shadow_shader_str = BLI_dynstr_get_cstring(ds_frag); + BLI_dynstr_free(ds_frag); + + e_data.shadow_store_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( + store_shadow_shader_str, + "#define VSM\n"); + e_data.shadow_store_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( + store_shadow_shader_str, + "#define VSM\n" + "#define CSM\n"); + MEM_freeN(store_shadow_shader_str); + + e_data.shadow_copy_cube_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define VSM\n" + "#define COPY\n"); + e_data.shadow_copy_cascade_sh[SHADOW_VSM] = DRW_shader_create_fullscreen( + datatoc_shadow_copy_frag_glsl, + "#define VSM\n" + "#define COPY\n" + "#define CSM\n"); + } } -void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) +void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_LampsInfo *linfo = sldata->lamps; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PassList *psl = vedata->psl; linfo->shcaster_frontbuffer->count = 0; linfo->num_light = 0; @@ -228,7 +241,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRWShadingGroup *grp = DRW_shgroup_create( e_data.shadow_store_cube_sh[linfo->shadow_method], psl->shadow_cube_store_pass); - DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cube_blur); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_blur); DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); @@ -239,7 +252,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRWShadingGroup *grp = DRW_shgroup_create( e_data.shadow_store_cascade_sh[linfo->shadow_method], psl->shadow_cascade_store_pass); - DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cascade_blur); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_blur); DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); @@ -251,7 +264,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRWShadingGroup *grp = DRW_shgroup_create( e_data.shadow_copy_cube_sh[linfo->shadow_method], psl->shadow_cube_copy_pass); - DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cube_target); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cube_target); DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); DRW_shgroup_uniform_int(grp, "faceId", &linfo->current_shadow_face, 1); @@ -263,7 +276,7 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) DRWShadingGroup *grp = DRW_shgroup_create( e_data.shadow_copy_cascade_sh[linfo->shadow_method], psl->shadow_cascade_copy_pass); - DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_cascade_target); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_cascade_target); DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); DRW_shgroup_uniform_float(grp, "shadowFilterSize", &linfo->filter_size, 1); DRW_shgroup_uniform_int(grp, "cascadeId", &linfo->current_shadow_cascade, 1); @@ -271,15 +284,11 @@ void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) } { - psl->shadow_cube_pass = DRW_pass_create( - "Shadow Cube Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); - } + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; + psl->shadow_pass = DRW_pass_create("Shadow Pass", state); - { - psl->shadow_cascade_pass = DRW_pass_create( - "Shadow Cascade Pass", - DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS); + DRWShadingGroup *grp = stl->g_data->shadow_shgrp = DRW_shgroup_create(e_data.shadow_sh, psl->shadow_pass); + DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); } } @@ -343,7 +352,7 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* For light update tracking. */ if ((prev_cube_sh_id >= 0) && - (prev_cube_sh_id < linfo->shcaster_backbuffer->count)) + (prev_cube_sh_id < linfo->shcaster_backbuffer->count)) { linfo->new_shadow_id[prev_cube_sh_id] = linfo->cpu_cube_ct; } @@ -378,24 +387,20 @@ void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, Object *ob) /* Add a shadow caster to the shadowpasses */ void EEVEE_lights_cache_shcaster_add( - EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct Gwn_Batch *geom, float (*obmat)[4]) + EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, struct Gwn_Batch *geom, Object *ob) { - DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cube_pass, geom); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat); - DRW_shgroup_set_instance_count(grp, 6); - - grp = DRW_shgroup_instance_create(e_data.shadow_sh, psl->shadow_cascade_pass, geom); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat); - DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM); + DRW_shgroup_call_object_instances_add( + stl->g_data->shadow_shgrp, + geom, ob, + &sldata->lamps->shadow_instance_count); } void EEVEE_lights_cache_shcaster_material_add( EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat, struct Gwn_Batch *geom, struct Object *ob, float (*obmat)[4], float *alpha_threshold) { - DRWShadingGroup *grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cube_pass, geom, ob); + /* TODO / PERF : reuse the same shading group for objects with the same material */ + DRWShadingGroup *grp = DRW_shgroup_material_create(gpumat, psl->shadow_pass); if (grp == NULL) return; @@ -405,16 +410,7 @@ void EEVEE_lights_cache_shcaster_material_add( if (alpha_threshold != NULL) DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); - DRW_shgroup_set_instance_count(grp, 6); - - grp = DRW_shgroup_material_instance_create(gpumat, psl->shadow_cascade_pass, geom, ob); - DRW_shgroup_uniform_block(grp, "shadow_render_block", sldata->shadow_render_ubo); - DRW_shgroup_uniform_mat4(grp, "ShadowModelMatrix", (float *)obmat); - - if (alpha_threshold != NULL) - DRW_shgroup_uniform_float(grp, "alphaThreshold", alpha_threshold, 1); - - DRW_shgroup_set_instance_count(grp, MAX_CASCADE_NUM); + DRW_shgroup_call_object_instances_add(grp, geom, ob, &sldata->lamps->shadow_instance_count); } /* Make that object update shadow casting lamps inside its influence bounding box. */ @@ -519,7 +515,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( @@ -528,19 +523,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); @@ -653,9 +647,15 @@ static void eevee_shadow_cube_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE_La #define LERP(t, a, b) ((a) + (t) * ((b) - (a))) -static void frustum_min_bounding_sphere(const float corners[8][4], float r_center[3], float *r_radius) +static double round_to_digits(double value, int digits) { -#if 0 /* Simple solution but waist too much space. */ + double factor = pow(10.0, digits - ceil(log10(fabs(value)))); + return round(value * factor) / factor; +} + +static void frustum_min_bounding_sphere(const float corners[8][3], float r_center[3], float *r_radius) +{ +#if 0 /* Simple solution but waste too much space. */ float minvec[3], maxvec[3]; /* compute the bounding box */ @@ -669,19 +669,27 @@ static void frustum_min_bounding_sphere(const float corners[8][4], float r_cente add_v3_v3v3(r_center, minvec, maxvec); mul_v3_fl(r_center, 0.5f); #else - /* Make the bouding sphere always centered on the front diagonal */ - add_v3_v3v3(r_center, corners[4], corners[7]); - mul_v3_fl(r_center, 0.5f); - *r_radius = len_v3v3(corners[0], r_center); + /* Find averaged center. */ + zero_v3(r_center); + for (int i = 0; i < 8; ++i) { + add_v3_v3(r_center, corners[i]); + } + mul_v3_fl(r_center, 1.0f / 8.0f); - /* Search the largest distance between the sphere center - * and the front plane corners. */ - for (int i = 0; i < 4; ++i) { - float rad = len_v3v3(corners[4 + i], r_center); + /* Search the largest distance from the sphere center. */ + *r_radius = 0.0f; + for (int i = 0; i < 8; ++i) { + float rad = len_squared_v3v3(corners[i], r_center); if (rad > *r_radius) { *r_radius = rad; } } + + /* TODO try to reduce the radius further by moving the center. + * Remember we need a __stable__ solution! */ + + /* Try to reduce float imprecision leading to shimmering. */ + *r_radius = (float)round_to_digits(sqrtf(*r_radius), 3); #endif } @@ -711,7 +719,7 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE } /* Lamps Matrices */ - float viewmat[4][4], projmat[4][4]; + float (*viewmat)[4], projmat[4][4]; int sh_nbr = 1; /* TODO : MSM */ int cascade_nbr = la->cascade_count; @@ -720,6 +728,13 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE EEVEE_Shadow *ubo_data = linfo->shadow_data + sh_data->shadow_id; EEVEE_ShadowCascade *cascade_data = linfo->shadow_cascade_data + sh_data->cascade_id; + /* obmat = Object Space > World Space */ + /* viewmat = World Space > View Space */ + invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_VIEW], ob->obmat); + viewmat = sh_data->clipmat.mat[DRW_MAT_VIEW]; + normalize_m4(viewmat); + invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_VIEWINV], viewmat); + /* The technique consists into splitting * the view frustum into several sub-frustum * that are individually receiving one shadow map */ @@ -818,50 +833,41 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE cascade_data->split_start[0] = LERP(la->cascade_fade, cascade_data->split_end[cascade_nbr - 1], prev_split); /* For each cascade */ + rctf rect_clip, rect_cascade; for (int c = 0; c < cascade_nbr; ++c) { /* Given 8 frustum corners */ - float corners[8][4] = { + float corners[8][3] = { /* Near Cap */ - {-1.0f, -1.0f, splits_start_ndc[c], 1.0f}, - { 1.0f, -1.0f, splits_start_ndc[c], 1.0f}, - {-1.0f, 1.0f, splits_start_ndc[c], 1.0f}, - { 1.0f, 1.0f, splits_start_ndc[c], 1.0f}, + {-1.0f, -1.0f, splits_start_ndc[c]}, + { 1.0f, -1.0f, splits_start_ndc[c]}, + {-1.0f, 1.0f, splits_start_ndc[c]}, + { 1.0f, 1.0f, splits_start_ndc[c]}, /* Far Cap */ - {-1.0f, -1.0f, splits_end_ndc[c], 1.0f}, - { 1.0f, -1.0f, splits_end_ndc[c], 1.0f}, - {-1.0f, 1.0f, splits_end_ndc[c], 1.0f}, - { 1.0f, 1.0f, splits_end_ndc[c], 1.0f} + {-1.0f, -1.0f, splits_end_ndc[c]}, + { 1.0f, -1.0f, splits_end_ndc[c]}, + {-1.0f, 1.0f, splits_end_ndc[c]}, + { 1.0f, 1.0f, splits_end_ndc[c]} }; /* Transform them into world space */ for (int i = 0; i < 8; ++i) { - mul_m4_v4(persinv, corners[i]); - mul_v3_fl(corners[i], 1.0f / corners[i][3]); - corners[i][3] = 1.0f; - } - - - /* Project them into light space */ - invert_m4_m4(viewmat, ob->obmat); - normalize_v3(viewmat[0]); - normalize_v3(viewmat[1]); - normalize_v3(viewmat[2]); - - for (int i = 0; i < 8; ++i) { - mul_m4_v4(viewmat, corners[i]); + mul_project_m4_v3(persinv, corners[i]); } float center[3]; frustum_min_bounding_sphere(corners, center, &(sh_data->radius[c])); + /* Project into lightspace */ + mul_mat3_m4_v3(viewmat, center); + /* Snap projection center to nearest texel to cancel shimmering. */ float shadow_origin[2], shadow_texco[2]; /* Light to texture space. */ mul_v2_v2fl(shadow_origin, center, linfo->shadow_size / (2.0f * sh_data->radius[c])); /* Find the nearest texel. */ - shadow_texco[0] = round(shadow_origin[0]); - shadow_texco[1] = round(shadow_origin[1]); + shadow_texco[0] = roundf(shadow_origin[0]); + shadow_texco[1] = roundf(shadow_origin[1]); /* Compute offset. */ sub_v2_v2(shadow_texco, shadow_origin); @@ -871,17 +877,32 @@ static void eevee_shadow_cascade_setup(Object *ob, EEVEE_LampsInfo *linfo, EEVEE add_v2_v2(center, shadow_texco); /* Expand the projection to cover frustum range */ + BLI_rctf_init_pt_radius(&rect_cascade, center, sh_data->radius[c]); orthographic_m4(projmat, - center[0] - sh_data->radius[c], - center[0] + sh_data->radius[c], - center[1] - sh_data->radius[c], - center[1] + sh_data->radius[c], + rect_cascade.xmin, rect_cascade.xmax, + rect_cascade.ymin, rect_cascade.ymax, la->clipsta, la->clipend); + if (c == 0) { + memcpy(&rect_clip, &rect_cascade, sizeof(rect_clip)); + } + else { + BLI_rctf_union(&rect_clip, &rect_cascade); + } + mul_m4_m4m4(sh_data->viewprojmat[c], projmat, viewmat); mul_m4_m4m4(cascade_data->shadowmat[c], texcomat, sh_data->viewprojmat[c]); } + /* Clipping mats */ + orthographic_m4(sh_data->clipmat.mat[DRW_MAT_WIN], + rect_clip.xmin, rect_clip.xmax, + rect_clip.ymin, rect_clip.ymax, + la->clipsta, la->clipend); + mul_m4_m4m4(sh_data->clipmat.mat[DRW_MAT_PERS], sh_data->clipmat.mat[DRW_MAT_WIN], viewmat); + invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_WININV], sh_data->clipmat.mat[DRW_MAT_WIN]); + invert_m4_m4(sh_data->clipmat.mat[DRW_MAT_PERSINV], sh_data->clipmat.mat[DRW_MAT_PERS]); + ubo_data->bias = 0.05f * la->bias; ubo_data->near = la->clipsta; ubo_data->far = la->clipend; @@ -983,25 +1004,56 @@ void EEVEE_lights_update(EEVEE_ViewLayerData *sldata) } } +static void eevee_shadows_cube_culling_frustum(EEVEE_ShadowRender *srd) +{ + float persmat[4][4], persinv[4][4]; + float viewmat[4][4], viewinv[4][4]; + float winmat[4][4], wininv[4][4]; + orthographic_m4(winmat, -srd->clip_far, srd->clip_far, -srd->clip_far, srd->clip_far, -srd->clip_far, srd->clip_far); + DRW_viewport_matrix_override_set(winmat, DRW_MAT_WIN); + + invert_m4_m4(wininv, winmat); + DRW_viewport_matrix_override_set(wininv, DRW_MAT_WININV); + + unit_m4(viewmat); + negate_v3_v3(viewmat[3], srd->position); + DRW_viewport_matrix_override_set(viewmat, DRW_MAT_VIEW); + + unit_m4(viewinv); + copy_v3_v3(viewinv[3], srd->position); + DRW_viewport_matrix_override_set(viewinv, DRW_MAT_VIEWINV); + + mul_m4_m4m4(persmat, winmat, viewmat); + DRW_viewport_matrix_override_set(persmat, DRW_MAT_PERS); + + invert_m4_m4(persinv, persmat); + DRW_viewport_matrix_override_set(persinv, DRW_MAT_PERSINV); +} + +static void eevee_shadows_cascade_culling_frustum(EEVEE_ShadowCascadeData *evscd) +{ + DRW_viewport_matrix_override_set_all(&evscd->clipmat); +} + /* this refresh lamps shadow buffers */ 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; + + /* We need to save the Matrices before overidding them */ + DRW_viewport_matrix_get_all(&saved_mats); /* 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); Lamp *la = (Lamp *)ob->data; - float cube_projmat[4][4]; - perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend); - if (!led->need_update) { continue; } @@ -1009,25 +1061,29 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl) EEVEE_ShadowRender *srd = &linfo->shadow_render_data; EEVEE_ShadowCubeData *evscd = &led->data.scd; + float cube_projmat[4][4]; + float cube_viewmat[4][4]; + perspective_m4(cube_projmat, -la->clipsta, la->clipsta, -la->clipsta, la->clipsta, la->clipsta, la->clipend); + unit_m4(cube_viewmat); + srd->clip_near = la->clipsta; srd->clip_far = la->clipend; copy_v3_v3(srd->position, ob->obmat[3]); - for (int j = 0; j < 6; j++) { - float tmp[4][4]; - - unit_m4(tmp); - negate_v3_v3(tmp[3], ob->obmat[3]); - mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], tmp); + negate_v3_v3(cube_viewmat[3], srd->position); + for (int j = 0; j < 6; j++) { + mul_m4_m4m4(srd->viewmat[j], cubefacemat[j], cube_viewmat); mul_m4_m4m4(srd->shadowmat[j], cube_projmat, srd->viewmat[j]); } DRW_uniformbuffer_update(sldata->shadow_render_ubo, srd); - DRW_framebuffer_bind(sldata->shadow_target_fb); - DRW_framebuffer_clear(true, true, false, clear_col, 1.0f); + eevee_shadows_cube_culling_frustum(srd); /* Render shadow cube */ - DRW_draw_pass(psl->shadow_cube_pass); + 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. */ float filter_texture_size = la->soft * 0.001f; @@ -1040,10 +1096,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 */ @@ -1067,20 +1123,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; @@ -1097,11 +1152,13 @@ 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 */ - DRW_draw_pass(psl->shadow_cascade_pass); + 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 */ for (linfo->current_shadow_cascade = 0; @@ -1114,11 +1171,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 */ @@ -1142,15 +1198,16 @@ 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); + DRW_uniformbuffer_update(sldata->light_ubo, &linfo->light_data); DRW_uniformbuffer_update(sldata->shadow_ubo, &linfo->shadow_data); /* Update all data at once */ } diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index cde14f0efc3..d146fda5373 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -52,6 +52,7 @@ /* *********** STATIC *********** */ static struct { + char *shadow_shader_lib; char *frag_shader_lib; char *volume_shader_lib; @@ -70,7 +71,6 @@ static struct { unsigned int sss_count; - float view_vecs[2][4]; float alpha_hash_offset; float noise_offsets[3]; } e_data = {NULL}; /* Engine data */ @@ -89,6 +89,7 @@ extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; @@ -145,9 +146,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"); @@ -207,9 +208,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"); @@ -223,7 +224,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"); @@ -375,46 +376,47 @@ static void add_standard_uniforms( DRW_shgroup_uniform_block(shgrp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(shgrp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(shgrp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_block(shgrp, "clip_block", sldata->clip_ubo); /* TODO if glossy or diffuse bsdf */ if (true) { DRW_shgroup_uniform_texture(shgrp, "utilTex", e_data.util_tex); - DRW_shgroup_uniform_buffer(shgrp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_buffer(shgrp, "maxzBuffer", &vedata->txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(shgrp, "shadowTexture", &sldata->shadow_pool); + DRW_shgroup_uniform_texture_ref(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_texture_ref(shgrp, "horizonBuffer", &vedata->stl->effects->gtao_horizons); } else { /* Use maxzbuffer as fallback to avoid sampling problem on certain platform, see: T52593 */ - DRW_shgroup_uniform_buffer(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(shgrp, "horizonBuffer", &vedata->txl->maxzbuffer); } } /* TODO if diffuse bsdf */ if (true) { - DRW_shgroup_uniform_buffer(shgrp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_texture_ref(shgrp, "irradianceGrid", &sldata->irradiance_pool); } /* TODO if glossy bsdf */ if (true) { - DRW_shgroup_uniform_buffer(shgrp, "probeCubes", &sldata->probe_pool); - DRW_shgroup_uniform_buffer(shgrp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_texture_ref(shgrp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_texture_ref(shgrp, "probePlanars", &vedata->txl->planar_pool); DRW_shgroup_uniform_int(shgrp, "outputSsrId", ssr_id, 1); } if (use_ssrefraction) { BLI_assert(refract_depth != NULL); DRW_shgroup_uniform_float(shgrp, "refractionDepth", refract_depth, 1); - DRW_shgroup_uniform_buffer(shgrp, "colorBuffer", &vedata->txl->refract_color); + DRW_shgroup_uniform_texture_ref(shgrp, "colorBuffer", &vedata->txl->refract_color); } if ((vedata->stl->effects->enabled_effects & EFFECT_VOLUMETRIC) != 0 && use_alpha_blend) { /* Do not use history buffers as they already have been swapped */ - DRW_shgroup_uniform_buffer(shgrp, "inScattering", &vedata->txl->volume_scatter); - DRW_shgroup_uniform_buffer(shgrp, "inTransmittance", &vedata->txl->volume_transmittance); + DRW_shgroup_uniform_texture_ref(shgrp, "inScattering", &vedata->txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(shgrp, "inTransmittance", &vedata->txl->volume_transmittance); } } @@ -488,7 +490,7 @@ static void eevee_init_util_texture(void) MEM_freeN(texels); } -void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double offsets[3]) +void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]) { e_data.noise_offsets[0] = offsets[0]; e_data.noise_offsets[1] = offsets[1]; @@ -496,17 +498,55 @@ void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double /* 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]) +{ + /* view vectors for the corners of the view frustum. + * Can be used to recreate the world space position easily */ + float view_vecs[4][4] = { + {-1.0f, -1.0f, -1.0f, 1.0f}, + { 1.0f, -1.0f, -1.0f, 1.0f}, + {-1.0f, 1.0f, -1.0f, 1.0f}, + {-1.0f, -1.0f, 1.0f, 1.0f} + }; + + /* convert the view vectors to view space */ + const bool is_persp = (winmat[3][3] == 0.0f); + for (int i = 0; i < 4; i++) { + mul_project_m4_v3(invproj, view_vecs[i]); + /* normalized trick see: + * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + if (is_persp) { + /* Divide XY by Z. */ + mul_v2_fl(view_vecs[i], 1.0f / view_vecs[i][2]); + } + } + + /** + * If ortho : view_vecs[0] is the near-bottom-left corner of the frustum and + * view_vecs[1] is the vector going from the near-bottom-left corner to + * the far-top-right corner. + * If Persp : view_vecs[0].xy and view_vecs[1].xy are respectively the bottom-left corner + * when Z = 1, and top-left corner if Z = 1. + * view_vecs[0].z the near clip distance and view_vecs[1].z is the (signed) + * distance from the near plane to the far clip plane. + **/ + copy_v4_v4(r_viewvecs[0], view_vecs[0]); + + /* we need to store the differences */ + r_viewvecs[1][0] = view_vecs[1][0] - view_vecs[0][0]; + r_viewvecs[1][1] = view_vecs[2][1] - view_vecs[0][1]; + r_viewvecs[1][2] = view_vecs[3][2] - view_vecs[0][2]; } void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl) { if (!e_data.frag_shader_lib) { /* Shaders */ - e_data.frag_shader_lib = BLI_string_joinN( + e_data.shadow_shader_lib = BLI_string_joinN( datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, @@ -530,7 +570,12 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E datatoc_lit_surface_frag_glsl, datatoc_volumetric_lib_glsl); + e_data.frag_shader_lib = BLI_string_joinN( + datatoc_common_view_lib_glsl, + e_data.shadow_shader_lib); + e_data.volume_shader_lib = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, @@ -584,67 +629,32 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, E eevee_init_noise_texture(); } - /* Alpha hash scale: Non-flickering size if we are not refining the render. */ if (!DRW_state_is_image_render() && - (((stl->effects->enabled_effects & EFFECT_TAA) == 0) || - (stl->effects->taa_current_sample == 1))) + ((stl->effects->enabled_effects & EFFECT_TAA) == 0)) { e_data.alpha_hash_offset = 0.0f; } else { double r; - BLI_halton_1D(5, 0.0, stl->effects->taa_current_sample, &r); + BLI_halton_1D(5, 0.0, stl->effects->taa_current_sample - 1, &r); e_data.alpha_hash_offset = (float)r; } { /* Update view_vecs */ - const bool is_persp = DRW_viewport_is_persp_get(); float invproj[4][4], winmat[4][4]; - /* view vectors for the corners of the view frustum. - * Can be used to recreate the world space position easily */ - float view_vecs[3][4] = { - {-1.0f, -1.0f, -1.0f, 1.0f}, - {1.0f, -1.0f, -1.0f, 1.0f}, - {-1.0f, 1.0f, -1.0f, 1.0f} - }; - - /* invert the view matrix */ DRW_viewport_matrix_get(winmat, DRW_MAT_WIN); - invert_m4_m4(invproj, winmat); - - /* convert the view vectors to view space */ - for (int i = 0; i < 3; i++) { - mul_m4_v4(invproj, view_vecs[i]); - /* normalized trick see: - * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ - mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][3]); - if (is_persp) - mul_v3_fl(view_vecs[i], 1.0f / view_vecs[i][2]); - view_vecs[i][3] = 1.0; - } - - copy_v4_v4(sldata->common_data.view_vecs[0], view_vecs[0]); - copy_v4_v4(sldata->common_data.view_vecs[1], view_vecs[1]); + DRW_viewport_matrix_get(invproj, DRW_MAT_WININV); - /* we need to store the differences */ - sldata->common_data.view_vecs[1][0] -= view_vecs[0][0]; - sldata->common_data.view_vecs[1][1] = view_vecs[2][1] - view_vecs[0][1]; - - /* calculate a depth offset as well */ - if (!is_persp) { - float vec_far[] = {-1.0f, -1.0f, 1.0f, 1.0f}; - mul_m4_v4(invproj, vec_far); - mul_v3_fl(vec_far, 1.0f / vec_far[3]); - sldata->common_data.view_vecs[1][2] = vec_far[2] - view_vecs[0][2]; - } + EEVEE_update_viewvecs(invproj, winmat, sldata->common_data.view_vecs); } { /* 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) + }); } } @@ -653,12 +663,12 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor const void *engine = &DRW_engine_viewport_eevee_type; const int options = VAR_WORLD_PROBE; - GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options); if (mat != NULL) { return mat; } - return GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine, options, + return DRW_shader_create_from_world( + scene, wo, engine, options, datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib, SHADER_DEFINES "#define PROBE_CAPTURE\n"); } @@ -668,12 +678,12 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_WORLD_BACKGROUND; - GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options); if (mat != NULL) { return mat; } - return GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine, options, + return DRW_shader_create_from_world( + scene, wo, engine, options, datatoc_background_vert_glsl, NULL, e_data.frag_shader_lib, SHADER_DEFINES "#define WORLD_BACKGROUND\n"); } @@ -683,15 +693,15 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_WORLD_VOLUME; - GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_world(wo, engine, options); if (mat != NULL) { return mat; } char *defines = eevee_get_volume_defines(options); - mat = GPU_material_from_nodetree( - scene, wo->nodetree, &wo->gpumaterial, engine, options, + mat = DRW_shader_create_from_world( + scene, wo, engine, options, datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib, defines); @@ -718,15 +728,15 @@ struct GPUMaterial *EEVEE_material_mesh_get( options |= eevee_material_shadow_option(shadow_method); - GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options); if (mat) { return mat; } char *defines = eevee_get_defines(options); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, datatoc_lit_surface_vert_glsl, NULL, e_data.frag_shader_lib, defines); @@ -740,15 +750,15 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material const void *engine = &DRW_engine_viewport_eevee_type; int options = VAR_MAT_VOLUME; - GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options); if (mat != NULL) { return mat; } char *defines = eevee_get_volume_defines(options); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, datatoc_volumetric_vert_glsl, datatoc_volumetric_geom_glsl, e_data.volume_shader_lib, defines); @@ -774,7 +784,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( if (is_shadow) options |= VAR_MAT_SHADOW; - GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options); if (mat) { return mat; } @@ -782,11 +792,11 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get( char *defines = eevee_get_defines(options); char *frag_str = BLI_string_joinN( - e_data.frag_shader_lib, + (is_shadow) ? e_data.shadow_shader_lib : e_data.frag_shader_lib, datatoc_prepass_frag_glsl); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, (is_shadow) ? datatoc_shadow_vert_glsl : datatoc_lit_surface_vert_glsl, (is_shadow) ? datatoc_shadow_geom_glsl : NULL, frag_str, @@ -807,7 +817,7 @@ struct GPUMaterial *EEVEE_material_hair_get( if (use_fibers) { options |= VAR_MAT_HAIR_FIBERS; } - GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine, options); + GPUMaterial *mat = DRW_shader_find_from_material(ma, engine, options); if (mat) { return mat; } @@ -823,8 +833,8 @@ struct GPUMaterial *EEVEE_material_hair_get( char *defines = eevee_get_defines(options); - mat = GPU_material_from_nodetree( - scene, ma->nodetree, &ma->gpumaterial, engine, options, + mat = DRW_shader_create_from_material( + scene, ma, engine, options, vert_str, NULL, e_data.frag_shader_lib, defines); @@ -891,13 +901,15 @@ static struct DRWShadingGroup *EEVEE_default_shading_group_get( vedata->psl->default_pass[options] = DRW_pass_create("Default Lit Pass", state); DRWShadingGroup *shgrp = DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); + /* XXX / WATCH: This creates non persistent binds for the ubos and textures. + * But it's currently OK because the following shgroups does not add any bind. */ add_standard_uniforms(shgrp, sldata, vedata, &ssr_id, NULL, false, false); } return DRW_shgroup_create(e_data.default_lit[options], vedata->psl->default_pass[options]); } -void EEVEE_materials_cache_init(EEVEE_Data *vedata) +void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; @@ -924,17 +936,25 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) col = &wo->horr; if (wo->use_nodes && wo->nodetree) { + static float error_col[3] = {1.0f, 0.0f, 1.0f}; + static float compile_col[3] = {0.5f, 0.5f, 0.5f}; struct GPUMaterial *gpumat = EEVEE_material_world_background_get(scene, wo); - grp = DRW_shgroup_material_create(gpumat, psl->background_pass); - if (grp) { - DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); - DRW_shgroup_call_add(grp, geom, NULL); - } - else { - /* Shader failed : pink background */ - static float pink[3] = {1.0f, 0.0f, 1.0f}; - col = pink; + switch (GPU_material_status(gpumat)) { + case GPU_MAT_SUCCESS: + grp = DRW_shgroup_material_create(gpumat, psl->background_pass); + DRW_shgroup_uniform_float(grp, "backgroundAlpha", &stl->g_data->background_alpha, 1); + DRW_shgroup_call_add(grp, geom, NULL); + break; + case GPU_MAT_QUEUED: + sldata->probes->all_materials_updated = false; + /* TODO Bypass probe compilation. */ + col = compile_col; + break; + case GPU_MAT_FAILED: + default: + col = error_col; + break; } } } @@ -963,11 +983,15 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) psl->depth_pass_clip = DRW_pass_create("Depth Pass Clip", state); stl->g_data->depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip); stl->g_data->hair_fibers_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_hair_fiber_clip_sh, psl->depth_pass_clip); + DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip, "clip_block", sldata->clip_ubo); + DRW_shgroup_uniform_block(stl->g_data->hair_fibers_depth_shgrp_clip, "clip_block", sldata->clip_ubo); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK; psl->depth_pass_clip_cull = DRW_pass_create("Depth Pass Cull Clip", state); stl->g_data->depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->depth_pass_clip_cull); stl->g_data->hair_fibers_depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_hair_fiber_clip_sh, psl->depth_pass_clip_cull); + DRW_shgroup_uniform_block(stl->g_data->depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); + DRW_shgroup_uniform_block(stl->g_data->hair_fibers_depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); } { @@ -987,10 +1011,12 @@ void EEVEE_materials_cache_init(EEVEE_Data *vedata) state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_WIRE; psl->refract_depth_pass_clip = DRW_pass_create("Refract Depth Pass Clip", state); stl->g_data->refract_depth_shgrp_clip = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip); + DRW_shgroup_uniform_block(stl->g_data->refract_depth_shgrp_clip, "clip_block", sldata->clip_ubo); state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | DRW_STATE_CLIP_PLANES | DRW_STATE_CULL_BACK; psl->refract_depth_pass_clip_cull = DRW_pass_create("Refract Depth Pass Cull Clip", state); stl->g_data->refract_depth_shgrp_clip_cull = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->refract_depth_pass_clip_cull); + DRW_shgroup_uniform_block(stl->g_data->refract_depth_shgrp_clip_cull, "clip_block", sldata->clip_ubo); } { @@ -1080,53 +1106,29 @@ static void material_opaque( } if (use_gpumat) { + static float error_col[3] = {1.0f, 0.0f, 1.0f}; + static float compile_col[3] = {0.5f, 0.5f, 0.5f}; + static float half = 0.5f; + /* Shading */ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, false, false, use_refract, use_sss, use_translucency, linfo->shadow_method); - *shgrp = DRW_shgroup_material_create(*gpumat, - (use_refract) ? psl->refract_pass : - (use_sss) ? psl->sss_pass : psl->material_pass); - if (*shgrp) { - static int no_ssr = -1; - static int first_ssr = 1; - int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr; - add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false); - - if (use_sss) { - struct GPUTexture *sss_tex_profile = NULL; - struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(*gpumat, - stl->effects->sss_sample_count, - &sss_tex_profile); - - if (sss_profile) { - if (use_translucency) { - DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile); - DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile); - } - - DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); - EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); - e_data.sss_count++; - } - } - } - else { - /* Shader failed : pink color */ - static float col[3] = {1.0f, 0.0f, 1.0f}; - static float half = 0.5f; - - color_p = col; - metal_p = spec_p = rough_p = ½ - } + GPUMaterialStatus status_mat_surface = GPU_material_status(*gpumat); /* Alpha CLipped : Discard pixel from depth pass, then * fail the depth test for shading. */ if (ELEM(ma->blend_method, MA_BM_CLIP, MA_BM_HASHED)) { *gpumat_depth = EEVEE_material_mesh_depth_get(scene, ma, - (ma->blend_method == MA_BM_HASHED), false); + (ma->blend_method == MA_BM_HASHED), false); - if (use_refract) { + GPUMaterialStatus status_mat_depth = GPU_material_status(*gpumat_depth); + if (status_mat_depth != GPU_MAT_SUCCESS) { + /* Mixing both flags. If depth shader fails, show it to the user by not using + * the surface shader. */ + status_mat_surface = status_mat_depth; + } + else if (use_refract) { *shgrp_depth = DRW_shgroup_material_create(*gpumat_depth, (do_cull) ? psl->refract_depth_pass_cull : psl->refract_depth_pass); *shgrp_depth_clip = DRW_shgroup_material_create(*gpumat_depth, (do_cull) ? psl->refract_depth_pass_clip_cull : psl->refract_depth_pass_clip); } @@ -1137,6 +1139,7 @@ static void material_opaque( if (*shgrp_depth != NULL) { add_standard_uniforms(*shgrp_depth, sldata, vedata, NULL, NULL, false, false); + add_standard_uniforms(*shgrp_depth_clip, sldata, vedata, NULL, NULL, false, false); if (ma->blend_method == MA_BM_CLIP) { DRW_shgroup_uniform_float(*shgrp_depth, "alphaThreshold", &ma->alpha_threshold, 1); @@ -1148,6 +1151,59 @@ static void material_opaque( } } } + + switch (status_mat_surface) { + case GPU_MAT_SUCCESS: + { + static int no_ssr = -1; + static int first_ssr = 1; + int *ssr_id = (((effects->enabled_effects & EFFECT_SSR) != 0) && !use_refract) ? &first_ssr : &no_ssr; + + *shgrp = DRW_shgroup_material_create(*gpumat, + (use_refract) ? psl->refract_pass : + (use_sss) ? psl->sss_pass : psl->material_pass); + add_standard_uniforms(*shgrp, sldata, vedata, ssr_id, &ma->refract_depth, use_refract, false); + + if (use_sss) { + struct GPUTexture *sss_tex_profile = NULL; + struct GPUUniformBuffer *sss_profile = GPU_material_sss_profile_get(*gpumat, + stl->effects->sss_sample_count, + &sss_tex_profile); + + if (sss_profile) { + if (use_translucency) { + DRW_shgroup_uniform_block(*shgrp, "sssProfile", sss_profile); + DRW_shgroup_uniform_texture(*shgrp, "sssTexProfile", sss_tex_profile); + } + + /* Limit of 8 bit stencil buffer. ID 255 is refraction. */ + if (e_data.sss_count < 254) { + DRW_shgroup_stencil_mask(*shgrp, e_data.sss_count + 1); + EEVEE_subsurface_add_pass(sldata, vedata, e_data.sss_count + 1, sss_profile); + e_data.sss_count++; + } + else { + /* TODO : display message. */ + printf("Error: Too many different Subsurface shader in the scene.\n"); + } + } + } + break; + } + case GPU_MAT_QUEUED: + { + sldata->probes->all_materials_updated = false; + /* TODO Bypass probe compilation. */ + color_p = compile_col; + metal_p = spec_p = rough_p = ½ + break; + } + case GPU_MAT_FAILED: + default: + color_p = error_col; + metal_p = spec_p = rough_p = ½ + break; + } } /* Fallback to default shader */ @@ -1172,7 +1228,7 @@ static void material_opaque( } } - emsg = MEM_mallocN(sizeof("EeveeMaterialShadingGroups"), "EeveeMaterialShadingGroups"); + emsg = MEM_mallocN(sizeof(EeveeMaterialShadingGroups), "EeveeMaterialShadingGroups"); emsg->shading_grp = *shgrp; emsg->depth_grp = *shgrp_depth; emsg->depth_clip_grp = *shgrp_depth_clip; @@ -1197,23 +1253,37 @@ static void material_transparent( float *rough_p = &ma->gloss_mir; if (ma->use_nodes && ma->nodetree) { + static float error_col[3] = {1.0f, 0.0f, 1.0f}; + static float compile_col[3] = {0.5f, 0.5f, 0.5f}; + static float half = 0.5f; + /* Shading */ *gpumat = EEVEE_material_mesh_get(scene, ma, vedata, true, (ma->blend_method == MA_BM_MULTIPLY), use_refract, false, false, linfo->shadow_method); - *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); - if (*shgrp) { - static int ssr_id = -1; /* TODO transparent SSR */ - bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0; - add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend); - } - else { - /* Shader failed : pink color */ - static float col[3] = {1.0f, 0.0f, 1.0f}; - static float half = 0.5f; + switch (GPU_material_status(*gpumat)) { + case GPU_MAT_SUCCESS: + { + static int ssr_id = -1; /* TODO transparent SSR */ + bool use_blend = (ma->blend_method & MA_BM_BLEND) != 0; - color_p = col; - metal_p = spec_p = rough_p = ½ + *shgrp = DRW_shgroup_material_create(*gpumat, psl->transparent_pass); + add_standard_uniforms(*shgrp, sldata, vedata, &ssr_id, &ma->refract_depth, use_refract, use_blend); + break; + } + case GPU_MAT_QUEUED: + { + sldata->probes->all_materials_updated = false; + /* TODO Bypass probe compilation. */ + color_p = compile_col; + metal_p = spec_p = rough_p = ½ + break; + } + case GPU_MAT_FAILED: + default: + color_p = error_col; + metal_p = spec_p = rough_p = ½ + break; } } @@ -1259,6 +1329,7 @@ static void material_transparent( /* Depth prepass */ if (use_prepass) { *shgrp_depth = DRW_shgroup_create(e_data.default_prepass_clip_sh, psl->transparent_pass); + DRW_shgroup_uniform_block(*shgrp_depth, "clip_block", sldata->clip_ubo); cur_state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS; cur_state |= (do_cull) ? DRW_STATE_CULL_BACK : 0; @@ -1442,8 +1513,8 @@ static void material_hair( void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob) { - EEVEE_PassList *psl = ((EEVEE_Data *)vedata)->psl; - EEVEE_StorageList *stl = ((EEVEE_Data *)vedata)->stl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; GHash *material_hash = stl->g_data->material_hash; @@ -1451,7 +1522,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld IDProperty *ces_mode_ob = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_OBJECT, ""); const bool do_cull = BKE_collection_engine_property_value_get_bool(ces_mode_ob, "show_backface_culling"); const bool is_active = (ob == draw_ctx->obact); - const bool is_sculpt_mode = is_active && (ob->mode & OB_MODE_SCULPT) != 0; + const bool is_sculpt_mode = is_active && (draw_ctx->object_mode & OB_MODE_SCULPT) != 0; #if 0 const bool is_sculpt_mode_draw = is_sculpt_mode && (draw_ctx->v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) == 0; #else @@ -1559,7 +1630,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld struct GPUMaterial *gpumat; switch (ma->blend_shadow) { case MA_BS_SOLID: - EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat); + EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob); break; case MA_BS_CLIP: gpumat = EEVEE_material_mesh_depth_get(scene, ma, false, true); @@ -1575,7 +1646,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld } } else { - EEVEE_lights_cache_shcaster_add(sldata, psl, mat_geom[i], ob->obmat); + EEVEE_lights_cache_shcaster_add(sldata, stl, mat_geom[i], ob); } } } @@ -1587,7 +1658,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sld } if (ob->type == OB_MESH) { - if (ob != draw_ctx->scene->obedit) { + if (ob != draw_ctx->object_edit) { for (ModifierData *md = ob->modifiers.first; md; md = md->next) { if (md->type == eModifierType_ParticleSystem) { ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; @@ -1619,6 +1690,7 @@ void EEVEE_materials_free(void) for (int i = 0; i < VAR_MAT_MAX; ++i) { DRW_SHADER_FREE_SAFE(e_data.default_lit[i]); } + MEM_SAFE_FREE(e_data.shadow_shader_lib); MEM_SAFE_FREE(e_data.frag_shader_lib); MEM_SAFE_FREE(e_data.volume_shader_lib); DRW_SHADER_FREE_SAFE(e_data.default_prepass_sh); diff --git a/source/blender/draw/engines/eevee/eevee_mist.c b/source/blender/draw/engines/eevee/eevee_mist.c new file mode 100644 index 00000000000..1675142613d --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_mist.c @@ -0,0 +1,139 @@ +/* + * 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 eevee_mist.c + * \ingroup draw_engine + * + * Implementation of Blender Mist pass. + * IMPORTANT: This is a "post process" of the Z depth so it will lack any transparent objects. + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "DNA_world_types.h" + +#include "BLI_string_utils.h" + +#include "eevee_private.h" + +extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_common_uniforms_lib_glsl[]; +extern char datatoc_bsdf_common_lib_glsl[]; +extern char datatoc_effect_mist_frag_glsl[]; + +static struct { + struct GPUShader *mist_sh; +} e_data = {NULL}; /* Engine data */ + +void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + EEVEE_FramebufferList *fbl = vedata->fbl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + EEVEE_TextureList *txl = vedata->txl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PassList *psl = vedata->psl; + EEVEE_PrivateData *g_data = stl->g_data; + Scene *scene = draw_ctx->scene; + + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + if (e_data.mist_sh == NULL) { + char *frag_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, + datatoc_common_uniforms_lib_glsl, + datatoc_bsdf_common_lib_glsl, + datatoc_effect_mist_frag_glsl); + + e_data.mist_sh = DRW_shader_create_fullscreen(frag_str, "#define FIRST_PASS\n"); + + MEM_freeN(frag_str); + } + + /* Create FrameBuffer. */ + 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. */ + GPU_framebuffer_bind(fbl->mist_accum_fb); + GPU_framebuffer_clear_color(fbl->mist_accum_fb, clear); + + /* Mist settings. */ + if (scene && scene->world) { + g_data->mist_start = scene->world->miststa; + g_data->mist_inv_dist = (scene->world->mistdist > 0.0f) ? 1.0f / scene->world->mistdist : 0.0f; + + switch (scene->world->mistype) { + case WO_MIST_QUADRATIC: + g_data->mist_falloff = 2.0f; + break; + case WO_MIST_LINEAR: + g_data->mist_falloff = 1.0f; + break; + case WO_MIST_INVERSE_QUADRATIC: + g_data->mist_falloff = 0.5f; + break; + } + } + else { + float near = -sldata->common_data.view_vecs[0][2]; + float range = sldata->common_data.view_vecs[1][2]; + /* Fallback */ + g_data->mist_start = near; + g_data->mist_inv_dist = 1.0f / fabsf(range); + g_data->mist_falloff = 1.0f; + } + + /* XXX ??!! WHY? If not it does not match cycles. */ + g_data->mist_falloff *= 0.5f; + + /* Create Pass and shgroup. */ + psl->mist_accum_ps = DRW_pass_create("Mist Accum", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.mist_sh, psl->mist_accum_ps); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_vec3(grp, "mistSettings", &g_data->mist_start, 1); + DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); +} + +void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + + if (fbl->mist_accum_fb != NULL) { + GPU_framebuffer_bind(fbl->mist_accum_fb); + DRW_draw_pass(psl->mist_accum_ps); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + +void EEVEE_mist_free(void) +{ + DRW_SHADER_FREE_SAFE(e_data.mist_sh); +} diff --git a/source/blender/draw/engines/eevee/eevee_motion_blur.c b/source/blender/draw/engines/eevee/eevee_motion_blur.c index b05fbf8c7fb..9b19163c8d7 100644 --- a/source/blender/draw/engines/eevee/eevee_motion_blur.c +++ b/source/blender/draw/engines/eevee/eevee_motion_blur.c @@ -59,7 +59,6 @@ static void eevee_motion_blur_camera_get_matrix_at_time( float time, float r_mat[4][4]) { - EvaluationContext eval_ctx; float obmat[4][4]; /* HACK */ @@ -68,18 +67,9 @@ static void eevee_motion_blur_camera_get_matrix_at_time( memcpy(&camdata_cpy, camera->data, sizeof(camdata_cpy)); cam_cpy.data = &camdata_cpy; - /* NOTE: Mode corresponds to old usage of eval_ctx from viewport (which was - * actually coming from bmain). It was always DAG_EVAL_VIEWPORT. For F12 - * render this should be DAG_EVAL_RENDER, but the whole hack is to be - * reconsidered first anyway. - */ const DRWContextState *draw_ctx = DRW_context_state_get(); - DEG_evaluation_context_init_from_scene( - &eval_ctx, - scene, - draw_ctx->view_layer, - draw_ctx->engine_type, - DAG_EVAL_VIEWPORT); + /* We will be modifying time, so we create copy of eval_ctx. */ + EvaluationContext eval_ctx = draw_ctx->eval_ctx; eval_ctx.ctime = time; /* Past matrix */ @@ -93,27 +83,15 @@ static void eevee_motion_blur_camera_get_matrix_at_time( CameraParams params; BKE_camera_params_init(¶ms); - /* copy of BKE_camera_params_from_view3d */ - { - params.lens = v3d->lens; - params.clipsta = v3d->near; - params.clipend = v3d->far; - - /* camera view */ + if (v3d != NULL) { + BKE_camera_params_from_view3d(¶ms, draw_ctx->depsgraph, v3d, rv3d); + BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); + } + else { BKE_camera_params_from_object(¶ms, &cam_cpy); - - params.zoom = BKE_screen_view3d_zoom_to_fac(rv3d->camzoom); - - params.offsetx = 2.0f * rv3d->camdx * params.zoom; - params.offsety = 2.0f * rv3d->camdy * params.zoom; - - params.shiftx *= params.zoom; - params.shifty *= params.zoom; - - params.zoom = CAMERA_PARAM_ZOOM_INIT_CAMOB / params.zoom; + BKE_camera_params_compute_viewplane(¶ms, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp); } - BKE_camera_params_compute_viewplane(¶ms, ar->winx, ar->winy, 1.0f, 1.0f); BKE_camera_params_compute_matrix(¶ms); /* FIXME Should be done per view (MULTIVIEW) */ @@ -127,7 +105,7 @@ static void eevee_create_shader_motion_blur(void) e_data.motion_blur_sh = DRW_shader_create_fullscreen(datatoc_effect_motion_blur_frag_glsl, NULL); } -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata, Object *camera) { EEVEE_StorageList *stl = vedata->stl; EEVEE_EffectsInfo *effects = stl->effects; @@ -144,11 +122,11 @@ int EEVEE_motion_blur_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *veda if (BKE_collection_engine_property_value_get_bool(props, "motion_blur_enable")) { /* Update Motion Blur Matrices */ - if (rv3d->persp == RV3D_CAMOB && v3d->camera) { + if (camera) { float persmat[4][4]; float ctime = BKE_scene_frame_get(scene); float delta = BKE_collection_engine_property_value_get_float(props, "motion_blur_shutter"); - Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); + Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, camera); /* Current matrix */ eevee_motion_blur_camera_get_matrix_at_time(scene, @@ -212,8 +190,8 @@ void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Dat DRW_shgroup_uniform_int(grp, "samples", &effects->motion_blur_samples, 1); DRW_shgroup_uniform_mat4(grp, "currInvViewProjMatrix", (float *)effects->current_ndc_to_world); DRW_shgroup_uniform_mat4(grp, "pastViewProjMatrix", (float *)effects->past_world_to_ndc); - DRW_shgroup_uniform_buffer(grp, "colorBuffer", &effects->source_buffer); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &effects->source_buffer); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_call_add(grp, quad, NULL); } } @@ -228,7 +206,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 9da438e825f..9fd7f6d4126 100644 --- a/source/blender/draw/engines/eevee/eevee_occlusion.c +++ b/source/blender/draw/engines/eevee/eevee_occlusion.c @@ -44,6 +44,7 @@ static struct { } e_data = {NULL}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_gtao_frag_glsl[]; @@ -51,6 +52,7 @@ extern char datatoc_effect_gtao_frag_glsl[]; static void eevee_create_shader_occlusion(void) { char *frag_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, @@ -66,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; @@ -78,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) { @@ -98,31 +101,82 @@ 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; } +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; + 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, "gtao_enable")) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + float clear[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + + 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. */ + 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; + psl->ao_accum_ps = DRW_pass_create("AO Accum", state); + DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_accum_ps); + DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); + DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_texture_ref(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); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->ao_accum_fb); + } +} + void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; @@ -148,16 +202,16 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) psl->ao_horizon_search = DRW_pass_create("GTAO Horizon Search", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.gtao_sh, psl->ao_horizon_search); 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", &effects->ao_src_depth); + DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, quad, NULL); psl->ao_horizon_search_layer = DRW_pass_create("GTAO Horizon Search Layer", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.gtao_layer_sh, psl->ao_horizon_search_layer); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); - DRW_shgroup_uniform_buffer(grp, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_buffer(grp, "depthBufferLayered", &effects->ao_src_depth); + DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(grp, "depthBufferLayered", &effects->ao_src_depth); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_uniform_int(grp, "layer", &stl->effects->ao_depth_layer, 1); DRW_shgroup_call_add(grp, quad, NULL); @@ -166,10 +220,10 @@ void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) psl->ao_horizon_debug = DRW_pass_create("GTAO Horizon Debug", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.gtao_debug_sh, psl->ao_horizon_debug); 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_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, quad, NULL); } @@ -189,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); @@ -199,7 +253,7 @@ void EEVEE_occlusion_compute( } /* Restore */ - DRW_framebuffer_bind(fbl->main); + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } @@ -215,19 +269,36 @@ 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(); } } +void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) +{ + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_PassList *psl = vedata->psl; + + if (fbl->ao_accum_fb != NULL) { + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + /* Update the min_max/horizon buffers so the refracion materials appear in it. */ + EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); + EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); + + GPU_framebuffer_bind(fbl->ao_accum_fb); + DRW_draw_pass(psl->ao_accum_ps); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + void EEVEE_occlusion_free(void) { DRW_SHADER_FREE_SAFE(e_data.gtao_sh); diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 22440fb62c6..d203fadc073 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -29,6 +29,8 @@ struct Object; struct EEVEE_BoundSphere; struct EEVEE_ShadowCasterBuffer; +struct RenderLayer; +struct RenderResult; extern struct DrawEngineType draw_engine_eevee_type; @@ -70,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) @@ -105,22 +108,22 @@ enum { VAR_MAT_BLEND = (1 << 4), VAR_MAT_VSM = (1 << 5), VAR_MAT_ESM = (1 << 6), - VAR_MAT_HAIR_FIBERS = (1 << 7), + VAR_MAT_VOLUME = (1 << 7), + VAR_MAT_HAIR_FIBERS = (1 << 8), /* Max number of variation */ /* IMPORTANT : Leave it last and set * it's value accordingly. */ - VAR_MAT_MAX = (1 << 8), + VAR_MAT_MAX = (1 << 9), /* These are options that are not counted in VAR_MAT_MAX * because they are not cumulative with the others above. */ - VAR_MAT_CLIP = (1 << 9), - VAR_MAT_HASH = (1 << 10), - VAR_MAT_MULT = (1 << 11), - VAR_MAT_SHADOW = (1 << 12), - VAR_MAT_REFRACT = (1 << 12), - VAR_MAT_VOLUME = (1 << 13), - VAR_MAT_SSS = (1 << 14), - VAR_MAT_TRANSLUC = (1 << 15), - VAR_MAT_SSSALBED = (1 << 16), + VAR_MAT_CLIP = (1 << 10), + VAR_MAT_HASH = (1 << 11), + VAR_MAT_MULT = (1 << 12), + VAR_MAT_SHADOW = (1 << 13), + VAR_MAT_REFRACT = (1 << 14), + VAR_MAT_SSS = (1 << 15), + VAR_MAT_TRANSLUC = (1 << 16), + VAR_MAT_SSSALBED = (1 << 17), }; /* Shadow Technique */ @@ -141,10 +144,8 @@ typedef struct EEVEE_BoundBox { typedef struct EEVEE_PassList { /* Shadows */ struct DRWPass *shadow_pass; - struct DRWPass *shadow_cube_pass; struct DRWPass *shadow_cube_copy_pass; struct DRWPass *shadow_cube_store_pass; - struct DRWPass *shadow_cascade_pass; struct DRWPass *shadow_cascade_copy_pass; struct DRWPass *shadow_cascade_store_pass; @@ -161,6 +162,8 @@ typedef struct EEVEE_PassList { struct DRWPass *ao_horizon_search; struct DRWPass *ao_horizon_search_layer; struct DRWPass *ao_horizon_debug; + struct DRWPass *ao_accum_ps; + struct DRWPass *mist_accum_ps; struct DRWPass *motion_blur; struct DRWPass *bloom_blit; struct DRWPass *bloom_downsample_first; @@ -179,6 +182,7 @@ typedef struct EEVEE_PassList { struct DRWPass *ssr_resolve; struct DRWPass *sss_blur_ps; struct DRWPass *sss_resolve_ps; + struct DRWPass *sss_accum_ps; struct DRWPass *color_downsample_ps; struct DRWPass *color_downsample_cube_ps; struct DRWPass *taa_resolve; @@ -215,12 +219,13 @@ 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; struct GPUFrameBuffer *dof_scatter_far_fb; struct GPUFrameBuffer *dof_scatter_near_fb; @@ -229,30 +234,30 @@ typedef struct EEVEE_FramebufferList { struct GPUFrameBuffer *volumetric_integ_fb; struct GPUFrameBuffer *screen_tracing_fb; struct GPUFrameBuffer *refract_fb; + struct GPUFrameBuffer *mist_accum_fb; + struct GPUFrameBuffer *ao_accum_fb; 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 *ssr_normal_input; - struct GPUTexture *ssr_specrough_input; - struct GPUTexture *ssr_hit_output; + struct GPUTexture *mist_accum; + struct GPUTexture *ao_accum; + struct GPUTexture *sss_dir_accum; + struct GPUTexture *sss_col_accum; struct GPUTexture *refract_color; struct GPUTexture *volume_prop_scattering; @@ -267,13 +272,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 */ @@ -356,6 +354,7 @@ typedef struct EEVEE_LampsInfo { int shadow_cube_target_size; int current_shadow_cascade; int current_shadow_face; + unsigned int shadow_instance_count; float filter_size; /* List of lights in the scene. */ /* XXX This is fragile, can get out of sync quickly. */ @@ -431,7 +430,10 @@ typedef struct EEVEE_LightProbesInfo { int target_size; int grid_initialized; struct World *prev_world; + int update_world; + bool prev_wo_sh_compiled; bool do_cube_update; + bool all_materials_updated; /* For rendering probes */ float probemat[6][4][4]; int layer; @@ -467,18 +469,42 @@ enum { }; /* ************ EFFECTS DATA ************* */ + +typedef enum EEVEE_EffectsFlag { + EFFECT_MOTION_BLUR = (1 << 0), + EFFECT_BLOOM = (1 << 1), + EFFECT_DOF = (1 << 2), + EFFECT_VOLUMETRIC = (1 << 3), + EFFECT_SSR = (1 << 4), + EFFECT_DOUBLE_BUFFER = (1 << 5), /* Not really an effect but a feature */ + EFFECT_REFRACT = (1 << 6), + EFFECT_GTAO = (1 << 7), + EFFECT_TAA = (1 << 8), + EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ + EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ + EFFECT_SSS = (1 << 11), +} EEVEE_EffectsFlag; + typedef struct EEVEE_EffectsInfo { - int enabled_effects; + EEVEE_EffectsFlag enabled_effects; bool swap_double_buffer; /* 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; @@ -493,6 +519,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]; @@ -503,6 +531,13 @@ 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 */ int bloom_iteration_ct; float source_texel_size[2]; @@ -513,28 +548,18 @@ 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. */ struct GPUTexture *source_buffer; /* latest updated texture */ struct GPUFrameBuffer *target_buffer; /* next target to render to */ + struct GPUTexture *final_tx; /* Final color to transform to display color space. */ + struct GPUFrameBuffer *final_fb; /* Framebuffer with final_tx as attachement. */ } EEVEE_EffectsInfo; -enum { - EFFECT_MOTION_BLUR = (1 << 0), - EFFECT_BLOOM = (1 << 1), - EFFECT_DOF = (1 << 2), - EFFECT_VOLUMETRIC = (1 << 3), - EFFECT_SSR = (1 << 4), - EFFECT_DOUBLE_BUFFER = (1 << 5), /* Not really an effect but a feature */ - EFFECT_REFRACT = (1 << 6), - EFFECT_GTAO = (1 << 7), - EFFECT_TAA = (1 << 8), - EFFECT_POST_BUFFER = (1 << 9), /* Not really an effect but a feature */ - EFFECT_NORMAL_BUFFER = (1 << 10), /* Not really an effect but a feature */ - EFFECT_SSS = (1 << 11), -}; - /* ***************** COMMON DATA **************** */ /* Common uniform buffer containing all "constant" data over the whole drawing pipeline. */ @@ -587,6 +612,12 @@ typedef struct EEVEE_CommonUniformBuffer { float prb_lod_planar_max; /* float */ } EEVEE_CommonUniformBuffer; +/* ***************** CLIP PLANES DATA **************** */ + +typedef struct EEVEE_ClipPlanesUniformBuffer { + float clip_planes[1][4]; /* must be less than MAX_CLIP_PLANES */ +} EEVEE_ClipPlanesUniformBuffer; + /* ************** SCENE LAYER DATA ************** */ typedef struct EEVEE_ViewLayerData { /* Lamps */ @@ -597,7 +628,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; @@ -615,8 +647,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; @@ -627,6 +659,9 @@ typedef struct EEVEE_ViewLayerData { /* Common Uniform Buffer */ struct EEVEE_CommonUniformBuffer common_data; struct GPUUniformBuffer *common_ubo; + + struct EEVEE_ClipPlanesUniformBuffer clip_data; + struct GPUUniformBuffer *clip_ubo; } EEVEE_ViewLayerData; /* ************ OBJECT DATA ************ */ @@ -641,6 +676,7 @@ typedef struct EEVEE_ShadowCubeData { typedef struct EEVEE_ShadowCascadeData { short light_id, shadow_id, cascade_id, layer_id; float viewprojmat[MAX_CASCADE_NUM][4][4]; /* World->Lamp->NDC : used for rendering the shadow map. */ + DRWMatrixState clipmat; /* Override matrices used for clipping. */ float radius[MAX_CASCADE_NUM]; } EEVEE_ShadowCascadeData; @@ -648,6 +684,8 @@ typedef struct EEVEE_ShadowCascadeData { * It works with even if the object is in multiple layers * because we don't get the same "Object *" for each layer. */ typedef struct EEVEE_LampEngineData { + ObjectEngineData engine_data; + bool need_update; /* This needs to be out of the union to avoid undefined behaviour. */ short prev_cube_shadow_id; @@ -659,6 +697,8 @@ typedef struct EEVEE_LampEngineData { } EEVEE_LampEngineData; typedef struct EEVEE_LightProbeEngineData { + ObjectEngineData engine_data; + /* NOTE: need_full_update is set by dependency graph when the probe or it's * object is updated. This triggers full probe update, including it's * "progressive" GI refresh. @@ -679,14 +719,14 @@ typedef struct EEVEE_LightProbeEngineData { int max_lvl; int probe_id; /* Only used for display data */ float probe_size; /* Only used for display data */ - /* For planar reflection rendering */ - float viewmat[4][4]; - float persmat[4][4]; + DRWMatrixState mats; /* For planar probes */ float planer_eq_offset[4]; struct ListBase captured_object_list; } EEVEE_LightProbeEngineData; typedef struct EEVEE_ObjectEngineData { + ObjectEngineData engine_data; + bool need_update; unsigned int shadow_caster_id; } EEVEE_ObjectEngineData; @@ -717,18 +757,20 @@ typedef struct EEVEE_PrivateData { struct DRWShadingGroup *refract_depth_shgrp_clip_cull; struct DRWShadingGroup *cube_display_shgrp; struct DRWShadingGroup *planar_display_shgrp; - struct DRWShadingGroup *planar_downsample; 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]; /* For double buffering */ bool view_updated; bool valid_double_buffer; + /* Render Matrices */ + float persmat[4][4], persinv[4][4]; + float viewmat[4][4], viewinv[4][4]; + float winmat[4][4], wininv[4][4]; + /* Mist Settings */ + float mist_start, mist_inv_dist, mist_falloff; } EEVEE_PrivateData; /* Transient data */ /* eevee_data.c */ @@ -744,7 +786,7 @@ EEVEE_LampEngineData *EEVEE_lamp_data_ensure(Object *ob); /* eevee_materials.c */ struct GPUTexture *EEVEE_materials_get_util_tex(void); /* XXX */ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, EEVEE_FramebufferList *fbl); -void EEVEE_materials_cache_init(EEVEE_Data *vedata); +void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_materials_cache_populate(EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata, Object *ob); void EEVEE_materials_cache_finish(EEVEE_Data *vedata); struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, struct World *wo); @@ -758,14 +800,14 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, Material struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma, int shadow_method, bool use_fibers); void EEVEE_materials_free(void); void EEVEE_draw_default_passes(EEVEE_PassList *psl); -void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, double offsets[3]); +void EEVEE_update_noise(EEVEE_PassList *psl, EEVEE_FramebufferList *fbl, const double offsets[3]); /* eevee_lights.c */ void EEVEE_lights_init(EEVEE_ViewLayerData *sldata); -void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); +void EEVEE_lights_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lights_cache_add(EEVEE_ViewLayerData *sldata, struct Object *ob); void EEVEE_lights_cache_shcaster_add( - EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct Gwn_Batch *geom, float (*obmat)[4]); + EEVEE_ViewLayerData *sldata, EEVEE_StorageList *stl, struct Gwn_Batch *geom, Object *ob); void EEVEE_lights_cache_shcaster_material_add( EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl, struct GPUMaterial *gpumat, struct Gwn_Batch *geom, struct Object *ob, @@ -777,15 +819,17 @@ void EEVEE_draw_shadows(EEVEE_ViewLayerData *sldata, EEVEE_PassList *psl); void EEVEE_lights_free(void); /* eevee_lightprobes.c */ +bool EEVEE_lightprobes_all_probes_ready(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, Object *ob); void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_refresh(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_lightprobes_refresh_planar(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_lightprobes_free(void); /* eevee_depth_of_field.c */ -int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +int EEVEE_depth_of_field_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); void EEVEE_depth_of_field_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_depth_of_field_draw(EEVEE_Data *vedata); void EEVEE_depth_of_field_free(void); @@ -798,6 +842,8 @@ void EEVEE_bloom_free(void); /* eevee_occlusion.c */ int EEVEE_occlusion_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_occlusion_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_occlusion_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_occlusion_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct GPUTexture *depth_src, int layer); void EEVEE_occlusion_draw_debug(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -813,26 +859,36 @@ void EEVEE_screen_raytrace_free(void); /* eevee_subsurface.c */ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_add_pass( EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, unsigned int sss_id, struct GPUUniformBuffer *sss_profile); void EEVEE_subsurface_data_render(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_subsurface_free(void); /* eevee_motion_blur.c */ -int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +int EEVEE_motion_blur_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, Object *camera); void EEVEE_motion_blur_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_motion_blur_draw(EEVEE_Data *vedata); void EEVEE_motion_blur_free(void); +/* eevee_mist.c */ +void EEVEE_mist_output_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_mist_output_accumulate(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata);; +void EEVEE_mist_free(void); + /* eevee_temporal_sampling.c */ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_temporal_sampling_matrices_calc( + EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], const double ht_point[2]); void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_temporal_sampling_draw(EEVEE_Data *vedata); void EEVEE_temporal_sampling_free(void); /* eevee_volumes.c */ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, unsigned int current_sample); void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata, struct Scene *scene, Object *ob); void EEVEE_volumes_compute(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); @@ -841,15 +897,21 @@ void EEVEE_volumes_free_smoke_textures(void); void EEVEE_volumes_free(void); /* eevee_effects.c */ -void EEVEE_effects_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata); +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); +/* eevee_render.c */ +void EEVEE_render_init(EEVEE_Data *vedata, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_cache(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *depsgraph); +void EEVEE_render_draw(EEVEE_Data *vedata, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); +void EEVEE_render_update_passes(struct RenderEngine *engine, struct Scene *scene, struct ViewLayer *view_layer); + /* Shadow Matrix */ static const float texcomat[4][4] = { /* From NDC to TexCo */ {0.5f, 0.0f, 0.0f, 0.0f}, diff --git a/source/blender/draw/engines/eevee/eevee_render.c b/source/blender/draw/engines/eevee/eevee_render.c new file mode 100644 index 00000000000..130999adb39 --- /dev/null +++ b/source/blender/draw/engines/eevee/eevee_render.c @@ -0,0 +1,562 @@ +/* + * 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 eevee_render.c + * \ingroup draw_engine + */ + +/** + * Render functions for final render outputs. + */ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "DNA_node_types.h" +#include "DNA_object_types.h" + +#include "BLI_rand.h" +#include "BLI_rect.h" + +#include "DEG_depsgraph_query.h" + +#include "GPU_framebuffer.h" +#include "GPU_glew.h" + +#include "RE_pipeline.h" + +#include "eevee_private.h" + +void EEVEE_render_init(EEVEE_Data *ved, RenderEngine *engine, struct Depsgraph *depsgraph) +{ + EEVEE_Data *vedata = (EEVEE_Data *)ved; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_TextureList *txl = vedata->txl; + EEVEE_FramebufferList *fbl = vedata->fbl; + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + Scene *scene = DEG_get_evaluated_scene(depsgraph); + + /* Init default FB and render targets: + * In render mode the default framebuffer is not generated + * because there is no viewport. So we need to manually create it or + * not use it. For code clarity we just allocate it make use of it. */ + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + /* 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); + + 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) { + stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); + } + EEVEE_PrivateData *g_data = stl->g_data; + g_data->background_alpha = DRW_state_draw_background() ? 1.0f : 0.0f; + g_data->valid_double_buffer = 0; + + /* Alloc common ubo data. */ + if (sldata->common_ubo == NULL) { + sldata->common_ubo = DRW_uniformbuffer_create(sizeof(sldata->common_data), &sldata->common_data); + } + if (sldata->clip_ubo == NULL) { + sldata->clip_ubo = DRW_uniformbuffer_create(sizeof(sldata->clip_data), &sldata->clip_data); + } + + /* Set the pers & view matrix. */ + /* TODO(sergey): Shall render hold pointer to an evaluated camera instead? */ + struct Object *camera = DEG_get_evaluated_object(depsgraph, RE_GetCamera(engine->re)); + float frame = BKE_scene_frame_get(scene); + RE_GetCameraWindow(engine->re, camera, frame, g_data->winmat); + RE_GetCameraModelMatrix(engine->re, camera, g_data->viewinv); + + invert_m4_m4(g_data->viewmat, g_data->viewinv); + mul_m4_m4m4(g_data->persmat, g_data->winmat, g_data->viewmat); + invert_m4_m4(g_data->persinv, g_data->persmat); + invert_m4_m4(g_data->wininv, g_data->winmat); + + DRW_viewport_matrix_override_set(g_data->persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(g_data->persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(g_data->winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(g_data->wininv, DRW_MAT_WININV); + DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW); + DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV); + + /* EEVEE_effects_init needs to go first for TAA */ + EEVEE_effects_init(sldata, vedata, camera); + EEVEE_materials_init(sldata, stl, fbl); + EEVEE_lights_init(sldata); + EEVEE_lightprobes_init(sldata, vedata); + + /* INIT CACHE */ + EEVEE_bloom_cache_init(sldata, vedata); + EEVEE_depth_of_field_cache_init(sldata, vedata); + EEVEE_effects_cache_init(sldata, vedata); + EEVEE_lightprobes_cache_init(sldata, vedata); + EEVEE_lights_cache_init(sldata, vedata); + EEVEE_materials_cache_init(sldata, vedata); + EEVEE_motion_blur_cache_init(sldata, vedata); + EEVEE_occlusion_cache_init(sldata, vedata); + EEVEE_screen_raytrace_cache_init(sldata, vedata); + EEVEE_subsurface_cache_init(sldata, vedata); + EEVEE_temporal_sampling_cache_init(sldata, vedata); + EEVEE_volumes_cache_init(sldata, vedata); +} + +void EEVEE_render_cache( + void *vedata, struct Object *ob, + struct RenderEngine *engine, struct Depsgraph *UNUSED(depsgraph)) +{ + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + + char info[42]; + BLI_snprintf(info, sizeof(info), "Syncing %s", ob->id.name + 2); + RE_engine_update_stats(engine, NULL, info); + + if (DRW_check_object_visible_within_active_context(ob) == false) { + return; + } + + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT)) { + EEVEE_materials_cache_populate(vedata, sldata, ob); + + const bool cast_shadow = true; + + if (cast_shadow) { + EEVEE_lights_cache_shcaster_object_add(sldata, ob); + } + } + else if (ob->type == OB_LIGHTPROBE) { + EEVEE_lightprobes_cache_add(sldata, ob); + } + else if (ob->type == OB_LAMP) { + EEVEE_lights_cache_add(sldata, ob); + } +} + +static void eevee_render_result_combined( + RenderLayer *rl, const char *viewname, const rcti *rect, + EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata)) +{ + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_COMBINED, viewname); + + 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( + RenderLayer *rl, const char *viewname, const rcti *rect, + EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + if (vedata->fbl->sss_accum_fb == NULL) { + /* SSS is not enabled. */ + return; + } + + if ((view_layer->passflag & SCE_PASS_SUBSURFACE_COLOR) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_COLOR, viewname); + + 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++) { + rp->rect[i] /= (float)render_samples; + } + } + + if ((view_layer->passflag & SCE_PASS_SUBSURFACE_DIRECT) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_SUBSURFACE_DIRECT, viewname); + + 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++) { + rp->rect[i] /= (float)render_samples; + } + } + + if ((view_layer->passflag & SCE_PASS_SUBSURFACE_INDIRECT) != 0) { + /* Do nothing as all the lighting is in the direct pass. + * TODO : Separate Direct from indirect lighting. */ + } +} + +static void eevee_render_result_normal( + RenderLayer *rl, const char *viewname, const rcti *rect, + EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata)) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + + /* Only read the center texel. */ + if (stl->effects->taa_current_sample > 1) + return; + + if ((view_layer->passflag & SCE_PASS_NORMAL) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_NORMAL, viewname); + + 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) { + if (rp->rect[i] == 0.0f && rp->rect[i + 1] == 0.0f) { + /* If normal is not correct then do not produce NANs. */ + continue; + } + + float fenc[2]; + fenc[0] = rp->rect[i+0] * 4.0f - 2.0f; + fenc[1] = rp->rect[i+1] * 4.0f - 2.0f; + + float f = dot_v2v2(fenc, fenc); + float g = sqrtf(1.0f - f / 4.0f); + + rp->rect[i + 0] = fenc[0] * g; + rp->rect[i + 1] = fenc[1] * g; + rp->rect[i + 2] = 1.0f - f / 2.0f; + + mul_mat3_m4_v3(g_data->viewinv, &rp->rect[i]); + } + } +} + +static void eevee_render_result_z( + RenderLayer *rl, const char *viewname, const rcti *rect, + EEVEE_Data *vedata, EEVEE_ViewLayerData *sldata) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_PrivateData *g_data = stl->g_data; + + /* Only read the center texel. */ + if (stl->effects->taa_current_sample > 1) + return; + + if ((view_layer->passflag & SCE_PASS_Z) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_Z, viewname); + + 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(); + + /* Convert ogl depth [0..1] to view Z [near..far] */ + for (int i = 0; i < rp->rectx * rp->recty; ++i) { + if (rp->rect[i] == 1.0f ) { + rp->rect[i] = 1e10f; /* Background */ + } + else { + if (is_persp) { + rp->rect[i] = rp->rect[i] * 2.0f - 1.0f; + rp->rect[i] = g_data->winmat[3][2] / (rp->rect[i] + g_data->winmat[2][2]); + } + else { + rp->rect[i] = -common_data->view_vecs[0][2] + rp->rect[i] * -common_data->view_vecs[1][2]; + } + } + } + } +} + +static void eevee_render_result_mist( + RenderLayer *rl, const char *viewname, const rcti *rect, + EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + if ((view_layer->passflag & SCE_PASS_MIST) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_MIST, viewname); + + 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++) { + rp->rect[i] /= (float)render_samples; + } + } +} + +static void eevee_render_result_occlusion( + RenderLayer *rl, const char *viewname, const rcti *rect, + EEVEE_Data *vedata, EEVEE_ViewLayerData *UNUSED(sldata), int render_samples) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + + if (vedata->fbl->ao_accum_fb == NULL) { + /* AO is not enabled. */ + return; + } + + if ((view_layer->passflag & SCE_PASS_AO) != 0) { + RenderPass *rp = RE_pass_find_by_name(rl, RE_PASSNAME_AO, viewname); + + 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) { + rp->rect[i] = rp->rect[i + 1] = rp->rect[i+2] = min_ff(1.0f, rp->rect[i] / (float)render_samples); + } + } +} + +static void eevee_render_draw_background(EEVEE_Data *vedata) +{ + 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. */ + 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); + + 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) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + ViewLayer *view_layer = draw_ctx->view_layer; + const char *viewname = RE_GetActiveRenderView(engine->re); + EEVEE_PassList *psl = vedata->psl; + EEVEE_StorageList *stl = vedata->stl; + EEVEE_FramebufferList *fbl = vedata->fbl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); + EEVEE_PrivateData *g_data = stl->g_data; + + /* FINISH CACHE */ + EEVEE_materials_cache_finish(vedata); + EEVEE_lights_cache_finish(sldata); + EEVEE_lightprobes_cache_finish(sldata, vedata); + + /* Sort transparents before the loop. */ + DRW_pass_sort_shgroup_z(psl->transparent_pass); + + /* Push instances attribs to the GPU. */ + DRW_render_instance_buffer_finish(); + + if ((view_layer->passflag & (SCE_PASS_SUBSURFACE_COLOR | + SCE_PASS_SUBSURFACE_DIRECT | + SCE_PASS_SUBSURFACE_INDIRECT)) != 0) + { + EEVEE_subsurface_output_init(sldata, vedata); + } + + if ((view_layer->passflag & SCE_PASS_MIST) != 0) { + EEVEE_mist_output_init(sldata, vedata); + } + + if ((view_layer->passflag & SCE_PASS_AO) != 0) { + EEVEE_occlusion_output_init(sldata, vedata); + } + + IDProperty *props = BKE_view_layer_engine_evaluated_get(view_layer, COLLECTION_MODE_NONE, RE_engine_id_BLENDER_EEVEE); + unsigned int tot_sample = BKE_collection_engine_property_value_get_int(props, "taa_render_samples"); + unsigned int render_samples = 0; + + if (RE_engine_test_break(engine)) { + return; + } + + 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]; + + /* Restore winmat before jittering again. */ + copy_m4_m4(stl->effects->overide_winmat, g_data->winmat); + /* Copy previous persmat to UBO data */ + copy_m4_m4(sldata->common_data.prev_persmat, stl->effects->prev_persmat); + + BLI_halton_3D(primes, offset, stl->effects->taa_current_sample, r); + EEVEE_update_noise(psl, fbl, r); + EEVEE_temporal_sampling_matrices_calc(stl->effects, g_data->viewmat, g_data->persmat, r); + EEVEE_volumes_set_jitter(sldata, stl->effects->taa_current_sample - 1); + EEVEE_materials_init(sldata, stl, fbl); + + /* Set matrices. */ + DRW_viewport_matrix_override_set(stl->effects->overide_persmat, DRW_MAT_PERS); + DRW_viewport_matrix_override_set(stl->effects->overide_persinv, DRW_MAT_PERSINV); + DRW_viewport_matrix_override_set(stl->effects->overide_winmat, DRW_MAT_WIN); + DRW_viewport_matrix_override_set(stl->effects->overide_wininv, DRW_MAT_WININV); + DRW_viewport_matrix_override_set(g_data->viewmat, DRW_MAT_VIEW); + DRW_viewport_matrix_override_set(g_data->viewinv, DRW_MAT_VIEWINV); + + /* Refresh Probes */ + while (EEVEE_lightprobes_all_probes_ready(sldata, vedata) == false) { + RE_engine_update_stats(engine, NULL, "Updating Probes"); + EEVEE_lightprobes_refresh(sldata, vedata); + /* Refreshing probes can take some times, allow exit. */ + if (RE_engine_test_break(engine)) { + return; + } + } + EEVEE_lightprobes_refresh_planar(sldata, vedata); + DRW_uniformbuffer_update(sldata->common_ubo, &sldata->common_data); + + char info[42]; + BLI_snprintf(info, sizeof(info), "Rendering %u / %u samples", render_samples+1, tot_sample); + RE_engine_update_stats(engine, NULL, info); + + /* Refresh Shadows */ + EEVEE_draw_shadows(sldata, psl); + + 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); + /* Create minmax texture */ + EEVEE_create_minmax_buffer(vedata, dtxl->depth, -1); + EEVEE_occlusion_compute(sldata, vedata, dtxl->depth, -1); + EEVEE_volumes_compute(sldata, vedata); + /* Shading pass */ + eevee_render_draw_background(vedata); + GPU_framebuffer_bind(fbl->main_fb); + EEVEE_draw_default_passes(psl); + DRW_draw_pass(psl->material_pass); + EEVEE_subsurface_data_render(sldata, vedata); + /* Effects pre-transparency */ + EEVEE_subsurface_compute(sldata, vedata); + EEVEE_reflection_compute(sldata, vedata); + EEVEE_refraction_compute(sldata, vedata); + /* Opaque refraction */ + DRW_draw_pass(psl->refract_depth_pass); + DRW_draw_pass(psl->refract_depth_pass_cull); + DRW_draw_pass(psl->refract_pass); + /* Subsurface output */ + EEVEE_subsurface_output_accumulate(sldata, vedata); + /* Occlusion output */ + EEVEE_occlusion_output_accumulate(sldata, vedata); + /* Result NORMAL */ + eevee_render_result_normal(rl, viewname, rect, vedata, sldata); + /* Volumetrics Resolve Opaque */ + EEVEE_volumes_resolve(sldata, vedata); + /* Mist output */ + EEVEE_mist_output_accumulate(sldata, vedata); + /* Transparent */ + DRW_draw_pass(psl->transparent_pass); + /* Result Z */ + eevee_render_result_z(rl, viewname, rect, vedata, sldata); + /* Post Process */ + EEVEE_draw_effects(sldata, vedata); + + RE_engine_update_progress(engine, (float)(render_samples++) / (float)tot_sample); + } + + eevee_render_result_combined(rl, viewname, rect, vedata, sldata); + eevee_render_result_subsurface(rl, viewname, rect, vedata, sldata, render_samples); + eevee_render_result_mist(rl, viewname, rect, vedata, sldata, render_samples); + eevee_render_result_occlusion(rl, viewname, rect, vedata, sldata, render_samples); +} + +void EEVEE_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) +{ + int type; + + RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_COMBINED, 4, "RGBA", SOCK_RGBA); + +#define CHECK_PASS(name, channels, chanid) \ + if (view_layer->passflag & (SCE_PASS_ ## name)) { \ + if (channels == 4) type = SOCK_RGBA; \ + else if (channels == 3) type = SOCK_VECTOR; \ + else type = SOCK_FLOAT; \ + RE_engine_register_pass(engine, scene, view_layer, RE_PASSNAME_ ## name, channels, chanid, type); \ + } + + CHECK_PASS(Z, 1, "Z"); + CHECK_PASS(MIST, 1, "Z"); + CHECK_PASS(NORMAL, 3, "XYZ"); + CHECK_PASS(AO, 3, "RGB"); + CHECK_PASS(SUBSURFACE_COLOR, 3, "RGB"); + CHECK_PASS(SUBSURFACE_DIRECT, 3, "RGB"); + +#undef CHECK_PASS +} diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index 2917bfd1236..7d4860ea1b5 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -48,9 +48,10 @@ static struct { /* Theses are just references, not actually allocated */ struct GPUTexture *depth_src; struct GPUTexture *color_src; -} e_data = {NULL}; /* Engine data */ +} e_data = {{NULL}}; /* Engine data */ extern char datatoc_ambient_occlusion_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; @@ -63,6 +64,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) { if (e_data.ssr_sh[options] == NULL) { char *ssr_shader_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_sampling_lib_glsl, @@ -122,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"); @@ -142,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; } @@ -218,11 +213,11 @@ 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, "maxzBuffer", &txl->maxzbuffer); - DRW_shgroup_uniform_buffer(grp, "planarDepth", &vedata->txl->planar_depth); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input); + DRW_shgroup_uniform_texture_ref(grp, "maxzBuffer", &txl->maxzbuffer); + DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); DRW_shgroup_uniform_texture(grp, "utilTex", EEVEE_materials_get_util_tex()); DRW_shgroup_uniform_block(grp, "planar_block", sldata->planar_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); @@ -233,22 +228,22 @@ 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, "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, "prevColorBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &effects->ssr_normal_input); + DRW_shgroup_uniform_texture_ref(grp, "specroughBuffer", &effects->ssr_specrough_input); + DRW_shgroup_uniform_texture_ref(grp, "probeCubes", &sldata->probe_pool); + DRW_shgroup_uniform_texture_ref(grp, "probePlanars", &vedata->txl->planar_pool); + DRW_shgroup_uniform_texture_ref(grp, "planarDepth", &vedata->txl->planar_depth); + DRW_shgroup_uniform_texture_ref(grp, "hitBuffer", &effects->ssr_hit_output); + DRW_shgroup_uniform_texture_ref(grp, "pdfBuffer", &effects->ssr_pdf_output); + DRW_shgroup_uniform_texture_ref(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); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); 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_texture_ref(grp, "horizonBuffer", &effects->gtao_horizons); } DRW_shgroup_call_add(grp, quad, NULL); @@ -263,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); } } @@ -285,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; @@ -318,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 17da4a18b78..ebaf559d22b 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -33,15 +33,17 @@ #include "GPU_texture.h" static struct { - struct GPUShader *sss_sh[3]; -} e_data = {NULL}; /* Engine data */ + struct GPUShader *sss_sh[4]; +} e_data = {{NULL}}; /* Engine data */ +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; static void eevee_create_shader_subsurface(void) { char *frag_str = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_effect_subsurface_frag_glsl); @@ -49,6 +51,9 @@ static void eevee_create_shader_subsurface(void) e_data.sss_sh[1] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n"); e_data.sss_sh[2] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n" "#define USE_SEP_ALBEDO\n"); + e_data.sss_sh[3] = DRW_shader_create_fullscreen(frag_str, "#define SECOND_PASS\n" + "#define USE_SEP_ALBEDO\n" + "#define RESULT_ACCUM\n"); MEM_freeN(frag_str); } @@ -61,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; @@ -71,6 +77,11 @@ int EEVEE_subsurface_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) effects->sss_separate_albedo = BKE_collection_engine_property_value_get_bool(props, "sss_separate_albedo"); common_data->sss_jitter_threshold = BKE_collection_engine_property_value_get_float(props, "sss_jitter_threshold"); + /* Force separate albedo for final render */ + if (DRW_state_is_image_render()) { + effects->sss_separate_albedo = true; + } + /* Shaders */ if (!e_data.sss_sh[0]) { eevee_create_shader_subsurface(); @@ -80,35 +91,94 @@ 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}}; - - DRW_framebuffer_init(&fbl->sss_blur_fb, &draw_engine_eevee_type, (int)viewport_size[0], (int)viewport_size[1], - texs, 2); + 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); + + GPU_framebuffer_ensure_config(&fbl->sss_blur_fb, { + GPU_ATTACHMENT_TEXTURE(effects->sss_stencil), + GPU_ATTACHMENT_TEXTURE(effects->sss_blur) + }); + + 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) + }); - 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); - - if (effects->sss_separate_albedo && (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); + if (effects->sss_separate_albedo) { + 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 { + 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; } +static void set_shgrp_stencil(void *UNUSED(userData), DRWShadingGroup *shgrp) +{ + DRW_shgroup_stencil_mask(shgrp, 255); +} + +void EEVEE_subsurface_output_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + 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; + 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")) { + 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); + + 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. */ + 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 | + DRW_STATE_WIRE | DRW_STATE_WRITE_STENCIL; + DRW_pass_state_set(vedata->psl->refract_pass, state); + DRW_pass_foreach_shgroup(vedata->psl->refract_pass, &set_shgrp_stencil, NULL); + } + else { + /* Cleanup to release memory */ + DRW_TEXTURE_FREE_SAFE(txl->sss_dir_accum); + DRW_TEXTURE_FREE_SAFE(txl->sss_col_accum); + GPU_FRAMEBUFFER_FREE_SAFE(fbl->sss_accum_fb); + } +} + void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_PassList *psl = vedata->psl; @@ -121,7 +191,9 @@ void EEVEE_subsurface_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data */ psl->sss_blur_ps = DRW_pass_create("Blur Horiz", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL); - psl->sss_resolve_ps = DRW_pass_create("Blur Vert", DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE | DRW_STATE_STENCIL_EQUAL); + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_ADDITIVE | DRW_STATE_STENCIL_EQUAL; + psl->sss_resolve_ps = DRW_pass_create("Blur Vert", state); + psl->sss_accum_ps = DRW_pass_create("Resolve Accum", state); } } @@ -129,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; @@ -137,8 +208,8 @@ 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_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(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); @@ -147,22 +218,33 @@ void EEVEE_subsurface_add_pass( struct GPUShader *sh = (effects->sss_separate_albedo) ? e_data.sss_sh[2] : e_data.sss_sh[1]; 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_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(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_texture_ref(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_texture_ref(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "sssData", &effects->sss_blur); + DRW_shgroup_uniform_texture_ref(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); + DRW_shgroup_call_add(grp, quad, NULL); } } 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; @@ -170,98 +252,88 @@ 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); - - - 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->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) + }); + + 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); - /* First horizontal pass */ - DRW_framebuffer_bind(fbl->sss_blur_fb); - DRW_framebuffer_clear(true, false, false, clear, 0.0f); + /* 1. horizontal pass */ + GPU_framebuffer_bind(fbl->sss_blur_fb); + GPU_framebuffer_clear_color(fbl->sss_blur_fb, clear); DRW_draw_pass(psl->sss_blur_ps); - /* First vertical pass + Resolve */ - DRW_framebuffer_texture_detach(txl->sss_stencil); - DRW_framebuffer_texture_attach(fbl->main, txl->sss_stencil, 0, 0); - DRW_framebuffer_bind(fbl->main); + /* 2. vertical pass + Resolve */ + 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); - + GPU_framebuffer_bind(fbl->main_fb); DRW_stats_group_end(); } } +void EEVEE_subsurface_output_accumulate(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) +{ + EEVEE_PassList *psl = vedata->psl; + EEVEE_FramebufferList *fbl = vedata->fbl; + 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) */ + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->sss_blur_fb, 0, GPU_STENCIL_BIT); + + /* Only do vertical pass + Resolve */ + GPU_framebuffer_bind(fbl->sss_accum_fb); + DRW_draw_pass(psl->sss_accum_ps); + + /* Restore */ + GPU_framebuffer_bind(fbl->main_fb); + } +} + void EEVEE_subsurface_free(void) { DRW_SHADER_FREE_SAFE(e_data.sss_sh[0]); DRW_SHADER_FREE_SAFE(e_data.sss_sh[1]); DRW_SHADER_FREE_SAFE(e_data.sss_sh[2]); + DRW_SHADER_FREE_SAFE(e_data.sss_sh[3]); } diff --git a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c index 3ed2a20e68c..acc1bff6331 100644 --- a/source/blender/draw/engines/eevee/eevee_temporal_sampling.c +++ b/source/blender/draw/engines/eevee/eevee_temporal_sampling.c @@ -32,9 +32,14 @@ #include "eevee_private.h" #include "GPU_texture.h" +#define FILTER_CDF_TABLE_SIZE 512 + static struct { /* Temporal Anti Aliasing */ struct GPUShader *taa_resolve_sh; + + /* Pixel filter table: Only blackman-harris for now. */ + float inverted_cdf[FILTER_CDF_TABLE_SIZE]; } e_data = {NULL}; /* Engine data */ extern char datatoc_effect_temporal_aa_glsl[]; @@ -44,6 +49,113 @@ static void eevee_create_shader_temporal_sampling(void) e_data.taa_resolve_sh = DRW_shader_create_fullscreen(datatoc_effect_temporal_aa_glsl, NULL); } +static float UNUSED_FUNCTION(filter_box)(float UNUSED(x)) +{ + return 1.0f; +} + +static float filter_blackman_harris(float x) +{ + /* Hardcoded 1px footprint [-0.5..0.5]. We resize later. */ + const float width = 1.0f; + x = 2.0f * M_PI * (x / width + 0.5f); + return 0.35875f - 0.48829f * cosf(x) + 0.14128f * cosf(2.0f * x) - 0.01168f * cosf(3.0f * x); +} + +/* Compute cumulative distribution function of a discrete function. */ +static void compute_cdf(float (*func)(float x), float cdf[FILTER_CDF_TABLE_SIZE]) +{ + cdf[0] = 0.0f; + /* Actual CDF evaluation. */ + for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; ++u) { + float x = (float)(u + 1) / (float)(FILTER_CDF_TABLE_SIZE - 1); + cdf[u + 1] = cdf[u] + func(x - 0.5f); /* [-0.5..0.5]. We resize later. */ + } + /* Normalize the CDF. */ + for (int u = 0; u < FILTER_CDF_TABLE_SIZE - 1; u++) { + cdf[u] /= cdf[FILTER_CDF_TABLE_SIZE - 1]; + } + /* Just to make sure. */ + cdf[FILTER_CDF_TABLE_SIZE - 1] = 1.0f; +} + +static void invert_cdf(const float cdf[FILTER_CDF_TABLE_SIZE], float invert_cdf[FILTER_CDF_TABLE_SIZE]) +{ + for (int u = 0; u < FILTER_CDF_TABLE_SIZE; u++) { + float x = (float)u / (float)(FILTER_CDF_TABLE_SIZE - 1); + for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) { + if (cdf[i] >= x) { + if (i == FILTER_CDF_TABLE_SIZE - 1) { + invert_cdf[u] = 1.0f; + } + else { + float t = (x - cdf[i]) / (cdf[i + 1] - cdf[i]); + invert_cdf[u] = ((float)i + t) / (float)(FILTER_CDF_TABLE_SIZE - 1); + } + break; + } + } + } +} + +/* Evaluate a discrete function table with linear interpolation. */ +static float eval_table(float *table, float x) +{ + CLAMP(x, 0.0f, 1.0f); + x = x * (FILTER_CDF_TABLE_SIZE - 1); + + int index = min_ii((int)(x), FILTER_CDF_TABLE_SIZE - 1); + int nindex = min_ii(index + 1, FILTER_CDF_TABLE_SIZE - 1); + float t = x - index; + + return (1.0f - t) * table[index] + t * table[nindex]; +} + +static void eevee_create_cdf_table_temporal_sampling(void) +{ + float *cdf_table = MEM_mallocN(sizeof(float) * FILTER_CDF_TABLE_SIZE, "Eevee Filter CDF table"); + + float filter_width = 2.0f; /* Use a 2 pixel footprint by default. */ + + { + /* Use blackman-harris filter. */ + filter_width *= 2.0f; + compute_cdf(filter_blackman_harris, cdf_table); + } + + invert_cdf(cdf_table, e_data.inverted_cdf); + + /* Scale and offset table. */ + for (int i = 0; i < FILTER_CDF_TABLE_SIZE; ++i) { + e_data.inverted_cdf[i] = (e_data.inverted_cdf[i] - 0.5f) * filter_width; + } + + MEM_freeN(cdf_table); +} + +void EEVEE_temporal_sampling_matrices_calc( + EEVEE_EffectsInfo *effects, float viewmat[4][4], float persmat[4][4], const double ht_point[2]) +{ + const float *viewport_size = DRW_viewport_size_get(); + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + RenderData *rd = &scene->r; + + float filter_size = rd->gauss; /* Sigh.. Stupid legacy naming. */ + + float ofs_x = eval_table(e_data.inverted_cdf, (float)(ht_point[0])) * filter_size; + float ofs_y = eval_table(e_data.inverted_cdf, (float)(ht_point[1])) * filter_size; + + window_translate_m4( + effects->overide_winmat, persmat, + ofs_x / viewport_size[0], + ofs_y / viewport_size[1]); + + mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); + invert_m4_m4(effects->overide_persinv, effects->overide_persmat); + invert_m4_m4(effects->overide_wininv, effects->overide_winmat); +} + int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -67,11 +179,11 @@ 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) { eevee_create_shader_temporal_sampling(); + eevee_create_cdf_table_temporal_sampling(); } /* Until we support reprojection, we need to make sure @@ -110,14 +222,7 @@ int EEVEE_temporal_sampling_init(EEVEE_ViewLayerData *UNUSED(sldata), EEVEE_Data BLI_halton_2D(ht_primes, ht_offset, effects->taa_current_sample - 1, ht_point); - window_translate_m4( - effects->overide_winmat, persmat, - ((float)(ht_point[0]) * 2.0f - 1.0f) / viewport_size[0], - ((float)(ht_point[1]) * 2.0f - 1.0f) / viewport_size[1]); - - mul_m4_m4m4(effects->overide_persmat, effects->overide_winmat, viewmat); - invert_m4_m4(effects->overide_persinv, effects->overide_persmat); - invert_m4_m4(effects->overide_wininv, effects->overide_winmat); + EEVEE_temporal_sampling_matrices_calc(effects, viewmat, persmat, ht_point); DRW_viewport_matrix_override_set(effects->overide_persmat, DRW_MAT_PERS); DRW_viewport_matrix_override_set(effects->overide_persinv, DRW_MAT_PERSINV); @@ -133,18 +238,20 @@ 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; } + effects->taa_current_sample = 1; + /* 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; } @@ -160,8 +267,8 @@ void EEVEE_temporal_sampling_cache_init(EEVEE_ViewLayerData *UNUSED(sldata), EEV psl->taa_resolve = DRW_pass_create("Temporal AA Resolve", DRW_STATE_WRITE_COLOR); DRWShadingGroup *grp = DRW_shgroup_create(e_data.taa_resolve_sh, psl->taa_resolve); - DRW_shgroup_uniform_buffer(grp, "historyBuffer", &txl->color_double_buffer); - DRW_shgroup_uniform_buffer(grp, "colorBuffer", &txl->color); + DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->color_double_buffer); + DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", &txl->color); DRW_shgroup_uniform_float(grp, "alpha", &effects->taa_alpha, 1); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } @@ -185,24 +292,29 @@ 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. */ - DRW_framebuffer_blit(fbl->depth_double_buffer_fb, fbl->main, true, false); + if (!DRW_state_is_image_render()) { + 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_color_fb; } else { /* Save the depth buffer for the next frame. * This saves us from doing anything special * in the other mode engines. */ - DRW_framebuffer_blit(fbl->main, fbl->depth_double_buffer_fb, true, false); + if (!DRW_state_is_image_render()) { + GPU_framebuffer_blit(fbl->main_fb, 0, fbl->double_buffer_depth_fb, 0, GPU_DEPTH_BIT); + } } /* Make each loop count when doing a render. */ diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index a960682e8c9..408015addd4 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -30,7 +30,7 @@ #include "BLI_rand.h" #include "BLI_string_utils.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_smoke_types.h" #include "DNA_world_types.h" @@ -65,6 +65,7 @@ static struct { extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_direct_lib_glsl[]; extern char datatoc_common_uniforms_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lamps_lib_glsl[]; @@ -75,16 +76,18 @@ extern char datatoc_volumetric_resolve_frag_glsl[]; extern char datatoc_volumetric_scatter_frag_glsl[]; extern char datatoc_volumetric_integration_frag_glsl[]; extern char datatoc_volumetric_lib_glsl[]; -extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; +extern char datatoc_common_fullscreen_vert_glsl[]; static void eevee_create_shader_volumes(void) { e_data.volumetric_common_lib = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_volumetric_lib_glsl); e_data.volumetric_common_lamps_lib = BLI_string_joinN( + datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_bsdf_direct_lib_glsl, @@ -123,11 +126,26 @@ static void eevee_create_shader_volumes(void) datatoc_volumetric_integration_frag_glsl, e_data.volumetric_common_lib, NULL); e_data.volumetric_resolve_sh = DRW_shader_create_with_lib( - datatoc_gpu_shader_fullscreen_vert_glsl, NULL, + datatoc_common_fullscreen_vert_glsl, NULL, datatoc_volumetric_resolve_frag_glsl, e_data.volumetric_common_lib, NULL); } +void EEVEE_volumes_set_jitter(EEVEE_ViewLayerData *sldata, unsigned int current_sample) +{ + EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; + + double ht_point[3]; + double ht_offset[3] = {0.0, 0.0}; + unsigned int ht_primes[3] = {3, 7, 2}; + + BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point); + + common_data->vol_jitter[0] = (float)ht_point[0]; + common_data->vol_jitter[1] = (float)ht_point[1]; + common_data->vol_jitter[2] = (float)ht_point[2]; +} + int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) { EEVEE_StorageList *stl = vedata->stl; @@ -177,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]; @@ -223,8 +241,6 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } /* Temporal Super sampling jitter */ - double ht_point[3]; - double ht_offset[3] = {0.0, 0.0}; unsigned int ht_primes[3] = {3, 7, 2}; unsigned int current_sample = 0; @@ -248,35 +264,27 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_viewport_request_redraw(); } } - BLI_halton_3D(ht_primes, ht_offset, current_sample, ht_point); - common_data->vol_jitter[0] = (float)ht_point[0]; - common_data->vol_jitter[1] = (float)ht_point[1]; - common_data->vol_jitter[2] = (float)ht_point[2]; + 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"); @@ -304,7 +312,7 @@ int EEVEE_volumes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) } else { const float clip_start = common_data->view_vecs[0][2]; - const float clip_end = common_data->view_vecs[1][2]; + const float clip_end = clip_start + common_data->view_vecs[1][2]; integration_start = min_ff(integration_end, clip_start); integration_end = max_ff(-integration_end, clip_end); @@ -332,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; } @@ -350,7 +358,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) if ((effects->enabled_effects & EFFECT_VOLUMETRIC) != 0) { const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - DRWShadingGroup *grp; + DRWShadingGroup *grp = NULL; /* Quick breakdown of the Volumetric rendering: * @@ -394,7 +402,8 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); } } - else { + + if (grp == NULL) { /* If no world or volume material is present just clear the buffer with this drawcall */ grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_clear_sh, psl->volumetric_world_ps, @@ -412,14 +421,14 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) psl->volumetric_scatter_ps = DRW_pass_create("Volumetric Scattering", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_empty_tri_batch_create(scatter_sh, psl->volumetric_scatter_ps, common_data->vol_tex_size[2]); - DRW_shgroup_uniform_buffer(grp, "irradianceGrid", &sldata->irradiance_pool); - DRW_shgroup_uniform_buffer(grp, "shadowTexture", &sldata->shadow_pool); - DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_prop_scattering); - DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_prop_extinction); - DRW_shgroup_uniform_buffer(grp, "volumeEmission", &txl->volume_prop_emission); - DRW_shgroup_uniform_buffer(grp, "volumePhase", &txl->volume_prop_phase); - DRW_shgroup_uniform_buffer(grp, "historyScattering", &txl->volume_scatter_history); - DRW_shgroup_uniform_buffer(grp, "historyTransmittance", &txl->volume_transmittance_history); + DRW_shgroup_uniform_texture_ref(grp, "irradianceGrid", &sldata->irradiance_pool); + DRW_shgroup_uniform_texture_ref(grp, "shadowTexture", &sldata->shadow_pool); + DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_prop_scattering); + DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_prop_extinction); + DRW_shgroup_uniform_texture_ref(grp, "volumeEmission", &txl->volume_prop_emission); + DRW_shgroup_uniform_texture_ref(grp, "volumePhase", &txl->volume_prop_phase); + DRW_shgroup_uniform_texture_ref(grp, "historyScattering", &txl->volume_scatter_history); + DRW_shgroup_uniform_texture_ref(grp, "historyTransmittance", &txl->volume_transmittance_history); DRW_shgroup_uniform_block(grp, "light_block", sldata->light_ubo); DRW_shgroup_uniform_block(grp, "shadow_block", sldata->shadow_ubo); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); @@ -428,16 +437,16 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp = DRW_shgroup_empty_tri_batch_create(e_data.volumetric_integration_sh, psl->volumetric_integration_ps, common_data->vol_tex_size[2]); - DRW_shgroup_uniform_buffer(grp, "volumeScattering", &txl->volume_scatter); - DRW_shgroup_uniform_buffer(grp, "volumeExtinction", &txl->volume_transmittance); + DRW_shgroup_uniform_texture_ref(grp, "volumeScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "volumeExtinction", &txl->volume_transmittance); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); psl->volumetric_resolve_ps = DRW_pass_create("Volumetric Resolve", DRW_STATE_WRITE_COLOR); grp = DRW_shgroup_create(e_data.volumetric_resolve_sh, psl->volumetric_resolve_ps); - DRW_shgroup_uniform_buffer(grp, "inScattering", &txl->volume_scatter); - DRW_shgroup_uniform_buffer(grp, "inTransmittance", &txl->volume_transmittance); - DRW_shgroup_uniform_buffer(grp, "inSceneColor", &e_data.color_src); - DRW_shgroup_uniform_buffer(grp, "inSceneDepth", &e_data.depth_src); + DRW_shgroup_uniform_texture_ref(grp, "inScattering", &txl->volume_scatter); + DRW_shgroup_uniform_texture_ref(grp, "inTransmittance", &txl->volume_transmittance); + DRW_shgroup_uniform_texture_ref(grp, "inSceneColor", &e_data.color_src); + DRW_shgroup_uniform_texture_ref(grp, "inSceneDepth", &e_data.depth_src); DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); DRW_shgroup_call_add(grp, DRW_cache_fullscreen_quad_get(), NULL); } @@ -458,17 +467,20 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved DRWShadingGroup *grp = DRW_shgroup_material_empty_tri_batch_create(mat, vedata->psl->volumetric_objects_ps, sldata->common_data.vol_tex_size[2]); + /* If shader failed to compile or is currently compiling. */ + if (grp == NULL) { + return; + } + /* Making sure it's updated. */ invert_m4_m4(ob->imat, ob->obmat); BKE_mesh_texspace_get_reference((struct Mesh *)ob->data, NULL, &texcoloc, NULL, &texcosize); - if (grp) { - DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); - DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); - DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); - } + DRW_shgroup_uniform_block(grp, "common_block", sldata->common_ubo); + DRW_shgroup_uniform_mat4(grp, "volumeObjectMatrix", (float *)ob->imat); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); + DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); /* Smoke Simulation */ if (((ob->base_flag & BASE_FROMDUPLI) == 0) && @@ -491,11 +503,14 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved } if (sds->tex != NULL) { - DRW_shgroup_uniform_buffer(grp, "sampdensity", &sds->tex); + DRW_shgroup_uniform_texture_ref(grp, "sampdensity", &sds->tex); } if (sds->tex_flame != NULL) { - DRW_shgroup_uniform_buffer(grp, "sampflame", &sds->tex_flame); + DRW_shgroup_uniform_texture_ref(grp, "sampflame", &sds->tex_flame); } + + /* Output is such that 0..1 maps to 0..1000K */ + DRW_shgroup_uniform_vec2(grp, "unftemperature", &sds->flame_ignition, 1); } } @@ -510,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 */ @@ -528,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(); } @@ -549,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 68299fe7546..77c873c1503 100644 --- a/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl @@ -8,12 +8,7 @@ #define LUT_SIZE 64 -uniform mat4 ProjectionMatrix; -uniform mat4 ViewProjectionMatrix; -uniform mat4 ViewMatrixInverse; -#ifndef SHADOW_SHADER -uniform mat4 ViewMatrix; -#else +#ifdef SHADOW_SHADER layout(std140) uniform shadow_render_block { mat4 ShadowMatrix[6]; mat4 FaceViewMatrix[6]; @@ -27,7 +22,21 @@ layout(std140) uniform shadow_render_block { }; flat in int shFace; /* Shadow layer we are rendering to. */ -#define ViewMatrix FaceViewMatrix[shFace] + +/* Replacing viewBlock */ +#define ViewMatrix FaceViewMatrix[shFace] +#define ViewProjectionMatrix ShadowMatrix[shFace] +/* TODO optimize */ +#define ProjectionMatrix \ +mat4(vec4(1.0, 0.0, 0.0, 0.0), \ + vec4(0.0, 1.0, 0.0, 0.0), \ + vec4(0.0, 0.0, -(farClip + nearClip) / (farClip - nearClip), -1.0), \ + vec4(0.0, 0.0, (-2.0 * farClip * nearClip) / (farClip - nearClip), 0.0)) + +#define ViewMatrixInverse inverse(ViewMatrix) +#define ViewProjectionMatrixInverse inverse(ViewProjectionMatrix) +#define ProjectionMatrixInverse inverse(ProjectionMatrix) +#define CameraTexCoFactors vec4(1.0f, 1.0f, 0.0f, 0.0f) #endif /* Buffers */ @@ -325,7 +334,7 @@ vec2 get_uvs_from_view(vec3 view) vec3 get_view_space_from_depth(vec2 uvcoords, float depth) { if (ProjectionMatrix[3][3] == 0.0) { - return (viewVecs[0].xyz + vec3(uvcoords, 0.0) * viewVecs[1].xyz) * get_view_z_from_depth(depth); + return vec3(viewVecs[0].xy + uvcoords * viewVecs[1].xy, 1.0) * get_view_z_from_depth(depth); } else { return viewVecs[0].xyz + vec3(uvcoords, depth) * viewVecs[1].xyz; @@ -418,19 +427,19 @@ float get_btdf_lut(sampler2DArray btdf_lut_tex, float NV, float roughness, float * Using Method #4: Spheremap Transform */ vec2 normal_encode(vec3 n, vec3 view) { - float p = sqrt(n.z * 8.0 + 8.0); - return n.xy / p + 0.5; + float p = sqrt(n.z * 8.0 + 8.0); + return n.xy / p + 0.5; } vec3 normal_decode(vec2 enc, vec3 view) { - vec2 fenc = enc * 4.0 - 2.0; - float f = dot(fenc, fenc); - float g = sqrt(1.0 - f / 4.0); - vec3 n; - n.xy = fenc*g; - n.z = 1 - f / 2; - return n; + vec2 fenc = enc * 4.0 - 2.0; + float f = dot(fenc, fenc); + float g = sqrt(1.0 - f / 4.0); + vec3 n; + n.xy = fenc*g; + n.z = 1 - f / 2; + return n; } /* ---- RGBM (shared multiplier) encoding ---- */ @@ -654,12 +663,12 @@ Closure closure_add(Closure cl1, Closure cl2) struct Closure { vec3 radiance; float opacity; -#ifdef USE_SSS +# ifdef USE_SSS vec4 sss_data; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO vec3 sss_albedo; -#endif -#endif +# endif +# endif vec4 ssr_data; vec2 ssr_normal; int ssr_id; @@ -669,15 +678,15 @@ struct Closure { #define TRANSPARENT_CLOSURE_FLAG -2 #define REFRACT_CLOSURE_FLAG -3 -#ifdef USE_SSS -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS +# ifdef USE_SSS_ALBEDO #define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec3(0.0), vec4(0.0), vec2(0.0), -1) -#else +# else #define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec4(0.0), vec2(0.0), -1) -#endif -#else +# endif +# else #define CLOSURE_DEFAULT Closure(vec3(0.0), 1.0, vec4(0.0), vec2(0.0), -1) -#endif +# endif uniform int outputSsrId; @@ -685,45 +694,51 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) { Closure cl; - if (cl1.ssr_id == outputSsrId) { - cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac); /* do not blend roughness */ - cl.ssr_normal = cl1.ssr_normal; - cl.ssr_id = cl1.ssr_id; - } - else { - cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */ - cl.ssr_normal = cl2.ssr_normal; - cl.ssr_id = cl2.ssr_id; - } if (cl1.ssr_id == TRANSPARENT_CLOSURE_FLAG) { cl1.radiance = cl2.radiance; -#ifdef USE_SSS + cl1.ssr_normal = cl2.ssr_normal; + cl1.ssr_data = cl2.ssr_data; + cl1.ssr_id = cl2.ssr_id; +# ifdef USE_SSS cl1.sss_data = cl2.sss_data; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO cl1.sss_albedo = cl2.sss_albedo; -#endif -#endif +# endif +# endif } if (cl2.ssr_id == TRANSPARENT_CLOSURE_FLAG) { cl2.radiance = cl1.radiance; -#ifdef USE_SSS + cl2.ssr_normal = cl1.ssr_normal; + cl2.ssr_data = cl1.ssr_data; + cl2.ssr_id = cl1.ssr_id; +# ifdef USE_SSS cl2.sss_data = cl1.sss_data; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO cl2.sss_albedo = cl1.sss_albedo; -#endif -#endif +# endif +# endif + } + if (cl1.ssr_id == outputSsrId) { + cl.ssr_data = mix(cl1.ssr_data.xyzw, vec4(vec3(0.0), cl1.ssr_data.w), fac); /* do not blend roughness */ + cl.ssr_normal = cl1.ssr_normal; + cl.ssr_id = cl1.ssr_id; + } + else { + cl.ssr_data = mix(vec4(vec3(0.0), cl2.ssr_data.w), cl2.ssr_data.xyzw, fac); /* do not blend roughness */ + cl.ssr_normal = cl2.ssr_normal; + cl.ssr_id = cl2.ssr_id; } cl.radiance = mix(cl1.radiance, cl2.radiance, fac); cl.opacity = mix(cl1.opacity, cl2.opacity, fac); -#ifdef USE_SSS +# ifdef USE_SSS cl.sss_data.rgb = mix(cl1.sss_data.rgb, cl2.sss_data.rgb, fac); cl.sss_data.a = (cl1.sss_data.a > 0.0) ? cl1.sss_data.a : cl2.sss_data.a; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO /* TODO Find a solution to this. Dither? */ cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo; -#endif -#endif +# endif +# endif return cl; } @@ -731,80 +746,73 @@ Closure closure_mix(Closure cl1, Closure cl2, float fac) Closure closure_add(Closure cl1, Closure cl2) { Closure cl = (cl1.ssr_id == outputSsrId) ? cl1 : cl2; -#ifdef USE_SSS +# ifdef USE_SSS cl.sss_data = (cl1.sss_data.a > 0.0) ? cl1.sss_data : cl2.sss_data; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO /* TODO Find a solution to this. Dither? */ cl.sss_albedo = (cl1.sss_data.a > 0.0) ? cl1.sss_albedo : cl2.sss_albedo; -#endif -#endif +# endif +# endif cl.radiance = cl1.radiance + cl2.radiance; cl.opacity = saturate(cl1.opacity + cl2.opacity); return cl; } -#if defined(MESH_SHADER) && !defined(USE_ALPHA_HASH) && !defined(USE_ALPHA_CLIP) && !defined(SHADOW_SHADER) && !defined(USE_MULTIPLY) +# 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; -#endif /* USE_SSS */ +# 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 */ -#if defined(USE_ALPHA_BLEND_VOLUMETRICS) +# if defined(USE_ALPHA_BLEND_VOLUMETRICS) /* Prototype because this file is included before volumetric_lib.glsl */ vec4 volumetric_resolve(vec4 scene_color, vec2 frag_uvs, float frag_depth); -#endif +# endif #define NODETREE_EXEC void main() { Closure cl = nodetree_exec(); -#ifndef USE_ALPHA_BLEND +# ifndef USE_ALPHA_BLEND /* Prevent alpha hash material writing into alpha channel. */ cl.opacity = 1.0; -#endif +# endif -#if defined(USE_ALPHA_BLEND_VOLUMETRICS) +# if defined(USE_ALPHA_BLEND_VOLUMETRICS) /* XXX fragile, better use real viewport resolution */ vec2 uvs = gl_FragCoord.xy / vec2(2 * textureSize(maxzBuffer, 0).xy); fragColor = volumetric_resolve(vec4(cl.radiance, cl.opacity), uvs, gl_FragCoord.z); -#else +# else fragColor = vec4(cl.radiance, cl.opacity); -#endif +# endif ssrNormals = cl.ssr_normal.xyyy; ssrData = cl.ssr_data; -#ifdef USE_SSS +# ifdef USE_SSS sssData = cl.sss_data; -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS_ALBEDO sssAlbedo = cl.sss_albedo.rgbb; -#endif -#endif +# endif +# endif /* For Probe capture */ -#ifdef USE_SSS -#ifdef USE_SSS_ALBEDO +# ifdef USE_SSS +# ifdef USE_SSS_ALBEDO fragColor.rgb += cl.sss_data.rgb * cl.sss_albedo.rgb * float(!sssToggle); -#else +# else fragColor.rgb += cl.sss_data.rgb * float(!sssToggle); -#endif -#endif +# endif +# endif } -#endif /* MESH_SHADER && !SHADOW_SHADER */ +# endif /* MESH_SHADER && !SHADOW_SHADER */ #endif /* VOLUMETRICS */ diff --git a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl index 32edf709d88..b7bcf5c8a8b 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl @@ -28,7 +28,8 @@ void main() gtao_deferred(normal, viewPosition, noise, depth, visibility, bent_normal); - FragColor = vec4(visibility); + /* Handle Background case. Prevent artifact due to uncleared Horizon Render Target. */ + FragColor = vec4((depth == 1.0) ? 0.0 : visibility); } #else diff --git a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl index 65d3970a82a..05fef73b159 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl @@ -23,7 +23,9 @@ uniform sampler2D depthBuffer; #define minmax(a, b) max(a, b) #endif -#ifdef GPU_INTEL +/* On some AMD card / driver conbination, it is needed otherwise, + * the shader does not write anything. */ +#if defined(GPU_INTEL) || defined(GPU_ATI) out vec4 fragColor; #endif @@ -65,10 +67,9 @@ void main() } #endif -#ifdef GPU_INTEL +#if defined(GPU_INTEL) || defined(GPU_ATI) /* Use color format instead of 24bit depth texture */ fragColor = vec4(val); -#else - gl_FragDepth = val; #endif + gl_FragDepth = val; }
\ No newline at end of file diff --git a/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl new file mode 100644 index 00000000000..fe38b2e9aac --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl @@ -0,0 +1,31 @@ +/* Convert depth to Mist factor */ +uniform vec3 mistSettings; + +#define mistStart mistSettings.x +#define mistInvDistance mistSettings.y +#define mistFalloff mistSettings.z + +out vec4 fragColor; + +void main() +{ + vec2 texel_size = 1.0 / vec2(textureSize(depthBuffer, 0)).xy; + vec2 uvs = gl_FragCoord.xy * texel_size; + + float depth = textureLod(depthBuffer, uvs, 0.0).r; + vec3 co = get_view_space_from_depth(uvs, depth); + + float zcor = (ProjectionMatrix[3][3] == 0.0) ? length(co) : -co.z; + + /* bring depth into 0..1 range */ + float mist = saturate((zcor - mistStart) * mistInvDistance); + + /* falloff */ + mist = pow(mist, mistFalloff); + + fragColor = vec4(mist); + + // if (mist > 0.999) fragColor = vec4(1.0); + // else if (mist > 0.0001) fragColor = vec4(0.5); + // else fragColor = vec4(0.0); +} diff --git a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl index 184eac54c26..5ecf6323255 100644 --- a/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl @@ -18,9 +18,10 @@ uniform sampler2DArray utilTex; #define texelfetch_noise_tex(coord) texelFetch(utilTex, ivec3(ivec2(coord) % LUT_SIZE, 2.0), 0) #endif /* UTIL_TEX */ -out vec4 FragColor; - -uniform mat4 ProjectionMatrix; +layout(location = 0) out vec4 FragColor; +#ifdef RESULT_ACCUM +layout(location = 1) out vec4 sssColor; +#endif float get_view_z_from_depth(float depth) { @@ -84,10 +85,15 @@ void main(void) #ifdef FIRST_PASS FragColor = vec4(accum, sss_data.a); #else /* SECOND_PASS */ - #ifdef USE_SEP_ALBEDO +# ifdef USE_SEP_ALBEDO +# ifdef RESULT_ACCUM + FragColor = vec4(accum, 1.0); + sssColor = texture(sssAlbedo, uvs); +# else FragColor = vec4(accum * texture(sssAlbedo, uvs).rgb, 1.0); - #else +# endif +# else FragColor = vec4(accum, 1.0); - #endif +# endif #endif } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl index 202b27be0ef..57da4d0d1ec 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl @@ -6,8 +6,6 @@ in int probe_id; in vec3 probe_location; in float sphere_size; -uniform mat4 ViewProjectionMatrix; - flat out int pid; out vec3 worldNormal; out vec3 worldPosition; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl index fd200ec5984..37f73714a8e 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl @@ -1,8 +1,6 @@ in vec3 pos; -uniform mat4 ViewProjectionMatrix; - uniform float sphere_size; uniform int offset; uniform ivec3 grid_resolution; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl index 655cc626bba..3808b59761f 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl @@ -1,5 +1,4 @@ -uniform mat4 ViewProjectionMatrix; uniform sampler2DArray probePlanars; in vec3 worldPosition; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl index a9716332eb5..3ecd85fd72e 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl @@ -4,8 +4,6 @@ in vec3 pos; in int probe_id; in mat4 probe_mat; -uniform mat4 ViewProjectionMatrix; - out vec3 worldPosition; flat out int probeIdx; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl index 40b04c986f3..23c16f0fa30 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl @@ -11,13 +11,13 @@ void main() { gl_Layer = instance[0]; layer = float(instance[0]); - gl_Position = vec4(vPos[0], 0.0, 0.0); + gl_Position = vec4(vPos[0], 0.0, 1.0); EmitVertex(); - gl_Position = vec4(vPos[1], 0.0, 0.0); + gl_Position = vec4(vPos[1], 0.0, 1.0); EmitVertex(); - gl_Position = vec4(vPos[2], 0.0, 0.0); + gl_Position = vec4(vPos[2], 0.0, 1.0); EmitVertex(); EndPrimitive(); diff --git a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl index fd7f3870d27..d53852193d5 100644 --- a/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl @@ -19,7 +19,10 @@ out vec3 worldPosition; out vec3 viewPosition; /* Used for planar reflections */ -uniform vec4 ClipPlanes[1]; +/* keep in sync with EEVEE_ClipPlanesUniformBuffer */ +layout(std140) uniform clip_block { + vec4 ClipPlanes[1]; +}; #ifdef USE_FLAT_NORMAL flat out vec3 worldNormal; diff --git a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl index 1b53e503003..974c5724842 100644 --- a/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/prepass_vert.glsl @@ -2,9 +2,11 @@ uniform mat4 ModelViewProjectionMatrix; uniform mat4 ModelMatrix; uniform mat4 ModelViewMatrix; -#ifdef CLIP_PLANES -uniform vec4 ClipPlanes[1]; -#endif + +/* keep in sync with DRWManager.view_data */ +layout(std140) uniform clip_block { + vec4 ClipPlanes[1]; +}; #ifndef HAIR_SHADER_FIBERS in vec3 pos; @@ -28,7 +30,7 @@ void main() #ifdef CLIP_PLANES vec4 worldPosition = (ModelMatrix * vec4(pos, 1.0)); - gl_ClipDistance[0] = dot(worldPosition, ClipPlanes[0]); + gl_ClipDistance[0] = dot(vec4(worldPosition.xyz, 1.0), ClipPlanes[0]); #endif /* TODO motion vectors */ } diff --git a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl index fcc304ca289..0fc7e4c9396 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl @@ -47,7 +47,7 @@ vec4 ln_space_prefilter(float w0, vec4 x, float w1, vec4 y) } #ifdef CSM -vec3 get_texco(vec3 cos, vec2 ofs) +vec3 get_texco(vec3 cos, const vec2 ofs) { cos.xy += ofs * shadowFilterSize; return cos; @@ -64,13 +64,43 @@ void make_orthonormal_basis(vec3 N) B = cross(N, T); } -vec3 get_texco(vec3 cos, vec2 ofs) +vec3 get_texco(vec3 cos, const vec2 ofs) { return cos + ofs.x * T + ofs.y * B; } #endif +#ifdef ESM +void grouped_samples_accum( + vec3 cos, + const vec2 co1, const vec2 co2, const vec2 co3, const vec2 co4, + inout vec4 accum) +{ + vec4 depths; + depths.x = texture(shadowTexture, get_texco(cos, co1)).r; + depths.y = texture(shadowTexture, get_texco(cos, co2)).r; + depths.z = texture(shadowTexture, get_texco(cos, co3)).r; + depths.w = texture(shadowTexture, get_texco(cos, co4)).r; + + accum = ln_space_prefilter(1.0, accum, shadowInvSampleCount, depths); +} +#else /* VSM */ +void grouped_samples_accum( + vec3 cos, + const vec2 co1, const vec2 co2, const vec2 co3, const vec2 co4, + inout vec2 accum) +{ + vec4 depths1, depths2; + depths1.xy = texture(shadowTexture, get_texco(cos, co1)).rg; + depths1.zw = texture(shadowTexture, get_texco(cos, co2)).rg; + depths2.xy = texture(shadowTexture, get_texco(cos, co3)).rg; + depths2.zw = texture(shadowTexture, get_texco(cos, co4)).rg; + + accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw; +} +#endif + void main() { vec3 cos; @@ -105,9 +135,8 @@ void main() { #endif #ifdef ESM - vec4 accum = vec4(0.0); - /* disc blur in log space. */ + vec4 accum = vec4(0.0); vec4 depths; depths.x = texture(shadowTexture, get_texco(cos, concentric[0])).r; depths.y = texture(shadowTexture, get_texco(cos, concentric[1])).r; @@ -115,32 +144,102 @@ void main() { depths.w = texture(shadowTexture, get_texco(cos, concentric[3])).r; accum = ln_space_prefilter(0.0, accum, shadowInvSampleCount, depths); - for (int i = 4; i < shadowSampleCount && i < CONCENTRIC_SAMPLE_NUM; i += 4) { - depths.x = texture(shadowTexture, get_texco(cos, concentric[i+0])).r; - depths.y = texture(shadowTexture, get_texco(cos, concentric[i+1])).r; - depths.z = texture(shadowTexture, get_texco(cos, concentric[i+2])).r; - depths.w = texture(shadowTexture, get_texco(cos, concentric[i+3])).r; - accum = ln_space_prefilter(1.0, accum, shadowInvSampleCount, depths); +#else /* VSM */ + vec2 accum = vec2(0.0); + grouped_samples_accum(cos, concentric[0], concentric[1], concentric[2], concentric[3], accum); +#endif + + /** + * Making the `grouped_samples_accum` be called within a loop would be + * the most conventional solution, however in some older gpus, transverse the huge + * `const vec2 concentric[]` array with variable indices is extremely slow. + * The solution is to use constant indices to access the array. + */ + if (shadowSampleCount > 4) { + grouped_samples_accum(cos, concentric[4], concentric[5], concentric[6], concentric[7], accum); + grouped_samples_accum(cos, concentric[8], concentric[9], concentric[10], concentric[11], accum); + grouped_samples_accum(cos, concentric[12], concentric[13], concentric[14], concentric[15], accum); + } + if (shadowSampleCount > 16) { + grouped_samples_accum(cos, concentric[16], concentric[17], concentric[18], concentric[19], accum); + grouped_samples_accum(cos, concentric[20], concentric[21], concentric[22], concentric[23], accum); + grouped_samples_accum(cos, concentric[24], concentric[25], concentric[26], concentric[27], accum); + grouped_samples_accum(cos, concentric[28], concentric[29], concentric[30], concentric[31], accum); + grouped_samples_accum(cos, concentric[32], concentric[33], concentric[34], concentric[35], accum); + } + if (shadowSampleCount > 36) { + grouped_samples_accum(cos, concentric[36], concentric[37], concentric[38], concentric[39], accum); + grouped_samples_accum(cos, concentric[40], concentric[41], concentric[42], concentric[43], accum); + grouped_samples_accum(cos, concentric[44], concentric[45], concentric[46], concentric[47], accum); + grouped_samples_accum(cos, concentric[48], concentric[49], concentric[50], concentric[51], accum); + grouped_samples_accum(cos, concentric[52], concentric[53], concentric[54], concentric[55], accum); + grouped_samples_accum(cos, concentric[56], concentric[57], concentric[58], concentric[59], accum); + grouped_samples_accum(cos, concentric[60], concentric[61], concentric[62], concentric[63], accum); + } + if (shadowSampleCount > 64) { + grouped_samples_accum(cos, concentric[64], concentric[65], concentric[66], concentric[67], accum); + grouped_samples_accum(cos, concentric[68], concentric[69], concentric[70], concentric[71], accum); + grouped_samples_accum(cos, concentric[72], concentric[73], concentric[74], concentric[75], accum); + grouped_samples_accum(cos, concentric[76], concentric[77], concentric[78], concentric[79], accum); + grouped_samples_accum(cos, concentric[80], concentric[81], concentric[82], concentric[83], accum); + grouped_samples_accum(cos, concentric[84], concentric[85], concentric[86], concentric[87], accum); + grouped_samples_accum(cos, concentric[88], concentric[89], concentric[90], concentric[91], accum); + grouped_samples_accum(cos, concentric[92], concentric[93], concentric[94], concentric[95], accum); + grouped_samples_accum(cos, concentric[96], concentric[97], concentric[98], concentric[99], accum); + } + if (shadowSampleCount > 100) { + grouped_samples_accum(cos, concentric[100], concentric[101], concentric[102], concentric[103], accum); + grouped_samples_accum(cos, concentric[104], concentric[105], concentric[106], concentric[107], accum); + grouped_samples_accum(cos, concentric[108], concentric[109], concentric[110], concentric[111], accum); + grouped_samples_accum(cos, concentric[112], concentric[113], concentric[114], concentric[115], accum); + grouped_samples_accum(cos, concentric[116], concentric[117], concentric[118], concentric[119], accum); + grouped_samples_accum(cos, concentric[120], concentric[121], concentric[122], concentric[123], accum); + grouped_samples_accum(cos, concentric[124], concentric[125], concentric[126], concentric[127], accum); + grouped_samples_accum(cos, concentric[128], concentric[129], concentric[130], concentric[131], accum); + grouped_samples_accum(cos, concentric[132], concentric[133], concentric[134], concentric[135], accum); + grouped_samples_accum(cos, concentric[136], concentric[137], concentric[138], concentric[139], accum); + grouped_samples_accum(cos, concentric[140], concentric[141], concentric[142], concentric[143], accum); + } + if (shadowSampleCount > 144) { + grouped_samples_accum(cos, concentric[144], concentric[145], concentric[146], concentric[147], accum); + grouped_samples_accum(cos, concentric[148], concentric[149], concentric[150], concentric[151], accum); + grouped_samples_accum(cos, concentric[152], concentric[153], concentric[154], concentric[155], accum); + grouped_samples_accum(cos, concentric[156], concentric[157], concentric[158], concentric[159], accum); + grouped_samples_accum(cos, concentric[160], concentric[161], concentric[162], concentric[163], accum); + grouped_samples_accum(cos, concentric[164], concentric[165], concentric[166], concentric[167], accum); + grouped_samples_accum(cos, concentric[168], concentric[169], concentric[170], concentric[171], accum); + grouped_samples_accum(cos, concentric[172], concentric[173], concentric[174], concentric[175], accum); + grouped_samples_accum(cos, concentric[176], concentric[177], concentric[178], concentric[179], accum); + grouped_samples_accum(cos, concentric[180], concentric[181], concentric[182], concentric[183], accum); + grouped_samples_accum(cos, concentric[184], concentric[185], concentric[186], concentric[187], accum); + grouped_samples_accum(cos, concentric[188], concentric[189], concentric[190], concentric[191], accum); + grouped_samples_accum(cos, concentric[192], concentric[193], concentric[194], concentric[195], accum); + } + if (shadowSampleCount > 196) { + grouped_samples_accum(cos, concentric[196], concentric[197], concentric[198], concentric[199], accum); + grouped_samples_accum(cos, concentric[200], concentric[201], concentric[202], concentric[203], accum); + grouped_samples_accum(cos, concentric[204], concentric[205], concentric[206], concentric[207], accum); + grouped_samples_accum(cos, concentric[208], concentric[209], concentric[210], concentric[211], accum); + grouped_samples_accum(cos, concentric[212], concentric[213], concentric[114], concentric[215], accum); + grouped_samples_accum(cos, concentric[216], concentric[217], concentric[218], concentric[219], accum); + grouped_samples_accum(cos, concentric[220], concentric[221], concentric[222], concentric[223], accum); + grouped_samples_accum(cos, concentric[224], concentric[225], concentric[226], concentric[227], accum); + grouped_samples_accum(cos, concentric[228], concentric[229], concentric[230], concentric[231], accum); + grouped_samples_accum(cos, concentric[232], concentric[233], concentric[234], concentric[235], accum); + grouped_samples_accum(cos, concentric[236], concentric[237], concentric[238], concentric[239], accum); + grouped_samples_accum(cos, concentric[240], concentric[241], concentric[242], concentric[243], accum); + grouped_samples_accum(cos, concentric[244], concentric[245], concentric[246], concentric[247], accum); + grouped_samples_accum(cos, concentric[248], concentric[249], concentric[250], concentric[251], accum); + grouped_samples_accum(cos, concentric[252], concentric[253], concentric[254], concentric[255], accum); } +#ifdef ESM accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.y); accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.z); accum.x = ln_space_prefilter(1.0, accum.x, 1.0, accum.w); FragColor = accum.xxxx; #else /* VSM */ - vec2 accum = vec2(0.0); - - /* disc blur. */ - vec4 depths1, depths2; - for (int i = 0; i < shadowSampleCount && i < CONCENTRIC_SAMPLE_NUM; i += 4) { - depths1.xy = texture(shadowTexture, get_texco(cos, concentric[i+0])).rg; - depths1.zw = texture(shadowTexture, get_texco(cos, concentric[i+1])).rg; - depths2.xy = texture(shadowTexture, get_texco(cos, concentric[i+2])).rg; - depths2.zw = texture(shadowTexture, get_texco(cos, concentric[i+3])).rg; - accum += depths1.xy + depths1.zw + depths2.xy + depths2.zw; - } - FragColor = accum.xyxy * shadowInvSampleCount; #endif -}
\ No newline at end of file +} diff --git a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl index 777902ccba8..29cbcfdd6e4 100644 --- a/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl +++ b/source/blender/draw/engines/eevee/shaders/shadow_vert.glsl @@ -1,5 +1,5 @@ -uniform mat4 ShadowModelMatrix; +uniform mat4 ModelMatrix; #ifdef MESH_SHADER uniform mat3 WorldNormalMatrix; #endif @@ -17,7 +17,7 @@ out vec3 vNor; flat out int face; void main() { - vPos = ShadowModelMatrix * vec4(pos, 1.0); + vPos = ModelMatrix * vec4(pos, 1.0); face = gl_InstanceID; #ifdef MESH_SHADER diff --git a/source/blender/draw/engines/external/external_engine.c b/source/blender/draw/engines/external/external_engine.c index 851d0ef9eb7..ec0141953fe 100644 --- a/source/blender/draw/engines/external/external_engine.c +++ b/source/blender/draw/engines/external/external_engine.c @@ -218,6 +218,7 @@ DrawEngineType draw_engine_external_type = { &external_draw_scene, NULL, NULL, + NULL, }; /* Note: currently unused, we should not register unless we want to see this when debugging the view. */ diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index 1f16f63ba14..60e855108f9 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" @@ -55,6 +57,9 @@ #include "RE_engine.h" +#include "DEG_depsgraph.h" + +struct rcti; struct bContext; struct GPUFrameBuffer; struct GPUShader; @@ -76,6 +81,11 @@ typedef struct DRWInterface DRWInterface; typedef struct DRWPass DRWPass; typedef struct DRWShadingGroup DRWShadingGroup; +/* TODO Put it somewhere else? */ +typedef struct BoundSphere { + float center[3], radius; +} BoundSphere; + /* declare members as empty (unused) */ typedef char DRWViewportEmptyList; @@ -94,9 +104,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(); \ } \ } @@ -104,9 +113,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(); \ } \ } @@ -139,12 +147,16 @@ typedef struct DrawEngineType { void (*view_update)(void *vedata); void (*id_update)(void *vedata, struct ID *id); + + void (*render_to_image)(void *vedata, struct RenderEngine *engine, struct RenderLayer *layer, const struct rcti *rect); } DrawEngineType; #ifndef __DRW_ENGINE_H__ /* 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; @@ -174,6 +186,7 @@ typedef enum { DRW_TEX_RG_32, DRW_TEX_R_8, DRW_TEX_R_16, + DRW_TEX_R_16I, DRW_TEX_R_32, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24, @@ -186,9 +199,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( @@ -199,8 +216,13 @@ 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_update(struct GPUTexture *tex, const float *pixels); void DRW_texture_free(struct GPUTexture *tex); #define DRW_TEXTURE_FREE_SAFE(tex) do { \ if (tex != NULL) { \ @@ -220,39 +242,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_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 */ @@ -264,6 +253,14 @@ struct GPUShader *DRW_shader_create_2D(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_3D(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines); struct GPUShader *DRW_shader_create_3D_depth_only(void); +struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, int options); +struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, int options); +struct GPUMaterial *DRW_shader_create_from_world( + struct Scene *scene, struct World *wo, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines); +struct GPUMaterial *DRW_shader_create_from_material( + struct Scene *scene, struct Material *ma, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines); void DRW_shader_free(struct GPUShader *shader); #define DRW_SHADER_FREE_SAFE(shader) do { \ if (shader != NULL) { \ @@ -284,7 +281,7 @@ typedef enum { DRW_STATE_CULL_BACK = (1 << 6), DRW_STATE_CULL_FRONT = (1 << 7), DRW_STATE_WIRE = (1 << 8), - DRW_STATE_WIRE_LARGE = (1 << 9), +// DRW_STATE_WIRE_LARGE = (1 << 9), /* Removed from ogl in 3.0 */ DRW_STATE_POINT = (1 << 10), DRW_STATE_STIPPLE_2 = (1 << 11), DRW_STATE_STIPPLE_3 = (1 << 12), @@ -302,13 +299,33 @@ typedef enum { #define DRW_STATE_DEFAULT (DRW_STATE_WRITE_DEPTH | DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS) +typedef enum { + DRW_ATTRIB_INT, + DRW_ATTRIB_FLOAT, +} DRWAttribType; + +typedef struct DRWInstanceAttribFormat { + char name[32]; + DRWAttribType type; + int components; +} DRWInstanceAttribFormat; + +struct Gwn_VertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize); +#define DRW_shgroup_instance_format(format, ...) do { \ + if (format == NULL) { \ + DRWInstanceAttribFormat drw_format[] = __VA_ARGS__;\ + format = DRW_shgroup_instance_format_array(drw_format, (sizeof(drw_format) / sizeof(DRWInstanceAttribFormat))); \ + } \ +} while (0) DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass); DRWShadingGroup *DRW_shgroup_material_instance_create( - struct GPUMaterial *material, DRWPass *pass, struct Gwn_Batch *geom, struct Object *ob); + struct GPUMaterial *material, DRWPass *pass, struct Gwn_Batch *geom, struct Object *ob, + struct Gwn_VertFormat *format); DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create(struct GPUMaterial *material, DRWPass *pass, int size); -DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, struct Gwn_Batch *geom); +DRWShadingGroup *DRW_shgroup_instance_create( + struct GPUShader *shader, DRWPass *pass, struct Gwn_Batch *geom, struct Gwn_VertFormat *format); DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass); DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int size); @@ -318,11 +335,16 @@ typedef void (DRWCallGenerateFn)( void (*draw_fn)(DRWShadingGroup *shgroup, struct Gwn_Batch *geom), void *user_data); -void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances); +void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batch); void DRW_shgroup_free(struct DRWShadingGroup *shgroup); void DRW_shgroup_call_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4]); void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob); +/* Used for drawing a batch with instancing without instance attribs. */ +void DRW_shgroup_call_instances_add( + DRWShadingGroup *shgroup, struct Gwn_Batch *geom, float (*obmat)[4], unsigned int *count); +void DRW_shgroup_call_object_instances_add( + DRWShadingGroup *shgroup, struct Gwn_Batch *geom, struct Object *ob, unsigned int *count); void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, struct Object *ob, float (*obmat)[4]); void DRW_shgroup_call_generate_add( DRWShadingGroup *shgroup, DRWCallGenerateFn *geometry_fn, void *user_data, float (*obmat)[4]); @@ -331,17 +353,18 @@ void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *at const void *array[] = {__VA_ARGS__}; \ DRW_shgroup_call_dynamic_add_array(shgroup, array, (sizeof(array) / sizeof(*array))); \ } while (0) -/* Use this to set a high number of instances. */ -void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count); + +unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup); void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask); -void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size); void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); +void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUTexture *tex); void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo); -void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); +void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const struct GPUUniformBuffer *ubo); +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, struct GPUTexture **tex); void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize); @@ -370,13 +393,24 @@ typedef enum { DRW_MAT_VIEWINV, DRW_MAT_WIN, DRW_MAT_WININV, + + DRW_MAT_COUNT, // Don't use this. } DRWViewportMatrixType; +typedef struct DRWMatrixState { + float mat[DRW_MAT_COUNT][4][4]; +} DRWMatrixState; + void DRW_viewport_init(const bContext *C); void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type); +void DRW_viewport_matrix_get_all(DRWMatrixState *state); void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type); +void DRW_viewport_matrix_override_set_all(DRWMatrixState *state); void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type); +void DRW_viewport_matrix_override_unset_all(void); + const float *DRW_viewport_size_get(void); +const float *DRW_viewport_invert_size_get(void); const float *DRW_viewport_screenvecs_get(void); const float *DRW_viewport_pixelsize_get(void); bool DRW_viewport_is_persp_get(void); @@ -386,14 +420,24 @@ struct DefaultTextureList *DRW_viewport_texture_list_get(void); void DRW_viewport_request_redraw(void); +void DRW_render_to_image(struct RenderEngine *engine, struct Depsgraph *graph); +void DRW_render_object_iter( + void *vedata, struct RenderEngine *engine, struct Depsgraph *graph, + void (*callback)(void *vedata, struct Object *ob, struct RenderEngine *engine, struct Depsgraph *graph)); +void DRW_render_instance_buffer_finish(void); + /* ViewLayers */ void *DRW_view_layer_engine_data_get(DrawEngineType *engine_type); void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*callback)(void *storage)); /* Objects */ -void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type); -void **DRW_object_engine_data_ensure( - Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage)); +ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type); +ObjectEngineData *DRW_object_engine_data_ensure( + Object *ob, + DrawEngineType *engine_type, + size_t size, + ObjectEngineDataInitCb init_cb, + ObjectEngineDataFreeCb free_cb); struct LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, struct RenderEngineType *engine_type); void DRW_lamp_engine_data_free(struct LampEngineData *led); @@ -417,12 +461,17 @@ void DRW_draw_region_engine_info(void); void DRW_state_reset_ex(DRWState state); void DRW_state_reset(void); +void DRW_state_lock(DRWState state); void DRW_state_invert_facing(void); -void DRW_state_clip_planes_add(float plane_eq[4]); +void DRW_state_clip_planes_count_set(unsigned int plane_ct); void DRW_state_clip_planes_reset(void); +/* Culling, return true if object is inside view frustum. */ +bool DRW_culling_sphere_test(BoundSphere *bsphere); +bool DRW_culling_box_test(BoundBox *bbox); + /* Selection */ void DRW_select_load_id(unsigned int id); @@ -433,6 +482,7 @@ bool DRW_state_is_select(void); bool DRW_state_is_depth(void); bool DRW_state_is_image_render(void); bool DRW_state_is_scene_render(void); +bool DRW_state_is_opengl_render(void); bool DRW_state_show_text(void); bool DRW_state_draw_support(void); bool DRW_state_draw_background(void); @@ -443,6 +493,7 @@ struct DRWTextStore *DRW_state_text_cache_get(void); /* Avoid too many lookups while drawing */ typedef struct DRWContextState { + struct ARegion *ar; /* 'CTX_wm_region(C)' */ struct RegionView3D *rv3d; /* 'CTX_wm_region_view3d(C)' */ struct View3D *v3d; /* 'CTX_wm_view3d(C)' */ @@ -450,16 +501,26 @@ typedef struct DRWContextState { struct Scene *scene; /* 'CTX_data_scene(C)' */ struct ViewLayer *view_layer; /* 'CTX_data_view_layer(C)' */ - /* Use 'scene->obedit' for edit-mode */ + /* Use 'object_edit' for edit-mode */ struct Object *obact; /* 'OBACT' */ struct RenderEngineType *engine_type; + EvaluationContext eval_ctx; struct Depsgraph *depsgraph; + eObjectMode object_mode; + /* Last resort (some functions take this as an arg so we can't easily avoid). * May be NULL when used for selection or depth buffer. */ const struct bContext *evil_C; + + /* ---- */ + + /* Cache: initialized by 'drw_context_state_init'. */ + struct Object *object_pose; + struct Object *object_edit; + } DRWContextState; const DRWContextState *DRW_context_state_get(void); diff --git a/source/blender/draw/intern/draw_armature.c b/source/blender/draw/intern/draw_armature.c index 09fe3d68651..c14fe70e0c3 100644 --- a/source/blender/draw/intern/draw_armature.c +++ b/source/blender/draw/intern/draw_armature.c @@ -1308,7 +1308,9 @@ static void draw_armature_pose(Object *ob, const float const_color[4]) // if (!(base->flag & OB_FROMDUPLI)) // TODO { - if (ob->mode & OB_MODE_POSE) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + + if ((draw_ctx->object_mode & OB_MODE_POSE) || (ob == draw_ctx->object_pose)) { arm->flag |= ARM_POSEMODE; } diff --git a/source/blender/draw/intern/draw_cache.c b/source/blender/draw/intern/draw_cache.c index 5faf397cc37..06fb71b7e67 100644 --- a/source/blender/draw/intern/draw_cache.c +++ b/source/blender/draw/intern/draw_cache.c @@ -32,6 +32,8 @@ #include "DNA_modifier_types.h" #include "DNA_lattice_types.h" +#include "UI_resources.h" + #include "BLI_utildefines.h" #include "BLI_math.h" @@ -43,8 +45,10 @@ /* Batch's only (free'd as an array) */ static struct DRWShapeCache { Gwn_Batch *drw_single_vertice; + Gwn_Batch *drw_cursor; Gwn_Batch *drw_fullscreen_quad; Gwn_Batch *drw_quad; + Gwn_Batch *drw_sphere; Gwn_Batch *drw_screenspace_circle; Gwn_Batch *drw_plain_axes; Gwn_Batch *drw_single_arrow; @@ -266,7 +270,6 @@ Gwn_Batch *DRW_cache_fullscreen_quad_get(void) Gwn_Batch *DRW_cache_quad_get(void) { if (!SHC.drw_quad) { - /* Use a triangle instead of a real quad */ float pos[4][2] = {{-1.0f, -1.0f}, { 1.0f, -1.0f}, {1.0f, 1.0f}, {-1.0f, 1.0f}}; float uvs[4][2] = {{ 0.0f, 0.0f}, { 1.0f, 0.0f}, {1.0f, 1.0f}, { 0.0f, 1.0f}}; @@ -294,7 +297,10 @@ Gwn_Batch *DRW_cache_quad_get(void) /* Sphere */ Gwn_Batch *DRW_cache_sphere_get(void) { - return GPU_batch_preset_sphere(2); + if (!SHC.drw_sphere) { + SHC.drw_sphere = gpu_batch_sphere(32, 24); + } + return SHC.drw_sphere; } /** \} */ @@ -1068,7 +1074,7 @@ Gwn_Batch *DRW_cache_lamp_sunrays_get(void) if (!SHC.drw_lamp_sunrays) { float v[2], v1[2], v2[2]; - /* Position Only 3D format */ + /* Position Only 2D format */ static Gwn_VertFormat format = { 0 }; static struct { uint pos; } attr_id; if (format.attrib_ct == 0) { @@ -1076,17 +1082,21 @@ Gwn_Batch *DRW_cache_lamp_sunrays_get(void) } Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(vbo, 16); + GWN_vertbuf_data_alloc(vbo, 32); for (int a = 0; a < 8; a++) { v[0] = sinf((2.0f * M_PI * a) / 8.0f); v[1] = cosf((2.0f * M_PI * a) / 8.0f); - mul_v2_v2fl(v1, v, 1.2f); - mul_v2_v2fl(v2, v, 2.5f); + mul_v2_v2fl(v1, v, 1.6f); + mul_v2_v2fl(v2, v, 1.9f); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4, v1); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 1, v2); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2, v1); - GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 2 + 1, v2); + mul_v2_v2fl(v1, v, 2.2f); + mul_v2_v2fl(v2, v, 2.5f); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 2, v1); + GWN_vertbuf_attr_set(vbo, attr_id.pos, a * 4 + 3, v2); } SHC.drw_lamp_sunrays = GWN_batch_create_ex(GWN_PRIM_LINES, vbo, NULL, GWN_BATCH_OWNS_VBO); @@ -2594,9 +2604,9 @@ Gwn_Batch *DRW_cache_particles_get_hair(ParticleSystem *psys, ModifierData *md) return DRW_particles_batch_cache_get_hair(psys, md); } -Gwn_Batch *DRW_cache_particles_get_dots(ParticleSystem *psys) +Gwn_Batch *DRW_cache_particles_get_dots(Object *object, ParticleSystem *psys) { - return DRW_particles_batch_cache_get_dots(psys); + return DRW_particles_batch_cache_get_dots(object, psys); } Gwn_Batch *DRW_cache_particles_get_prim(int type) @@ -2763,3 +2773,91 @@ Gwn_Batch *DRW_cache_hair_get_guide_curve_edges(struct HairSystem *hsys, struct { return DRW_hair_batch_cache_get_guide_curve_edges(hsys, scalp, subdiv); } + +/* 3D cursor */ +Gwn_Batch *DRW_cache_cursor_get(void) +{ + if (!SHC.drw_cursor) { + const float f5 = 0.25f; + const float f10 = 0.5f; + const float f20 = 1.0f; + + const int segments = 16; + const int vert_ct = segments + 8; + const int index_ct = vert_ct + 5; + + unsigned char red[3] = {255, 0, 0}; + unsigned char white[3] = {255, 255, 255}; + unsigned char crosshair_color[3]; + UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color); + + static Gwn_VertFormat format = { 0 }; + static struct { uint pos, color; } attr_id; + if (format.attrib_ct == 0) { + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + attr_id.color = GWN_vertformat_attr_add(&format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); + } + + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init_ex(&elb, GWN_PRIM_LINE_STRIP, index_ct, vert_ct, true); + + Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(vbo, vert_ct); + + int v = 0; + for (int i = 0; i < segments; ++i) { + float angle = (float)(2 * M_PI) * ((float)i / (float)segments); + float x = f10 * cosf(angle); + float y = f10 * sinf(angle); + + if (i % 2 == 0) + GWN_vertbuf_attr_set(vbo, attr_id.color, v, red); + else + GWN_vertbuf_attr_set(vbo, attr_id.color, v, white); + + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){x, y}); + GWN_indexbuf_add_generic_vert(&elb, v++); + } + GWN_indexbuf_add_generic_vert(&elb, 0); + GWN_indexbuf_add_primitive_restart(&elb); + + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){-f20, 0}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){-f5, 0}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + + GWN_indexbuf_add_primitive_restart(&elb); + + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){+f5, 0}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){+f20, 0}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + + GWN_indexbuf_add_primitive_restart(&elb); + + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, -f20}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, -f5}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + + GWN_indexbuf_add_primitive_restart(&elb); + + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, +f5}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + GWN_vertbuf_attr_set(vbo, attr_id.pos, v, (const float[2]){0, +f20}); + GWN_vertbuf_attr_set(vbo, attr_id.color, v, crosshair_color); + GWN_indexbuf_add_generic_vert(&elb, v++); + + Gwn_IndexBuf *ibo = GWN_indexbuf_build(&elb); + + SHC.drw_cursor = GWN_batch_create_ex(GWN_PRIM_LINE_STRIP, vbo, ibo, GWN_BATCH_OWNS_VBO | GWN_BATCH_OWNS_INDEX); + } + return SHC.drw_cursor; +}
\ No newline at end of file diff --git a/source/blender/draw/intern/draw_cache.h b/source/blender/draw/intern/draw_cache.h index 10539af5a94..bae59ff3604 100644 --- a/source/blender/draw/intern/draw_cache.h +++ b/source/blender/draw/intern/draw_cache.h @@ -37,6 +37,9 @@ struct DerivedMesh; void DRW_shape_cache_free(void); +/* 3D cursor */ +struct Gwn_Batch *DRW_cache_cursor_get(void); + /* Common Shapes */ struct Gwn_Batch *DRW_cache_fullscreen_quad_get(void); struct Gwn_Batch *DRW_cache_quad_get(void); @@ -171,7 +174,7 @@ struct Gwn_Batch *DRW_cache_groom_vert_overlay_get(struct Object *ob, int mode); /* Particles */ struct Gwn_Batch *DRW_cache_particles_get_hair(struct ParticleSystem *psys, struct ModifierData *md); -struct Gwn_Batch *DRW_cache_particles_get_dots(struct ParticleSystem *psys); +struct Gwn_Batch *DRW_cache_particles_get_dots(struct Object *object, struct ParticleSystem *psys); struct Gwn_Batch *DRW_cache_particles_get_prim(int type); /* Hair */ diff --git a/source/blender/draw/intern/draw_cache_impl.h b/source/blender/draw/intern/draw_cache_impl.h index 21393a2a609..0ac2f11849a 100644 --- a/source/blender/draw/intern/draw_cache_impl.h +++ b/source/blender/draw/intern/draw_cache_impl.h @@ -137,7 +137,7 @@ void DRW_mesh_cache_sculpt_coords_ensure(struct Mesh *me); /* Particles */ struct Gwn_Batch *DRW_particles_batch_cache_get_hair(struct ParticleSystem *psys, struct ModifierData *md); -struct Gwn_Batch *DRW_particles_batch_cache_get_dots(struct ParticleSystem *psys); +struct Gwn_Batch *DRW_particles_batch_cache_get_dots(struct Object *object, struct ParticleSystem *psys); /* Hair */ struct Gwn_Batch *DRW_hair_batch_cache_get_fibers(struct HairSystem *hsys, struct DerivedMesh *scalp, int subdiv, diff --git a/source/blender/draw/intern/draw_cache_impl_mesh.c b/source/blender/draw/intern/draw_cache_impl_mesh.c index b44c5b8a20b..f7a82c6d0c5 100644 --- a/source/blender/draw/intern/draw_cache_impl_mesh.c +++ b/source/blender/draw/intern/draw_cache_impl_mesh.c @@ -1665,6 +1665,46 @@ void DRW_mesh_batch_cache_dirty(Mesh *me, int mode) } } +/** + * This only clear the batches associated to the given vertex buffer. + **/ +static void mesh_batch_cache_clear_selective(Mesh *me, Gwn_VertBuf *vert) +{ + MeshBatchCache *cache = me->batch_cache; + if (!cache) { + return; + } + + BLI_assert(vert != NULL); + + if (cache->pos_with_normals == vert) { + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_normals); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_weights); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_vert_colors); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_id); + GWN_BATCH_DISCARD_SAFE(cache->triangles_with_select_mask); + GWN_BATCH_DISCARD_SAFE(cache->points_with_normals); + if (cache->shaded_triangles) { + for (int i = 0; i < cache->mat_len; ++i) { + GWN_BATCH_DISCARD_SAFE(cache->shaded_triangles[i]); + } + } + MEM_SAFE_FREE(cache->shaded_triangles); + if (cache->texpaint_triangles) { + for (int i = 0; i < cache->mat_len; ++i) { + GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles[i]); + } + } + MEM_SAFE_FREE(cache->texpaint_triangles); + GWN_BATCH_DISCARD_SAFE(cache->texpaint_triangles_single); + } + /* TODO: add the other ones if needed. */ + else { + /* Does not match any vertbuf in the batch cache! */ + BLI_assert(0); + } +} + static void mesh_batch_cache_clear(Mesh *me) { MeshBatchCache *cache = me->batch_cache; @@ -3878,21 +3918,10 @@ void DRW_mesh_cache_sculpt_coords_ensure(Mesh *me) if (me->batch_cache) { MeshBatchCache *cache = mesh_batch_cache_get(me); if (cache && cache->pos_with_normals && cache->is_sculpt_points_tag) { - - const int datatype = MR_DATATYPE_VERT | MR_DATATYPE_LOOPTRI | MR_DATATYPE_LOOP | MR_DATATYPE_POLY; - MeshRenderData *rdata = mesh_render_data_create(me, datatype); - - Gwn_VertBuf *pos_with_normals = cache->pos_with_normals; - cache->pos_with_normals = NULL; - GWN_vertbuf_clear(pos_with_normals); - Gwn_VertBuf *vbo = mesh_batch_cache_get_tri_pos_and_normals(rdata, cache); - *pos_with_normals = *vbo; - GWN_vertformat_copy(&pos_with_normals->format, &vbo->format); - - free(vbo); - cache->pos_with_normals = pos_with_normals; - - mesh_render_data_free(rdata); + /* XXX Force update of all the batches that contains the pos_with_normals buffer. + * TODO(fclem): Ideally, Gawain should provide a way to update a buffer without destroying it. */ + mesh_batch_cache_clear_selective(me, cache->pos_with_normals); + GWN_VERTBUF_DISCARD_SAFE(cache->pos_with_normals); } cache->is_sculpt_points_tag = false; } diff --git a/source/blender/draw/intern/draw_cache_impl_particles.c b/source/blender/draw/intern/draw_cache_impl_particles.c index da0cc457b99..0530d05c199 100644 --- a/source/blender/draw/intern/draw_cache_impl_particles.c +++ b/source/blender/draw/intern/draw_cache_impl_particles.c @@ -29,6 +29,8 @@ * \brief Particle API for render engines */ +#include "DRW_render.h" + #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" @@ -53,11 +55,11 @@ static void particle_batch_cache_clear(ParticleSystem *psys); typedef struct ParticleBatchCache { Gwn_VertBuf *pos; - Gwn_IndexBuf *segments; + Gwn_IndexBuf *indices; Gwn_Batch *hairs; - int segment_count; + int elems_count; int point_count; /* settings to determine if cache is invalid */ @@ -132,7 +134,7 @@ static void particle_batch_cache_clear(ParticleSystem *psys) GWN_BATCH_DISCARD_SAFE(cache->hairs); GWN_VERTBUF_DISCARD_SAFE(cache->pos); - GWN_INDEXBUF_DISCARD_SAFE(cache->segments); + GWN_INDEXBUF_DISCARD_SAFE(cache->indices); } void DRW_particle_batch_cache_free(ParticleSystem *psys) @@ -143,8 +145,8 @@ void DRW_particle_batch_cache_free(ParticleSystem *psys) static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache) { - if (cache->pos == NULL || cache->segments == NULL) { - cache->segment_count = 0; + if (cache->pos == NULL || cache->indices == NULL) { + cache->elems_count = 0; cache->point_count = 0; if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { @@ -152,7 +154,7 @@ static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache) ParticleCacheKey *path = psys->pathcache[i]; if (path->segments > 0) { - cache->segment_count += path->segments; + cache->elems_count += path->segments + 2; cache->point_count += path->segments + 1; } } @@ -165,7 +167,7 @@ static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache) ParticleCacheKey *path = psys->childcache[i]; if (path->segments > 0) { - cache->segment_count += path->segments; + cache->elems_count += path->segments + 2; cache->point_count += path->segments + 1; } } @@ -176,128 +178,114 @@ static void ensure_seg_pt_count(ParticleSystem *psys, ParticleBatchCache *cache) /* Gwn_Batch cache usage. */ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, ModifierData *md, ParticleBatchCache *cache) { - if (cache->pos == NULL || cache->segments == NULL) { - int curr_point = 0; - ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; - - GWN_VERTBUF_DISCARD_SAFE(cache->pos); - GWN_INDEXBUF_DISCARD_SAFE(cache->segments); - - static Gwn_VertFormat format = { 0 }; - static struct { uint pos, tan, ind; } attr_id; - unsigned int *uv_id = NULL; - int uv_layers = 0; - MTFace **mtfaces = NULL; - float (**parent_uvs)[2] = NULL; - bool simple = psys->part->childtype == PART_CHILD_PARTICLES; - - if (psmd) { - if (CustomData_has_layer(&psmd->dm_final->loopData, CD_MLOOPUV)) { - uv_layers = CustomData_number_of_layers(&psmd->dm_final->loopData, CD_MLOOPUV); - } + if (cache->pos != NULL && cache->indices != NULL) { + return; + } + + int curr_point = 0; + ParticleSystemModifierData *psmd = (ParticleSystemModifierData *)md; + + GWN_VERTBUF_DISCARD_SAFE(cache->pos); + GWN_INDEXBUF_DISCARD_SAFE(cache->indices); + + static Gwn_VertFormat format = { 0 }; + static struct { uint pos, tan, ind; } attr_id; + unsigned int *uv_id = NULL; + int uv_layers = 0; + MTFace **mtfaces = NULL; + float (**parent_uvs)[2] = NULL; + bool simple = psys->part->childtype == PART_CHILD_PARTICLES; + + if (psmd) { + if (CustomData_has_layer(&psmd->dm_final->loopData, CD_MLOOPUV)) { + uv_layers = CustomData_number_of_layers(&psmd->dm_final->loopData, CD_MLOOPUV); } + } - GWN_vertformat_clear(&format); + GWN_vertformat_clear(&format); - /* initialize vertex format */ - attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - attr_id.tan = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - attr_id.ind = GWN_vertformat_attr_add(&format, "ind", GWN_COMP_I32, 1, GWN_FETCH_INT); + /* initialize vertex format */ + attr_id.pos = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + attr_id.tan = GWN_vertformat_attr_add(&format, "nor", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + attr_id.ind = GWN_vertformat_attr_add(&format, "ind", GWN_COMP_I32, 1, GWN_FETCH_INT); - if (psmd) { - uv_id = MEM_mallocN(sizeof(*uv_id) * uv_layers, "UV attrib format"); + if (psmd) { + uv_id = MEM_mallocN(sizeof(*uv_id) * uv_layers, "UV attrib format"); - for (int i = 0; i < uv_layers; i++) { - const char *name = CustomData_get_layer_name(&psmd->dm_final->loopData, CD_MLOOPUV, i); - char uuid[32]; + for (int i = 0; i < uv_layers; i++) { + const char *name = CustomData_get_layer_name(&psmd->dm_final->loopData, CD_MLOOPUV, i); + char uuid[32]; - BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(name)); - uv_id[i] = GWN_vertformat_attr_add(&format, uuid, GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - } + BLI_snprintf(uuid, sizeof(uuid), "u%u", BLI_ghashutil_strhash_p(name)); + uv_id[i] = GWN_vertformat_attr_add(&format, uuid, GWN_COMP_F32, 2, GWN_FETCH_FLOAT); } + } - cache->pos = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(cache->pos, cache->point_count); + cache->pos = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(cache->pos, cache->point_count); - Gwn_IndexBufBuilder elb; - GWN_indexbuf_init(&elb, GWN_PRIM_LINES, cache->segment_count, cache->point_count); + Gwn_IndexBufBuilder elb; + GWN_indexbuf_init_ex(&elb, GWN_PRIM_LINE_STRIP, cache->elems_count, cache->point_count, true); - if (uv_layers) { - DM_ensure_tessface(psmd->dm_final); + if (uv_layers) { + DM_ensure_tessface(psmd->dm_final); - mtfaces = MEM_mallocN(sizeof(*mtfaces) * uv_layers, "Faces UV layers"); + mtfaces = MEM_mallocN(sizeof(*mtfaces) * uv_layers, "Faces UV layers"); - for (int i = 0; i < uv_layers; i++) { - mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->dm_final->faceData, CD_MTFACE, i); - } + for (int i = 0; i < uv_layers; i++) { + mtfaces[i] = (MTFace *)CustomData_get_layer_n(&psmd->dm_final->faceData, CD_MTFACE, i); } + } - if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { - if (simple) { - parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs"); - } + if (psys->pathcache && (!psys->childcache || (psys->part->draw & PART_DRAW_PARENT))) { + if (simple) { + parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs"); + } - for (int i = 0; i < psys->totpart; i++) { - ParticleCacheKey *path = psys->pathcache[i]; + for (int i = 0; i < psys->totpart; i++) { + ParticleCacheKey *path = psys->pathcache[i]; - if (path->segments > 0) { - float tangent[3]; - int from = psmd ? psmd->psys->part->from : 0; - float (*uv)[2] = NULL; + if (path->segments > 0) { + float tangent[3]; + int from = psmd ? psmd->psys->part->from : 0; + float (*uv)[2] = NULL; - if (psmd) { - uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs"); + if (psmd) { + uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs"); - if (simple) { - parent_uvs[i] = uv; - } + if (simple) { + parent_uvs[i] = uv; } + } - if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { - ParticleData *particle = &psys->particles[i]; - int num = particle->num_dmcache; + if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + ParticleData *particle = &psys->particles[i]; + int num = particle->num_dmcache; - if (num == DMCACHE_NOTFOUND) { - if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) { - num = particle->num; - } - } - - if (num != DMCACHE_NOTFOUND) { - MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); - - for (int j = 0; j < uv_layers; j++) { - psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]); - } + if (num == DMCACHE_NOTFOUND) { + if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) { + num = particle->num; } } - for (int j = 0; j < path->segments; j++) { - if (j == 0) { - sub_v3_v3v3(tangent, path[j + 1].co, path[j].co); - } - else { - sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co); - } - - GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[j].co); - GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent); - GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i); + if (num != DMCACHE_NOTFOUND) { + MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); - if (psmd) { - for (int k = 0; k < uv_layers; k++) { - GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]); - } + for (int j = 0; j < uv_layers; j++) { + psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]); } - - GWN_indexbuf_add_line_verts(&elb, curr_point, curr_point + 1); - - curr_point++; } + } - sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co); + for (int j = 0; j < path->segments; j++) { + if (j == 0) { + sub_v3_v3v3(tangent, path[j + 1].co, path[j].co); + } + else { + sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co); + } - GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[path->segments].co); + GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[j].co); GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent); GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i); @@ -305,102 +293,105 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Modifi for (int k = 0; k < uv_layers; k++) { GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]); } - - if (!simple) { - MEM_freeN(uv); - } } + GWN_indexbuf_add_generic_vert(&elb, curr_point); + curr_point++; } - } - } - if (psys->childcache) { - int child_count = psys->totchild * psys->part->disp / 100; + sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co); - if (simple && !parent_uvs) { - parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs"); - } + GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[path->segments].co); + GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent); + GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &i); - for (int i = 0, x = psys->totpart; i < child_count; i++, x++) { - ParticleCacheKey *path = psys->childcache[i]; - float tangent[3]; - - if (path->segments > 0) { - int from = psmd ? psmd->psys->part->from : 0; - float (*uv)[2] = NULL; + if (psmd) { + for (int k = 0; k < uv_layers; k++) { + GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, uv[k]); + } if (!simple) { - if (psmd) { - uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs"); - } + MEM_freeN(uv); + } + } - if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { - ChildParticle *particle = &psys->child[i]; - int num = particle->num; + /* finish the segment and add restart primitive */ + GWN_indexbuf_add_generic_vert(&elb, curr_point); + GWN_indexbuf_add_primitive_restart(&elb); - if (num != DMCACHE_NOTFOUND) { - MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); + curr_point++; + } + } + } - for (int j = 0; j < uv_layers; j++) { - psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]); - } - } - } - } - else if (!parent_uvs[psys->child[i].parent]) { - if (psmd) { - parent_uvs[psys->child[i].parent] = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs"); - } + if (psys->childcache) { + int child_count = psys->totchild * psys->part->disp / 100; - if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { - ParticleData *particle = &psys->particles[psys->child[i].parent]; - int num = particle->num_dmcache; + if (simple && !parent_uvs) { + parent_uvs = MEM_callocN(sizeof(*parent_uvs) * psys->totpart, "Parent particle UVs"); + } - if (num == DMCACHE_NOTFOUND) { - if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) { - num = particle->num; - } - } + for (int i = 0, x = psys->totpart; i < child_count; i++, x++) { + ParticleCacheKey *path = psys->childcache[i]; + float tangent[3]; - if (num != DMCACHE_NOTFOUND) { - MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); + if (path->segments > 0) { + int from = psmd ? psmd->psys->part->from : 0; + float (*uv)[2] = NULL; - for (int j = 0; j < uv_layers; j++) { - psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, parent_uvs[psys->child[i].parent][j]); - } - } - } + if (!simple) { + if (psmd) { + uv = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs"); } - for (int j = 0; j < path->segments; j++) { - if (j == 0) { - sub_v3_v3v3(tangent, path[j + 1].co, path[j].co); - } - else { - sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co); + if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + ChildParticle *particle = &psys->child[i]; + int num = particle->num; + + if (num != DMCACHE_NOTFOUND) { + MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); + + for (int j = 0; j < uv_layers; j++) { + psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, uv[j]); + } } + } + } + else if (!parent_uvs[psys->child[i].parent]) { + if (psmd) { + parent_uvs[psys->child[i].parent] = MEM_callocN(sizeof(*uv) * uv_layers, "Particle UVs"); + } - GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[j].co); - GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent); - GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x); + if (ELEM(from, PART_FROM_FACE, PART_FROM_VOLUME)) { + ParticleData *particle = &psys->particles[psys->child[i].parent]; + int num = particle->num_dmcache; - if (psmd) { - for (int k = 0; k < uv_layers; k++) { - GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, - simple ? parent_uvs[psys->child[i].parent][k] : uv[k]); + if (num == DMCACHE_NOTFOUND) { + if (particle->num < psmd->dm_final->getNumTessFaces(psmd->dm_final)) { + num = particle->num; } } - GWN_indexbuf_add_line_verts(&elb, curr_point, curr_point + 1); + if (num != DMCACHE_NOTFOUND) { + MFace *mface = psmd->dm_final->getTessFaceData(psmd->dm_final, num, CD_MFACE); - curr_point++; + for (int j = 0; j < uv_layers; j++) { + psys_interpolate_uvs(mtfaces[j] + num, mface->v4, particle->fuv, parent_uvs[psys->child[i].parent][j]); + } + } } + } - sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co); + for (int j = 0; j < path->segments; j++) { + if (j == 0) { + sub_v3_v3v3(tangent, path[j + 1].co, path[j].co); + } + else { + sub_v3_v3v3(tangent, path[j + 1].co, path[j - 1].co); + } - GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[path->segments].co); + GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[j].co); GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent); GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x); @@ -409,88 +400,129 @@ static void particle_batch_cache_ensure_pos_and_seg(ParticleSystem *psys, Modifi GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, simple ? parent_uvs[psys->child[i].parent][k] : uv[k]); } - - if (!simple) { - MEM_freeN(uv); - } } + GWN_indexbuf_add_generic_vert(&elb, curr_point); + curr_point++; } - } - } - if (parent_uvs) { - for (int i = 0; i < psys->totpart; i++) { - MEM_SAFE_FREE(parent_uvs[i]); - } + sub_v3_v3v3(tangent, path[path->segments].co, path[path->segments - 1].co); - MEM_freeN(parent_uvs); - } + GWN_vertbuf_attr_set(cache->pos, attr_id.pos, curr_point, path[path->segments].co); + GWN_vertbuf_attr_set(cache->pos, attr_id.tan, curr_point, tangent); + GWN_vertbuf_attr_set(cache->pos, attr_id.ind, curr_point, &x); + + if (psmd) { + for (int k = 0; k < uv_layers; k++) { + GWN_vertbuf_attr_set(cache->pos, uv_id[k], curr_point, + simple ? parent_uvs[psys->child[i].parent][k] : uv[k]); + } + + if (!simple) { + MEM_freeN(uv); + } + } + + /* finish the segment and add restart primitive */ + GWN_indexbuf_add_generic_vert(&elb, curr_point); + GWN_indexbuf_add_primitive_restart(&elb); - if (uv_layers) { - MEM_freeN(mtfaces); + curr_point++; + } } + } - if (psmd) { - MEM_freeN(uv_id); + if (parent_uvs) { + for (int i = 0; i < psys->totpart; i++) { + MEM_SAFE_FREE(parent_uvs[i]); } - cache->segments = GWN_indexbuf_build(&elb); + MEM_freeN(parent_uvs); + } + + if (uv_layers) { + MEM_freeN(mtfaces); } + + if (psmd) { + MEM_freeN(uv_id); + } + + cache->indices = GWN_indexbuf_build(&elb); } -static void particle_batch_cache_ensure_pos(ParticleSystem *psys, ParticleBatchCache *cache) +static void particle_batch_cache_ensure_pos(Object *object, ParticleSystem *psys, ParticleBatchCache *cache) { - if (cache->pos == NULL) { - static Gwn_VertFormat format = { 0 }; - static unsigned pos_id, rot_id, val_id; - int i, curr_point; - ParticleData *pa; - - GWN_VERTBUF_DISCARD_SAFE(cache->pos); - GWN_INDEXBUF_DISCARD_SAFE(cache->segments); - - if (format.attrib_ct == 0) { - /* initialize vertex format */ - pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); - rot_id = GWN_vertformat_attr_add(&format, "rot", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); - val_id = GWN_vertformat_attr_add(&format, "val", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); + if (cache->pos != NULL) { + return; + } + + static Gwn_VertFormat format = { 0 }; + static unsigned pos_id, rot_id, val_id; + int i, curr_point; + ParticleData *pa; + ParticleKey state; + ParticleSimulationData sim = {NULL}; + const DRWContextState *draw_ctx = DRW_context_state_get(); + + sim.eval_ctx = &draw_ctx->eval_ctx; + sim.scene = draw_ctx->scene; + sim.ob = object; + sim.psys = psys; + sim.psmd = psys_get_modifier(object, psys); + + if (psys->part->phystype == PART_PHYS_KEYED) { + if (psys->flag & PSYS_KEYED) { + psys_count_keyed_targets(&sim); + if (psys->totkeyed == 0) + return; } + } - cache->pos = GWN_vertbuf_create_with_format(&format); - GWN_vertbuf_data_alloc(cache->pos, psys->totpart); - - for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) { - if (pa->state.time >= pa->time && pa->state.time < pa->dietime && - !(pa->flag & (PARS_NO_DISP | PARS_UNEXIST))) - { - float val; - - GWN_vertbuf_attr_set(cache->pos, pos_id, curr_point, pa->state.co); - GWN_vertbuf_attr_set(cache->pos, rot_id, curr_point, pa->state.rot); - - switch (psys->part->draw_col) { - case PART_DRAW_COL_VEL: - val = len_v3(pa->state.vel) / psys->part->color_vec_max; - break; - case PART_DRAW_COL_ACC: - val = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * psys->part->color_vec_max); - break; - default: - val = -1.0f; - break; - } + GWN_VERTBUF_DISCARD_SAFE(cache->pos); + GWN_INDEXBUF_DISCARD_SAFE(cache->indices); - GWN_vertbuf_attr_set(cache->pos, val_id, curr_point, &val); + if (format.attrib_ct == 0) { + /* initialize vertex format */ + pos_id = GWN_vertformat_attr_add(&format, "pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + rot_id = GWN_vertformat_attr_add(&format, "rot", GWN_COMP_F32, 4, GWN_FETCH_FLOAT); + val_id = GWN_vertformat_attr_add(&format, "val", GWN_COMP_F32, 1, GWN_FETCH_FLOAT); + } - curr_point++; - } + cache->pos = GWN_vertbuf_create_with_format(&format); + GWN_vertbuf_data_alloc(cache->pos, psys->totpart); + + for (curr_point = 0, i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) { + state.time = draw_ctx->eval_ctx.ctime; + if (!psys_get_particle_state(&sim, curr_point, &state, 0)) { + continue; } - if (curr_point != psys->totpart) { - GWN_vertbuf_data_resize(cache->pos, curr_point); + float val; + + GWN_vertbuf_attr_set(cache->pos, pos_id, curr_point, pa->state.co); + GWN_vertbuf_attr_set(cache->pos, rot_id, curr_point, pa->state.rot); + + switch (psys->part->draw_col) { + case PART_DRAW_COL_VEL: + val = len_v3(pa->state.vel) / psys->part->color_vec_max; + break; + case PART_DRAW_COL_ACC: + val = len_v3v3(pa->state.vel, pa->prev_state.vel) / ((pa->state.time - pa->prev_state.time) * psys->part->color_vec_max); + break; + default: + val = -1.0f; + break; } + + GWN_vertbuf_attr_set(cache->pos, val_id, curr_point, &val); + + curr_point++; + } + + if (curr_point != psys->totpart) { + GWN_vertbuf_data_resize(cache->pos, curr_point); } } @@ -501,18 +533,18 @@ Gwn_Batch *DRW_particles_batch_cache_get_hair(ParticleSystem *psys, ModifierData if (cache->hairs == NULL) { ensure_seg_pt_count(psys, cache); particle_batch_cache_ensure_pos_and_seg(psys, md, cache); - cache->hairs = GWN_batch_create(GWN_PRIM_LINES, cache->pos, cache->segments); + cache->hairs = GWN_batch_create(GWN_PRIM_LINE_STRIP, cache->pos, cache->indices); } return cache->hairs; } -Gwn_Batch *DRW_particles_batch_cache_get_dots(ParticleSystem *psys) +Gwn_Batch *DRW_particles_batch_cache_get_dots(Object *object, ParticleSystem *psys) { ParticleBatchCache *cache = particle_batch_cache_get(psys); if (cache->hairs == NULL) { - particle_batch_cache_ensure_pos(psys, cache); + particle_batch_cache_ensure_pos(object, psys, cache); cache->hairs = GWN_batch_create(GWN_PRIM_POINTS, cache->pos, NULL); } diff --git a/source/blender/draw/intern/draw_common.c b/source/blender/draw/intern/draw_common.c index 0eb97a54ba5..8d23688959c 100644 --- a/source/blender/draw/intern/draw_common.c +++ b/source/blender/draw/intern/draw_common.c @@ -35,7 +35,6 @@ #include "draw_common.h" - #if 0 #define UI_COLOR_RGB_FROM_U8(r, g, b, v4) \ ARRAY_SET_ITEMS(v4, (float)r / 255.0f, (float)g / 255.0f, (float)b / 255.0f, 1.0) @@ -123,12 +122,12 @@ void DRW_globals_update(void) ts.sizeEdge = 1.0f / 2.0f; /* TODO Theme */ ts.sizeEdgeFix = 0.5f + 2.0f * (2.0f * (MAX2(ts.sizeVertex, ts.sizeEdge)) * (float)M_SQRT1_2); - /* TODO Waiting for notifiers to invalidate cache */ - if (globals_ubo) { - DRW_uniformbuffer_free(globals_ubo); + + if (globals_ubo == NULL) { + globals_ubo = DRW_uniformbuffer_create(sizeof(GlobalsUboStorage), &ts); } - globals_ubo = DRW_uniformbuffer_create(sizeof(GlobalsUboStorage), &ts); + DRW_uniformbuffer_update(globals_ubo, &ts); ColorBand ramp = {0}; float *colors; @@ -157,6 +156,29 @@ void DRW_globals_update(void) /* ********************************* SHGROUP ************************************* */ +static struct { + struct Gwn_VertFormat *instance_screenspace; + struct Gwn_VertFormat *instance_color; + struct Gwn_VertFormat *instance_screen_aligned; + struct Gwn_VertFormat *instance_scaled; + struct Gwn_VertFormat *instance_sized; + struct Gwn_VertFormat *instance; + struct Gwn_VertFormat *instance_camera; + struct Gwn_VertFormat *instance_distance_lines; + struct Gwn_VertFormat *instance_spot; + struct Gwn_VertFormat *instance_bone_envelope_wire; + struct Gwn_VertFormat *instance_bone_envelope_solid; + struct Gwn_VertFormat *instance_mball_handles; +} g_formats = {NULL}; + +void DRW_globals_free(void) +{ + struct Gwn_VertFormat **format = &g_formats.instance_screenspace; + for (int i = 0; i < sizeof(g_formats) / sizeof(void *); ++i, ++format) { + MEM_SAFE_FREE(*format); + } +} + DRWShadingGroup *shgroup_dynlines_uniform_color(DRWPass *pass, float color[4]) { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_UNIFORM_COLOR); @@ -204,9 +226,12 @@ DRWShadingGroup *shgroup_instance_screenspace(DRWPass *pass, struct Gwn_Batch *g { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "world_pos", 3); - DRW_shgroup_attrib_float(grp, "color", 3); + DRW_shgroup_instance_format(g_formats.instance_screenspace, { + {"world_pos", DRW_ATTRIB_FLOAT, 3}, + {"color" , DRW_ATTRIB_FLOAT, 3} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_screenspace); DRW_shgroup_uniform_float(grp, "size", size, 1); DRW_shgroup_uniform_float(grp, "pixel_size", DRW_viewport_pixelsize_get(), 1); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); @@ -220,9 +245,12 @@ DRWShadingGroup *shgroup_instance_solid(DRWPass *pass, struct Gwn_Batch *geom) static float light[3] = {0.0f, 0.0f, 1.0f}; GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_SIMPLE_LIGHTING_VARIYING_COLOR); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); - DRW_shgroup_attrib_float(grp, "color", 4); + DRW_shgroup_instance_format(g_formats.instance_color, { + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}, + {"color" , DRW_ATTRIB_FLOAT, 4} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_color); DRW_shgroup_uniform_vec3(grp, "light", light, 1); return grp; @@ -232,9 +260,12 @@ DRWShadingGroup *shgroup_instance_wire(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_OBJECTSPACE_VARIYING_COLOR); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); - DRW_shgroup_attrib_float(grp, "color", 4); + DRW_shgroup_instance_format(g_formats.instance_color, { + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}, + {"color" , DRW_ATTRIB_FLOAT, 4} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_color); return grp; } @@ -243,10 +274,13 @@ DRWShadingGroup *shgroup_instance_screen_aligned(DRWPass *pass, struct Gwn_Batch { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "size", 1); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_screen_aligned, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"size" , DRW_ATTRIB_FLOAT, 1}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_screen_aligned); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); return grp; @@ -256,10 +290,13 @@ DRWShadingGroup *shgroup_instance_axis_names(DRWPass *pass, struct Gwn_Batch *ge { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_SCREEN_ALIGNED_AXIS); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "size", 1); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_screen_aligned, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"size" , DRW_ATTRIB_FLOAT, 1}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_screen_aligned); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); return grp; @@ -269,10 +306,13 @@ DRWShadingGroup *shgroup_instance_scaled(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SCALE); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "size", 3); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_scaled, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"size" , DRW_ATTRIB_FLOAT, 3}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_scaled); return grp; } @@ -281,10 +321,13 @@ DRWShadingGroup *shgroup_instance(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_INSTANCE_VARIYING_COLOR_VARIYING_SIZE); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "size", 1); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_sized, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"size" , DRW_ATTRIB_FLOAT, 1}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_sized); return grp; } @@ -293,12 +336,15 @@ DRWShadingGroup *shgroup_camera_instance(DRWPass *pass, struct Gwn_Batch *geom) { GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_CAMERA); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "corners", 8); - DRW_shgroup_attrib_float(grp, "depth", 1); - DRW_shgroup_attrib_float(grp, "tria", 4); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_camera, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"corners" , DRW_ATTRIB_FLOAT, 8}, + {"depth" , DRW_ATTRIB_FLOAT, 1}, + {"tria" , DRW_ATTRIB_FLOAT, 4}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_camera); return grp; } @@ -308,11 +354,14 @@ DRWShadingGroup *shgroup_distance_lines_instance(DRWPass *pass, struct Gwn_Batch GPUShader *sh_inst = GPU_shader_get_builtin_shader(GPU_SHADER_DISTANCE_LINES); static float point_size = 4.0f; - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "start", 1); - DRW_shgroup_attrib_float(grp, "end", 1); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_distance_lines, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"start" , DRW_ATTRIB_FLOAT, 1}, + {"end" , DRW_ATTRIB_FLOAT, 1}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_distance_lines); DRW_shgroup_uniform_float(grp, "size", &point_size, 1); return grp; @@ -324,9 +373,12 @@ DRWShadingGroup *shgroup_spot_instance(DRWPass *pass, struct Gwn_Batch *geom) static const int True = true; static const int False = false; - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); + DRW_shgroup_instance_format(g_formats.instance_spot, { + {"color" , DRW_ATTRIB_FLOAT, 3}, + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh_inst, pass, geom, g_formats.instance_spot); DRW_shgroup_uniform_bool(grp, "drawFront", &False, 1); DRW_shgroup_uniform_bool(grp, "drawBack", &False, 1); DRW_shgroup_uniform_bool(grp, "drawSilhouette", &True, 1); @@ -338,12 +390,15 @@ DRWShadingGroup *shgroup_instance_bone_envelope_wire(DRWPass *pass, struct Gwn_B { GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_WIRE); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); - DRW_shgroup_attrib_float(grp, "color", 4); - DRW_shgroup_attrib_float(grp, "radius_head", 1); - DRW_shgroup_attrib_float(grp, "radius_tail", 1); - DRW_shgroup_attrib_float(grp, "distance", 1); + DRW_shgroup_instance_format(g_formats.instance_bone_envelope_wire, { + {"InstanceModelMatrix", DRW_ATTRIB_FLOAT, 16}, + {"color" , DRW_ATTRIB_FLOAT, 4}, + {"radius_head" , DRW_ATTRIB_FLOAT, 1}, + {"radius_tail" , DRW_ATTRIB_FLOAT, 1}, + {"distance" , DRW_ATTRIB_FLOAT, 1} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_bone_envelope_wire); return grp; } @@ -353,24 +408,30 @@ DRWShadingGroup *shgroup_instance_bone_envelope_solid(DRWPass *pass, struct Gwn_ static float light[3] = {0.0f, 0.0f, 1.0f}; GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_BONE_ENVELOPE_SOLID); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); - DRW_shgroup_attrib_float(grp, "color", 4); - DRW_shgroup_attrib_float(grp, "radius_head", 1); - DRW_shgroup_attrib_float(grp, "radius_tail", 1); + DRW_shgroup_instance_format(g_formats.instance_bone_envelope_solid, { + {"InstanceModelMatrix" , DRW_ATTRIB_FLOAT, 16}, + {"color" , DRW_ATTRIB_FLOAT, 4}, + {"radius_head" , DRW_ATTRIB_FLOAT, 1}, + {"radius_tail" , DRW_ATTRIB_FLOAT, 1} + }); + + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_bone_envelope_solid); DRW_shgroup_uniform_vec3(grp, "light", light, 1); return grp; } -DRWShadingGroup *shgroup_instance_mball_helpers(DRWPass *pass, struct Gwn_Batch *geom) +DRWShadingGroup *shgroup_instance_mball_handles(DRWPass *pass, struct Gwn_Batch *geom) { - GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_MBALL_HELPERS); + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_INSTANCE_MBALL_HANDLES); + + DRW_shgroup_instance_format(g_formats.instance_mball_handles, { + {"ScaleTranslationMatrix" , DRW_ATTRIB_FLOAT, 12}, + {"radius" , DRW_ATTRIB_FLOAT, 1}, + {"color" , DRW_ATTRIB_FLOAT, 3} + }); - DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom); - DRW_shgroup_attrib_float(grp, "ScaleTranslationMatrix", 12); - DRW_shgroup_attrib_float(grp, "radius", 1); - DRW_shgroup_attrib_float(grp, "color", 3); + DRWShadingGroup *grp = DRW_shgroup_instance_create(sh, pass, geom, g_formats.instance_mball_handles); DRW_shgroup_uniform_vec3(grp, "screen_vecs[0]", DRW_viewport_screenvecs_get(), 2); return grp; @@ -386,7 +447,8 @@ DRWShadingGroup *shgroup_instance_mball_helpers(DRWPass *pass, struct Gwn_Batch */ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color) { - const bool is_edit = (ob->mode & OB_MODE_EDIT) != 0; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_edit = (draw_ctx->object_mode & OB_MODE_EDIT) != 0; const bool active = (view_layer->basact && view_layer->basact->object == ob); /* confusing logic here, there are 2 methods of setting the color * 'colortab[colindex]' and 'theme_id', colindex overrides theme_id. @@ -419,6 +481,7 @@ int DRW_object_wire_theme_get(Object *ob, ViewLayer *view_layer, float **r_color else if (ob->type == OB_SPEAKER) theme_id = TH_SPEAKER; else if (ob->type == OB_CAMERA) theme_id = TH_CAMERA; else if (ob->type == OB_EMPTY) theme_id = TH_EMPTY; + else if (ob->type == OB_LIGHTPROBE) theme_id = TH_EMPTY; /* TODO add lightprobe color */ /* fallback to TH_WIRE */ } } diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 93e63308fb6..3d498cba8b6 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -105,6 +105,7 @@ typedef struct GlobalsUboStorage { /* Keep in sync with globalsBlock in shaders */ void DRW_globals_update(void); +void DRW_globals_free(void); struct DRWShadingGroup *shgroup_dynlines_uniform_color(struct DRWPass *pass, float color[4]); struct DRWShadingGroup *shgroup_dynpoints_uniform_color(struct DRWPass *pass, float color[4], float *size); @@ -123,9 +124,10 @@ struct DRWShadingGroup *shgroup_distance_lines_instance(struct DRWPass *pass, st struct DRWShadingGroup *shgroup_spot_instance(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_bone_envelope_wire(struct DRWPass *pass, struct Gwn_Batch *geom); struct DRWShadingGroup *shgroup_instance_bone_envelope_solid(struct DRWPass *pass, struct Gwn_Batch *geom); -struct DRWShadingGroup *shgroup_instance_mball_helpers(struct DRWPass *pass, struct Gwn_Batch *geom); +struct DRWShadingGroup *shgroup_instance_mball_handles(struct DRWPass *pass, struct Gwn_Batch *geom); -int DRW_object_wire_theme_get(struct Object *ob, struct ViewLayer *view_layer, float **r_color); +int DRW_object_wire_theme_get( + struct Object *ob, struct ViewLayer *view_layer, float **r_color); float *DRW_color_background_blend_get(int theme_id); /* draw_armature.c */ diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 82a2143e72a..8f61c46479c 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -55,7 +55,7 @@ void DRW_hair_shader_uniforms(DRWShadingGroup *shgrp, Scene *UNUSED(scene), static float test = 2.5f; DRW_shgroup_uniform_float(shgrp, "ribbon_width", &test, 1); - DRW_shgroup_uniform_buffer(shgrp, "fiber_data", fibertex); + DRW_shgroup_uniform_texture_ref(shgrp, "fiber_data", fibertex); DRW_shgroup_uniform_int(shgrp, "strand_map_start", &texbuffer->strand_map_start, 1); DRW_shgroup_uniform_int(shgrp, "strand_vertex_start", &texbuffer->strand_vertex_start, 1); DRW_shgroup_uniform_int(shgrp, "fiber_start", &texbuffer->fiber_start, 1); diff --git a/source/blender/draw/intern/draw_instance_data.c b/source/blender/draw/intern/draw_instance_data.c index e7ce4374d1c..ee73a2ba2c6 100644 --- a/source/blender/draw/intern/draw_instance_data.c +++ b/source/blender/draw/intern/draw_instance_data.c @@ -34,11 +34,37 @@ #include "draw_instance_data.h" #include "DRW_engine.h" +#include "DRW_render.h" /* For DRW_shgroup_get_instance_count() */ #include "MEM_guardedalloc.h" #include "BLI_utildefines.h" -#define MAX_INSTANCE_DATA_SIZE 32 /* Can be adjusted for more */ +#define BUFFER_CHUNK_SIZE 32 +#define BUFFER_VERTS_CHUNK 32 + +typedef struct DRWBatchingBuffer { + struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */ + Gwn_VertFormat *format; /* Identifier. */ + Gwn_VertBuf *vert; /* Gwn_VertBuf contained in the Gwn_Batch. */ + Gwn_Batch *batch; /* Gwn_Batch containing the Gwn_VertBuf. */ +} DRWBatchingBuffer; + +typedef struct DRWInstancingBuffer { + struct DRWShadingGroup *shgroup; /* Link back to the owning shGroup. Also tells if it's used */ + Gwn_VertFormat *format; /* Identifier. */ + Gwn_Batch *instance; /* Identifier. */ + Gwn_VertBuf *vert; /* Gwn_VertBuf contained in the Gwn_Batch. */ + Gwn_Batch *batch; /* Gwn_Batch containing the Gwn_VertBuf. */ +} DRWInstancingBuffer; + +typedef struct DRWInstanceChunk { + size_t cursor; /* Offset to the next instance data. */ + size_t alloc_size; /* Number of DRWBatchingBuffer/Batches alloc'd in ibufs/btchs. */ + union { + DRWBatchingBuffer *bbufs; + DRWInstancingBuffer *ibufs; + }; +} DRWInstanceChunk; struct DRWInstanceData { struct DRWInstanceData *next; @@ -51,13 +77,206 @@ struct DRWInstanceData { }; struct DRWInstanceDataList { + struct DRWInstanceDataList *next, *prev; /* Linked lists for all possible data pool size */ /* Not entirely sure if we should separate them in the first place. * This is done to minimize the reattribution misses. */ DRWInstanceData *idata_head[MAX_INSTANCE_DATA_SIZE]; DRWInstanceData *idata_tail[MAX_INSTANCE_DATA_SIZE]; + + DRWInstanceChunk instancing; + DRWInstanceChunk batching; }; +static ListBase g_idatalists = {NULL, NULL}; + +/* -------------------------------------------------------------------- */ + +/** \name Instance Buffer Management + * \{ */ + +/** + * This manager allows to distribute existing batches for instancing + * attributes. This reduce the number of batches creation. + * Querying a batch is done with a vertex format. This format should + * be static so that it's pointer never changes (because we are using + * this pointer as identifier [we don't want to check the full format + * that would be too slow]). + **/ + +static void instance_batch_free(Gwn_Batch *batch, void *UNUSED(user_data)) +{ + /* Free all batches that have the same key before they are reused. */ + /* TODO: Make it thread safe! Batch freeing can happen from another thread. */ + /* XXX we need to iterate over all idatalists unless we make some smart + * data structure to store the locations to update. */ + for (DRWInstanceDataList *idatalist = g_idatalists.first; idatalist; idatalist = idatalist->next) { + DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs; + for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) { + if (ibuf->instance == batch) { + BLI_assert(ibuf->shgroup == NULL); /* Make sure it has no other users. */ + GWN_VERTBUF_DISCARD_SAFE(ibuf->vert); + GWN_BATCH_DISCARD_SAFE(ibuf->batch); + /* Tag as non alloced. */ + ibuf->format = NULL; + } + } + } +} + +void DRW_batching_buffer_request( + DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_PrimType type, struct DRWShadingGroup *shgroup, + Gwn_Batch **r_batch, Gwn_VertBuf **r_vert) +{ + DRWInstanceChunk *chunk = &idatalist->batching; + DRWBatchingBuffer *bbuf = idatalist->batching.bbufs; + BLI_assert(format); + /* Search for an unused batch. */ + for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) { + if (bbuf->shgroup == NULL) { + if (bbuf->format == format) { + bbuf->shgroup = shgroup; + *r_batch = bbuf->batch; + *r_vert = bbuf->vert; + return; + } + } + } + int new_id = 0; /* Find insertion point. */ + for (; new_id < chunk->alloc_size; ++new_id) { + if (chunk->bbufs[new_id].format == NULL) + break; + } + /* If there is no batch left. Allocate more. */ + if (new_id == chunk->alloc_size) { + new_id = chunk->alloc_size; + chunk->alloc_size += BUFFER_CHUNK_SIZE; + chunk->bbufs = MEM_reallocN(chunk->bbufs, chunk->alloc_size * sizeof(DRWBatchingBuffer)); + memset(chunk->bbufs + new_id, 0, sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE); + } + /* Create the batch. */ + bbuf = chunk->bbufs + new_id; + bbuf->vert = *r_vert = GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_DYNAMIC); + bbuf->batch = *r_batch = GWN_batch_create_ex(type, bbuf->vert, NULL, 0); + bbuf->format = format; + bbuf->shgroup = shgroup; + GWN_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK); +} + +void DRW_instancing_buffer_request( + DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_Batch *instance, struct DRWShadingGroup *shgroup, + Gwn_Batch **r_batch, Gwn_VertBuf **r_vert) +{ + DRWInstanceChunk *chunk = &idatalist->instancing; + DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs; + BLI_assert(format); + /* Search for an unused batch. */ + for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) { + if (ibuf->shgroup == NULL) { + if (ibuf->format == format) { + if (ibuf->instance == instance) { + ibuf->shgroup = shgroup; + *r_batch = ibuf->batch; + *r_vert = ibuf->vert; + return; + } + } + } + } + int new_id = 0; /* Find insertion point. */ + for (; new_id < chunk->alloc_size; ++new_id) { + if (chunk->ibufs[new_id].format == NULL) + break; + } + /* If there is no batch left. Allocate more. */ + if (new_id == chunk->alloc_size) { + new_id = chunk->alloc_size; + chunk->alloc_size += BUFFER_CHUNK_SIZE; + chunk->ibufs = MEM_reallocN(chunk->ibufs, chunk->alloc_size * sizeof(DRWInstancingBuffer)); + memset(chunk->ibufs + new_id, 0, sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE); + } + /* Create the batch. */ + ibuf = chunk->ibufs + new_id; + ibuf->vert = *r_vert = GWN_vertbuf_create_with_format_ex(format, GWN_USAGE_DYNAMIC); + ibuf->batch = *r_batch = GWN_batch_duplicate(instance); + ibuf->format = format; + ibuf->shgroup = shgroup; + ibuf->instance = instance; + GWN_vertbuf_data_alloc(*r_vert, BUFFER_VERTS_CHUNK); + GWN_batch_instbuf_set(ibuf->batch, ibuf->vert, false); + /* Make sure to free this ibuf if the instance batch gets free. */ + GWN_batch_callback_free_set(instance, &instance_batch_free, NULL); +} + +void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist) +{ + size_t realloc_size = 1; /* Avoid 0 size realloc. */ + /* Resize down buffers in use and send data to GPU & free unused buffers. */ + DRWInstanceChunk *batching = &idatalist->batching; + DRWBatchingBuffer *bbuf = batching->bbufs; + for (int i = 0; i < batching->alloc_size; i++, bbuf++) { + if (bbuf->shgroup != NULL) { + realloc_size = i + 1; + unsigned int vert_ct = DRW_shgroup_get_instance_count(bbuf->shgroup); + vert_ct += (vert_ct == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */ + if (vert_ct + BUFFER_VERTS_CHUNK <= bbuf->vert->vertex_ct) { + unsigned int size = vert_ct + BUFFER_VERTS_CHUNK - 1; + size = size - size % BUFFER_VERTS_CHUNK; + GWN_vertbuf_data_resize(bbuf->vert, size); + } + GWN_vertbuf_use(bbuf->vert); /* Send data. */ + bbuf->shgroup = NULL; /* Set as non used for the next round. */ + } + else { + GWN_VERTBUF_DISCARD_SAFE(bbuf->vert); + GWN_BATCH_DISCARD_SAFE(bbuf->batch); + bbuf->format = NULL; /* Tag as non alloced. */ + } + } + /* Rounding up to nearest chunk size. */ + realloc_size += BUFFER_CHUNK_SIZE - 1; + realloc_size -= realloc_size % BUFFER_CHUNK_SIZE; + /* Resize down if necessary. */ + if (realloc_size < batching->alloc_size) { + batching->alloc_size = realloc_size; + batching->ibufs = MEM_reallocN(batching->ibufs, realloc_size * sizeof(DRWBatchingBuffer)); + } + + realloc_size = 1; + /* Resize down buffers in use and send data to GPU & free unused buffers. */ + DRWInstanceChunk *instancing = &idatalist->instancing; + DRWInstancingBuffer *ibuf = instancing->ibufs; + for (int i = 0; i < instancing->alloc_size; i++, ibuf++) { + if (ibuf->shgroup != NULL) { + realloc_size = i + 1; + unsigned int vert_ct = DRW_shgroup_get_instance_count(ibuf->shgroup); + vert_ct += (vert_ct == 0) ? 1 : 0; /* Do not realloc to 0 size buffer */ + if (vert_ct + BUFFER_VERTS_CHUNK <= ibuf->vert->vertex_ct) { + unsigned int size = vert_ct + BUFFER_VERTS_CHUNK - 1; + size = size - size % BUFFER_VERTS_CHUNK; + GWN_vertbuf_data_resize(ibuf->vert, size); + } + GWN_vertbuf_use(ibuf->vert); /* Send data. */ + ibuf->shgroup = NULL; /* Set as non used for the next round. */ + } + else { + GWN_VERTBUF_DISCARD_SAFE(ibuf->vert); + GWN_BATCH_DISCARD_SAFE(ibuf->batch); + ibuf->format = NULL; /* Tag as non alloced. */ + } + } + /* Rounding up to nearest chunk size. */ + realloc_size += BUFFER_CHUNK_SIZE - 1; + realloc_size -= realloc_size % BUFFER_CHUNK_SIZE; + /* Resize down if necessary. */ + if (realloc_size < instancing->alloc_size) { + instancing->alloc_size = realloc_size; + instancing->ibufs = MEM_reallocN(instancing->ibufs, realloc_size * sizeof(DRWInstancingBuffer)); + } +} + +/** \} */ + /* -------------------------------------------------------------------- */ /** \name Instance Data (DRWInstanceData) @@ -66,7 +285,7 @@ struct DRWInstanceDataList { static DRWInstanceData *drw_instance_data_create( DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group) { - DRWInstanceData *idata = MEM_mallocN(sizeof(DRWInstanceData), "DRWInstanceData"); + DRWInstanceData *idata = MEM_callocN(sizeof(DRWInstanceData), "DRWInstanceData"); idata->next = NULL; idata->used = true; idata->data_size = attrib_size; @@ -145,7 +364,15 @@ DRWInstanceData *DRW_instance_data_request( DRWInstanceDataList *DRW_instance_data_list_create(void) { - return MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"); + DRWInstanceDataList *idatalist = MEM_callocN(sizeof(DRWInstanceDataList), "DRWInstanceDataList"); + idatalist->batching.bbufs = MEM_callocN(sizeof(DRWBatchingBuffer) * BUFFER_CHUNK_SIZE, "DRWBatchingBuffers"); + idatalist->batching.alloc_size = BUFFER_CHUNK_SIZE; + idatalist->instancing.ibufs = MEM_callocN(sizeof(DRWInstancingBuffer) * BUFFER_CHUNK_SIZE, "DRWInstancingBuffers"); + idatalist->instancing.alloc_size = BUFFER_CHUNK_SIZE; + + BLI_addtail(&g_idatalists, idatalist); + + return idatalist; } void DRW_instance_data_list_free(DRWInstanceDataList *idatalist) @@ -161,6 +388,22 @@ void DRW_instance_data_list_free(DRWInstanceDataList *idatalist) idatalist->idata_head[i] = NULL; idatalist->idata_tail[i] = NULL; } + + DRWBatchingBuffer *bbuf = idatalist->batching.bbufs; + for (int i = 0; i < idatalist->batching.alloc_size; i++, bbuf++) { + GWN_VERTBUF_DISCARD_SAFE(bbuf->vert); + GWN_BATCH_DISCARD_SAFE(bbuf->batch); + } + MEM_freeN(idatalist->batching.bbufs); + + DRWInstancingBuffer *ibuf = idatalist->instancing.ibufs; + for (int i = 0; i < idatalist->instancing.alloc_size; i++, ibuf++) { + GWN_VERTBUF_DISCARD_SAFE(ibuf->vert); + GWN_BATCH_DISCARD_SAFE(ibuf->batch); + } + MEM_freeN(idatalist->instancing.ibufs); + + BLI_remlink(&g_idatalists, idatalist); } void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist) diff --git a/source/blender/draw/intern/draw_instance_data.h b/source/blender/draw/intern/draw_instance_data.h index 637c0e3cc24..3b0f7839277 100644 --- a/source/blender/draw/intern/draw_instance_data.h +++ b/source/blender/draw/intern/draw_instance_data.h @@ -26,14 +26,33 @@ #ifndef __DRAW_INSTANCE_DATA_H__ #define __DRAW_INSTANCE_DATA_H__ +#include "BLI_compiler_attrs.h" +#include "BLI_sys_types.h" + +#include "GPU_batch.h" + +#define MAX_INSTANCE_DATA_SIZE 42 /* Can be adjusted for more */ + typedef struct DRWInstanceData DRWInstanceData; typedef struct DRWInstanceDataList DRWInstanceDataList; +struct DRWShadingGroup; + void *DRW_instance_data_next(DRWInstanceData *idata); void *DRW_instance_data_get(DRWInstanceData *idata); DRWInstanceData *DRW_instance_data_request( DRWInstanceDataList *idatalist, unsigned int attrib_size, unsigned int instance_group); +void DRW_batching_buffer_request( + DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_PrimType type, struct DRWShadingGroup *shgroup, + Gwn_Batch **r_batch, Gwn_VertBuf **r_vert); +void DRW_instancing_buffer_request( + DRWInstanceDataList *idatalist, Gwn_VertFormat *format, Gwn_Batch *instance, struct DRWShadingGroup *shgroup, + Gwn_Batch **r_batch, Gwn_VertBuf **r_vert); + +/* Upload all instance data to the GPU as soon as possible. */ +void DRW_instance_buffer_finish(DRWInstanceDataList *idatalist); + void DRW_instance_data_list_reset(DRWInstanceDataList *idatalist); void DRW_instance_data_list_free_unused(DRWInstanceDataList *idatalist); void DRW_instance_data_list_resize(DRWInstanceDataList *idatalist); diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index e5b959cdd3b..752fc52b9b7 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -29,45 +29,28 @@ #include "BLI_mempool.h" #include "BLI_rect.h" #include "BLI_string.h" -#include "BLI_string_utils.h" +#include "BLI_threads.h" -#include "BIF_glutil.h" +#include "BLF_api.h" -#include "BKE_curve.h" #include "BKE_global.h" #include "BKE_mesh.h" #include "BKE_object.h" -#include "BKE_pbvh.h" -#include "BKE_paint.h" #include "BKE_workspace.h" -#include "BLT_translation.h" -#include "BLF_api.h" - -#include "DRW_engine.h" -#include "DRW_render.h" - +#include "draw_manager.h" #include "DNA_camera_types.h" -#include "DNA_curve_types.h" -#include "DNA_view3d_types.h" -#include "DNA_screen_types.h" #include "DNA_mesh_types.h" #include "DNA_meshdata_types.h" -#include "DNA_meta_types.h" #include "ED_space_api.h" #include "ED_screen.h" +#include "ED_view3d.h" -#include "intern/gpu_codegen.h" -#include "GPU_batch.h" #include "GPU_draw.h" #include "GPU_extensions.h" #include "GPU_framebuffer.h" #include "GPU_immediate.h" -#include "GPU_lamp.h" -#include "GPU_material.h" -#include "GPU_shader.h" -#include "GPU_texture.h" #include "GPU_uniformbuffer.h" #include "GPU_viewport.h" #include "GPU_matrix.h" @@ -75,12 +58,13 @@ #include "IMB_colormanagement.h" #include "RE_engine.h" +#include "RE_pipeline.h" #include "UI_interface.h" #include "UI_resources.h" #include "WM_api.h" -#include "WM_types.h" +#include "wm_window.h" #include "draw_manager_text.h" #include "draw_manager_profiling.h" @@ -88,2043 +72,45 @@ /* only for callbacks */ #include "draw_cache_impl.h" -#include "draw_instance_data.h" - #include "draw_mode_engines.h" #include "engines/clay/clay_engine.h" #include "engines/eevee/eevee_engine.h" #include "engines/basic/basic_engine.h" #include "engines/external/external_engine.h" +#include "../../../intern/gawain/gawain/gwn_context.h" + #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" -/* -------------------------------------------------------------------- */ -/** \name Local Features - * \{ */ - -#define USE_PROFILE - -#ifdef USE_PROFILE -# include "PIL_time.h" - -# define PROFILE_TIMER_FALLOFF 0.1 - -# define PROFILE_START(time_start) \ - double time_start = PIL_check_seconds_timer(); - -# define PROFILE_END_ACCUM(time_accum, time_start) { \ - time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \ -} ((void)0) - -/* exp average */ -# define PROFILE_END_UPDATE(time_update, time_start) { \ - double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \ - time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \ - (_time_delta * PROFILE_TIMER_FALLOFF); \ -} ((void)0) - -#else /* USE_PROFILE */ - -# define PROFILE_START(time_start) ((void)0) -# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0) -# define PROFILE_END_UPDATE(time_update, time_start) ((void)0) - -#endif /* USE_PROFILE */ - - -/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */ -#define USE_GPU_SELECT - #ifdef USE_GPU_SELECT -# include "ED_view3d.h" -# include "ED_armature.h" # include "GPU_select.h" #endif -/** \} */ - - -#define MAX_ATTRIB_NAME 32 -#define MAX_ATTRIB_COUNT 6 /* Can be adjusted for more */ -#define MAX_PASS_NAME 32 -#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */ - -extern char datatoc_gpu_shader_2D_vert_glsl[]; -extern char datatoc_gpu_shader_3D_vert_glsl[]; -extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; - -/* Prototypes. */ -static void drw_engines_enable_external(void); - -/* Structures */ -typedef enum { - DRW_UNIFORM_BOOL, - DRW_UNIFORM_SHORT_TO_INT, - DRW_UNIFORM_SHORT_TO_FLOAT, - DRW_UNIFORM_INT, - DRW_UNIFORM_FLOAT, - DRW_UNIFORM_TEXTURE, - DRW_UNIFORM_BUFFER, - DRW_UNIFORM_MAT3, - DRW_UNIFORM_MAT4, - DRW_UNIFORM_BLOCK -} DRWUniformType; - -typedef enum { - DRW_ATTRIB_INT, - DRW_ATTRIB_FLOAT, -} DRWAttribType; - -struct DRWUniform { - struct DRWUniform *next; - DRWUniformType type; - int location; - int length; - int arraysize; - const void *value; -}; - -struct DRWInterface { - DRWUniform *uniforms; /* DRWUniform, single-linked list */ - int attribs_count; - int attribs_stride; - int attribs_size[16]; - int attribs_loc[16]; - /* matrices locations */ - int model; - int modelinverse; - int modelview; - int modelviewinverse; - int projection; - int projectioninverse; - int view; - int viewinverse; - int modelviewprojection; - int viewprojection; - int viewprojectioninverse; - int normal; - int worldnormal; - int camtexfac; - int orcotexfac; - int eye; - int clipplanes; - /* Dynamic batch */ - Gwn_Batch *instance_batch; /* contains instances attributes */ - GLuint instance_vbo; /* same as instance_batch but generated from DRWCalls */ - struct DRWInstanceData *inst_data; -#ifdef USE_GPU_SELECT - struct DRWInstanceData *inst_selectid; - /* Override for single object instances. */ - int override_selectid; -#endif - int instance_count; - Gwn_VertFormat vbo_format; -}; - -struct DRWPass { - /* Single linked list with last member to append */ - DRWShadingGroup *shgroups; - DRWShadingGroup *shgroups_last; - - DRWState state; - char name[MAX_PASS_NAME]; -}; - -typedef struct DRWCallHeader { - void *prev; - -#ifdef USE_GPU_SELECT - int select_id; -#endif - uchar type; -} DRWCallHeader; - -typedef struct DRWCall { - DRWCallHeader head; - - float obmat[4][4]; - Gwn_Batch *geometry; - - Object *ob; /* Optional */ - ID *ob_data; /* Optional. */ -} DRWCall; - -typedef struct DRWCallGenerate { - DRWCallHeader head; - - float obmat[4][4]; - - DRWCallGenerateFn *geometry_fn; - void *user_data; -} DRWCallGenerate; - -struct DRWShadingGroup { - struct DRWShadingGroup *next; - - GPUShader *shader; /* Shader to bind */ - DRWInterface interface; /* Uniforms pointers */ - - /* DRWCall or DRWCallDynamic depending of type */ - void *calls; - void *calls_first; /* To be able to traverse the list in the order of addition */ - - DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */ - DRWState state_extra_disable; /* State changes for this batch only (and'd with the pass's state) */ - unsigned int stencil_mask; /* Stencil mask to use for stencil test / write operations */ - int type; - - ID *instance_data; /* Object->data to instance */ - Gwn_Batch *instance_geom; /* Geometry to instance */ - Gwn_Batch *batch_geom; /* Result of call batching */ - -#ifdef USE_GPU_SELECT - /* backlink to pass we're in */ - DRWPass *pass_parent; -#endif -}; - -/* Used by DRWShadingGroup.type */ -enum { - DRW_SHG_NORMAL, - DRW_SHG_POINT_BATCH, - DRW_SHG_LINE_BATCH, - DRW_SHG_TRIANGLE_BATCH, - DRW_SHG_INSTANCE, -}; - -/* Used by DRWCall.type */ -enum { - /* A single batch */ - DRW_CALL_SINGLE, - /* Uses a callback to draw with any number of batches. */ - DRW_CALL_GENERATE, - /* Arbitrary number of multiple args. */ - DRW_CALL_DYNAMIC, -}; - /** Render State: No persistent data between draw calls. */ -static struct DRWGlobalState { - /* Cache generation */ - ViewportMemoryPool *vmempool; - DRWUniform *last_uniform; - DRWCall *last_call; - DRWCallGenerate *last_callgenerate; - DRWShadingGroup *last_shgroup; - DRWInstanceDataList *idatalist; - - /* Rendering state */ - GPUShader *shader; - - /* Managed by `DRW_state_set`, `DRW_state_reset` */ - DRWState state; - unsigned int stencil_mask; - - /* Per viewport */ - GPUViewport *viewport; - struct GPUFrameBuffer *default_framebuffer; - float size[2]; - float screenvecs[2][3]; - float pixsize; - - GLenum backface, frontface; - - /* Clip planes */ - int num_clip_planes; - float clip_planes_eq[MAX_CLIP_PLANES][4]; - - struct { - unsigned int is_select : 1; - unsigned int is_depth : 1; - unsigned int is_image_render : 1; - unsigned int is_scene_render : 1; - unsigned int draw_background : 1; - } options; - - /* Current rendering context */ - DRWContextState draw_ctx; - - /* Convenience pointer to text_store owned by the viewport */ - struct DRWTextStore **text_store_p; - - ListBase enabled_engines; /* RenderEngineType */ - - /* Profiling */ - double cache_time; -} DST = {NULL}; - -/** GPU Resource State: Memory storage between drawing. */ -static struct DRWResourceState { - GPUTexture **bound_texs; - - bool *bound_tex_slots; - - int bind_tex_inc; - int bind_ubo_inc; -} RST = {NULL}; - -static struct DRWMatrixOveride { - float mat[6][4][4]; - bool override[6]; -} viewport_matrix_override = {{{{0}}}}; +DRWManager DST = {NULL}; ListBase DRW_engines = {NULL, NULL}; -#ifdef USE_GPU_SELECT -static unsigned int g_DRW_select_id = (unsigned int)-1; - -void DRW_select_load_id(unsigned int id) -{ - BLI_assert(G.f & G_PICKSEL); - g_DRW_select_id = id; -} -#endif - - -/* -------------------------------------------------------------------- */ - -/** \name Textures (DRW_texture) - * \{ */ - -static void drw_texture_get_format( - DRWTextureFormat format, - GPUTextureFormat *r_data_type, int *r_channels) -{ - switch (format) { - case DRW_TEX_RGBA_8: *r_data_type = GPU_RGBA8; break; - case DRW_TEX_RGBA_16: *r_data_type = GPU_RGBA16F; break; - case DRW_TEX_RGB_16: *r_data_type = GPU_RGB16F; break; - case DRW_TEX_RGB_11_11_10: *r_data_type = GPU_R11F_G11F_B10F; break; - case DRW_TEX_RG_8: *r_data_type = GPU_RG8; break; - case DRW_TEX_RG_16: *r_data_type = GPU_RG16F; break; - case DRW_TEX_RG_16I: *r_data_type = GPU_RG16I; break; - case DRW_TEX_RG_32: *r_data_type = GPU_RG32F; break; - case DRW_TEX_R_8: *r_data_type = GPU_R8; break; - case DRW_TEX_R_16: *r_data_type = GPU_R16F; break; - case DRW_TEX_R_32: *r_data_type = GPU_R32F; break; -#if 0 - case DRW_TEX_RGBA_32: *r_data_type = GPU_RGBA32F; break; - case DRW_TEX_RGB_8: *r_data_type = GPU_RGB8; break; - case DRW_TEX_RGB_32: *r_data_type = GPU_RGB32F; break; -#endif - case DRW_TEX_DEPTH_16: *r_data_type = GPU_DEPTH_COMPONENT16; break; - case DRW_TEX_DEPTH_24: *r_data_type = GPU_DEPTH_COMPONENT24; break; - case DRW_TEX_DEPTH_24_STENCIL_8: *r_data_type = GPU_DEPTH24_STENCIL8; break; - case DRW_TEX_DEPTH_32: *r_data_type = GPU_DEPTH_COMPONENT32F; break; - default : - /* file type not supported you must uncomment it from above */ - BLI_assert(false); - break; - } - - switch (format) { - case DRW_TEX_RGBA_8: - case DRW_TEX_RGBA_16: - case DRW_TEX_RGBA_32: - *r_channels = 4; - break; - case DRW_TEX_RGB_8: - case DRW_TEX_RGB_16: - case DRW_TEX_RGB_32: - case DRW_TEX_RGB_11_11_10: - *r_channels = 3; - break; - case DRW_TEX_RG_8: - case DRW_TEX_RG_16: - case DRW_TEX_RG_16I: - case DRW_TEX_RG_32: - *r_channels = 2; - break; - default: - *r_channels = 1; - break; - } -} - -static void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) -{ - GPU_texture_bind(tex, 0); - if (flags & DRW_TEX_MIPMAP) { - GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER); - DRW_texture_generate_mipmaps(tex); - } - else { - GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); - } - GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP); - GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); - GPU_texture_unbind(tex); -} - -GPUTexture *DRW_texture_create_1D(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) -{ - GPUTexture *tex; - GPUTextureFormat data_type; - int channels; - - drw_texture_get_format(format, &data_type, &channels); - tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL); - drw_texture_set_parameters(tex, flags); - - return tex; -} - -GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) -{ - GPUTexture *tex; - GPUTextureFormat data_type; - int channels; - - drw_texture_get_format(format, &data_type, &channels); - tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL); - drw_texture_set_parameters(tex, flags); - - return tex; -} - -GPUTexture *DRW_texture_create_2D_array( - int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) -{ - GPUTexture *tex; - GPUTextureFormat data_type; - int channels; - - drw_texture_get_format(format, &data_type, &channels); - tex = GPU_texture_create_2D_array_custom(w, h, d, channels, data_type, fpixels, NULL); - drw_texture_set_parameters(tex, flags); - - return tex; -} - -GPUTexture *DRW_texture_create_3D( - int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) -{ - GPUTexture *tex; - GPUTextureFormat data_type; - int channels; - - drw_texture_get_format(format, &data_type, &channels); - tex = GPU_texture_create_3D_custom(w, h, d, channels, data_type, fpixels, NULL); - drw_texture_set_parameters(tex, flags); - - return tex; -} - -GPUTexture *DRW_texture_create_cube(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) -{ - GPUTexture *tex; - GPUTextureFormat data_type; - int channels; - - drw_texture_get_format(format, &data_type, &channels); - tex = GPU_texture_create_cube_custom(w, channels, data_type, fpixels, NULL); - drw_texture_set_parameters(tex, flags); - - return tex; -} - -void DRW_texture_generate_mipmaps(GPUTexture *tex) -{ - GPU_texture_bind(tex, 0); - GPU_texture_generate_mipmap(tex); - GPU_texture_unbind(tex); -} - -void DRW_texture_update(GPUTexture *tex, const float *pixels) -{ - GPU_texture_update(tex, pixels); -} - -void DRW_texture_free(GPUTexture *tex) -{ - GPU_texture_free(tex); -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Uniform Buffer Object (DRW_uniformbuffer) - * \{ */ - -GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data) -{ - return GPU_uniformbuffer_create(size, data, NULL); -} - -void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) -{ - GPU_uniformbuffer_update(ubo, data); -} - -void DRW_uniformbuffer_free(GPUUniformBuffer *ubo) -{ - GPU_uniformbuffer_free(ubo); -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Shaders (DRW_shader) - * \{ */ - -GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines) -{ - return GPU_shader_create(vert, frag, geom, NULL, defines); -} - -GPUShader *DRW_shader_create_with_lib( - const char *vert, const char *geom, const char *frag, const char *lib, const char *defines) -{ - GPUShader *sh; - char *vert_with_lib = NULL; - char *frag_with_lib = NULL; - char *geom_with_lib = NULL; - - vert_with_lib = BLI_string_joinN(lib, vert); - frag_with_lib = BLI_string_joinN(lib, frag); - - if (geom) { - geom_with_lib = BLI_string_joinN(lib, geom); - } - - sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines); - - MEM_freeN(vert_with_lib); - MEM_freeN(frag_with_lib); - if (geom) { - MEM_freeN(geom_with_lib); - } - - return sh; -} - -GPUShader *DRW_shader_create_2D(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines); -} - -GPUShader *DRW_shader_create_3D(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines); -} - -GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines) -{ - return GPU_shader_create(datatoc_gpu_shader_fullscreen_vert_glsl, frag, NULL, NULL, defines); -} - -GPUShader *DRW_shader_create_3D_depth_only(void) -{ - return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); -} - -void DRW_shader_free(GPUShader *shader) -{ - GPU_shader_free(shader); -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Interface (DRW_interface) - * \{ */ - -static void drw_interface_create(DRWInterface *interface, GPUShader *shader) -{ - interface->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL); - interface->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV); - interface->modelview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW); - interface->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW_INV); - interface->projection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_PROJECTION); - interface->projectioninverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_PROJECTION_INV); - interface->view = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEW); - interface->viewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEW_INV); - interface->viewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEWPROJECTION); - interface->viewprojectioninverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_VIEWPROJECTION_INV); - interface->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MVP); - interface->normal = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_NORMAL); - interface->worldnormal = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_WORLDNORMAL); - interface->camtexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_CAMERATEXCO); - interface->orcotexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_ORCO); - interface->clipplanes = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_CLIPPLANES); - interface->eye = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_EYE); - interface->instance_count = 0; - interface->attribs_count = 0; - interface->attribs_stride = 0; - interface->instance_vbo = 0; - interface->instance_batch = NULL; - interface->inst_data = NULL; - interface->uniforms = NULL; -#ifdef USE_GPU_SELECT - interface->inst_selectid = NULL; - interface->override_selectid = -1; -#endif - - memset(&interface->vbo_format, 0, sizeof(Gwn_VertFormat)); -} - - -static void drw_interface_uniform(DRWShadingGroup *shgroup, const char *name, - DRWUniformType type, const void *value, int length, int arraysize) -{ - int location; - if (type == DRW_UNIFORM_BLOCK) { - location = GPU_shader_get_uniform_block(shgroup->shader, name); - } - else { - location = GPU_shader_get_uniform(shgroup->shader, name); - } - - if (location == -1) { - if (G.debug & G_DEBUG) - fprintf(stderr, "Uniform '%s' not found!\n", name); - /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ - // BLI_assert(0); - return; - } - - DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms); - - BLI_assert(arraysize > 0); - - uni->location = location; - uni->type = type; - uni->value = value; - uni->length = length; - uni->arraysize = arraysize; - - /* Prepend */ - uni->next = shgroup->interface.uniforms; - shgroup->interface.uniforms = uni; -} - -static void drw_interface_attrib(DRWShadingGroup *shgroup, const char *name, DRWAttribType UNUSED(type), int size, bool dummy) -{ - unsigned int attrib_id = shgroup->interface.attribs_count; - GLuint program = GPU_shader_get_program(shgroup->shader); - - shgroup->interface.attribs_loc[attrib_id] = glGetAttribLocation(program, name); - shgroup->interface.attribs_size[attrib_id] = size; - shgroup->interface.attribs_stride += size; - shgroup->interface.attribs_count += 1; - - if (shgroup->type != DRW_SHG_INSTANCE) { - BLI_assert(size <= 4); /* Matrices are not supported by Gawain. */ - GWN_vertformat_attr_add(&shgroup->interface.vbo_format, name, GWN_COMP_F32, size, GWN_FETCH_FLOAT); - } - - BLI_assert(shgroup->interface.attribs_count < MAX_ATTRIB_COUNT); - -/* Adding attribute even if not found for now (to keep memory alignment). - * Should ideally take vertex format automatically from batch eventually */ -#if 0 - if (attrib->location == -1 && !dummy) { - if (G.debug & G_DEBUG) - fprintf(stderr, "Attribute '%s' not found!\n", name); - BLI_assert(0); - MEM_freeN(attrib); - return; - } -#else - UNUSED_VARS(dummy); -#endif -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Shading Group (DRW_shgroup) - * \{ */ - -DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) -{ - DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); - - /* Append */ - if (pass->shgroups != NULL) { - pass->shgroups_last->next = shgroup; - } - else { - pass->shgroups = shgroup; - } - pass->shgroups_last = shgroup; - shgroup->next = NULL; - - drw_interface_create(&shgroup->interface, shader); - - shgroup->type = DRW_SHG_NORMAL; - shgroup->shader = shader; - shgroup->state_extra = 0; - shgroup->state_extra_disable = ~0x0; - shgroup->stencil_mask = 0; - shgroup->batch_geom = NULL; - shgroup->instance_geom = NULL; - shgroup->instance_data = NULL; - - shgroup->calls = NULL; - shgroup->calls_first = NULL; - -#ifdef USE_GPU_SELECT - shgroup->pass_parent = pass; -#endif - - return shgroup; -} - -DRWShadingGroup *DRW_shgroup_material_create(struct GPUMaterial *material, DRWPass *pass) -{ - double time = 0.0; /* TODO make time variable */ - - /* TODO : Ideally we should not convert. But since the whole codegen - * is relying on GPUPass we keep it as is for now. */ - GPUPass *gpupass = GPU_material_get_pass(material); - - if (!gpupass) { - /* Shader compilation error */ - return NULL; - } - - struct GPUShader *shader = GPU_pass_shader(gpupass); - - DRWShadingGroup *grp = DRW_shgroup_create(shader, pass); - - /* Converting dynamic GPUInput to DRWUniform */ - ListBase *inputs = &gpupass->inputs; - - for (GPUInput *input = inputs->first; input; input = input->next) { - /* Textures */ - if (input->ima) { - GPUTexture *tex = GPU_texture_from_blender( - input->ima, input->iuser, input->textarget, input->image_isdata, time, 1); - - if (input->bindtex) { - DRW_shgroup_uniform_texture(grp, input->shadername, tex); - } - } - /* Color Ramps */ - else if (input->tex) { - DRW_shgroup_uniform_texture(grp, input->shadername, input->tex); - } - /* Floats */ - else { - switch (input->type) { - case GPU_FLOAT: - case GPU_VEC2: - case GPU_VEC3: - case GPU_VEC4: - /* Should already be in the material ubo. */ - break; - case GPU_MAT3: - DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec); - break; - case GPU_MAT4: - DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec); - break; - default: - break; - } - } - } - - GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material); - if (ubo != NULL) { - DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo); - } - - return grp; -} - -DRWShadingGroup *DRW_shgroup_material_instance_create( - struct GPUMaterial *material, DRWPass *pass, Gwn_Batch *geom, Object *ob) -{ - DRWShadingGroup *shgroup = DRW_shgroup_material_create(material, pass); - - if (shgroup) { - shgroup->type = DRW_SHG_INSTANCE; - shgroup->instance_geom = geom; - shgroup->instance_data = ob->data; - } - - return shgroup; -} - -DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( - struct GPUMaterial *material, DRWPass *pass, int size) -{ - DRWShadingGroup *shgroup = DRW_shgroup_material_create(material, pass); - - if (shgroup) { - shgroup->type = DRW_SHG_TRIANGLE_BATCH; - shgroup->interface.instance_count = size * 3; - drw_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); - } - - return shgroup; -} - -DRWShadingGroup *DRW_shgroup_instance_create(struct GPUShader *shader, DRWPass *pass, Gwn_Batch *geom) -{ - DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); - - shgroup->type = DRW_SHG_INSTANCE; - shgroup->instance_geom = geom; - - return shgroup; -} - -DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass) -{ - DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); - - shgroup->type = DRW_SHG_POINT_BATCH; - DRW_shgroup_attrib_float(shgroup, "pos", 3); - - return shgroup; -} - -DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass) -{ - DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); - - shgroup->type = DRW_SHG_LINE_BATCH; - DRW_shgroup_attrib_float(shgroup, "pos", 3); - - return shgroup; -} - -/* Very special batch. Use this if you position - * your vertices with the vertex shader - * and dont need any VBO attrib */ -DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int size) -{ - DRWShadingGroup *shgroup = DRW_shgroup_create(shader, pass); - - shgroup->type = DRW_SHG_TRIANGLE_BATCH; - shgroup->interface.instance_count = size * 3; - drw_interface_attrib(shgroup, "dummy", DRW_ATTRIB_FLOAT, 1, true); - - return shgroup; -} - -void DRW_shgroup_free(struct DRWShadingGroup *shgroup) -{ - if (shgroup->interface.instance_vbo && - (shgroup->interface.instance_batch == 0)) - { - glDeleteBuffers(1, &shgroup->interface.instance_vbo); - } - - GWN_BATCH_DISCARD_SAFE(shgroup->batch_geom); -} - -#define CALL_PREPEND(shgroup, call) { \ - if (shgroup->calls == NULL) { \ - shgroup->calls = call; \ - shgroup->calls_first = call; \ - } \ - else { \ - ((DRWCall *)(shgroup->calls))->head.prev = call; \ - shgroup->calls = call; \ - } \ - call->head.prev = NULL; \ -} ((void)0) - -void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *instances) -{ - BLI_assert(shgroup->type == DRW_SHG_INSTANCE); - BLI_assert(shgroup->interface.instance_batch == NULL); - - shgroup->interface.instance_batch = instances; - -#ifdef USE_GPU_SELECT - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - call->head.select_id = g_DRW_select_id; - - CALL_PREPEND(shgroup, call); -#endif -} - -void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4]) -{ - BLI_assert(geom != NULL); - BLI_assert(shgroup->type == DRW_SHG_NORMAL); - - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - - CALL_PREPEND(shgroup, call); - - call->head.type = DRW_CALL_SINGLE; -#ifdef USE_GPU_SELECT - call->head.select_id = g_DRW_select_id; -#endif - - if (obmat != NULL) { - copy_m4_m4(call->obmat, obmat); - } - - call->geometry = geom; - call->ob_data = NULL; -} +extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */ -void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob) +static void drw_state_prepare_clean_for_draw(DRWManager *dst) { - BLI_assert(geom != NULL); - BLI_assert(shgroup->type == DRW_SHG_NORMAL); - - DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); - - CALL_PREPEND(shgroup, call); - - call->head.type = DRW_CALL_SINGLE; -#ifdef USE_GPU_SELECT - call->head.select_id = g_DRW_select_id; -#endif - - copy_m4_m4(call->obmat, ob->obmat); - call->geometry = geom; - call->ob_data = ob->data; -} - -void DRW_shgroup_call_generate_add( - DRWShadingGroup *shgroup, - DRWCallGenerateFn *geometry_fn, void *user_data, - float (*obmat)[4]) -{ - BLI_assert(geometry_fn != NULL); - BLI_assert(shgroup->type == DRW_SHG_NORMAL); - - DRWCallGenerate *call = BLI_mempool_alloc(DST.vmempool->calls_generate); - - CALL_PREPEND(shgroup, call); - - call->head.type = DRW_CALL_GENERATE; -#ifdef USE_GPU_SELECT - call->head.select_id = g_DRW_select_id; -#endif - - if (obmat != NULL) { - copy_m4_m4(call->obmat, obmat); - } - - call->geometry_fn = geometry_fn; - call->user_data = user_data; + memset(dst, 0x0, offsetof(DRWManager, ogl_context)); } -static void sculpt_draw_cb( - DRWShadingGroup *shgroup, - void (*draw_fn)(DRWShadingGroup *shgroup, Gwn_Batch *geom), - void *user_data) -{ - Object *ob = user_data; - PBVH *pbvh = ob->sculpt->pbvh; - - if (pbvh) { - BKE_pbvh_draw_cb( - pbvh, NULL, NULL, false, - (void (*)(void *, Gwn_Batch *))draw_fn, shgroup); - } -} - -void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4]) -{ - DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat); -} - -void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len) -{ - DRWInterface *interface = &shgroup->interface; - -#ifdef USE_GPU_SELECT - if (G.f & G_PICKSEL) { - if (interface->inst_selectid == NULL) { - interface->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128); - } - - int *select_id = DRW_instance_data_next(interface->inst_selectid); - *select_id = g_DRW_select_id; - } -#endif - - BLI_assert(attr_len == interface->attribs_count); - UNUSED_VARS_NDEBUG(attr_len); - - if (interface->attribs_stride > 0) { - if (interface->inst_data == NULL) { - interface->inst_data = DRW_instance_data_request(DST.idatalist, interface->attribs_stride, 16); - } - - float *data = DRW_instance_data_next(interface->inst_data); - - for (int i = 0; i < interface->attribs_count; ++i) { - memcpy(data, attr[i], sizeof(float) * interface->attribs_size[i]); - data = data + interface->attribs_size[i]; - } - } - - interface->instance_count += 1; -} - -/* Used for instancing with no attributes */ -void DRW_shgroup_set_instance_count(DRWShadingGroup *shgroup, int count) -{ - DRWInterface *interface = &shgroup->interface; - - BLI_assert(interface->instance_count == 0); - BLI_assert(interface->attribs_count == 0); - -#ifdef USE_GPU_SELECT - if (G.f & G_PICKSEL) { - interface->override_selectid = g_DRW_select_id; - } -#endif - - interface->instance_count = count; -} - -/** - * State is added to #Pass.state while drawing. - * Use to temporarily enable draw options. +/* This function is used to reset draw manager to a state + * where we don't re-use data by accident across different + * draw calls. */ -void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) -{ - shgroup->state_extra |= state; -} - -void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) -{ - shgroup->state_extra_disable &= ~state; -} - -void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask) -{ - shgroup->stencil_mask = mask; -} - -void DRW_shgroup_attrib_float(DRWShadingGroup *shgroup, const char *name, int size) -{ - drw_interface_attrib(shgroup, name, DRW_ATTRIB_FLOAT, size, false); -} - -void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); -} - -void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); -} - -void DRW_shgroup_uniform_buffer(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_BUFFER, tex, 0, 1); -} - -void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize); -} - -void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize); -} - -void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize); -} - -void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize); -} - -void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize); -} - -void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize); -} - -void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize); -} - -void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize); -} - -void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize); -} - -void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize); -} - -void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT3, value, 9, 1); -} - -void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value) -{ - drw_interface_uniform(shgroup, name, DRW_UNIFORM_MAT4, value, 16, 1); -} - -/* Creates a VBO containing OGL primitives for all DRWCallDynamic */ -static void shgroup_dynamic_batch(DRWShadingGroup *shgroup) -{ - DRWInterface *interface = &shgroup->interface; - int nbr = interface->instance_count; - - Gwn_PrimType type = (shgroup->type == DRW_SHG_POINT_BATCH) ? GWN_PRIM_POINTS : - (shgroup->type == DRW_SHG_TRIANGLE_BATCH) ? GWN_PRIM_TRIS : GWN_PRIM_LINES; - - if (nbr == 0) - return; - - /* Upload Data */ - Gwn_VertBuf *vbo = GWN_vertbuf_create_with_format(&interface->vbo_format); - if (interface->inst_data) { - GWN_vertbuf_data_set(vbo, nbr, DRW_instance_data_get(interface->inst_data), false); - } else { - /* Use unitialized memory. This is for dummy vertex buffers. */ - /* XXX TODO do not alloc at all. */ - GWN_vertbuf_data_alloc(vbo, nbr); - } - - /* TODO make the batch dynamic instead of freeing it every times */ - if (shgroup->batch_geom) - GWN_batch_discard(shgroup->batch_geom); - - shgroup->batch_geom = GWN_batch_create_ex(type, vbo, NULL, GWN_BATCH_OWNS_VBO); -} - -static void shgroup_dynamic_instance(DRWShadingGroup *shgroup) -{ - DRWInterface *interface = &shgroup->interface; - int buffer_size = 0; - void *data = NULL; - - if (interface->instance_batch != NULL) { - return; - } - - /* TODO We still need this because gawain does not support Matrix attribs. */ - if (interface->instance_count == 0) { - if (interface->instance_vbo) { - glDeleteBuffers(1, &interface->instance_vbo); - interface->instance_vbo = 0; - } - return; - } - - /* Gather Data */ - buffer_size = sizeof(float) * interface->attribs_stride * interface->instance_count; - - /* TODO poke mike to add this to gawain */ - if (interface->instance_vbo) { - glDeleteBuffers(1, &interface->instance_vbo); - interface->instance_vbo = 0; - } - - if (interface->inst_data) { - data = DRW_instance_data_get(interface->inst_data); - } - - glGenBuffers(1, &interface->instance_vbo); - glBindBuffer(GL_ARRAY_BUFFER, interface->instance_vbo); - glBufferData(GL_ARRAY_BUFFER, buffer_size, data, GL_STATIC_DRAW); -} - -static void shgroup_dynamic_batch_from_calls(DRWShadingGroup *shgroup) -{ - if ((shgroup->interface.instance_vbo || shgroup->batch_geom) && - (G.debug_value == 667)) - { - return; - } - - if (shgroup->type == DRW_SHG_INSTANCE) { - shgroup_dynamic_instance(shgroup); - } - else { - shgroup_dynamic_batch(shgroup); - } -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Passes (DRW_pass) - * \{ */ - -DRWPass *DRW_pass_create(const char *name, DRWState state) -{ - DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes); - pass->state = state; - BLI_strncpy(pass->name, name, MAX_PASS_NAME); - - pass->shgroups = NULL; - pass->shgroups_last = NULL; - - return pass; -} - -void DRW_pass_state_set(DRWPass *pass, DRWState state) -{ - pass->state = state; -} - -void DRW_pass_free(DRWPass *pass) -{ - for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) { - DRW_shgroup_free(shgroup); - } - - pass->shgroups = NULL; - pass->shgroups_last = NULL; -} - -void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData) -{ - for (DRWShadingGroup *shgroup = pass->shgroups; shgroup; shgroup = shgroup->next) { - callback(userData, shgroup); - } -} - -typedef struct ZSortData { - float *axis; - float *origin; -} ZSortData; - -static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) -{ - const ZSortData *zsortdata = (ZSortData *)thunk; - const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a; - const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b; - - const DRWCall *call_a; - const DRWCall *call_b; - - call_a = shgrp_a->calls_first; - call_b = shgrp_b->calls_first; - - if (call_a == NULL) return -1; - if (call_b == NULL) return -1; - - float tmp[3]; - sub_v3_v3v3(tmp, zsortdata->origin, call_a->obmat[3]); - const float a_sq = dot_v3v3(zsortdata->axis, tmp); - sub_v3_v3v3(tmp, zsortdata->origin, call_b->obmat[3]); - const float b_sq = dot_v3v3(zsortdata->axis, tmp); - - if (a_sq < b_sq) return 1; - else if (a_sq > b_sq) return -1; - else { - /* If there is a depth prepass put it before */ - if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) { - return -1; - } - else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) { - return 1; - } - else return 0; - } -} - -/* ------------------ Shading group sorting --------------------- */ - -#define SORT_IMPL_LINKTYPE DRWShadingGroup - -#define SORT_IMPL_USE_THUNK -#define SORT_IMPL_FUNC shgroup_sort_fn_r -#include "../../blenlib/intern/list_sort_impl.h" -#undef SORT_IMPL_FUNC -#undef SORT_IMPL_USE_THUNK - -#undef SORT_IMPL_LINKTYPE - -/** - * Sort Shading groups by decreasing Z of their first draw call. - * This is usefull for order dependant effect such as transparency. - **/ -void DRW_pass_sort_shgroup_z(DRWPass *pass) -{ - RegionView3D *rv3d = DST.draw_ctx.rv3d; - - float (*viewinv)[4]; - viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV]) - ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv; - - ZSortData zsortdata = {viewinv[2], viewinv[3]}; - - if (pass->shgroups && pass->shgroups->next) { - pass->shgroups = shgroup_sort_fn_r(pass->shgroups, pass_shgroup_dist_sort, &zsortdata); - - /* Find the next last */ - DRWShadingGroup *last = pass->shgroups; - while ((last = last->next)) { - /* Do nothing */ - } - pass->shgroups_last = last; - } -} - -/** \} */ - - -/* -------------------------------------------------------------------- */ - -/** \name Draw (DRW_draw) - * \{ */ - -static void drw_state_set(DRWState state) -{ - if (DST.state == state) { - return; - } - - -#define CHANGED_TO(f) \ - ((DST.state & (f)) ? \ - ((state & (f)) ? 0 : -1) : \ - ((state & (f)) ? 1 : 0)) - -#define CHANGED_ANY(f) \ - ((DST.state & (f)) != (state & (f))) - -#define CHANGED_ANY_STORE_VAR(f, enabled) \ - ((DST.state & (f)) != (enabled = (state & (f)))) - - /* Depth Write */ - { - int test; - if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) { - if (test == 1) { - glDepthMask(GL_TRUE); - } - else { - glDepthMask(GL_FALSE); - } - } - } - - /* Color Write */ - { - int test; - if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) { - if (test == 1) { - glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); - } - else { - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); - } - } - } - - /* Cull */ - { - DRWState test; - if (CHANGED_ANY_STORE_VAR( - DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT, - test)) - { - if (test) { - glEnable(GL_CULL_FACE); - - if ((state & DRW_STATE_CULL_BACK) != 0) { - glCullFace(GL_BACK); - } - else if ((state & DRW_STATE_CULL_FRONT) != 0) { - glCullFace(GL_FRONT); - } - else { - BLI_assert(0); - } - } - else { - glDisable(GL_CULL_FACE); - } - } - } - - /* Depth Test */ - { - DRWState test; - if (CHANGED_ANY_STORE_VAR( - DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER | DRW_STATE_DEPTH_ALWAYS, - test)) - { - if (test) { - glEnable(GL_DEPTH_TEST); - - if (state & DRW_STATE_DEPTH_LESS) { - glDepthFunc(GL_LEQUAL); - } - else if (state & DRW_STATE_DEPTH_EQUAL) { - glDepthFunc(GL_EQUAL); - } - else if (state & DRW_STATE_DEPTH_GREATER) { - glDepthFunc(GL_GREATER); - } - else if (state & DRW_STATE_DEPTH_ALWAYS) { - glDepthFunc(GL_ALWAYS); - } - else { - BLI_assert(0); - } - } - else { - glDisable(GL_DEPTH_TEST); - } - } - } - - /* Wire Width */ - { - if (CHANGED_ANY(DRW_STATE_WIRE | DRW_STATE_WIRE_LARGE)) { - if ((state & DRW_STATE_WIRE) != 0) { - glLineWidth(1.0f); - } - else if ((state & DRW_STATE_WIRE_LARGE) != 0) { - glLineWidth(UI_GetThemeValuef(TH_OUTLINE_WIDTH) * 2.0f); - } - else { - /* do nothing */ - } - } - } - - /* Points Size */ - { - int test; - if ((test = CHANGED_TO(DRW_STATE_POINT))) { - if (test == 1) { - GPU_enable_program_point_size(); - glPointSize(5.0f); - } - else { - GPU_disable_program_point_size(); - } - } - } - - /* Blending (all buffer) */ - { - int test; - if (CHANGED_ANY_STORE_VAR( - DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION | - DRW_STATE_ADDITIVE_FULL, - test)) - { - if (test) { - glEnable(GL_BLEND); - - if ((state & DRW_STATE_BLEND) != 0) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, /* RGB */ - GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_MULTIPLY) != 0) { - glBlendFunc(GL_DST_COLOR, GL_ZERO); - } - else if ((state & DRW_STATE_TRANSMISSION) != 0) { - glBlendFunc(GL_ONE, GL_SRC_ALPHA); - } - else if ((state & DRW_STATE_ADDITIVE) != 0) { - /* Do not let alpha accumulate but premult the source RGB by it. */ - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, /* RGB */ - GL_ZERO, GL_ONE); /* Alpha */ - } - else if ((state & DRW_STATE_ADDITIVE_FULL) != 0) { - /* Let alpha accumulate. */ - glBlendFunc(GL_ONE, GL_ONE); - } - else { - BLI_assert(0); - } - } - else { - glDisable(GL_BLEND); - } - } - } - - /* Clip Planes */ - { - int test; - if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) { - if (test == 1) { - for (int i = 0; i < DST.num_clip_planes; ++i) { - glEnable(GL_CLIP_DISTANCE0 + i); - } - } - else { - for (int i = 0; i < MAX_CLIP_PLANES; ++i) { - glDisable(GL_CLIP_DISTANCE0 + i); - } - } - } - } - - /* Line Stipple */ - { - int test; - if (CHANGED_ANY_STORE_VAR( - DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4, - test)) - { - if (test) { - if ((state & DRW_STATE_STIPPLE_2) != 0) { - setlinestyle(2); - } - else if ((state & DRW_STATE_STIPPLE_3) != 0) { - setlinestyle(3); - } - else if ((state & DRW_STATE_STIPPLE_4) != 0) { - setlinestyle(4); - } - else { - BLI_assert(0); - } - } - else { - setlinestyle(0); - } - } - } - - /* Stencil */ - { - DRWState test; - if (CHANGED_ANY_STORE_VAR( - DRW_STATE_WRITE_STENCIL | - DRW_STATE_STENCIL_EQUAL, - test)) - { - if (test) { - glEnable(GL_STENCIL_TEST); - - /* Stencil Write */ - if ((state & DRW_STATE_WRITE_STENCIL) != 0) { - glStencilMask(0xFF); - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - /* Stencil Test */ - else if ((state & DRW_STATE_STENCIL_EQUAL) != 0) { - glStencilMask(0x00); /* disable write */ - DST.stencil_mask = 0; - } - else { - BLI_assert(0); - } - } - else { - /* disable write & test */ - DST.stencil_mask = 0; - glStencilMask(0x00); - glStencilFunc(GL_ALWAYS, 1, 0xFF); - glDisable(GL_STENCIL_TEST); - } - } - } - -#undef CHANGED_TO -#undef CHANGED_ANY -#undef CHANGED_ANY_STORE_VAR - - DST.state = state; -} - -static void drw_stencil_set(unsigned int mask) -{ - if (DST.stencil_mask != mask) { - /* Stencil Write */ - if ((DST.state & DRW_STATE_WRITE_STENCIL) != 0) { - glStencilFunc(GL_ALWAYS, mask, 0xFF); - DST.stencil_mask = mask; - } - /* Stencil Test */ - else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) { - glStencilFunc(GL_EQUAL, mask, 0xFF); - DST.stencil_mask = mask; - } - } -} - -typedef struct DRWBoundTexture { - struct DRWBoundTexture *next, *prev; - GPUTexture *tex; -} DRWBoundTexture; - -static void draw_geometry_prepare( - DRWShadingGroup *shgroup, const float (*obmat)[4], const float *texcoloc, const float *texcosize) -{ - RegionView3D *rv3d = DST.draw_ctx.rv3d; - DRWInterface *interface = &shgroup->interface; - - float mvp[4][4], mv[4][4], mi[4][4], mvi[4][4], pi[4][4], n[3][3], wn[3][3]; - float orcofacs[2][3] = {{0.0f, 0.0f, 0.0f}, {1.0f, 1.0f, 1.0f}}; - float eye[3] = { 0.0f, 0.0f, 1.0f }; /* looking into the screen */ - - bool do_pi = (interface->projectioninverse != -1); - bool do_mvp = (interface->modelviewprojection != -1); - bool do_mi = (interface->modelinverse != -1); - bool do_mv = (interface->modelview != -1); - bool do_mvi = (interface->modelviewinverse != -1); - bool do_n = (interface->normal != -1); - bool do_wn = (interface->worldnormal != -1); - bool do_eye = (interface->eye != -1); - bool do_orco = (interface->orcotexfac != -1) && (texcoloc != NULL) && (texcosize != NULL); - - /* Matrix override */ - float (*persmat)[4]; - float (*persinv)[4]; - float (*viewmat)[4]; - float (*viewinv)[4]; - float (*winmat)[4]; - float (*wininv)[4]; - - persmat = (viewport_matrix_override.override[DRW_MAT_PERS]) - ? viewport_matrix_override.mat[DRW_MAT_PERS] : rv3d->persmat; - persinv = (viewport_matrix_override.override[DRW_MAT_PERSINV]) - ? viewport_matrix_override.mat[DRW_MAT_PERSINV] : rv3d->persinv; - viewmat = (viewport_matrix_override.override[DRW_MAT_VIEW]) - ? viewport_matrix_override.mat[DRW_MAT_VIEW] : rv3d->viewmat; - viewinv = (viewport_matrix_override.override[DRW_MAT_VIEWINV]) - ? viewport_matrix_override.mat[DRW_MAT_VIEWINV] : rv3d->viewinv; - winmat = (viewport_matrix_override.override[DRW_MAT_WIN]) - ? viewport_matrix_override.mat[DRW_MAT_WIN] : rv3d->winmat; - wininv = viewport_matrix_override.mat[DRW_MAT_WININV]; - - if (do_pi) { - if (!viewport_matrix_override.override[DRW_MAT_WININV]) { - invert_m4_m4(pi, winmat); - wininv = pi; - } - } - if (do_mi) { - invert_m4_m4(mi, obmat); - } - if (do_mvp) { - mul_m4_m4m4(mvp, persmat, obmat); - } - if (do_mv || do_mvi || do_n || do_eye) { - mul_m4_m4m4(mv, viewmat, obmat); - } - if (do_mvi) { - invert_m4_m4(mvi, mv); - } - if (do_n || do_eye) { - copy_m3_m4(n, mv); - invert_m3(n); - transpose_m3(n); - } - if (do_wn) { - copy_m3_m4(wn, obmat); - invert_m3(wn); - transpose_m3(wn); - } - if (do_eye) { - /* Used by orthographic wires */ - float tmp[3][3]; - invert_m3_m3(tmp, n); - /* set eye vector, transformed to object coords */ - mul_m3_v3(tmp, eye); - } - if (do_orco) { - mul_v3_v3fl(orcofacs[1], texcosize, 2.0f); - invert_v3(orcofacs[1]); - sub_v3_v3v3(orcofacs[0], texcoloc, texcosize); - negate_v3(orcofacs[0]); - mul_v3_v3(orcofacs[0], orcofacs[1]); /* result in a nice MADD in the shader */ - } - - /* Should be really simple */ - /* step 1 : bind object dependent matrices */ - /* TODO : Some of these are not object dependant. - * They should be grouped inside a UBO updated once per redraw. - * The rest can also go into a UBO to reduce API calls. */ - GPU_shader_uniform_vector(shgroup->shader, interface->model, 16, 1, (float *)obmat); - GPU_shader_uniform_vector(shgroup->shader, interface->modelinverse, 16, 1, (float *)mi); - GPU_shader_uniform_vector(shgroup->shader, interface->modelviewprojection, 16, 1, (float *)mvp); - GPU_shader_uniform_vector(shgroup->shader, interface->viewinverse, 16, 1, (float *)viewinv); - GPU_shader_uniform_vector(shgroup->shader, interface->viewprojection, 16, 1, (float *)persmat); - GPU_shader_uniform_vector(shgroup->shader, interface->viewprojectioninverse, 16, 1, (float *)persinv); - GPU_shader_uniform_vector(shgroup->shader, interface->projection, 16, 1, (float *)winmat); - GPU_shader_uniform_vector(shgroup->shader, interface->projectioninverse, 16, 1, (float *)wininv); - GPU_shader_uniform_vector(shgroup->shader, interface->view, 16, 1, (float *)viewmat); - GPU_shader_uniform_vector(shgroup->shader, interface->modelview, 16, 1, (float *)mv); - GPU_shader_uniform_vector(shgroup->shader, interface->modelviewinverse, 16, 1, (float *)mvi); - GPU_shader_uniform_vector(shgroup->shader, interface->normal, 9, 1, (float *)n); - GPU_shader_uniform_vector(shgroup->shader, interface->worldnormal, 9, 1, (float *)wn); - GPU_shader_uniform_vector(shgroup->shader, interface->camtexfac, 4, 1, (float *)rv3d->viewcamtexcofac); - GPU_shader_uniform_vector(shgroup->shader, interface->orcotexfac, 3, 2, (float *)orcofacs); - GPU_shader_uniform_vector(shgroup->shader, interface->eye, 3, 1, (float *)eye); - GPU_shader_uniform_vector(shgroup->shader, interface->clipplanes, 4, DST.num_clip_planes, (float *)DST.clip_planes_eq); -} - -static void draw_geometry_execute_ex( - DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count) -{ - DRWInterface *interface = &shgroup->interface; - /* step 2 : bind vertex array & draw */ - GWN_batch_program_set(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); - if (interface->instance_batch) { - /* Used for Particles. Cannot do partial drawing. */ - GWN_batch_draw_stupid_instanced_with_batch(geom, interface->instance_batch); - } - else if (interface->instance_vbo) { - GWN_batch_draw_stupid_instanced( - geom, interface->instance_vbo, start, count, interface->attribs_count, - interface->attribs_stride, interface->attribs_size, interface->attribs_loc); - } - else { - GWN_batch_draw_stupid(geom, start, count); - } - /* XXX this just tells gawain we are done with the shader. - * This does not unbind the shader. */ - GWN_batch_program_unset(geom); -} - -static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) -{ - draw_geometry_execute_ex(shgroup, geom, 0, 0); -} - -static void draw_geometry( - DRWShadingGroup *shgroup, Gwn_Batch *geom, const float (*obmat)[4], ID *ob_data, - unsigned int start, unsigned int count) -{ - float *texcoloc = NULL; - float *texcosize = NULL; - - if (ob_data != NULL) { - switch (GS(ob_data->name)) { - case ID_ME: - BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); - break; - case ID_CU: - { - Curve *cu = (Curve *)ob_data; - if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { - BKE_curve_texspace_calc(cu); - } - texcoloc = cu->loc; - texcosize = cu->size; - break; - } - case ID_MB: - { - MetaBall *mb = (MetaBall *)ob_data; - texcoloc = mb->loc; - texcosize = mb->size; - break; - } - default: - break; - } - } - - draw_geometry_prepare(shgroup, obmat, texcoloc, texcosize); - - draw_geometry_execute_ex(shgroup, geom, start, count); -} - -static void bind_texture(GPUTexture *tex) -{ - int bind_num = GPU_texture_bound_number(tex); - if (bind_num == -1) { - for (int i = 0; i < GPU_max_textures(); ++i) { - RST.bind_tex_inc = (RST.bind_tex_inc + 1) % GPU_max_textures(); - if (RST.bound_tex_slots[RST.bind_tex_inc] == false) { - if (RST.bound_texs[RST.bind_tex_inc] != NULL) { - GPU_texture_unbind(RST.bound_texs[RST.bind_tex_inc]); - } - GPU_texture_bind(tex, RST.bind_tex_inc); - RST.bound_texs[RST.bind_tex_inc] = tex; - RST.bound_tex_slots[RST.bind_tex_inc] = true; - return; - } - } - - printf("Not enough texture slots! Reduce number of textures used by your shader.\n"); - } - RST.bound_tex_slots[bind_num] = true; -} - -static void bind_ubo(GPUUniformBuffer *ubo) -{ - if (RST.bind_ubo_inc < GPU_max_ubo_binds()) { - GPU_uniformbuffer_bind(ubo, RST.bind_ubo_inc); - RST.bind_ubo_inc++; - } - else { - /* This is not depending on user input. - * It is our responsability to make sure there enough slots. */ - BLI_assert(0 && "Not enough ubo slots! This should not happen!\n"); - - /* printf so user can report bad behaviour */ - printf("Not enough ubo slots! This should not happen!\n"); - } -} - -static void release_texture_slots(void) -{ - memset(RST.bound_tex_slots, 0x0, sizeof(bool) * GPU_max_textures()); -} - -static void release_ubo_slots(void) +#ifdef DEBUG +static void drw_state_ensure_not_reused(DRWManager *dst) { - RST.bind_ubo_inc = 0; + memset(dst, 0xff, offsetof(DRWManager, ogl_context)); } - -static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) -{ - BLI_assert(shgroup->shader); - - DRWInterface *interface = &shgroup->interface; - GPUTexture *tex; - GPUUniformBuffer *ubo; - int val; - float fval; - - if (DST.shader != shgroup->shader) { - if (DST.shader) GPU_shader_unbind(); - GPU_shader_bind(shgroup->shader); - DST.shader = shgroup->shader; - } - - const bool is_normal = ELEM(shgroup->type, DRW_SHG_NORMAL); - - if (!is_normal) { - shgroup_dynamic_batch_from_calls(shgroup); - } - - release_texture_slots(); - release_ubo_slots(); - - drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); - drw_stencil_set(shgroup->stencil_mask); - - /* Binding Uniform */ - /* Don't check anything, Interface should already contain the least uniform as possible */ - for (DRWUniform *uni = interface->uniforms; uni; uni = uni->next) { - switch (uni->type) { - case DRW_UNIFORM_SHORT_TO_INT: - val = (int)*((short *)uni->value); - GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)&val); - break; - case DRW_UNIFORM_SHORT_TO_FLOAT: - fval = (float)*((short *)uni->value); - GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval); - break; - case DRW_UNIFORM_BOOL: - case DRW_UNIFORM_INT: - GPU_shader_uniform_vector_int( - shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value); - break; - case DRW_UNIFORM_FLOAT: - case DRW_UNIFORM_MAT3: - case DRW_UNIFORM_MAT4: - GPU_shader_uniform_vector( - shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value); - break; - case DRW_UNIFORM_TEXTURE: - tex = (GPUTexture *)uni->value; - BLI_assert(tex); - bind_texture(tex); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); - break; - case DRW_UNIFORM_BUFFER: - if (!DRW_state_is_fbo()) { - break; - } - tex = *((GPUTexture **)uni->value); - BLI_assert(tex); - bind_texture(tex); - GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); - break; - case DRW_UNIFORM_BLOCK: - ubo = (GPUUniformBuffer *)uni->value; - bind_ubo(ubo); - GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); - break; - } - } - -#ifdef USE_GPU_SELECT - /* use the first item because of selection we only ever add one */ -# define GPU_SELECT_LOAD_IF_PICKSEL(_call) \ - if ((G.f & G_PICKSEL) && (_call)) { \ - GPU_select_load_id((_call)->head.select_id); \ - } ((void)0) - -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ - _start = 0; \ - _count = _shgroup->interface.instance_count; \ - int *select_id = NULL; \ - if (G.f & G_PICKSEL) { \ - if (_shgroup->interface.override_selectid == -1) { \ - select_id = DRW_instance_data_get(_shgroup->interface.inst_selectid); \ - switch (_shgroup->type) { \ - case DRW_SHG_TRIANGLE_BATCH: _count = 3; break; \ - case DRW_SHG_LINE_BATCH: _count = 2; break; \ - default: _count = 1; break; \ - } \ - } \ - else { \ - GPU_select_load_id(_shgroup->interface.override_selectid); \ - } \ - } \ - while (_start < _shgroup->interface.instance_count) { \ - if (select_id) { \ - GPU_select_load_id(select_id[_start]); \ - } - -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \ - _start += _count; \ - } - -#else -# define GPU_SELECT_LOAD_IF_PICKSEL(call) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) -# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ - _start = 0; \ - _count = _shgroup->interface.instance_count; - #endif - /* Rendering Calls */ - if (!is_normal) { - /* Replacing multiple calls with only one */ - float obmat[4][4]; - unit_m4(obmat); - - if (shgroup->type == DRW_SHG_INSTANCE && - (interface->instance_count > 0 || interface->instance_batch != NULL)) - { - if (interface->instance_batch != NULL) { - GPU_SELECT_LOAD_IF_PICKSEL((DRWCall *)shgroup->calls_first); - draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, 0, 0); - } - else { - unsigned int count, start; - GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) - { - draw_geometry(shgroup, shgroup->instance_geom, obmat, shgroup->instance_data, start, count); - } - GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) - } - } - else { - /* Some dynamic batch can have no geom (no call to aggregate) */ - if (shgroup->batch_geom) { - unsigned int count, start; - GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) - { - draw_geometry(shgroup, shgroup->batch_geom, obmat, NULL, start, count); - } - GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) - } - } - } - else { - for (DRWCall *call = shgroup->calls_first; call; call = call->head.prev) { - bool neg_scale = is_negative_m4(call->obmat); - - /* Negative scale objects */ - if (neg_scale) { - glFrontFace(DST.backface); - } - - GPU_SELECT_LOAD_IF_PICKSEL(call); - - if (call->head.type == DRW_CALL_SINGLE) { - draw_geometry(shgroup, call->geometry, call->obmat, call->ob_data, 0, 0); - } - else { - BLI_assert(call->head.type == DRW_CALL_GENERATE); - DRWCallGenerate *callgen = ((DRWCallGenerate *)call); - draw_geometry_prepare(shgroup, callgen->obmat, NULL, NULL); - callgen->geometry_fn(shgroup, draw_geometry_execute, callgen->user_data); - } - - /* Reset state */ - if (neg_scale) { - glFrontFace(DST.frontface); - } - } - } - - /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */ - DRW_state_reset(); -} - -static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) -{ - /* Start fresh */ - DST.shader = NULL; - - drw_state_set(pass->state); - - DRW_stats_query_start(pass->name); - - for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) { - draw_shgroup(shgroup, pass->state); - /* break if upper limit */ - if (shgroup == end_group) { - break; - } - } - - /* Clear Bound textures */ - for (int i = 0; i < GPU_max_textures(); i++) { - if (RST.bound_texs[i] != NULL) { - GPU_texture_unbind(RST.bound_texs[i]); - RST.bound_texs[i] = NULL; - } - } - - if (DST.shader) { - GPU_shader_unbind(); - DST.shader = NULL; - } - - DRW_stats_query_end(); -} - -void DRW_draw_pass(DRWPass *pass) -{ - drw_draw_pass_ex(pass, pass->shgroups, pass->shgroups_last); -} - -/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */ -void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) -{ - drw_draw_pass_ex(pass, start_group, end_group); -} +/* -------------------------------------------------------------------- */ void DRW_draw_callbacks_pre_scene(void) { @@ -2142,46 +128,6 @@ void DRW_draw_callbacks_post_scene(void) gpuLoadMatrix(rv3d->viewmat); } -/* Reset state to not interfer with other UI drawcall */ -void DRW_state_reset_ex(DRWState state) -{ - DST.state = ~state; - drw_state_set(state); -} - -void DRW_state_reset(void) -{ - /* Reset blending function */ - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - DRW_state_reset_ex(DRW_STATE_DEFAULT); -} - -/* NOTE : Make sure to reset after use! */ -void DRW_state_invert_facing(void) -{ - SWAP(GLenum, DST.backface, DST.frontface); - glFrontFace(DST.frontface); -} - -/** - * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES, - * and if the shaders have support for it (see usage of gl_ClipDistance). - * Be sure to call DRW_state_clip_planes_reset() after you finish drawing. - **/ -void DRW_state_clip_planes_add(float plane_eq[4]) -{ - copy_v4_v4(DST.clip_planes_eq[DST.num_clip_planes++], plane_eq); -} - -void DRW_state_clip_planes_reset(void) -{ - DST.num_clip_planes = 0; -} - -/** \} */ - - struct DRWTextStore *DRW_text_cache_ensure(void) { BLI_assert(DST.text_store_p); @@ -2199,13 +145,10 @@ struct DRWTextStore *DRW_text_cache_ensure(void) bool DRW_object_is_renderable(Object *ob) { - Scene *scene = DST.draw_ctx.scene; - Object *obedit = scene->obedit; - BLI_assert(BKE_object_is_visible(ob, OB_VISIBILITY_CHECK_UNKNOWN_RENDER_MODE)); if (ob->type == OB_MESH) { - if (ob == obedit) { + if (ob == DST.draw_ctx.object_edit) { IDProperty *props = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_EDIT, ""); bool do_show_occlude_wire = BKE_collection_engine_property_value_get_bool(props, "show_occlude_wire"); if (do_show_occlude_wire) { @@ -2250,8 +193,9 @@ bool DRW_object_is_flat_normal(const Object *ob) int DRW_object_is_mode_shade(const Object *ob) { BLI_assert(ob == DST.draw_ctx.obact); - if ((ob->mode & OB_MODE_EDIT) == 0) { - if (ob->mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) { + UNUSED_VARS_NDEBUG(ob); + if ((DST.draw_ctx.object_mode & OB_MODE_EDIT) == 0) { + if (DST.draw_ctx.object_mode & (OB_MODE_VERTEX_PAINT | OB_MODE_WEIGHT_PAINT | OB_MODE_TEXTURE_PAINT)) { if ((DST.draw_ctx.v3d->flag2 & V3D_SHOW_MODE_SHADE_OVERRIDE) == 0) { return true; } @@ -2268,188 +212,9 @@ int DRW_object_is_mode_shade(const Object *ob) /* -------------------------------------------------------------------- */ -/** \name Framebuffers (DRW_framebuffer) +/** \name Color Management * \{ */ -static GPUTextureFormat convert_tex_format( - int fbo_format, - int *r_channels, bool *r_is_depth) -{ - *r_is_depth = ELEM(fbo_format, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24, DRW_TEX_DEPTH_24_STENCIL_8); - - switch (fbo_format) { - case DRW_TEX_R_16: *r_channels = 1; return GPU_R16F; - case DRW_TEX_R_32: *r_channels = 1; return GPU_R32F; - case DRW_TEX_RG_8: *r_channels = 2; return GPU_RG8; - case DRW_TEX_RG_16: *r_channels = 2; return GPU_RG16F; - case DRW_TEX_RG_16I: *r_channels = 2; return GPU_RG16I; - case DRW_TEX_RG_32: *r_channels = 2; return GPU_RG32F; - case DRW_TEX_RGBA_8: *r_channels = 4; return GPU_RGBA8; - case DRW_TEX_RGBA_16: *r_channels = 4; return GPU_RGBA16F; - case DRW_TEX_RGBA_32: *r_channels = 4; return GPU_RGBA32F; - case DRW_TEX_DEPTH_16: *r_channels = 1; return GPU_DEPTH_COMPONENT16; - case DRW_TEX_DEPTH_24: *r_channels = 1; return GPU_DEPTH_COMPONENT24; - case DRW_TEX_DEPTH_24_STENCIL_8: *r_channels = 1; return GPU_DEPTH24_STENCIL8; - case DRW_TEX_DEPTH_32: *r_channels = 1; return GPU_DEPTH_COMPONENT32F; - case DRW_TEX_RGB_11_11_10: *r_channels = 3; return GPU_R11F_G11F_B10F; - default: - BLI_assert(false && "Texture format unsupported as render target!"); - *r_channels = 4; return GPU_RGBA8; - } -} - -struct GPUFrameBuffer *DRW_framebuffer_create(void) -{ - return GPU_framebuffer_create(); -} - -void DRW_framebuffer_init( - struct 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; - - DRWFboTexture fbotex = textures[i]; - bool is_temp = (fbotex.flag & DRW_TEX_TEMP) != 0; - - GPUTextureFormat gpu_format = convert_tex_format(fbotex.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); - } - } - - GPU_framebuffer_bind(DST.default_framebuffer); - } -} - -void DRW_framebuffer_free(struct GPUFrameBuffer *fb) -{ - GPU_framebuffer_free(fb); -} - -void DRW_framebuffer_bind(struct 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_texture_attach(struct GPUFrameBuffer *fb, GPUTexture *tex, int slot, int mip) -{ - GPU_framebuffer_texture_attach(fb, tex, slot, mip); -} - -void DRW_framebuffer_texture_layer_attach(struct GPUFrameBuffer *fb, struct GPUTexture *tex, int slot, int layer, int mip) -{ - GPU_framebuffer_texture_layer_attach(fb, tex, slot, layer, mip); -} - -void DRW_framebuffer_cubeface_attach(struct 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(struct GPUFrameBuffer *fb_read, struct GPUFrameBuffer *fb_write, bool depth, bool stencil) -{ - GPU_framebuffer_blit(fb_read, 0, fb_write, 0, depth, stencil); -} - -void DRW_framebuffer_recursive_downsample( - struct GPUFrameBuffer *fb, struct 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(struct GPUFrameBuffer *UNUSED(fb_read), int x, int y, int w, int h) -{ - glViewport(x, y, w, h); -} - /* Use color management profile to draw texture to framebuffer */ void DRW_transform_to_display(GPUTexture *tex) { @@ -2518,7 +283,7 @@ void DRW_transform_to_display(GPUTexture *tex) /** \name Viewport (DRW_viewport) * \{ */ -static void *DRW_viewport_engine_data_ensure(void *engine_type) +void *drw_viewport_engine_data_ensure(void *engine_type) { void *data = GPU_viewport_engine_data_get(DST.viewport, engine_type); @@ -2550,7 +315,12 @@ void DRW_engine_viewport_data_size_get( const float *DRW_viewport_size_get(void) { - return &DST.size[0]; + return DST.size; +} + +const float *DRW_viewport_invert_size_get(void) +{ + return DST.inv_size; } const float *DRW_viewport_screenvecs_get(void) @@ -2569,17 +339,59 @@ static void drw_viewport_cache_resize(void) GPU_viewport_cache_release(DST.viewport); if (DST.vmempool != NULL) { - BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_count(DST.vmempool->calls)); - BLI_mempool_clear_ex(DST.vmempool->calls_generate, BLI_mempool_count(DST.vmempool->calls_generate)); - BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_count(DST.vmempool->shgroups)); - BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_count(DST.vmempool->uniforms)); - BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_count(DST.vmempool->passes)); + BLI_mempool_clear_ex(DST.vmempool->calls, BLI_mempool_len(DST.vmempool->calls)); + BLI_mempool_clear_ex(DST.vmempool->states, BLI_mempool_len(DST.vmempool->states)); + BLI_mempool_clear_ex(DST.vmempool->shgroups, BLI_mempool_len(DST.vmempool->shgroups)); + BLI_mempool_clear_ex(DST.vmempool->uniforms, BLI_mempool_len(DST.vmempool->uniforms)); + BLI_mempool_clear_ex(DST.vmempool->passes, BLI_mempool_len(DST.vmempool->passes)); } DRW_instance_data_list_free_unused(DST.idatalist); DRW_instance_data_list_resize(DST.idatalist); } +static void drw_state_eval_ctx_init(DRWManager *dst) +{ + DRWContextState *draw_ctx = &dst->draw_ctx; + DEG_evaluation_context_init_from_scene( + &draw_ctx->eval_ctx, + draw_ctx->scene, + draw_ctx->view_layer, + DST.options.is_scene_render ? DAG_EVAL_RENDER : DAG_EVAL_VIEWPORT); +} + +/* Not a viewport variable, we could split this out. */ +static void drw_context_state_init(void) +{ + if (DST.draw_ctx.obact) { + DST.draw_ctx.object_mode = DST.draw_ctx.obact->mode; + } + else { + DST.draw_ctx.object_mode = OB_MODE_OBJECT; + } + + /* Edit object. */ + if (DST.draw_ctx.object_mode & OB_MODE_EDIT) { + DST.draw_ctx.object_edit = DST.draw_ctx.obact; + } + else { + DST.draw_ctx.object_edit = NULL; + } + + /* Pose object. */ + if (DST.draw_ctx.object_mode & OB_MODE_POSE) { + DST.draw_ctx.object_pose = DST.draw_ctx.obact; + } + else if (DST.draw_ctx.object_mode & OB_MODE_WEIGHT_PAINT) { + DST.draw_ctx.object_pose = BKE_object_pose_armature_get(DST.draw_ctx.obact); + } + else { + DST.draw_ctx.object_pose = NULL; + } + + drw_state_eval_ctx_init(&DST); +} + /* It also stores viewport variable to an immutable place: DST * This is because a cache uniform only store reference * to its value. And we don't want to invalidate the cache @@ -2587,13 +399,14 @@ static void drw_viewport_cache_resize(void) static void drw_viewport_var_init(void) { RegionView3D *rv3d = DST.draw_ctx.rv3d; - /* Refresh DST.size */ if (DST.viewport) { int size[2]; GPU_viewport_size_get(DST.viewport, size); DST.size[0] = size[0]; DST.size[1] = size[1]; + DST.inv_size[0] = 1.0f / size[0]; + DST.inv_size[1] = 1.0f / size[1]; DefaultFramebufferList *fbl = (DefaultFramebufferList *)GPU_viewport_framebuffer_list_get(DST.viewport); DST.default_framebuffer = fbl->default_fb; @@ -2603,8 +416,8 @@ static void drw_viewport_var_init(void) if (DST.vmempool->calls == NULL) { DST.vmempool->calls = BLI_mempool_create(sizeof(DRWCall), 0, 512, 0); } - if (DST.vmempool->calls_generate == NULL) { - DST.vmempool->calls_generate = BLI_mempool_create(sizeof(DRWCallGenerate), 0, 512, 0); + if (DST.vmempool->states == NULL) { + DST.vmempool->states = BLI_mempool_create(sizeof(DRWCallState), 0, 512, BLI_MEMPOOL_ALLOW_ITER); } if (DST.vmempool->shgroups == NULL) { DST.vmempool->shgroups = BLI_mempool_create(sizeof(DRWShadingGroup), 0, 256, 0); @@ -2623,88 +436,132 @@ static void drw_viewport_var_init(void) DST.size[0] = 0; DST.size[1] = 0; + DST.inv_size[0] = 0; + DST.inv_size[1] = 0; + DST.default_framebuffer = NULL; DST.vmempool = NULL; } - /* Refresh DST.screenvecs */ - copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); - copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); - normalize_v3(DST.screenvecs[0]); - normalize_v3(DST.screenvecs[1]); - /* Refresh DST.pixelsize */ - DST.pixsize = rv3d->pixsize; + if (rv3d != NULL) { + /* Refresh DST.screenvecs */ + copy_v3_v3(DST.screenvecs[0], rv3d->viewinv[0]); + copy_v3_v3(DST.screenvecs[1], rv3d->viewinv[1]); + normalize_v3(DST.screenvecs[0]); + normalize_v3(DST.screenvecs[1]); + + /* Refresh DST.pixelsize */ + DST.pixsize = rv3d->pixsize; + + copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERS], rv3d->persmat); + copy_m4_m4(DST.original_mat.mat[DRW_MAT_PERSINV], rv3d->persinv); + copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEW], rv3d->viewmat); + copy_m4_m4(DST.original_mat.mat[DRW_MAT_VIEWINV], rv3d->viewinv); + copy_m4_m4(DST.original_mat.mat[DRW_MAT_WIN], rv3d->winmat); + invert_m4_m4(DST.original_mat.mat[DRW_MAT_WININV], rv3d->winmat); + + memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DST.original_mat.mat)); + + copy_v4_v4(DST.view_data.viewcamtexcofac, rv3d->viewcamtexcofac); + } + else { + copy_v4_fl4(DST.view_data.viewcamtexcofac, 1.0f, 1.0f, 0.0f, 0.0f); + } /* Reset facing */ DST.frontface = GL_CCW; DST.backface = GL_CW; glFrontFace(DST.frontface); - if (DST.draw_ctx.scene->obedit) { - ED_view3d_init_mats_rv3d(DST.draw_ctx.scene->obedit, rv3d); + if (DST.draw_ctx.object_edit) { + ED_view3d_init_mats_rv3d(DST.draw_ctx.object_edit, rv3d); } /* Alloc array of texture reference. */ - if (RST.bound_texs == NULL) { - RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs"); + if (DST.RST.bound_texs == NULL) { + DST.RST.bound_texs = MEM_callocN(sizeof(GPUTexture *) * GPU_max_textures(), "Bound GPUTexture refs"); + } + if (DST.RST.bound_tex_slots == NULL) { + DST.RST.bound_tex_slots = MEM_callocN(sizeof(char) * GPU_max_textures(), "Bound Texture Slots"); } - if (RST.bound_tex_slots == NULL) { - RST.bound_tex_slots = MEM_callocN(sizeof(bool) * GPU_max_textures(), "Bound Texture Slots"); + if (DST.RST.bound_ubos == NULL) { + DST.RST.bound_ubos = MEM_callocN(sizeof(GPUUniformBuffer *) * GPU_max_ubo_binds(), "Bound GPUUniformBuffer refs"); } + if (DST.RST.bound_ubo_slots == NULL) { + DST.RST.bound_ubo_slots = MEM_callocN(sizeof(char) * GPU_max_ubo_binds(), "Bound Ubo Slots"); + } + + if (view_ubo == NULL) { + view_ubo = DRW_uniformbuffer_create(sizeof(ViewUboStorage), NULL); + } + + DST.override_mat = 0; + DST.dirty_mat = true; + DST.state_cache_id = 1; - memset(viewport_matrix_override.override, 0x0, sizeof(viewport_matrix_override.override)); + DST.clipping.updated = false; + + memset(DST.common_instance_data, 0x0, sizeof(DST.common_instance_data)); } void DRW_viewport_matrix_get(float mat[4][4], DRWViewportMatrixType type) { - RegionView3D *rv3d = DST.draw_ctx.rv3d; - BLI_assert(type >= DRW_MAT_PERS && type <= DRW_MAT_WININV); + BLI_assert(type >= 0 && type < DRW_MAT_COUNT); + BLI_assert(((DST.override_mat & (1 << type)) != 0)|| DST.draw_ctx.rv3d != NULL); /* Can't use this in render mode. */ - if (viewport_matrix_override.override[type]) { - copy_m4_m4(mat, viewport_matrix_override.mat[type]); - } - else { - switch (type) { - case DRW_MAT_PERS: - copy_m4_m4(mat, rv3d->persmat); - break; - case DRW_MAT_PERSINV: - copy_m4_m4(mat, rv3d->persinv); - break; - case DRW_MAT_VIEW: - copy_m4_m4(mat, rv3d->viewmat); - break; - case DRW_MAT_VIEWINV: - copy_m4_m4(mat, rv3d->viewinv); - break; - case DRW_MAT_WIN: - copy_m4_m4(mat, rv3d->winmat); - break; - case DRW_MAT_WININV: - invert_m4_m4(mat, rv3d->winmat); - break; - default: - BLI_assert(!"Matrix type invalid"); - break; - } - } + copy_m4_m4(mat, DST.view_data.matstate.mat[type]); +} + +void DRW_viewport_matrix_get_all(DRWMatrixState *state) +{ + memcpy(state, DST.view_data.matstate.mat, sizeof(DRWMatrixState)); } void DRW_viewport_matrix_override_set(float mat[4][4], DRWViewportMatrixType type) { - copy_m4_m4(viewport_matrix_override.mat[type], mat); - viewport_matrix_override.override[type] = true; + BLI_assert(type < DRW_MAT_COUNT); + copy_m4_m4(DST.view_data.matstate.mat[type], mat); + DST.override_mat |= (1 << type); + DST.dirty_mat = true; + DST.clipping.updated = false; } void DRW_viewport_matrix_override_unset(DRWViewportMatrixType type) { - viewport_matrix_override.override[type] = false; + BLI_assert(type < DRW_MAT_COUNT); + copy_m4_m4(DST.view_data.matstate.mat[type], DST.original_mat.mat[type]); + DST.override_mat &= ~(1 << type); + DST.dirty_mat = true; + DST.clipping.updated = false; +} + +void DRW_viewport_matrix_override_set_all(DRWMatrixState *state) +{ + memcpy(DST.view_data.matstate.mat, state, sizeof(DRWMatrixState)); + DST.override_mat = 0xFFFFFF; + DST.dirty_mat = true; + DST.clipping.updated = false; +} + +void DRW_viewport_matrix_override_unset_all(void) +{ + memcpy(DST.view_data.matstate.mat, DST.original_mat.mat, sizeof(DRWMatrixState)); + DST.override_mat = 0; + DST.dirty_mat = true; + DST.clipping.updated = false; } bool DRW_viewport_is_persp_get(void) { RegionView3D *rv3d = DST.draw_ctx.rv3d; - return rv3d->is_persp; + if (rv3d) { + return rv3d->is_persp; + } + else { + return DST.view_data.matstate.mat[DRW_MAT_WIN][3][3] == 0.0f; + } + BLI_assert(0); + return false; } DefaultFramebufferList *DRW_viewport_framebuffer_list_get(void) @@ -2765,51 +622,55 @@ void **DRW_view_layer_engine_data_ensure(DrawEngineType *engine_type, void (*cal /** \name Objects (DRW_object) * \{ */ -void *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) +ObjectEngineData *DRW_object_engine_data_get(Object *ob, DrawEngineType *engine_type) { for (ObjectEngineData *oed = ob->drawdata.first; oed; oed = oed->next) { if (oed->engine_type == engine_type) { - return oed->storage; + return oed; } } return NULL; } -void **DRW_object_engine_data_ensure( - Object *ob, DrawEngineType *engine_type, void (*callback)(void *storage)) -{ - ObjectEngineData *oed; - - for (oed = ob->drawdata.first; oed; oed = oed->next) { - if (oed->engine_type == engine_type) { - return &oed->storage; - } +ObjectEngineData *DRW_object_engine_data_ensure( + Object *ob, + DrawEngineType *engine_type, + size_t size, + ObjectEngineDataInitCb init_cb, + ObjectEngineDataFreeCb free_cb) +{ + BLI_assert(size >= sizeof(ObjectEngineData)); + /* Try to re-use existing data. */ + ObjectEngineData *oed = DRW_object_engine_data_get(ob, engine_type); + if (oed != NULL) { + return oed; + } + /* Allocate new data. */ + if ((ob->base_flag & BASE_FROMDUPLI) != 0) { + /* NOTE: data is not persistent in this case. It is reset each redraw. */ + BLI_assert(free_cb == NULL); /* No callback allowed. */ + /* Round to sizeof(float) for DRW_instance_data_request(). */ + const size_t t = sizeof(float) - 1; + size = (size + t) & ~t; + size_t fsize = size / sizeof(float); + if (DST.common_instance_data[fsize] == NULL) { + DST.common_instance_data[fsize] = DRW_instance_data_request(DST.idatalist, fsize, 16); + } + oed = (ObjectEngineData *)DRW_instance_data_next(DST.common_instance_data[fsize]); + memset(oed, 0, size); + } + else { + oed = MEM_callocN(size, "ObjectEngineData"); } - - oed = MEM_callocN(sizeof(ObjectEngineData), "ObjectEngineData"); oed->engine_type = engine_type; - oed->free = callback; + oed->free = free_cb; + /* Perform user-side initialization, if needed. */ + if (init_cb != NULL) { + init_cb(oed); + } + /* Register in the list. */ BLI_addtail(&ob->drawdata, oed); - - return &oed->storage; -} - -/* XXX There is definitly some overlap between this and DRW_object_engine_data_ensure. - * We should get rid of one of the two. */ -LampEngineData *DRW_lamp_engine_data_ensure(Object *ob, RenderEngineType *engine_type) -{ - BLI_assert(ob->type == OB_LAMP); - - Scene *scene = DST.draw_ctx.scene; - - /* TODO Dupliobjects */ - /* TODO Should be per scenelayer */ - return GPU_lamp_engine_data_get(scene, ob, NULL, engine_type); -} - -void DRW_lamp_engine_data_free(LampEngineData *led) -{ - GPU_lamp_engine_data_free(led); + return oed; } /** \} */ @@ -2824,7 +685,7 @@ static void drw_engines_init(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); PROFILE_START(stime); if (engine->engine_init) { @@ -2839,7 +700,7 @@ static void drw_engines_cache_init(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); if (data->text_draw_cache) { DRW_text_cache_destroy(data->text_draw_cache); @@ -2857,9 +718,15 @@ static void drw_engines_cache_init(void) static void drw_engines_cache_populate(Object *ob) { + DST.ob_state = NULL; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + + if (engine->id_update) { + engine->id_update(data, &ob->id); + } if (engine->cache_populate) { engine->cache_populate(data, ob); @@ -2871,7 +738,7 @@ static void drw_engines_cache_finish(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); if (engine->cache_finish) { engine->cache_finish(data); @@ -2883,7 +750,7 @@ static void drw_engines_draw_background(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); if (engine->draw_background) { PROFILE_START(stime); @@ -2907,12 +774,16 @@ static void drw_engines_draw_scene(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); PROFILE_START(stime); 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(); } @@ -2924,7 +795,7 @@ static void drw_engines_draw_text(void) { for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); PROFILE_START(stime); if (data->text_draw_cache) { @@ -2945,7 +816,7 @@ int DRW_draw_region_engine_info_offset(void) int lines = 0; for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); /* Count the number of lines. */ if (data->info[0] != '\0') { @@ -2980,7 +851,7 @@ void DRW_draw_region_engine_info(void) for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); if (data->info[0] != '\0') { char *chr_current = data->info; @@ -3024,6 +895,14 @@ static void use_drw_engine(DrawEngineType *engine) BLI_addtail(&DST.enabled_engines, ld); } +/** + * Use for external render engines. + */ +static void drw_engines_enable_external(void) +{ + use_drw_engine(DRW_engine_viewport_external_type.draw_engine); +} + /* TODO revisit this when proper layering is implemented */ /* Gather all draw engines needed and store them in DST.enabled_engines * That also define the rendering order of engines */ @@ -3106,18 +985,10 @@ static void drw_engines_enable_basic(void) use_drw_engine(DRW_engine_viewport_basic_type.draw_engine); } -/** - * Use for external render engines. - */ -static void drw_engines_enable_external(void) -{ - use_drw_engine(DRW_engine_viewport_external_type.draw_engine); -} - -static void drw_engines_enable(const Scene *scene, ViewLayer *view_layer, RenderEngineType *engine_type) +static void drw_engines_enable(ViewLayer *view_layer, RenderEngineType *engine_type) { Object *obact = OBACT(view_layer); - const int mode = CTX_data_mode_enum_ex(scene->obedit, obact); + const int mode = CTX_data_mode_enum_ex(DST.draw_ctx.object_edit, obact, DST.draw_ctx.object_mode); drw_engines_enable_from_engine(engine_type); @@ -3145,127 +1016,6 @@ static unsigned int DRW_engines_get_hash(void) return hash; } -static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size) -{ - BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit, - rect->ymax - (3 + v) * U.widget_unit, 0.0f, - txt, size); -} - -/* CPU stats */ -static void drw_debug_cpu_stats(void) -{ - int u, v; - double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0; - /* local coordinate visible rect inside region, to accomodate overlapping ui */ - rcti rect; - struct ARegion *ar = DST.draw_ctx.ar; - ED_region_visible_rect(ar, &rect); - - UI_FontThemeColor(BLF_default(), TH_TEXT_HI); - - /* row by row */ - v = 0; u = 0; - /* Label row */ - char col_label[32]; - sprintf(col_label, "Engine"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - sprintf(col_label, "Init"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - sprintf(col_label, "Background"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - sprintf(col_label, "Render"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - sprintf(col_label, "Total (w/o cache)"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - v++; - - /* Engines rows */ - char time_to_txt[16]; - for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { - u = 0; - DrawEngineType *engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(engine); - - draw_stat(&rect, u++, v, engine->idname, sizeof(engine->idname)); - - init_tot_time += data->init_time; - sprintf(time_to_txt, "%.2fms", data->init_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - - background_tot_time += data->background_time; - sprintf(time_to_txt, "%.2fms", data->background_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - - render_tot_time += data->render_time; - sprintf(time_to_txt, "%.2fms", data->render_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - - tot_time += data->init_time + data->background_time + data->render_time; - sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - v++; - } - - /* Totals row */ - u = 0; - sprintf(col_label, "Sub Total"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - sprintf(time_to_txt, "%.2fms", init_tot_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - sprintf(time_to_txt, "%.2fms", background_tot_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - sprintf(time_to_txt, "%.2fms", render_tot_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - sprintf(time_to_txt, "%.2fms", tot_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); - v += 2; - - u = 0; - sprintf(col_label, "Cache Time"); - draw_stat(&rect, u++, v, col_label, sizeof(col_label)); - sprintf(time_to_txt, "%.2fms", DST.cache_time); - draw_stat(&rect, u++, v, time_to_txt, sizeof(time_to_txt)); -} - -/* Display GPU time for each passes */ -static void drw_debug_gpu_stats(void) -{ - /* local coordinate visible rect inside region, to accomodate overlapping ui */ - rcti rect; - struct ARegion *ar = DST.draw_ctx.ar; - ED_region_visible_rect(ar, &rect); - - UI_FontThemeColor(BLF_default(), TH_TEXT_HI); - - int v = BLI_listbase_count(&DST.enabled_engines) + 5; - - char stat_string[32]; - - /* Memory Stats */ - unsigned int tex_mem = GPU_texture_memory_usage_get(); - unsigned int vbo_mem = GWN_vertbuf_get_memory_usage(); - - sprintf(stat_string, "GPU Memory"); - draw_stat(&rect, 0, v, stat_string, sizeof(stat_string)); - sprintf(stat_string, "%.2fMB", (double)(tex_mem + vbo_mem) / 1000000.0); - draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string)); - sprintf(stat_string, " |--> Textures"); - draw_stat(&rect, 0, v, stat_string, sizeof(stat_string)); - sprintf(stat_string, "%.2fMB", (double)tex_mem / 1000000.0); - draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string)); - sprintf(stat_string, " |--> Meshes"); - draw_stat(&rect, 0, v, stat_string, sizeof(stat_string)); - sprintf(stat_string, "%.2fMB", (double)vbo_mem / 1000000.0); - draw_stat(&rect, 1, v++, stat_string, sizeof(stat_string)); - - /* Pre offset for stats_draw */ - rect.ymax -= (3 + ++v) * U.widget_unit; - - /* Rendering Stats */ - DRW_stats_draw(&rect); -} - /* -------------------------------------------------------------------- */ /** \name View Update @@ -3285,21 +1035,27 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) return; } + /* XXX Really nasty locking. But else this could + * be executed by the material previews thread + * while rendering a viewport. */ + BLI_mutex_lock(&DST.ogl_context_mutex); /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); + drw_state_prepare_clean_for_draw(&DST); DST.viewport = rv3d->viewport; DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, - NULL, + .ar = ar, .rv3d = rv3d, .v3d = v3d, + .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer), + .engine_type = engine_type, + .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT, }; - drw_engines_enable(scene, view_layer, engine_type); + drw_engines_enable(view_layer, engine_type); for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *draw_engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine); if (draw_engine->view_update) { draw_engine->view_update(data); @@ -3309,6 +1065,8 @@ void DRW_notify_view_update(const DRWUpdateContext *update_ctx) DST.viewport = NULL; drw_engines_disable(); + + BLI_mutex_unlock(&DST.ogl_context_mutex); } /** \} */ @@ -3335,15 +1093,18 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id) return; } /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); + drw_state_prepare_clean_for_draw(&DST); DST.viewport = rv3d->viewport; DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, NULL, + .ar = ar, .rv3d = rv3d, .v3d = v3d, + .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer), + .engine_type = engine_type, + .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT, }; - drw_engines_enable(scene, view_layer, engine_type); + drw_engines_enable(view_layer, engine_type); for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { DrawEngineType *draw_engine = link->data; - ViewportEngineData *data = DRW_viewport_engine_data_ensure(draw_engine); + ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine); if (draw_engine->id_update) { draw_engine->id_update(data, id); } @@ -3364,14 +1125,15 @@ void DRW_notify_id_update(const DRWUpdateContext *update_ctx, ID *id) * for each relevant engine / mode engine. */ void DRW_draw_view(const bContext *C) { - struct Depsgraph *depsgraph = CTX_data_depsgraph(C); + EvaluationContext eval_ctx; + CTX_data_eval_ctx(C, &eval_ctx); RenderEngineType *engine_type = CTX_data_engine_type(C); ARegion *ar = CTX_wm_region(C); View3D *v3d = CTX_wm_view3d(C); /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); - DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, C); + drw_state_prepare_clean_for_draw(&DST); + DRW_draw_render_loop_ex(eval_ctx.depsgraph, engine_type, ar, v3d, C); } /** @@ -3384,6 +1146,7 @@ void DRW_draw_render_loop_ex( ARegion *ar, View3D *v3d, const bContext *evil_C) { + Scene *scene = DEG_get_evaluated_scene(depsgraph); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; @@ -3397,42 +1160,54 @@ void DRW_draw_render_loop_ex( GPU_viewport_engines_data_validate(DST.viewport, DRW_engines_get_hash()); DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, + .ar = ar, .rv3d = rv3d, .v3d = v3d, + .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer), + .engine_type = engine_type, + .depsgraph = depsgraph, /* reuse if caller sets */ - DST.draw_ctx.evil_C, + .evil_C = DST.draw_ctx.evil_C, }; - + drw_context_state_init(); drw_viewport_var_init(); /* Get list of enabled engines */ - drw_engines_enable(scene, view_layer, engine_type); + drw_engines_enable(view_layer, engine_type); /* Update ubos */ DRW_globals_update(); + /* No framebuffer allowed before drawing. */ + BLI_assert(GPU_framebuffer_current_get() == 0); + /* Init engines */ drw_engines_init(); - /* TODO : tag to refresh by the dependency graph */ - /* ideally only refresh when objects are added/removed */ - /* or render properties / materials change */ + /* Cache filling */ { PROFILE_START(stime); drw_engines_cache_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get()) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get()) { drw_engines_cache_populate(ob); } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; drw_engines_cache_finish(); - PROFILE_END_ACCUM(DST.cache_time, stime); + + DRW_render_instance_buffer_finish(); + +#ifdef USE_PROFILE + double *cache_time = GPU_viewport_cache_time_get(DST.viewport); + PROFILE_END_UPDATE(*cache_time, stime); +#endif } DRW_stats_begin(); + GPU_framebuffer_bind(DST.default_framebuffer); + /* Start Drawing */ DRW_state_reset(); @@ -3491,10 +1266,15 @@ void DRW_draw_render_loop_ex( } if (G.debug_value > 20) { - drw_debug_cpu_stats(); - drw_debug_gpu_stats(); + glDisable(GL_DEPTH_TEST); + rcti rect; /* local coordinate visible rect inside region, to accomodate overlapping ui */ + ED_region_visible_rect(DST.draw_ctx.ar, &rect); + DRW_stats_draw(&rect); + glEnable(GL_DEPTH_TEST); } + GPU_framebuffer_restore(); + DRW_state_reset(); drw_engines_disable(); @@ -3502,7 +1282,7 @@ void DRW_draw_render_loop_ex( #ifdef DEBUG /* Avoid accidental reuse. */ - memset(&DST, 0xFF, sizeof(DST)); + drw_state_ensure_not_reused(&DST); #endif } @@ -3511,7 +1291,7 @@ void DRW_draw_render_loop( ARegion *ar, View3D *v3d) { /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); + drw_state_prepare_clean_for_draw(&DST); Scene *scene = DEG_get_evaluated_scene(depsgraph); RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); @@ -3522,7 +1302,8 @@ void DRW_draw_render_loop( /* @viewport CAN be NULL, in this case we create one. */ void DRW_draw_render_loop_offscreen( struct Depsgraph *depsgraph, RenderEngineType *engine_type, - ARegion *ar, View3D *v3d, const bool draw_background, GPUOffScreen *ofs, + ARegion *ar, View3D *v3d, + const bool draw_background, GPUOffScreen *ofs, GPUViewport *viewport) { RegionView3D *rv3d = ar->regiondata; @@ -3539,8 +1320,10 @@ void DRW_draw_render_loop_offscreen( } } + GPU_framebuffer_restore(); + /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); + drw_state_prepare_clean_for_draw(&DST); DST.options.is_image_render = true; DST.options.draw_background = draw_background; DRW_draw_render_loop_ex(depsgraph, engine_type, ar, v3d, NULL); @@ -3551,7 +1334,6 @@ void DRW_draw_render_loop_offscreen( /* don't free data owned by 'ofs' */ GPU_viewport_clear_from_offscreen(rv3d->viewport); GPU_viewport_free(rv3d->viewport); - MEM_freeN(rv3d->viewport); } rv3d->viewport = backup_viewport; @@ -3561,24 +1343,163 @@ void DRW_draw_render_loop_offscreen( GPU_offscreen_bind(ofs, false); } +void DRW_render_to_image(RenderEngine *engine, struct Depsgraph *depsgraph) +{ + Scene *scene = DEG_get_evaluated_scene(depsgraph); + ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + RenderEngineType *engine_type = engine->type; + DrawEngineType *draw_engine_type = engine_type->draw_engine; + RenderData *r = &scene->r; + Render *render = engine->re; + /* Changing Context */ + DRW_opengl_context_enable(); + /* IMPORTANT: We dont support immediate mode in render mode! + * This shall remain in effect until immediate mode supports + * multiple threads. */ + + /* Reset before using it. */ + drw_state_prepare_clean_for_draw(&DST); + DST.options.is_image_render = true; + DST.options.is_scene_render = true; + DST.options.draw_background = scene->r.alphamode == R_ADDSKY; + + DST.draw_ctx = (DRWContextState){ + .scene = scene, .view_layer = view_layer, + .engine_type = engine_type, + .depsgraph = depsgraph, .object_mode = OB_MODE_OBJECT, + }; + drw_context_state_init(); + + DST.viewport = GPU_viewport_create(); + const int size[2] = {(r->size * r->xsch) / 100, (r->size * r->ysch) / 100}; + GPU_viewport_size_set(DST.viewport, size); + + drw_viewport_var_init(); + + ViewportEngineData *data = drw_viewport_engine_data_ensure(draw_engine_type); + + /* set default viewport */ + glViewport(0, 0, size[0], size[1]); + + /* Main rendering. */ + rctf view_rect; + rcti render_rect; + RE_GetViewPlane(render, &view_rect, &render_rect); + if (BLI_rcti_is_empty(&render_rect)) { + BLI_rcti_init(&render_rect, 0, size[0], 0, size[1]); + } + + /* Init render result. */ + RenderResult *render_result = RE_engine_begin_result( + engine, + 0, + 0, + (int)size[0], + (int)size[1], + view_layer->name, + /* RR_ALL_VIEWS */ NULL); + + RenderLayer *render_layer = render_result->layers.first; + for (RenderView *render_view = render_result->views.first; + render_view != NULL; + render_view = render_view->next) + { + RE_SetActiveRenderView(render, render_view->name); + engine_type->draw_engine->render_to_image(data, engine, render_layer, &render_rect); + DST.buffer_finish_called = false; + } + + RE_engine_end_result(engine, render_result, false, false, false); + + /* Force cache to reset. */ + drw_viewport_cache_resize(); + + /* TODO grease pencil */ + + GPU_viewport_free(DST.viewport); + GPU_framebuffer_restore(); + + /* Changing Context */ + DRW_opengl_context_disable(); + +#ifdef DEBUG + /* Avoid accidental reuse. */ + drw_state_ensure_not_reused(&DST); +#endif +} + +void DRW_render_object_iter( + void *vedata, RenderEngine *engine, struct Depsgraph *depsgraph, + void (*callback)(void *vedata, Object *ob, RenderEngine *engine, struct Depsgraph *depsgraph)) +{ + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get()) + { + DST.ob_state = NULL; + callback(vedata, ob, engine, depsgraph); + } + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END +} + +static struct DRWSelectBuffer { + struct GPUFrameBuffer *framebuffer; + struct GPUTexture *texture_depth; +} g_select_buffer = {NULL}; + +static void draw_select_framebuffer_setup(const rcti *rect) +{ + if (g_select_buffer.framebuffer == NULL) { + g_select_buffer.framebuffer = GPU_framebuffer_create(); + } + + /* If size mismatch recreate the texture. */ + if ((g_select_buffer.texture_depth != NULL) && + ((GPU_texture_width(g_select_buffer.texture_depth) != BLI_rcti_size_x(rect)) || + (GPU_texture_height(g_select_buffer.texture_depth) != BLI_rcti_size_y(rect)))) + { + GPU_texture_free(g_select_buffer.texture_depth); + g_select_buffer.texture_depth = NULL; + } + + if (g_select_buffer.texture_depth == NULL) { + g_select_buffer.texture_depth = GPU_texture_create_depth(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect), NULL); + + GPU_framebuffer_texture_attach(g_select_buffer.framebuffer, g_select_buffer.texture_depth, 0, 0); + + if (!GPU_framebuffer_check_valid(g_select_buffer.framebuffer, NULL)) { + printf("Error invalid selection framebuffer\n"); + } + } +} + +/* Must run after all instance datas have been added. */ +void DRW_render_instance_buffer_finish(void) +{ + BLI_assert(!DST.buffer_finish_called && "DRW_render_instance_buffer_finish called twice!"); + DST.buffer_finish_called = true; + DRW_instance_buffer_finish(DST.idatalist); +} + /** * object mode select-loop, see: ED_view3d_draw_select_loop (legacy drawing). */ void DRW_draw_select_loop( struct Depsgraph *depsgraph, ARegion *ar, View3D *v3d, - bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect) + bool UNUSED(use_obedit_skip), bool UNUSED(use_nearest), const rcti *rect, + DRW_SelectPassFn select_pass_fn, void *select_pass_user_data) { Scene *scene = DEG_get_evaluated_scene(depsgraph); RenderEngineType *engine_type = RE_engines_find(scene->view_render.engine_id); ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); + Object *obact = OBACT(view_layer); + Object *obedit = OBEDIT_FROM_OBACT(obact); #ifndef USE_GPU_SELECT UNUSED_VARS(vc, scene, view_layer, v3d, ar, rect); #else RegionView3D *rv3d = ar->regiondata; /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); + drw_state_prepare_clean_for_draw(&DST); /* backup (_never_ use rv3d->viewport) */ void *backup_viewport = rv3d->viewport; @@ -3586,14 +1507,12 @@ void DRW_draw_select_loop( bool use_obedit = false; int obedit_mode = 0; - if (scene->obedit && scene->obedit->type == OB_MBALL) { - use_obedit = true; - obedit_mode = CTX_MODE_EDIT_METABALL; - } - else if ((scene->obedit && scene->obedit->type == OB_ARMATURE)) { - /* if not drawing sketch, draw bones */ - // if (!BDR_drawSketchNames(vc)) - { + if (obedit != NULL) { + if (obedit->type == OB_MBALL) { + use_obedit = true; + obedit_mode = CTX_MODE_EDIT_METABALL; + } + else if (obedit->type == OB_ARMATURE) { use_obedit = true; obedit_mode = CTX_MODE_EDIT_ARMATURE; } @@ -3602,7 +1521,6 @@ void DRW_draw_select_loop( struct GPUViewport *viewport = GPU_viewport_create(); GPU_viewport_size_set(viewport, (const int[2]){BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)}); - bool cache_is_dirty; DST.viewport = viewport; v3d->zbuf = true; @@ -3618,13 +1536,15 @@ void DRW_draw_select_loop( } /* Setup viewport */ - cache_is_dirty = true; /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, (bContext *)NULL, + .ar = ar, .rv3d = rv3d, .v3d = v3d, + .scene = scene, .view_layer = view_layer, .obact = obact, + .engine_type = engine_type, + .depsgraph = depsgraph, }; - + drw_context_state_init(); drw_viewport_var_init(); /* Update ubos */ @@ -3633,36 +1553,64 @@ void DRW_draw_select_loop( /* Init engines */ drw_engines_init(); - /* TODO : tag to refresh by the dependency graph */ - /* ideally only refresh when objects are added/removed */ - /* or render properties / materials change */ - if (cache_is_dirty) { + { drw_engines_cache_init(); if (use_obedit) { - drw_engines_cache_populate(scene->obedit); + drw_engines_cache_populate(obact); } else { - DEG_OBJECT_ITER(depsgraph, ob, DRW_iterator_mode_get(), - DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | - DEG_ITER_OBJECT_FLAG_VISIBLE | - DEG_ITER_OBJECT_FLAG_DUPLI) + DEG_OBJECT_ITER_BEGIN( + depsgraph, ob, DRW_iterator_mode_get(), + DEG_ITER_OBJECT_FLAG_LINKED_DIRECTLY | + DEG_ITER_OBJECT_FLAG_VISIBLE | + DEG_ITER_OBJECT_FLAG_DUPLI) { if ((ob->base_flag & BASE_SELECTABLED) != 0) { DRW_select_load_id(ob->select_color); drw_engines_cache_populate(ob); } } - DEG_OBJECT_ITER_END + DEG_OBJECT_ITER_END; } drw_engines_cache_finish(); + + 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(); - drw_engines_draw_scene(); + + DRW_state_lock( + DRW_STATE_WRITE_DEPTH | + DRW_STATE_DEPTH_ALWAYS | + DRW_STATE_DEPTH_LESS | + DRW_STATE_DEPTH_EQUAL | + DRW_STATE_DEPTH_GREATER | + DRW_STATE_DEPTH_ALWAYS); + + /* Only 1-2 passes. */ + while (true) { + if (!select_pass_fn(DRW_SELECT_PASS_PRE, select_pass_user_data)) { + break; + } + + drw_engines_draw_scene(); + + if (!select_pass_fn(DRW_SELECT_PASS_POST, select_pass_user_data)) { + break; + } + } + + DRW_state_lock(0); + DRW_draw_callbacks_post_scene(); DRW_state_reset(); @@ -3670,18 +1618,54 @@ void DRW_draw_select_loop( #ifdef DEBUG /* Avoid accidental reuse. */ - memset(&DST, 0xFF, sizeof(DST)); + drw_state_ensure_not_reused(&DST); #endif + GPU_framebuffer_restore(); /* Cleanup for selection state */ GPU_viewport_free(viewport); - MEM_freeN(viewport); /* restore */ rv3d->viewport = backup_viewport; #endif /* USE_GPU_SELECT */ } +static void draw_depth_texture_to_screen(GPUTexture *texture) +{ + const float w = (float)GPU_texture_width(texture); + const float h = (float)GPU_texture_height(texture); + + Gwn_VertFormat *format = immVertexFormat(); + unsigned int texcoord = GWN_vertformat_attr_add(format, "texCoord", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); + + immBindBuiltinProgram(GPU_SHADER_3D_IMAGE_DEPTH_COPY); + + GPU_texture_bind(texture, 0); + + immUniform1i("image", 0); /* default GL_TEXTURE0 unit */ + + immBegin(GWN_PRIM_TRI_STRIP, 4); + + immAttrib2f(texcoord, 0.0f, 0.0f); + immVertex2f(pos, 0.0f, 0.0f); + + immAttrib2f(texcoord, 1.0f, 0.0f); + immVertex2f(pos, w, 0.0f); + + immAttrib2f(texcoord, 0.0f, 1.0f); + immVertex2f(pos, 0.0f, h); + + immAttrib2f(texcoord, 1.0f, 1.0f); + immVertex2f(pos, w, h); + + immEnd(); + + GPU_texture_unbind(texture); + + immUnbindProgram(); +} + /** * object mode select-loop, see: ED_view3d_draw_depth_loop (legacy drawing). */ @@ -3694,16 +1678,23 @@ void DRW_draw_depth_loop( ViewLayer *view_layer = DEG_get_evaluated_view_layer(depsgraph); RegionView3D *rv3d = ar->regiondata; + DRW_opengl_context_enable(); + /* backup (_never_ use rv3d->viewport) */ void *backup_viewport = rv3d->viewport; rv3d->viewport = NULL; /* Reset before using it. */ - memset(&DST, 0x0, sizeof(DST)); + drw_state_prepare_clean_for_draw(&DST); struct GPUViewport *viewport = GPU_viewport_create(); GPU_viewport_size_set(viewport, (const int[2]){ar->winx, ar->winy}); + /* Setup framebuffer */ + draw_select_framebuffer_setup(&ar->winrct); + GPU_framebuffer_bind(g_select_buffer.framebuffer); + GPU_framebuffer_clear_depth(g_select_buffer.framebuffer, 1.0f); + bool cache_is_dirty; DST.viewport = viewport; v3d->zbuf = true; @@ -3721,9 +1712,12 @@ void DRW_draw_depth_loop( /* Instead of 'DRW_context_state_init(C, &DST.draw_ctx)', assign from args */ DST.draw_ctx = (DRWContextState){ - ar, rv3d, v3d, scene, view_layer, OBACT(view_layer), engine_type, depsgraph, (bContext *)NULL, + .ar = ar, .rv3d = rv3d, .v3d = v3d, + .scene = scene, .view_layer = view_layer, .obact = OBACT(view_layer), + .engine_type = engine_type, + .depsgraph = depsgraph, }; - + drw_context_state_init(); drw_viewport_var_init(); /* Update ubos */ @@ -3738,13 +1732,15 @@ void DRW_draw_depth_loop( if (cache_is_dirty) { drw_engines_cache_init(); - DEG_OBJECT_ITER_FOR_RENDER_ENGINE(depsgraph, ob, DRW_iterator_mode_get()) + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_BEGIN(depsgraph, ob, DRW_iterator_mode_get()) { drw_engines_cache_populate(ob); } - DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END + DEG_OBJECT_ITER_FOR_RENDER_ENGINE_END; drw_engines_cache_finish(); + + DRW_render_instance_buffer_finish(); } /* Start Drawing */ @@ -3758,12 +1754,32 @@ void DRW_draw_depth_loop( #ifdef DEBUG /* Avoid accidental reuse. */ - memset(&DST, 0xFF, sizeof(DST)); + drw_state_ensure_not_reused(&DST); #endif + /* TODO: Reading depth for operators should be done here. */ + + GPU_framebuffer_restore(); + /* Cleanup for selection state */ GPU_viewport_free(viewport); - MEM_freeN(viewport); + + /* Changin context */ + DRW_opengl_context_disable(); + + /* XXX Drawing the resulting buffer to the BACK_BUFFER */ + gpuPushMatrix(); + gpuPushProjectionMatrix(); + wmOrtho2_region_pixelspace(ar); + gpuLoadIdentity(); + + glEnable(GL_DEPTH_TEST); /* Cannot write to depth buffer without testing */ + glDepthFunc(GL_ALWAYS); + draw_depth_texture_to_screen(g_select_buffer.texture_depth); + glDepthFunc(GL_LEQUAL); + + gpuPopMatrix(); + gpuPopProjectionMatrix(); /* restore */ rv3d->viewport = backup_viewport; @@ -3788,7 +1804,7 @@ void DRW_state_dfdy_factors_get(float dfdyfac[2]) */ bool DRW_state_is_fbo(void) { - return (DST.default_framebuffer != NULL); + return ((DST.default_framebuffer != NULL) || DST.options.is_image_render); } /** @@ -3824,6 +1840,14 @@ bool DRW_state_is_scene_render(void) } /** +* Whether we are rendering simple opengl render +*/ +bool DRW_state_is_opengl_render(void) +{ + return DST.options.is_image_render && !DST.options.is_scene_render; +} + +/** * Gives you the iterator mode to use for depsgraph. */ eDepsObjectIteratorMode DRW_iterator_mode_get(void) @@ -3886,6 +1910,11 @@ const DRWContextState *DRW_context_state_get(void) /** \name Init/Exit (DRW_engines) * \{ */ +bool DRW_engine_render_support(DrawEngineType *draw_engine_type) +{ + return draw_engine_type->render_to_image; +} + void DRW_engine_register(DrawEngineType *draw_engine_type) { BLI_addtail(&DRW_engines, draw_engine_type); @@ -3961,12 +1990,19 @@ void DRW_engines_register(void) } } +extern struct Gwn_VertFormat *g_pos_format; /* draw_shgroup.c */ extern struct GPUUniformBuffer *globals_ubo; /* draw_common.c */ extern struct GPUTexture *globals_ramp; /* draw_common.c */ void DRW_engines_free(void) { + DRW_opengl_context_enable(); + + DRW_TEXTURE_FREE_SAFE(g_select_buffer.texture_depth); + GPU_FRAMEBUFFER_FREE_SAFE(g_select_buffer.framebuffer); + DRW_shape_cache_free(); DRW_stats_free(); + DRW_globals_free(); DrawEngineType *next; for (DrawEngineType *type = DRW_engines.first; type; type = next) { @@ -3978,14 +2014,17 @@ void DRW_engines_free(void) } } - if (globals_ubo) - GPU_uniformbuffer_free(globals_ubo); + DRW_UBO_FREE_SAFE(globals_ubo); + DRW_UBO_FREE_SAFE(view_ubo); + DRW_TEXTURE_FREE_SAFE(globals_ramp); + MEM_SAFE_FREE(g_pos_format); - if (globals_ramp) - GPU_texture_free(globals_ramp); + MEM_SAFE_FREE(DST.RST.bound_texs); + MEM_SAFE_FREE(DST.RST.bound_tex_slots); + MEM_SAFE_FREE(DST.RST.bound_ubos); + MEM_SAFE_FREE(DST.RST.bound_ubo_slots); - MEM_SAFE_FREE(RST.bound_texs); - MEM_SAFE_FREE(RST.bound_tex_slots); + DRW_opengl_context_disable(); #ifdef WITH_CLAY_ENGINE BLI_remlink(&R_engines, &DRW_engine_viewport_clay_type); @@ -3993,3 +2032,78 @@ void DRW_engines_free(void) } /** \} */ + +/** \name Init/Exit (DRW_opengl_ctx) + * \{ */ + +void DRW_opengl_context_create(void) +{ + BLI_assert(DST.ogl_context == NULL); /* Ensure it's called once */ + + BLI_mutex_init(&DST.ogl_context_mutex); + + immDeactivate(); + /* This changes the active context. */ + DST.ogl_context = WM_opengl_context_create(); + /* Be sure to create gawain.context too. */ + DST.gwn_context = GWN_context_create(); + immActivate(); + /* Set default Blender OpenGL state */ + GPU_state_init(); + /* So we activate the window's one afterwards. */ + wm_window_reset_drawable(); +} + +void DRW_opengl_context_destroy(void) +{ + BLI_assert(BLI_thread_is_main()); + if (DST.ogl_context != NULL) { + WM_opengl_context_activate(DST.ogl_context); + GWN_context_active_set(DST.gwn_context); + GWN_context_discard(DST.gwn_context); + WM_opengl_context_dispose(DST.ogl_context); + BLI_mutex_end(&DST.ogl_context_mutex); + } +} + +void DRW_opengl_context_enable(void) +{ + if (DST.ogl_context != NULL) { + /* IMPORTANT: We dont support immediate mode in render mode! + * This shall remain in effect until immediate mode supports + * multiple threads. */ + BLI_mutex_lock(&DST.ogl_context_mutex); + if (BLI_thread_is_main()) { + immDeactivate(); + } + WM_opengl_context_activate(DST.ogl_context); + GWN_context_active_set(DST.gwn_context); + if (BLI_thread_is_main()) { + immActivate(); + BLF_batch_reset(); + } + } +} + +void DRW_opengl_context_disable(void) +{ + if (DST.ogl_context != NULL) { +#ifdef __APPLE__ + /* Need to flush before disabling draw context, otherwise it does not + * always finish drawing and viewport can be empty or partially drawn */ + glFlush(); +#endif + + if (BLI_thread_is_main()) { + wm_window_reset_drawable(); + } + else { + WM_opengl_context_release(DST.ogl_context); + GWN_context_active_set(NULL); + } + + BLI_mutex_unlock(&DST.ogl_context_mutex); + } +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_manager.h b/source/blender/draw/intern/draw_manager.h new file mode 100644 index 00000000000..dd7e84f67d4 --- /dev/null +++ b/source/blender/draw/intern/draw_manager.h @@ -0,0 +1,358 @@ +/* + * 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 draw_manager.h + * \ingroup draw + */ + +/* Private functions / structs of the draw manager */ + +#ifndef __DRAW_MANAGER_H__ +#define __DRAW_MANAGER_H__ + +#include "DRW_engine.h" +#include "DRW_render.h" + +#include "BLI_linklist.h" +#include "BLI_threads.h" + +#include "GPU_batch.h" +#include "GPU_framebuffer.h" +#include "GPU_shader.h" +#include "GPU_uniformbuffer.h" +#include "GPU_viewport.h" + +#include "draw_instance_data.h" + +/* Use draw manager to call GPU_select, see: DRW_draw_select_loop */ +#define USE_GPU_SELECT + +/* ------------ Profiling --------------- */ + +#define USE_PROFILE + +#ifdef USE_PROFILE +# include "PIL_time.h" + +# define PROFILE_TIMER_FALLOFF 0.04 + +# define PROFILE_START(time_start) \ + double time_start = PIL_check_seconds_timer(); + +# define PROFILE_END_ACCUM(time_accum, time_start) { \ + time_accum += (PIL_check_seconds_timer() - time_start) * 1e3; \ +} ((void)0) + +/* exp average */ +# define PROFILE_END_UPDATE(time_update, time_start) { \ + double _time_delta = (PIL_check_seconds_timer() - time_start) * 1e3; \ + time_update = (time_update * (1.0 - PROFILE_TIMER_FALLOFF)) + \ + (_time_delta * PROFILE_TIMER_FALLOFF); \ +} ((void)0) + +#else /* USE_PROFILE */ + +# define PROFILE_START(time_start) ((void)0) +# define PROFILE_END_ACCUM(time_accum, time_start) ((void)0) +# define PROFILE_END_UPDATE(time_update, time_start) ((void)0) + +#endif /* USE_PROFILE */ + +/* ------------ Data Structure --------------- */ +/** + * Data structure containing all drawcalls organized by passes and materials. + * DRWPass > DRWShadingGroup > DRWCall > DRWCallState + * > DRWUniform + **/ + +/* Used by DRWCallState.flag */ +enum { + DRW_CALL_CULLED = (1 << 0), + DRW_CALL_NEGSCALE = (1 << 1), +}; + +/* Used by DRWCallState.matflag */ +enum { + DRW_CALL_MODELINVERSE = (1 << 0), + DRW_CALL_MODELVIEW = (1 << 1), + DRW_CALL_MODELVIEWINVERSE = (1 << 2), + DRW_CALL_MODELVIEWPROJECTION = (1 << 3), + DRW_CALL_NORMALVIEW = (1 << 4), + DRW_CALL_NORMALWORLD = (1 << 5), + DRW_CALL_ORCOTEXFAC = (1 << 6), + DRW_CALL_EYEVEC = (1 << 7), +}; + +typedef struct DRWCallState { + unsigned char flag; + unsigned char cache_id; /* Compared with DST.state_cache_id to see if matrices are still valid. */ + uint16_t matflag; /* Which matrices to compute. */ + /* Culling: Using Bounding Sphere for now for faster culling. + * Not ideal for planes. */ + BoundSphere bsphere; + /* Matrices */ + float model[4][4]; + float modelinverse[4][4]; + float modelview[4][4]; + float modelviewinverse[4][4]; + float modelviewprojection[4][4]; + float normalview[3][3]; + float normalworld[3][3]; /* Not view dependant */ + float orcotexfac[2][3]; /* Not view dependant */ + float eyevec[3]; +} DRWCallState; + +typedef enum { + DRW_CALL_SINGLE, /* A single batch */ + DRW_CALL_INSTANCES, /* Draw instances without any instancing attribs. */ + DRW_CALL_GENERATE, /* Uses a callback to draw with any number of batches. */ +} DRWCallType; + +typedef struct DRWCall { + struct DRWCall *next; + DRWCallState *state; + + union { + struct { /* type == DRW_CALL_SINGLE */ + Gwn_Batch *geometry; + } single; + struct { /* type == DRW_CALL_INSTANCES */ + Gwn_Batch *geometry; + /* Count can be adjusted between redraw. If needed, we can add fixed count. */ + unsigned int *count; + } instances; + struct { /* type == DRW_CALL_GENERATE */ + DRWCallGenerateFn *geometry_fn; + void *user_data; + } generate; + }; + + DRWCallType type; +#ifdef USE_GPU_SELECT + int select_id; +#endif +} DRWCall; + +/* Used by DRWUniform.type */ +typedef enum { + DRW_UNIFORM_BOOL, + DRW_UNIFORM_SHORT_TO_INT, + DRW_UNIFORM_SHORT_TO_FLOAT, + DRW_UNIFORM_INT, + DRW_UNIFORM_FLOAT, + DRW_UNIFORM_TEXTURE, + DRW_UNIFORM_TEXTURE_PERSIST, + DRW_UNIFORM_TEXTURE_REF, + DRW_UNIFORM_BLOCK, + DRW_UNIFORM_BLOCK_PERSIST +} DRWUniformType; + +struct DRWUniform { + DRWUniform *next; /* single-linked list */ + const void *value; + int location; + char type; /* DRWUniformType */ + char length; /* cannot be more than 16 */ + char arraysize; /* cannot be more than 16 too */ +}; + +typedef enum { + DRW_SHG_NORMAL, + DRW_SHG_POINT_BATCH, + DRW_SHG_LINE_BATCH, + DRW_SHG_TRIANGLE_BATCH, + DRW_SHG_INSTANCE, + DRW_SHG_INSTANCE_EXTERNAL, +} DRWShadingGroupType; + +struct DRWShadingGroup { + DRWShadingGroup *next; + + GPUShader *shader; /* Shader to bind */ + DRWUniform *uniforms; /* Uniforms pointers */ + + /* Watch this! Can be nasty for debugging. */ + union { + struct { /* DRW_SHG_NORMAL */ + DRWCall *first, *last; /* Linked list of DRWCall or DRWCallDynamic depending of type */ + } calls; + struct { /* DRW_SHG_***_BATCH */ + struct Gwn_Batch *batch_geom; /* Result of call batching */ + struct Gwn_VertBuf *batch_vbo; + unsigned int primitive_count; + }; + struct { /* DRW_SHG_INSTANCE[_EXTERNAL] */ + struct Gwn_Batch *instance_geom; + struct Gwn_VertBuf *instance_vbo; + unsigned int instance_count; + float instance_orcofac[2][3]; /* TODO find a better place. */ + }; + }; + + DRWState state_extra; /* State changes for this batch only (or'd with the pass's state) */ + DRWState state_extra_disable; /* State changes for this batch only (and'd with the pass's state) */ + unsigned int stencil_mask; /* Stencil mask to use for stencil test / write operations */ + DRWShadingGroupType type; + + /* Builtin matrices locations */ + int model; + int modelinverse; + int modelview; + int modelviewinverse; + int modelviewprojection; + int normalview; + int normalworld; + int orcotexfac; + int eye; + uint16_t matflag; /* Matrices needed, same as DRWCall.flag */ + +#ifndef NDEBUG + char attribs_count; +#endif + +#ifdef USE_GPU_SELECT + DRWInstanceData *inst_selectid; + DRWPass *pass_parent; /* backlink to pass we're in */ + int override_selectid; /* Override for single object instances. */ +#endif +}; + +#define MAX_PASS_NAME 32 + +struct DRWPass { + /* Linked list */ + struct { + DRWShadingGroup *first; + DRWShadingGroup *last; + } shgroups; + + DRWState state; + char name[MAX_PASS_NAME]; +}; + +typedef struct ViewUboStorage { + DRWMatrixState matstate; + float viewcamtexcofac[4]; + float clipplanes[2][4]; +} ViewUboStorage; + +/* ------------- DRAW MANAGER ------------ */ + +#define MAX_CLIP_PLANES 6 /* GL_MAX_CLIP_PLANES is at least 6 */ + +typedef struct DRWManager { + /* TODO clean up this struct a bit */ + /* Cache generation */ + ViewportMemoryPool *vmempool; + DRWInstanceDataList *idatalist; + DRWInstanceData *common_instance_data[MAX_INSTANCE_DATA_SIZE]; + /* State of the object being evaluated if already allocated. */ + DRWCallState *ob_state; + unsigned char state_cache_id; /* Could be larger but 254 view changes is already a lot! */ + + /* Rendering state */ + GPUShader *shader; + + /* Managed by `DRW_state_set`, `DRW_state_reset` */ + DRWState state; + DRWState state_lock; + unsigned int stencil_mask; + + /* Per viewport */ + GPUViewport *viewport; + struct GPUFrameBuffer *default_framebuffer; + float size[2]; + float inv_size[2]; + float screenvecs[2][3]; + float pixsize; + + GLenum backface, frontface; + + struct { + unsigned int is_select : 1; + unsigned int is_depth : 1; + unsigned int is_image_render : 1; + unsigned int is_scene_render : 1; + unsigned int draw_background : 1; + } options; + + /* Current rendering context */ + DRWContextState draw_ctx; + + /* Convenience pointer to text_store owned by the viewport */ + struct DRWTextStore **text_store_p; + + ListBase enabled_engines; /* RenderEngineType */ + + bool buffer_finish_called; /* Avoid bad usage of DRW_render_instance_buffer_finish */ + + /* View dependant uniforms. */ + DRWMatrixState original_mat; /* Original rv3d matrices. */ + int override_mat; /* Bitflag of which matrices are overriden. */ + int num_clip_planes; /* Number of active clipplanes. */ + bool dirty_mat; + + /* keep in sync with viewBlock */ + ViewUboStorage view_data; + + struct { + float frustum_planes[6][4]; + BoundSphere frustum_bsphere; + bool updated; + } clipping; + +#ifdef USE_GPU_SELECT + unsigned int select_id; +#endif + + /* ---------- Nothing after this point is cleared after use ----------- */ + + /* ogl_context serves as the offset for clearing only + * the top portion of the struct so DO NOT MOVE IT! */ + void *ogl_context; /* Unique ghost context used by the draw manager. */ + Gwn_Context *gwn_context; + ThreadMutex ogl_context_mutex; /* Mutex to lock the drw manager and avoid concurent context usage. */ + + /** GPU Resource State: Memory storage between drawing. */ + struct { + GPUTexture **bound_texs; + char *bound_tex_slots; + int bind_tex_inc; + GPUUniformBuffer **bound_ubos; + char *bound_ubo_slots; + int bind_ubo_inc; + } RST; +} DRWManager; + +extern DRWManager DST; /* TODO : get rid of this and allow multithreaded rendering */ + +/* --------------- FUNCTIONS ------------- */ + +void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags); +void drw_texture_get_format( + DRWTextureFormat format, bool is_framebuffer, + GPUTextureFormat *r_data_type, int *r_channels, bool *r_is_depth); + +void *drw_viewport_engine_data_ensure(void *engine_type); + +void drw_state_set(DRWState state); + +#endif /* __DRAW_MANAGER_H__ */ diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c new file mode 100644 index 00000000000..ae7854b436c --- /dev/null +++ b/source/blender/draw/intern/draw_manager_data.c @@ -0,0 +1,935 @@ +/* + * 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_data.c + * \ingroup draw + */ + +#include "draw_manager.h" + +#include "BKE_curve.h" +#include "BKE_global.h" +#include "BKE_mesh.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_pbvh.h" + +#include "DNA_curve_types.h" +#include "DNA_mesh_types.h" +#include "DNA_meta_types.h" + +#include "BLI_link_utils.h" +#include "BLI_mempool.h" + +#include "intern/gpu_codegen.h" + +struct Gwn_VertFormat *g_pos_format = NULL; + +extern struct GPUUniformBuffer *view_ubo; /* draw_manager_exec.c */ + +/* -------------------------------------------------------------------- */ + +/** \name Uniform Buffer Object (DRW_uniformbuffer) + * \{ */ + +GPUUniformBuffer *DRW_uniformbuffer_create(int size, const void *data) +{ + return GPU_uniformbuffer_create(size, data, NULL); +} + +void DRW_uniformbuffer_update(GPUUniformBuffer *ubo, const void *data) +{ + GPU_uniformbuffer_update(ubo, data); +} + +void DRW_uniformbuffer_free(GPUUniformBuffer *ubo) +{ + GPU_uniformbuffer_free(ubo); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Uniforms (DRW_shgroup_uniform) + * \{ */ + +static void drw_shgroup_uniform_create_ex(DRWShadingGroup *shgroup, int loc, + DRWUniformType type, const void *value, int length, int arraysize) +{ + DRWUniform *uni = BLI_mempool_alloc(DST.vmempool->uniforms); + uni->location = loc; + uni->type = type; + uni->value = value; + uni->length = length; + uni->arraysize = arraysize; + + BLI_LINKS_PREPEND(shgroup->uniforms, uni); +} + +static void drw_shgroup_builtin_uniform( + DRWShadingGroup *shgroup, int builtin, const void *value, int length, int arraysize) +{ + int loc = GPU_shader_get_builtin_uniform(shgroup->shader, builtin); + + if (loc != -1) { + drw_shgroup_uniform_create_ex(shgroup, loc, DRW_UNIFORM_FLOAT, value, length, arraysize); + } +} + +static void drw_shgroup_uniform(DRWShadingGroup *shgroup, const char *name, + DRWUniformType type, const void *value, int length, int arraysize) +{ + int location; + if (ELEM(type, DRW_UNIFORM_BLOCK, DRW_UNIFORM_BLOCK_PERSIST)) { + location = GPU_shader_get_uniform_block(shgroup->shader, name); + } + else { + location = GPU_shader_get_uniform(shgroup->shader, name); + } + + if (location == -1) { + if (G.debug & G_DEBUG) + fprintf(stderr, "Uniform '%s' not found!\n", name); + /* Nice to enable eventually, for now eevee uses uniforms that might not exist. */ + // BLI_assert(0); + return; + } + + BLI_assert(arraysize > 0 && arraysize <= 16); + BLI_assert(length >= 0 && length <= 16); + + drw_shgroup_uniform_create_ex(shgroup, location, type, value, length, arraysize); +} + +void DRW_shgroup_uniform_texture(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) +{ + BLI_assert(tex != NULL); + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE, tex, 0, 1); +} + +/* Same as DRW_shgroup_uniform_texture but is garanteed to be bound if shader does not change between shgrp. */ +void DRW_shgroup_uniform_texture_persistent(DRWShadingGroup *shgroup, const char *name, const GPUTexture *tex) +{ + BLI_assert(tex != NULL); + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_PERSIST, tex, 0, 1); +} + +void DRW_shgroup_uniform_block(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo) +{ + BLI_assert(ubo != NULL); + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK, ubo, 0, 1); +} + +/* Same as DRW_shgroup_uniform_block but is garanteed to be bound if shader does not change between shgrp. */ +void DRW_shgroup_uniform_block_persistent(DRWShadingGroup *shgroup, const char *name, const GPUUniformBuffer *ubo) +{ + BLI_assert(ubo != NULL); + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BLOCK_PERSIST, ubo, 0, 1); +} + +void DRW_shgroup_uniform_texture_ref(DRWShadingGroup *shgroup, const char *name, GPUTexture **tex) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_TEXTURE_REF, tex, 0, 1); +} + +void DRW_shgroup_uniform_bool(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_BOOL, value, 1, arraysize); +} + +void DRW_shgroup_uniform_float(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 1, arraysize); +} + +void DRW_shgroup_uniform_vec2(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 2, arraysize); +} + +void DRW_shgroup_uniform_vec3(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 3, arraysize); +} + +void DRW_shgroup_uniform_vec4(DRWShadingGroup *shgroup, const char *name, const float *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 4, arraysize); +} + +void DRW_shgroup_uniform_short_to_int(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_INT, value, 1, arraysize); +} + +void DRW_shgroup_uniform_short_to_float(DRWShadingGroup *shgroup, const char *name, const short *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_SHORT_TO_FLOAT, value, 1, arraysize); +} + +void DRW_shgroup_uniform_int(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 1, arraysize); +} + +void DRW_shgroup_uniform_ivec2(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 2, arraysize); +} + +void DRW_shgroup_uniform_ivec3(DRWShadingGroup *shgroup, const char *name, const int *value, int arraysize) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_INT, value, 3, arraysize); +} + +void DRW_shgroup_uniform_mat3(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 9, 1); +} + +void DRW_shgroup_uniform_mat4(DRWShadingGroup *shgroup, const char *name, const float *value) +{ + drw_shgroup_uniform(shgroup, name, DRW_UNIFORM_FLOAT, value, 16, 1); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Draw Call (DRW_calls) + * \{ */ + +static void drw_call_calc_orco(Object *ob, float (*r_orcofacs)[3]) +{ + ID *ob_data = (ob) ? ob->data : NULL; + float *texcoloc = NULL; + float *texcosize = NULL; + if (ob_data != NULL) { + switch (GS(ob_data->name)) { + case ID_ME: + BKE_mesh_texspace_get_reference((Mesh *)ob_data, NULL, &texcoloc, NULL, &texcosize); + break; + case ID_CU: + { + Curve *cu = (Curve *)ob_data; + if (cu->bb == NULL || (cu->bb->flag & BOUNDBOX_DIRTY)) { + BKE_curve_texspace_calc(cu); + } + texcoloc = cu->loc; + texcosize = cu->size; + break; + } + case ID_MB: + { + MetaBall *mb = (MetaBall *)ob_data; + texcoloc = mb->loc; + texcosize = mb->size; + break; + } + default: + break; + } + } + + if ((texcoloc != NULL) && (texcosize != NULL)) { + mul_v3_v3fl(r_orcofacs[1], texcosize, 2.0f); + invert_v3(r_orcofacs[1]); + sub_v3_v3v3(r_orcofacs[0], texcoloc, texcosize); + negate_v3(r_orcofacs[0]); + mul_v3_v3(r_orcofacs[0], r_orcofacs[1]); /* result in a nice MADD in the shader */ + } + else { + copy_v3_fl(r_orcofacs[0], 0.0f); + copy_v3_fl(r_orcofacs[1], 1.0f); + } +} + +static DRWCallState *drw_call_state_create(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) +{ + DRWCallState *state = BLI_mempool_alloc(DST.vmempool->states); + state->flag = 0; + state->cache_id = 0; + state->matflag = shgroup->matflag; + + /* Matrices */ + if (obmat != NULL) { + copy_m4_m4(state->model, obmat); + + if (is_negative_m4(state->model)) { + state->flag |= DRW_CALL_NEGSCALE; + } + } + else { + unit_m4(state->model); + } + + if (ob != NULL) { + float corner[3]; + BoundBox *bbox = BKE_object_boundbox_get(ob); + /* Get BoundSphere center and radius from the BoundBox. */ + mid_v3_v3v3(state->bsphere.center, bbox->vec[0], bbox->vec[6]); + mul_v3_m4v3(corner, obmat, bbox->vec[0]); + mul_m4_v3(obmat, state->bsphere.center); + state->bsphere.radius = len_v3v3(state->bsphere.center, corner); + } + else { + /* Bypass test. */ + state->bsphere.radius = -1.0f; + } + + /* Orco factors: We compute this at creation to not have to save the *ob_data */ + if ((state->matflag & DRW_CALL_ORCOTEXFAC) != 0) { + drw_call_calc_orco(ob, state->orcotexfac); + state->matflag &= ~DRW_CALL_ORCOTEXFAC; + } + + return state; +} + +static DRWCallState *drw_call_state_object(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) +{ + if (DST.ob_state == NULL) { + DST.ob_state = drw_call_state_create(shgroup, obmat, ob); + } + else { + /* If the DRWCallState is reused, add necessary matrices. */ + DST.ob_state->matflag |= shgroup->matflag; + } + + return DST.ob_state; +} + +void DRW_shgroup_call_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4]) +{ + BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_create(shgroup, obmat, NULL); + call->type = DRW_CALL_SINGLE; + call->single.geometry = geom; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + +/* These calls can be culled and are optimized for redraw */ +void DRW_shgroup_call_object_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob) +{ + BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_object(shgroup, ob->obmat, ob); + call->type = DRW_CALL_SINGLE; + call->single.geometry = geom; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + +void DRW_shgroup_call_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, float (*obmat)[4], unsigned int *count) +{ + BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_create(shgroup, obmat, NULL); + call->type = DRW_CALL_INSTANCES; + call->instances.geometry = geom; + call->instances.count = count; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + +/* These calls can be culled and are optimized for redraw */ +void DRW_shgroup_call_object_instances_add(DRWShadingGroup *shgroup, Gwn_Batch *geom, Object *ob, unsigned int *count) +{ + BLI_assert(geom != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_object(shgroup, ob->obmat, ob); + call->type = DRW_CALL_INSTANCES; + call->instances.geometry = geom; + call->instances.count = count; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + +void DRW_shgroup_call_generate_add( + DRWShadingGroup *shgroup, + DRWCallGenerateFn *geometry_fn, void *user_data, + float (*obmat)[4]) +{ + BLI_assert(geometry_fn != NULL); + BLI_assert(shgroup->type == DRW_SHG_NORMAL); + + DRWCall *call = BLI_mempool_alloc(DST.vmempool->calls); + call->state = drw_call_state_create(shgroup, obmat, NULL); + call->type = DRW_CALL_GENERATE; + call->generate.geometry_fn = geometry_fn; + call->generate.user_data = user_data; +#ifdef USE_GPU_SELECT + call->select_id = DST.select_id; +#endif + + BLI_LINKS_APPEND(&shgroup->calls, call); +} + +static void sculpt_draw_cb( + DRWShadingGroup *shgroup, + void (*draw_fn)(DRWShadingGroup *shgroup, Gwn_Batch *geom), + void *user_data) +{ + Object *ob = user_data; + PBVH *pbvh = ob->sculpt->pbvh; + + if (pbvh) { + BKE_pbvh_draw_cb( + pbvh, NULL, NULL, false, + (void (*)(void *, Gwn_Batch *))draw_fn, shgroup); + } +} + +void DRW_shgroup_call_sculpt_add(DRWShadingGroup *shgroup, Object *ob, float (*obmat)[4]) +{ + DRW_shgroup_call_generate_add(shgroup, sculpt_draw_cb, ob, obmat); +} + +void DRW_shgroup_call_dynamic_add_array(DRWShadingGroup *shgroup, const void *attr[], unsigned int attr_len) +{ +#ifdef USE_GPU_SELECT + if (G.f & G_PICKSEL) { + if (shgroup->inst_selectid == NULL) { + shgroup->inst_selectid = DRW_instance_data_request(DST.idatalist, 1, 128); + } + + int *select_id = DRW_instance_data_next(shgroup->inst_selectid); + *select_id = DST.select_id; + } +#endif + + BLI_assert(attr_len == shgroup->attribs_count); + UNUSED_VARS_NDEBUG(attr_len); + + for (int i = 0; i < attr_len; ++i) { + if (shgroup->instance_count == shgroup->instance_vbo->vertex_ct) { + GWN_vertbuf_data_resize(shgroup->instance_vbo, shgroup->instance_count + 32); + } + GWN_vertbuf_attr_set(shgroup->instance_vbo, i, shgroup->instance_count, attr[i]); + } + + shgroup->instance_count += 1; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Shading Groups (DRW_shgroup) + * \{ */ + +static void drw_shgroup_init(DRWShadingGroup *shgroup, GPUShader *shader) +{ + shgroup->instance_geom = NULL; + shgroup->instance_vbo = NULL; + shgroup->instance_count = 0; + shgroup->uniforms = NULL; +#ifdef USE_GPU_SELECT + shgroup->inst_selectid = NULL; + shgroup->override_selectid = -1; +#endif +#ifndef NDEBUG + shgroup->attribs_count = 0; +#endif + + int view_ubo_location = GPU_shader_get_uniform_block(shader, "viewBlock"); + + if (view_ubo_location != -1) { + drw_shgroup_uniform_create_ex(shgroup, view_ubo_location, DRW_UNIFORM_BLOCK_PERSIST, view_ubo, 0, 1); + } + else { + /* Only here to support builtin shaders. This should not be used by engines. */ + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_VIEW, DST.view_data.matstate.mat[DRW_MAT_VIEW], 16, 1); + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_VIEW_INV, DST.view_data.matstate.mat[DRW_MAT_VIEWINV], 16, 1); + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_VIEWPROJECTION, DST.view_data.matstate.mat[DRW_MAT_PERS], 16, 1); + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_VIEWPROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_PERSINV], 16, 1); + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_PROJECTION, DST.view_data.matstate.mat[DRW_MAT_WIN], 16, 1); + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_PROJECTION_INV, DST.view_data.matstate.mat[DRW_MAT_WININV], 16, 1); + drw_shgroup_builtin_uniform(shgroup, GWN_UNIFORM_CAMERATEXCO, DST.view_data.viewcamtexcofac, 3, 2); + } + + shgroup->model = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL); + shgroup->modelinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODEL_INV); + shgroup->modelview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW); + shgroup->modelviewinverse = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MODELVIEW_INV); + shgroup->modelviewprojection = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_MVP); + shgroup->normalview = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_NORMAL); + shgroup->normalworld = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_WORLDNORMAL); + shgroup->orcotexfac = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_ORCO); + shgroup->eye = GPU_shader_get_builtin_uniform(shader, GWN_UNIFORM_EYE); + + shgroup->matflag = 0; + if (shgroup->modelinverse > -1) + shgroup->matflag |= DRW_CALL_MODELINVERSE; + if (shgroup->modelview > -1) + shgroup->matflag |= DRW_CALL_MODELVIEW; + if (shgroup->modelviewinverse > -1) + shgroup->matflag |= DRW_CALL_MODELVIEWINVERSE; + if (shgroup->modelviewprojection > -1) + shgroup->matflag |= DRW_CALL_MODELVIEWPROJECTION; + if (shgroup->normalview > -1) + shgroup->matflag |= DRW_CALL_NORMALVIEW; + if (shgroup->normalworld > -1) + shgroup->matflag |= DRW_CALL_NORMALWORLD; + if (shgroup->orcotexfac > -1) + shgroup->matflag |= DRW_CALL_ORCOTEXFAC; + if (shgroup->eye > -1) + shgroup->matflag |= DRW_CALL_EYEVEC; +} + +static void drw_shgroup_instance_init( + DRWShadingGroup *shgroup, GPUShader *shader, Gwn_Batch *batch, Gwn_VertFormat *format) +{ + BLI_assert(shgroup->type == DRW_SHG_INSTANCE); + BLI_assert(batch != NULL); + BLI_assert(format != NULL); + + drw_shgroup_init(shgroup, shader); + + shgroup->instance_geom = batch; +#ifndef NDEBUG + shgroup->attribs_count = format->attrib_ct; +#endif + + DRW_instancing_buffer_request(DST.idatalist, format, batch, shgroup, + &shgroup->instance_geom, &shgroup->instance_vbo); +} + +static void drw_shgroup_batching_init( + DRWShadingGroup *shgroup, GPUShader *shader, Gwn_VertFormat *format) +{ + drw_shgroup_init(shgroup, shader); + +#ifndef NDEBUG + shgroup->attribs_count = (format != NULL) ? format->attrib_ct : 0; +#endif + BLI_assert(format != NULL); + + Gwn_PrimType type; + switch (shgroup->type) { + case DRW_SHG_POINT_BATCH: type = GWN_PRIM_POINTS; break; + case DRW_SHG_LINE_BATCH: type = GWN_PRIM_LINES; break; + case DRW_SHG_TRIANGLE_BATCH: type = GWN_PRIM_TRIS; break; + default: type = GWN_PRIM_NONE; BLI_assert(0); break; + } + + DRW_batching_buffer_request(DST.idatalist, format, type, shgroup, + &shgroup->batch_geom, &shgroup->batch_vbo); +} + +static DRWShadingGroup *drw_shgroup_create_ex(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = BLI_mempool_alloc(DST.vmempool->shgroups); + + BLI_LINKS_APPEND(&pass->shgroups, shgroup); + + shgroup->type = DRW_SHG_NORMAL; + shgroup->shader = shader; + shgroup->state_extra = 0; + shgroup->state_extra_disable = ~0x0; + shgroup->stencil_mask = 0; + shgroup->calls.first = NULL; + shgroup->calls.last = NULL; +#if 0 /* All the same in the union! */ + shgroup->batch_geom = NULL; + shgroup->batch_vbo = NULL; + + shgroup->instance_geom = NULL; + shgroup->instance_vbo = NULL; +#endif + +#ifdef USE_GPU_SELECT + shgroup->pass_parent = pass; +#endif + + return shgroup; +} + +static DRWShadingGroup *drw_shgroup_material_create_ex(GPUPass *gpupass, DRWPass *pass) +{ + if (!gpupass) { + /* Shader compilation error */ + return NULL; + } + + DRWShadingGroup *grp = drw_shgroup_create_ex(GPU_pass_shader(gpupass), pass); + return grp; +} + +static DRWShadingGroup *drw_shgroup_material_inputs(DRWShadingGroup *grp, struct GPUMaterial *material) +{ + /* TODO : Ideally we should not convert. But since the whole codegen + * is relying on GPUPass we keep it as is for now. */ + + ListBase *inputs = GPU_material_get_inputs(material); + + /* Converting dynamic GPUInput to DRWUniform */ + for (GPUInput *input = inputs->first; input; input = input->next) { + /* Textures */ + if (input->ima) { + double time = 0.0; /* TODO make time variable */ + GPUTexture *tex = GPU_texture_from_blender( + input->ima, input->iuser, input->textarget, input->image_isdata, time, 1); + + if (input->bindtex) { + DRW_shgroup_uniform_texture(grp, input->shadername, tex); + } + } + /* Color Ramps */ + else if (input->tex) { + DRW_shgroup_uniform_texture(grp, input->shadername, input->tex); + } + /* Floats */ + else { + switch (input->type) { + case GPU_FLOAT: + case GPU_VEC2: + case GPU_VEC3: + case GPU_VEC4: + /* Should already be in the material ubo. */ + break; + case GPU_MAT3: + DRW_shgroup_uniform_mat3(grp, input->shadername, (float *)input->dynamicvec); + break; + case GPU_MAT4: + DRW_shgroup_uniform_mat4(grp, input->shadername, (float *)input->dynamicvec); + break; + default: + break; + } + } + } + + GPUUniformBuffer *ubo = GPU_material_get_uniform_buffer(material); + if (ubo != NULL) { + DRW_shgroup_uniform_block(grp, GPU_UBO_BLOCK_NAME, ubo); + } + + return grp; +} + +Gwn_VertFormat *DRW_shgroup_instance_format_array(const DRWInstanceAttribFormat attribs[], int arraysize) +{ + Gwn_VertFormat *format = MEM_callocN(sizeof(Gwn_VertFormat), "Gwn_VertFormat"); + + for (int i = 0; i < arraysize; ++i) { + GWN_vertformat_attr_add(format, attribs[i].name, + (attribs[i].type == DRW_ATTRIB_INT) ? GWN_COMP_I32 : GWN_COMP_F32, + attribs[i].components, + (attribs[i].type == DRW_ATTRIB_INT) ? GWN_FETCH_INT : GWN_FETCH_FLOAT); + } + return format; +} + +DRWShadingGroup *DRW_shgroup_material_create( + struct GPUMaterial *material, DRWPass *pass) +{ + GPUPass *gpupass = GPU_material_get_pass(material); + DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); + + if (shgroup) { + drw_shgroup_init(shgroup, GPU_pass_shader(gpupass)); + drw_shgroup_material_inputs(shgroup, material); + } + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_material_instance_create( + struct GPUMaterial *material, DRWPass *pass, Gwn_Batch *geom, Object *ob, Gwn_VertFormat *format) +{ + GPUPass *gpupass = GPU_material_get_pass(material); + DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); + + if (shgroup) { + shgroup->type = DRW_SHG_INSTANCE; + shgroup->instance_geom = geom; + drw_call_calc_orco(ob, shgroup->instance_orcofac); + drw_shgroup_instance_init(shgroup, GPU_pass_shader(gpupass), geom, format); + drw_shgroup_material_inputs(shgroup, material); + } + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_material_empty_tri_batch_create( + struct GPUMaterial *material, DRWPass *pass, int tri_count) +{ +#ifdef USE_GPU_SELECT + BLI_assert((G.f & G_PICKSEL) == 0); +#endif + GPUPass *gpupass = GPU_material_get_pass(material); + DRWShadingGroup *shgroup = drw_shgroup_material_create_ex(gpupass, pass); + + if (shgroup) { + /* Calling drw_shgroup_init will cause it to call GWN_draw_primitive(). */ + drw_shgroup_init(shgroup, GPU_pass_shader(gpupass)); + shgroup->type = DRW_SHG_TRIANGLE_BATCH; + shgroup->instance_count = tri_count * 3; + drw_shgroup_material_inputs(shgroup, material); + } + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_create(struct GPUShader *shader, DRWPass *pass) +{ + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + drw_shgroup_init(shgroup, shader); + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_instance_create( + struct GPUShader *shader, DRWPass *pass, Gwn_Batch *geom, Gwn_VertFormat *format) +{ + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + shgroup->type = DRW_SHG_INSTANCE; + shgroup->instance_geom = geom; + drw_call_calc_orco(NULL, shgroup->instance_orcofac); + drw_shgroup_instance_init(shgroup, shader, geom, format); + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_point_batch_create(struct GPUShader *shader, DRWPass *pass) +{ + DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}}); + + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + shgroup->type = DRW_SHG_POINT_BATCH; + + drw_shgroup_batching_init(shgroup, shader, g_pos_format); + + return shgroup; +} + +DRWShadingGroup *DRW_shgroup_line_batch_create(struct GPUShader *shader, DRWPass *pass) +{ + DRW_shgroup_instance_format(g_pos_format, {{"pos", DRW_ATTRIB_FLOAT, 3}}); + + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + shgroup->type = DRW_SHG_LINE_BATCH; + + drw_shgroup_batching_init(shgroup, shader, g_pos_format); + + return shgroup; +} + +/* Very special batch. Use this if you position + * your vertices with the vertex shader + * and dont need any VBO attrib */ +DRWShadingGroup *DRW_shgroup_empty_tri_batch_create(struct GPUShader *shader, DRWPass *pass, int tri_count) +{ +#ifdef USE_GPU_SELECT + BLI_assert((G.f & G_PICKSEL) == 0); +#endif + DRWShadingGroup *shgroup = drw_shgroup_create_ex(shader, pass); + + /* Calling drw_shgroup_init will cause it to call GWN_draw_primitive(). */ + drw_shgroup_init(shgroup, shader); + + shgroup->type = DRW_SHG_TRIANGLE_BATCH; + shgroup->instance_count = tri_count * 3; + + return shgroup; +} + +/* Specify an external batch instead of adding each attrib one by one. */ +void DRW_shgroup_instance_batch(DRWShadingGroup *shgroup, struct Gwn_Batch *batch) +{ + BLI_assert(shgroup->type == DRW_SHG_INSTANCE); + BLI_assert(shgroup->instance_count == 0); + /* You cannot use external instancing batch without a dummy format. */ + BLI_assert(shgroup->attribs_count != 0); + + shgroup->type = DRW_SHG_INSTANCE_EXTERNAL; + drw_call_calc_orco(NULL, shgroup->instance_orcofac); + /* PERF : This destroys the vaos cache so better check if it's necessary. */ + /* Note: This WILL break if batch->verts[0] is destroyed and reallocated + * at the same adress. Bindings/VAOs would remain obsolete. */ + //if (shgroup->instancing_geom->inst != batch->verts[0]) + GWN_batch_instbuf_set(shgroup->instance_geom, batch->verts[0], false); + +#ifdef USE_GPU_SELECT + shgroup->override_selectid = DST.select_id; +#endif +} + +unsigned int DRW_shgroup_get_instance_count(const DRWShadingGroup *shgroup) +{ + return shgroup->instance_count; +} + +/** + * State is added to #Pass.state while drawing. + * Use to temporarily enable draw options. + */ +void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state) +{ + shgroup->state_extra |= state; +} + +void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) +{ + shgroup->state_extra_disable &= ~state; +} + +void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, unsigned int mask) +{ + BLI_assert(mask <= 255); + shgroup->stencil_mask = mask; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Passes (DRW_pass) + * \{ */ + +DRWPass *DRW_pass_create(const char *name, DRWState state) +{ + DRWPass *pass = BLI_mempool_alloc(DST.vmempool->passes); + pass->state = state; + if (G.debug_value > 20) { + BLI_strncpy(pass->name, name, MAX_PASS_NAME); + } + + pass->shgroups.first = NULL; + pass->shgroups.last = NULL; + + return pass; +} + +void DRW_pass_state_set(DRWPass *pass, DRWState state) +{ + pass->state = state; +} + +void DRW_pass_free(DRWPass *pass) +{ + pass->shgroups.first = NULL; + pass->shgroups.last = NULL; +} + +void DRW_pass_foreach_shgroup(DRWPass *pass, void (*callback)(void *userData, DRWShadingGroup *shgrp), void *userData) +{ + for (DRWShadingGroup *shgroup = pass->shgroups.first; shgroup; shgroup = shgroup->next) { + callback(userData, shgroup); + } +} + +typedef struct ZSortData { + float *axis; + float *origin; +} ZSortData; + +static int pass_shgroup_dist_sort(void *thunk, const void *a, const void *b) +{ + const ZSortData *zsortdata = (ZSortData *)thunk; + const DRWShadingGroup *shgrp_a = (const DRWShadingGroup *)a; + const DRWShadingGroup *shgrp_b = (const DRWShadingGroup *)b; + + const DRWCall *call_a = (DRWCall *)shgrp_a->calls.first; + const DRWCall *call_b = (DRWCall *)shgrp_b->calls.first; + + if (call_a == NULL) return -1; + if (call_b == NULL) return -1; + + float tmp[3]; + sub_v3_v3v3(tmp, zsortdata->origin, call_a->state->model[3]); + const float a_sq = dot_v3v3(zsortdata->axis, tmp); + sub_v3_v3v3(tmp, zsortdata->origin, call_b->state->model[3]); + const float b_sq = dot_v3v3(zsortdata->axis, tmp); + + if (a_sq < b_sq) return 1; + else if (a_sq > b_sq) return -1; + else { + /* If there is a depth prepass put it before */ + if ((shgrp_a->state_extra & DRW_STATE_WRITE_DEPTH) != 0) { + return -1; + } + else if ((shgrp_b->state_extra & DRW_STATE_WRITE_DEPTH) != 0) { + return 1; + } + else return 0; + } +} + +/* ------------------ Shading group sorting --------------------- */ + +#define SORT_IMPL_LINKTYPE DRWShadingGroup + +#define SORT_IMPL_USE_THUNK +#define SORT_IMPL_FUNC shgroup_sort_fn_r +#include "../../blenlib/intern/list_sort_impl.h" +#undef SORT_IMPL_FUNC +#undef SORT_IMPL_USE_THUNK + +#undef SORT_IMPL_LINKTYPE + +/** + * Sort Shading groups by decreasing Z of their first draw call. + * This is usefull for order dependant effect such as transparency. + **/ +void DRW_pass_sort_shgroup_z(DRWPass *pass) +{ + float (*viewinv)[4]; + viewinv = DST.view_data.matstate.mat[DRW_MAT_VIEWINV]; + + ZSortData zsortdata = {viewinv[2], viewinv[3]}; + + if (pass->shgroups.first && pass->shgroups.first->next) { + pass->shgroups.first = shgroup_sort_fn_r(pass->shgroups.first, pass_shgroup_dist_sort, &zsortdata); + + /* Find the next last */ + DRWShadingGroup *last = pass->shgroups.first; + while ((last = last->next)) { + /* Do nothing */ + } + pass->shgroups.last = last; + } +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c new file mode 100644 index 00000000000..e69a1026815 --- /dev/null +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -0,0 +1,1170 @@ +/* + * 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_exec.c + * \ingroup draw + */ + +#include "draw_manager.h" + +#include "BLI_mempool.h" + +#include "BIF_glutil.h" + +#include "BKE_global.h" +#include "BKE_object.h" + +#include "GPU_draw.h" +#include "GPU_extensions.h" + +#ifdef USE_GPU_SELECT +# include "ED_view3d.h" +# include "ED_armature.h" +# include "GPU_select.h" +#endif + +#ifdef USE_GPU_SELECT +void DRW_select_load_id(unsigned int id) +{ + BLI_assert(G.f & G_PICKSEL); + DST.select_id = id; +} +#endif + +struct GPUUniformBuffer *view_ubo; + +/* -------------------------------------------------------------------- */ + +/** \name Draw State (DRW_state) + * \{ */ + +void drw_state_set(DRWState state) +{ + if (DST.state == state) { + return; + } + +#define CHANGED_TO(f) \ + ((DST.state_lock & (f)) ? 0 : \ + (((DST.state & (f)) ? \ + ((state & (f)) ? 0 : -1) : \ + ((state & (f)) ? 1 : 0)))) + +#define CHANGED_ANY(f) \ + (((DST.state & (f)) != (state & (f))) && \ + ((DST.state_lock & (f)) == 0)) + +#define CHANGED_ANY_STORE_VAR(f, enabled) \ + (((DST.state & (f)) != (enabled = (state & (f)))) && \ + (((DST.state_lock & (f)) == 0))) + + /* Depth Write */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_WRITE_DEPTH))) { + if (test == 1) { + glDepthMask(GL_TRUE); + } + else { + glDepthMask(GL_FALSE); + } + } + } + + /* Color Write */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_WRITE_COLOR))) { + if (test == 1) { + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); + } + else { + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } + } + } + + /* Cull */ + { + DRWState test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_CULL_BACK | DRW_STATE_CULL_FRONT, + test)) + { + if (test) { + glEnable(GL_CULL_FACE); + + if ((state & DRW_STATE_CULL_BACK) != 0) { + glCullFace(GL_BACK); + } + else if ((state & DRW_STATE_CULL_FRONT) != 0) { + glCullFace(GL_FRONT); + } + else { + BLI_assert(0); + } + } + else { + glDisable(GL_CULL_FACE); + } + } + } + + /* Depth Test */ + { + DRWState test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_DEPTH_LESS | DRW_STATE_DEPTH_EQUAL | DRW_STATE_DEPTH_GREATER | DRW_STATE_DEPTH_ALWAYS, + test)) + { + if (test) { + glEnable(GL_DEPTH_TEST); + + if (state & DRW_STATE_DEPTH_LESS) { + glDepthFunc(GL_LEQUAL); + } + else if (state & DRW_STATE_DEPTH_EQUAL) { + glDepthFunc(GL_EQUAL); + } + else if (state & DRW_STATE_DEPTH_GREATER) { + glDepthFunc(GL_GREATER); + } + else if (state & DRW_STATE_DEPTH_ALWAYS) { + glDepthFunc(GL_ALWAYS); + } + else { + BLI_assert(0); + } + } + else { + glDisable(GL_DEPTH_TEST); + } + } + } + + /* Wire Width */ + { + if (CHANGED_ANY(DRW_STATE_WIRE)) { + if ((state & DRW_STATE_WIRE) != 0) { + glLineWidth(1.0f); + } + else { + /* do nothing */ + } + } + } + + /* Points Size */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_POINT))) { + if (test == 1) { + GPU_enable_program_point_size(); + glPointSize(5.0f); + } + else { + GPU_disable_program_point_size(); + } + } + } + + /* Blending (all buffer) */ + { + int test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_BLEND | DRW_STATE_ADDITIVE | DRW_STATE_MULTIPLY | DRW_STATE_TRANSMISSION | + DRW_STATE_ADDITIVE_FULL, + test)) + { + if (test) { + glEnable(GL_BLEND); + + if ((state & DRW_STATE_BLEND) != 0) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, /* RGB */ + GL_ONE, GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ + } + else if ((state & DRW_STATE_MULTIPLY) != 0) { + glBlendFunc(GL_DST_COLOR, GL_ZERO); + } + else if ((state & DRW_STATE_TRANSMISSION) != 0) { + glBlendFunc(GL_ONE, GL_SRC_ALPHA); + } + else if ((state & DRW_STATE_ADDITIVE) != 0) { + /* Do not let alpha accumulate but premult the source RGB by it. */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, /* RGB */ + GL_ZERO, GL_ONE); /* Alpha */ + } + else if ((state & DRW_STATE_ADDITIVE_FULL) != 0) { + /* Let alpha accumulate. */ + glBlendFunc(GL_ONE, GL_ONE); + } + else { + BLI_assert(0); + } + } + else { + glDisable(GL_BLEND); + } + } + } + + /* Clip Planes */ + { + int test; + if ((test = CHANGED_TO(DRW_STATE_CLIP_PLANES))) { + if (test == 1) { + for (int i = 0; i < DST.num_clip_planes; ++i) { + glEnable(GL_CLIP_DISTANCE0 + i); + } + } + else { + for (int i = 0; i < MAX_CLIP_PLANES; ++i) { + glDisable(GL_CLIP_DISTANCE0 + i); + } + } + } + } + + /* Line Stipple */ + { + int test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_STIPPLE_2 | DRW_STATE_STIPPLE_3 | DRW_STATE_STIPPLE_4, + test)) + { + if (test) { + if ((state & DRW_STATE_STIPPLE_2) != 0) { + setlinestyle(2); + } + else if ((state & DRW_STATE_STIPPLE_3) != 0) { + setlinestyle(3); + } + else if ((state & DRW_STATE_STIPPLE_4) != 0) { + setlinestyle(4); + } + else { + BLI_assert(0); + } + } + else { + setlinestyle(0); + } + } + } + + /* Stencil */ + { + DRWState test; + if (CHANGED_ANY_STORE_VAR( + DRW_STATE_WRITE_STENCIL | + DRW_STATE_STENCIL_EQUAL, + test)) + { + if (test) { + glEnable(GL_STENCIL_TEST); + + /* Stencil Write */ + if ((state & DRW_STATE_WRITE_STENCIL) != 0) { + glStencilMask(0xFF); + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + } + /* Stencil Test */ + else if ((state & DRW_STATE_STENCIL_EQUAL) != 0) { + glStencilMask(0x00); /* disable write */ + DST.stencil_mask = 0; + } + else { + BLI_assert(0); + } + } + else { + /* disable write & test */ + DST.stencil_mask = 0; + glStencilMask(0x00); + glStencilFunc(GL_ALWAYS, 1, 0xFF); + glDisable(GL_STENCIL_TEST); + } + } + } + +#undef CHANGED_TO +#undef CHANGED_ANY +#undef CHANGED_ANY_STORE_VAR + + DST.state = state; +} + +static void drw_stencil_set(unsigned int mask) +{ + if (DST.stencil_mask != mask) { + /* Stencil Write */ + if ((DST.state & DRW_STATE_WRITE_STENCIL) != 0) { + glStencilFunc(GL_ALWAYS, mask, 0xFF); + DST.stencil_mask = mask; + } + /* Stencil Test */ + else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) { + glStencilFunc(GL_EQUAL, mask, 0xFF); + DST.stencil_mask = mask; + } + } +} + +/* Reset state to not interfer with other UI drawcall */ +void DRW_state_reset_ex(DRWState state) +{ + DST.state = ~state; + drw_state_set(state); +} + +/** + * Use with care, intended so selection code can override passes depth settings, + * which is important for selection to work properly. + * + * Should be set in main draw loop, cleared afterwards + */ +void DRW_state_lock(DRWState state) +{ + DST.state_lock = state; +} + +void DRW_state_reset(void) +{ + /* Reset blending function */ + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + + DRW_state_reset_ex(DRW_STATE_DEFAULT); +} + +/* NOTE : Make sure to reset after use! */ +void DRW_state_invert_facing(void) +{ + SWAP(GLenum, DST.backface, DST.frontface); + glFrontFace(DST.frontface); +} + +/** + * This only works if DRWPasses have been tagged with DRW_STATE_CLIP_PLANES, + * and if the shaders have support for it (see usage of gl_ClipDistance). + * Be sure to call DRW_state_clip_planes_reset() after you finish drawing. + **/ +void DRW_state_clip_planes_count_set(unsigned int plane_ct) +{ + BLI_assert(plane_ct <= MAX_CLIP_PLANES); + DST.num_clip_planes = plane_ct; +} + +void DRW_state_clip_planes_reset(void) +{ + DST.num_clip_planes = 0; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Clipping (DRW_clipping) + * \{ */ + +/* Extract the 8 corners (world space). + * Although less accurate, this solution can be simplified as follows: + * + * BKE_boundbox_init_from_minmax(&bbox, (const float[3]){-1.0f, -1.0f, -1.0f}, (const float[3]){1.0f, 1.0f, 1.0f}); + * for (int i = 0; i < 8; i++) {mul_project_m4_v3(viewprojinv, bbox.vec[i]);} + */ +static void draw_frustum_boundbox_calc(const float (*projmat)[4], const float (*viewinv)[4], BoundBox *r_bbox) +{ + float screenvecs[3][3], loc[3], near, far, w_half, h_half; + bool is_persp = projmat[3][3] == 0.0f; + copy_m3_m4(screenvecs, viewinv); + copy_v3_v3(loc, viewinv[3]); + + /* get the values of the minimum and maximum clipping planes distances + * and half the width and height of the nearplane rectangle. */ + if (is_persp) { + near = projmat[3][2] / (projmat[2][2] - 1.0f); + far = projmat[3][2] / (projmat[2][2] + 1.0f); + w_half = near / projmat[0][0]; + h_half = near / projmat[1][1]; + } + else { + near = (projmat[3][2] + 1.0f) / projmat[2][2]; + far = (projmat[3][2] - 1.0f) / projmat[2][2]; + w_half = 1.0f / projmat[0][0]; + h_half = 1.0f / projmat[1][1]; + } + + /* With vectors aligned to the screen, reconstruct + * the near plane from the dimensions obtained earlier. */ + float mid[3], hor[3], ver[3]; + mul_v3_v3fl(hor, screenvecs[0], w_half); + mul_v3_v3fl(ver, screenvecs[1], h_half); + madd_v3_v3v3fl(mid, loc, screenvecs[2], -near); + + /* The case below is for non-symmetric frustum. */ + if (is_persp) { + madd_v3_v3fl(mid, hor, projmat[2][0]); + madd_v3_v3fl(mid, ver, projmat[2][1]); + } + else { + madd_v3_v3fl(mid, hor, projmat[3][0]); + madd_v3_v3fl(mid, ver, projmat[3][1]); + } + + r_bbox->vec[0][0] = mid[0] - ver[0] - hor[0]; + r_bbox->vec[0][1] = mid[1] - ver[1] - hor[1]; + r_bbox->vec[0][2] = mid[2] - ver[2] - hor[2]; + + r_bbox->vec[3][0] = mid[0] + ver[0] - hor[0]; + r_bbox->vec[3][1] = mid[1] + ver[1] - hor[1]; + r_bbox->vec[3][2] = mid[2] + ver[2] - hor[2]; + + r_bbox->vec[7][0] = mid[0] + ver[0] + hor[0]; + r_bbox->vec[7][1] = mid[1] + ver[1] + hor[1]; + r_bbox->vec[7][2] = mid[2] + ver[2] + hor[2]; + + r_bbox->vec[4][0] = mid[0] - ver[0] + hor[0]; + r_bbox->vec[4][1] = mid[1] - ver[1] + hor[1]; + r_bbox->vec[4][2] = mid[2] - ver[2] + hor[2]; + + /* Get the coordinates of the far plane. */ + if (is_persp) { + float sca_far = far / near; + mid[0] = mid[0] + (mid[0] - loc[0]) * sca_far; + mid[1] = mid[1] + (mid[1] - loc[1]) * sca_far; + mid[2] = mid[2] + (mid[2] - loc[2]) * sca_far; + + mul_v3_fl(hor, sca_far); + mul_v3_fl(ver, sca_far); + } + else { + madd_v3_v3v3fl(mid, loc, screenvecs[2], -far); + + /* Non-symmetric frustum. */ + madd_v3_v3fl(mid, hor, projmat[3][0]); + madd_v3_v3fl(mid, ver, projmat[3][1]); + } + + r_bbox->vec[1][0] = mid[0] - ver[0] - hor[0]; + r_bbox->vec[1][1] = mid[1] - ver[1] - hor[1]; + r_bbox->vec[1][2] = mid[2] - ver[2] - hor[2]; + + r_bbox->vec[2][0] = mid[0] + ver[0] - hor[0]; + r_bbox->vec[2][1] = mid[1] + ver[1] - hor[1]; + r_bbox->vec[2][2] = mid[2] + ver[2] - hor[2]; + + r_bbox->vec[6][0] = mid[0] + ver[0] + hor[0]; + r_bbox->vec[6][1] = mid[1] + ver[1] + hor[1]; + r_bbox->vec[6][2] = mid[2] + ver[2] + hor[2]; + + r_bbox->vec[5][0] = mid[0] - ver[0] + hor[0]; + r_bbox->vec[5][1] = mid[1] - ver[1] + hor[1]; + r_bbox->vec[5][2] = mid[2] - ver[2] + hor[2]; +} + +static void draw_clipping_setup_from_view(void) +{ + if (DST.clipping.updated) + return; + + float (*viewinv)[4] = DST.view_data.matstate.mat[DRW_MAT_VIEWINV]; + float (*projmat)[4] = DST.view_data.matstate.mat[DRW_MAT_WIN]; + float (*projinv)[4] = DST.view_data.matstate.mat[DRW_MAT_WININV]; + BoundSphere *bsphere = &DST.clipping.frustum_bsphere; + + /* Extract Clipping Planes */ + BoundBox bbox; + draw_frustum_boundbox_calc(projmat, viewinv, &bbox); + + /* Compute clip planes using the world space frustum corners. */ + for (int p = 0; p < 6; p++) { + int q, r; + switch (p) { + case 0: q=1; r=2; break; + case 1: q=0; r=5; break; + case 2: q=1; r=5; break; + case 3: q=2; r=6; break; + case 4: q=0; r=3; break; + default: q=4; r=7; break; + } + if (DST.frontface == GL_CW) { + SWAP(int, q, r); + } + + normal_tri_v3(DST.clipping.frustum_planes[p], bbox.vec[p], bbox.vec[q], bbox.vec[r]); + DST.clipping.frustum_planes[p][3] = -dot_v3v3(DST.clipping.frustum_planes[p], bbox.vec[p]); + } + + /* Extract Bounding Sphere */ + if (projmat[3][3] != 0.0f) { + /* Orthographic */ + /* The most extreme points on the near and far plane. (normalized device coords). */ + float *nearpoint = bbox.vec[0]; + float *farpoint = bbox.vec[6]; + + mul_project_m4_v3(projinv, nearpoint); + mul_project_m4_v3(projinv, farpoint); + + /* just use median point */ + mid_v3_v3v3(bsphere->center, farpoint, nearpoint); + bsphere->radius = len_v3v3(bsphere->center, farpoint); + } + else if (projmat[2][0] == 0.0f && projmat[2][1] == 0.0f) { + /* Perspective with symmetrical frustum. */ + + /* We obtain the center and radius of the circumscribed circle of the + * isosceles trapezoid composed by the diagonals of the near and far clipping plane */ + + /* center of each clipping plane */ + float mid_min[3], mid_max[3]; + mid_v3_v3v3(mid_min, bbox.vec[3], bbox.vec[4]); + mid_v3_v3v3(mid_max, bbox.vec[2], bbox.vec[5]); + + /* square length of the diagonals of each clipping plane */ + float a_sq = len_squared_v3v3(bbox.vec[3], bbox.vec[4]); + float b_sq = len_squared_v3v3(bbox.vec[2], bbox.vec[5]); + + /* distance squared between clipping planes */ + float h_sq = len_squared_v3v3(mid_min, mid_max); + + float fac = (4 * h_sq + b_sq - a_sq) / (8 * h_sq); + BLI_assert(fac >= 0.0f); + + /* The goal is to get the smallest sphere, + * not the sphere that passes through each corner */ + CLAMP(fac, 0.0f, 1.0f); + + interp_v3_v3v3(bsphere->center, mid_min, mid_max, fac); + + /* distance from the center to one of the points of the far plane (1, 2, 5, 6) */ + bsphere->radius = len_v3v3(bsphere->center, bbox.vec[1]); + } + else { + /* Perspective with asymmetrical frustum. */ + + /* We put the sphere center on the line that goes from origin + * to the center of the far clipping plane. */ + + /* Detect which of the corner of the far clipping plane is the farthest to the origin */ + float nfar[4]; /* most extreme far point in NDC space */ + float farxy[2]; /* farpoint projection onto the near plane */ + float farpoint[3] = {0.0f}; /* most extreme far point in camera coordinate */ + float nearpoint[3]; /* most extreme near point in camera coordinate */ + float farcenter[3] = {0.0f}; /* center of far cliping plane in camera coordinate */ + float F = -1.0f, N; /* square distance of far and near point to origin */ + float f, n; /* distance of far and near point to z axis. f is always > 0 but n can be < 0 */ + float e, s; /* far and near clipping distance (<0) */ + float c; /* slope of center line = distance of far clipping center to z axis / far clipping distance */ + float z; /* projection of sphere center on z axis (<0) */ + + /* Find farthest corner and center of far clip plane. */ + float corner[3] = {1.0f, 1.0f, 1.0f}; /* in clip space */ + for (int i = 0; i < 4; i++) { + float point[3]; + mul_v3_project_m4_v3(point, projinv, corner); + float len = len_squared_v3(point); + if (len > F) { + copy_v3_v3(nfar, corner); + copy_v3_v3(farpoint, point); + F = len; + } + add_v3_v3(farcenter, point); + /* rotate by 90 degree to walk through the 4 points of the far clip plane */ + float tmp = corner[0]; + corner[0] = -corner[1]; + corner[1] = tmp; + } + + /* the far center is the average of the far clipping points */ + mul_v3_fl(farcenter, 0.25f); + /* the extreme near point is the opposite point on the near clipping plane */ + copy_v3_fl3(nfar, -nfar[0], -nfar[1], -1.0f); + mul_v3_project_m4_v3(nearpoint, projinv, nfar); + /* this is a frustum projection */ + N = len_squared_v3(nearpoint); + e = farpoint[2]; + s = nearpoint[2]; + /* distance to view Z axis */ + f = len_v2(farpoint); + /* get corresponding point on the near plane */ + mul_v2_v2fl(farxy, farpoint, s/e); + /* this formula preserve the sign of n */ + sub_v2_v2(nearpoint, farxy); + n = f * s / e - len_v2(nearpoint); + c = len_v2(farcenter) / e; + /* the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case */ + z = (F-N) / (2.0f * (e-s + c*(f-n))); + + bsphere->center[0] = farcenter[0] * z/e; + bsphere->center[1] = farcenter[1] * z/e; + bsphere->center[2] = z; + bsphere->radius = len_v3v3(bsphere->center, farpoint); + + /* Transform to world space. */ + mul_m4_v3(viewinv, bsphere->center); + } + + DST.clipping.updated = true; +} + +/* Return True if the given BoundSphere intersect the current view frustum */ +bool DRW_culling_sphere_test(BoundSphere *bsphere) +{ + draw_clipping_setup_from_view(); + + /* Bypass test if radius is negative. */ + if (bsphere->radius < 0.0f) + return true; + + /* Do a rough test first: Sphere VS Sphere intersect. */ + BoundSphere *frustum_bsphere = &DST.clipping.frustum_bsphere; + float center_dist = len_squared_v3v3(bsphere->center, frustum_bsphere->center); + if (center_dist > SQUARE(bsphere->radius + frustum_bsphere->radius)) + return false; + + /* Test against the 6 frustum planes. */ + for (int p = 0; p < 6; p++) { + float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bsphere->center); + if (dist < -bsphere->radius) { + return false; + } + } + + return true; +} + +/* Return True if the given BoundBox intersect the current view frustum. + * bbox must be in world space. */ +bool DRW_culling_box_test(BoundBox *bbox) +{ + draw_clipping_setup_from_view(); + + /* 6 view frustum planes */ + for (int p = 0; p < 6; p++) { + /* 8 box vertices. */ + for (int v = 0; v < 8 ; v++) { + float dist = plane_point_side_v3(DST.clipping.frustum_planes[p], bbox->vec[v]); + if (dist > 0.0f) { + /* At least one point in front of this plane. + * Go to next plane. */ + break; + } + else if (v == 7) { + /* 8 points behind this plane. */ + return false; + } + } + } + + return true; +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Draw (DRW_draw) + * \{ */ + +static void draw_matrices_model_prepare(DRWCallState *st) +{ + if (st->cache_id == DST.state_cache_id) { + return; /* Values are already updated for this view. */ + } + else { + st->cache_id = DST.state_cache_id; + } + + if (DRW_culling_sphere_test(&st->bsphere)) { + st->flag &= ~DRW_CALL_CULLED; + } + else { + st->flag |= DRW_CALL_CULLED; + return; /* No need to go further the call will not be used. */ + } + + /* Order matters */ + if (st->matflag & (DRW_CALL_MODELVIEW | DRW_CALL_MODELVIEWINVERSE | + DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC)) + { + mul_m4_m4m4(st->modelview, DST.view_data.matstate.mat[DRW_MAT_VIEW], st->model); + } + if (st->matflag & DRW_CALL_MODELVIEWINVERSE) { + invert_m4_m4(st->modelviewinverse, st->modelview); + } + if (st->matflag & DRW_CALL_MODELVIEWPROJECTION) { + mul_m4_m4m4(st->modelviewprojection, DST.view_data.matstate.mat[DRW_MAT_PERS], st->model); + } + if (st->matflag & (DRW_CALL_NORMALVIEW | DRW_CALL_EYEVEC)) { + copy_m3_m4(st->normalview, st->modelview); + invert_m3(st->normalview); + transpose_m3(st->normalview); + } + if (st->matflag & DRW_CALL_EYEVEC) { + /* Used by orthographic wires */ + float tmp[3][3]; + copy_v3_fl3(st->eyevec, 0.0f, 0.0f, 1.0f); + invert_m3_m3(tmp, st->normalview); + /* set eye vector, transformed to object coords */ + mul_m3_v3(tmp, st->eyevec); + } + /* Non view dependant */ + if (st->matflag & DRW_CALL_MODELINVERSE) { + invert_m4_m4(st->modelinverse, st->model); + st->matflag &= ~DRW_CALL_MODELINVERSE; + } + if (st->matflag & DRW_CALL_NORMALWORLD) { + copy_m3_m4(st->normalworld, st->model); + invert_m3(st->normalworld); + transpose_m3(st->normalworld); + st->matflag &= ~DRW_CALL_NORMALWORLD; + } +} + +static void draw_geometry_prepare(DRWShadingGroup *shgroup, DRWCallState *state) +{ + /* step 1 : bind object dependent matrices */ + if (state != NULL) { + GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)state->model); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)state->modelinverse); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelview, 16, 1, (float *)state->modelview); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)state->modelviewinverse); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)state->modelviewprojection); + GPU_shader_uniform_vector(shgroup->shader, shgroup->normalview, 9, 1, (float *)state->normalview); + GPU_shader_uniform_vector(shgroup->shader, shgroup->normalworld, 9, 1, (float *)state->normalworld); + GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)state->orcotexfac); + GPU_shader_uniform_vector(shgroup->shader, shgroup->eye, 3, 1, (float *)state->eyevec); + } + else { + BLI_assert((shgroup->normalview == -1) && (shgroup->normalworld == -1) && (shgroup->eye == -1)); + /* For instancing and batching. */ + float unitmat[4][4]; + unit_m4(unitmat); + GPU_shader_uniform_vector(shgroup->shader, shgroup->model, 16, 1, (float *)unitmat); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelinverse, 16, 1, (float *)unitmat); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelview, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_VIEW]); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewinverse, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_VIEWINV]); + GPU_shader_uniform_vector(shgroup->shader, shgroup->modelviewprojection, 16, 1, (float *)DST.view_data.matstate.mat[DRW_MAT_PERS]); + GPU_shader_uniform_vector(shgroup->shader, shgroup->orcotexfac, 3, 2, (float *)shgroup->instance_orcofac); + } +} + +static void draw_geometry_execute_ex( + DRWShadingGroup *shgroup, Gwn_Batch *geom, unsigned int start, unsigned int count, bool draw_instance) +{ + /* Special case: empty drawcall, placement is done via shader, don't bind anything. */ + if (geom == NULL) { + BLI_assert(shgroup->type == DRW_SHG_TRIANGLE_BATCH); /* Add other type if needed. */ + /* Shader is already bound. */ + GWN_draw_primitive(GWN_PRIM_TRIS, count); + return; + } + + /* step 2 : bind vertex array & draw */ + GWN_batch_program_set_no_use(geom, GPU_shader_get_program(shgroup->shader), GPU_shader_get_interface(shgroup->shader)); + /* XXX hacking gawain. we don't want to call glUseProgram! (huge performance loss) */ + geom->program_in_use = true; + + GWN_batch_draw_range_ex(geom, start, count, draw_instance); + + geom->program_in_use = false; /* XXX hacking gawain */ +} + +static void draw_geometry_execute(DRWShadingGroup *shgroup, Gwn_Batch *geom) +{ + draw_geometry_execute_ex(shgroup, geom, 0, 0, false); +} + +enum { + BIND_NONE = 0, + BIND_TEMP = 1, /* Release slot after this shading group. */ + BIND_PERSIST = 2, /* Release slot only after the next shader change. */ +}; + +static void bind_texture(GPUTexture *tex, char bind_type) +{ + int index; + char *slot_flags = DST.RST.bound_tex_slots; + int bind_num = GPU_texture_bound_number(tex); + if (bind_num == -1) { + for (int i = 0; i < GPU_max_textures(); ++i) { + index = DST.RST.bind_tex_inc = (DST.RST.bind_tex_inc + 1) % GPU_max_textures(); + if (slot_flags[index] == BIND_NONE) { + if (DST.RST.bound_texs[index] != NULL) { + GPU_texture_unbind(DST.RST.bound_texs[index]); + } + GPU_texture_bind(tex, index); + DST.RST.bound_texs[index] = tex; + slot_flags[index] = bind_type; + // printf("Binds Texture %d %p\n", DST.RST.bind_tex_inc, tex); + return; + } + } + printf("Not enough texture slots! Reduce number of textures used by your shader.\n"); + } + slot_flags[bind_num] = bind_type; +} + +static void bind_ubo(GPUUniformBuffer *ubo, char bind_type) +{ + int index; + char *slot_flags = DST.RST.bound_ubo_slots; + int bind_num = GPU_uniformbuffer_bindpoint(ubo); + if (bind_num == -1) { + for (int i = 0; i < GPU_max_ubo_binds(); ++i) { + index = DST.RST.bind_ubo_inc = (DST.RST.bind_ubo_inc + 1) % GPU_max_ubo_binds(); + if (slot_flags[index] == BIND_NONE) { + if (DST.RST.bound_ubos[index] != NULL) { + GPU_uniformbuffer_unbind(DST.RST.bound_ubos[index]); + } + GPU_uniformbuffer_bind(ubo, index); + DST.RST.bound_ubos[index] = ubo; + slot_flags[index] = bind_type; + return; + } + } + /* printf so user can report bad behaviour */ + printf("Not enough ubo slots! This should not happen!\n"); + /* This is not depending on user input. + * It is our responsability to make sure there is enough slots. */ + BLI_assert(0); + } + slot_flags[bind_num] = bind_type; +} + +static void release_texture_slots(bool with_persist) +{ + if (with_persist) { + memset(DST.RST.bound_tex_slots, 0x0, sizeof(*DST.RST.bound_tex_slots) * GPU_max_textures()); + } + else { + for (int i = 0; i < GPU_max_textures(); ++i) { + if (DST.RST.bound_tex_slots[i] != BIND_PERSIST) + DST.RST.bound_tex_slots[i] = BIND_NONE; + } + } + + /* Reset so that slots are consistenly assigned for different shader + * draw calls, to avoid shader specialization/patching by the driver. */ + DST.RST.bind_tex_inc = 0; +} + +static void release_ubo_slots(bool with_persist) +{ + if (with_persist) { + memset(DST.RST.bound_ubo_slots, 0x0, sizeof(*DST.RST.bound_ubo_slots) * GPU_max_ubo_binds()); + } + else { + for (int i = 0; i < GPU_max_ubo_binds(); ++i) { + if (DST.RST.bound_ubo_slots[i] != BIND_PERSIST) + DST.RST.bound_ubo_slots[i] = BIND_NONE; + } + } + + /* Reset so that slots are consistenly assigned for different shader + * draw calls, to avoid shader specialization/patching by the driver. */ + DST.RST.bind_ubo_inc = 0; +} + +static void draw_shgroup(DRWShadingGroup *shgroup, DRWState pass_state) +{ + BLI_assert(shgroup->shader); + + GPUTexture *tex; + GPUUniformBuffer *ubo; + int val; + float fval; + const bool shader_changed = (DST.shader != shgroup->shader); + + if (shader_changed) { + if (DST.shader) GPU_shader_unbind(); + GPU_shader_bind(shgroup->shader); + DST.shader = shgroup->shader; + } + + release_ubo_slots(shader_changed); + release_texture_slots(shader_changed); + + drw_state_set((pass_state & shgroup->state_extra_disable) | shgroup->state_extra); + drw_stencil_set(shgroup->stencil_mask); + + /* Binding Uniform */ + /* Don't check anything, Interface should already contain the least uniform as possible */ + for (DRWUniform *uni = shgroup->uniforms; uni; uni = uni->next) { + switch (uni->type) { + case DRW_UNIFORM_SHORT_TO_INT: + val = (int)*((short *)uni->value); + GPU_shader_uniform_vector_int( + shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)&val); + break; + case DRW_UNIFORM_SHORT_TO_FLOAT: + fval = (float)*((short *)uni->value); + GPU_shader_uniform_vector( + shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)&fval); + break; + case DRW_UNIFORM_BOOL: + case DRW_UNIFORM_INT: + GPU_shader_uniform_vector_int( + shgroup->shader, uni->location, uni->length, uni->arraysize, (int *)uni->value); + break; + case DRW_UNIFORM_FLOAT: + GPU_shader_uniform_vector( + shgroup->shader, uni->location, uni->length, uni->arraysize, (float *)uni->value); + break; + case DRW_UNIFORM_TEXTURE: + tex = (GPUTexture *)uni->value; + BLI_assert(tex); + bind_texture(tex, BIND_TEMP); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_TEXTURE_PERSIST: + tex = (GPUTexture *)uni->value; + BLI_assert(tex); + bind_texture(tex, BIND_PERSIST); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_TEXTURE_REF: + tex = *((GPUTexture **)uni->value); + BLI_assert(tex); + bind_texture(tex, BIND_TEMP); + GPU_shader_uniform_texture(shgroup->shader, uni->location, tex); + break; + case DRW_UNIFORM_BLOCK: + ubo = (GPUUniformBuffer *)uni->value; + bind_ubo(ubo, BIND_TEMP); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + case DRW_UNIFORM_BLOCK_PERSIST: + ubo = (GPUUniformBuffer *)uni->value; + bind_ubo(ubo, BIND_PERSIST); + GPU_shader_uniform_buffer(shgroup->shader, uni->location, ubo); + break; + } + } + +#ifdef USE_GPU_SELECT +# define GPU_SELECT_LOAD_IF_PICKSEL(_select_id) \ + if (G.f & G_PICKSEL) { \ + GPU_select_load_id(_select_id); \ + } ((void)0) + +# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(_call) \ + if ((G.f & G_PICKSEL) && (_call)) { \ + GPU_select_load_id((_call)->select_id); \ + } ((void)0) + +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ + _start = 0; \ + _count = _shgroup->instance_count; \ + int *select_id = NULL; \ + if (G.f & G_PICKSEL) { \ + if (_shgroup->override_selectid == -1) { \ + select_id = DRW_instance_data_get(_shgroup->inst_selectid); \ + switch (_shgroup->type) { \ + case DRW_SHG_TRIANGLE_BATCH: _count = 3; break; \ + case DRW_SHG_LINE_BATCH: _count = 2; break; \ + default: _count = 1; break; \ + } \ + } \ + else { \ + GPU_select_load_id(_shgroup->override_selectid); \ + } \ + } \ + while (_start < _shgroup->instance_count) { \ + if (select_id) { \ + GPU_select_load_id(select_id[_start]); \ + } + +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(_start, _count) \ + _start += _count; \ + } + +#else +# define GPU_SELECT_LOAD_IF_PICKSEL(select_id) +# define GPU_SELECT_LOAD_IF_PICKSEL_CALL(call) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) +# define GPU_SELECT_LOAD_IF_PICKSEL_LIST(_shgroup, _start, _count) \ + _start = 0; \ + _count = _shgroup->interface.instance_count; + +#endif + + /* Rendering Calls */ + if (!ELEM(shgroup->type, DRW_SHG_NORMAL)) { + /* Replacing multiple calls with only one */ + if (ELEM(shgroup->type, DRW_SHG_INSTANCE, DRW_SHG_INSTANCE_EXTERNAL)) { + if (shgroup->type == DRW_SHG_INSTANCE_EXTERNAL) { + if (shgroup->instance_geom != NULL) { + GPU_SELECT_LOAD_IF_PICKSEL(shgroup->override_selectid); + draw_geometry_prepare(shgroup, NULL); + draw_geometry_execute_ex(shgroup, shgroup->instance_geom, 0, 0, true); + } + } + else { + if (shgroup->instance_count > 0) { + unsigned int count, start; + draw_geometry_prepare(shgroup, NULL); + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry_execute_ex(shgroup, shgroup->instance_geom, start, count, true); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) + } + } + } + else { /* DRW_SHG_***_BATCH */ + /* Some dynamic batch can have no geom (no call to aggregate) */ + if (shgroup->instance_count > 0) { + unsigned int count, start; + draw_geometry_prepare(shgroup, NULL); + GPU_SELECT_LOAD_IF_PICKSEL_LIST(shgroup, start, count) + { + draw_geometry_execute_ex(shgroup, shgroup->batch_geom, start, count, false); + } + GPU_SELECT_LOAD_IF_PICKSEL_LIST_END(start, count) + } + } + } + else { + bool prev_neg_scale = false; + for (DRWCall *call = shgroup->calls.first; call; call = call->next) { + + /* OPTI/IDEA(clem): Do this preparation in another thread. */ + draw_matrices_model_prepare(call->state); + + if ((call->state->flag & DRW_CALL_CULLED) != 0) + continue; + + /* Negative scale objects */ + bool neg_scale = call->state->flag & DRW_CALL_NEGSCALE; + if (neg_scale != prev_neg_scale) { + glFrontFace((neg_scale) ? DST.backface : DST.frontface); + prev_neg_scale = neg_scale; + } + + GPU_SELECT_LOAD_IF_PICKSEL_CALL(call); + draw_geometry_prepare(shgroup, call->state); + + switch (call->type) { + case DRW_CALL_SINGLE: + draw_geometry_execute(shgroup, call->single.geometry); + break; + case DRW_CALL_INSTANCES: + draw_geometry_execute_ex(shgroup, call->instances.geometry, 0, *call->instances.count, true); + break; + case DRW_CALL_GENERATE: + call->generate.geometry_fn(shgroup, draw_geometry_execute, call->generate.user_data); + break; + default: + BLI_assert(0); + } + } + /* Reset state */ + glFrontFace(DST.frontface); + } + + /* TODO: remove, (currently causes alpha issue with sculpt, need to investigate) */ + DRW_state_reset(); +} + +static void drw_update_view(void) +{ + if (DST.dirty_mat) { + DST.state_cache_id++; + DST.dirty_mat = false; + + DRW_uniformbuffer_update(view_ubo, &DST.view_data); + + /* Catch integer wrap around. */ + if (UNLIKELY(DST.state_cache_id == 0)) { + DST.state_cache_id = 1; + /* We must reset all CallStates to ensure that not + * a single one stayed with cache_id equal to 1. */ + BLI_mempool_iter iter; + DRWCallState *state; + BLI_mempool_iternew(DST.vmempool->states, &iter); + while ((state = BLI_mempool_iterstep(&iter))) { + state->cache_id = 0; + } + } + + /* TODO dispatch threads to compute matrices/culling */ + } + + draw_clipping_setup_from_view(); +} + +static void drw_draw_pass_ex(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) +{ + DST.shader = NULL; + + BLI_assert(DST.buffer_finish_called && "DRW_render_instance_buffer_finish had not been called before drawing"); + + drw_update_view(); + + drw_state_set(pass->state); + + DRW_stats_query_start(pass->name); + + for (DRWShadingGroup *shgroup = start_group; shgroup; shgroup = shgroup->next) { + draw_shgroup(shgroup, pass->state); + /* break if upper limit */ + if (shgroup == end_group) { + break; + } + } + + /* Clear Bound textures */ + for (int i = 0; i < GPU_max_textures(); i++) { + if (DST.RST.bound_texs[i] != NULL) { + GPU_texture_unbind(DST.RST.bound_texs[i]); + DST.RST.bound_texs[i] = NULL; + } + } + + /* Clear Bound Ubos */ + for (int i = 0; i < GPU_max_ubo_binds(); i++) { + if (DST.RST.bound_ubos[i] != NULL) { + GPU_uniformbuffer_unbind(DST.RST.bound_ubos[i]); + DST.RST.bound_ubos[i] = NULL; + } + } + + if (DST.shader) { + GPU_shader_unbind(); + DST.shader = NULL; + } + + DRW_stats_query_end(); +} + +void DRW_draw_pass(DRWPass *pass) +{ + drw_draw_pass_ex(pass, pass->shgroups.first, pass->shgroups.last); +} + +/* Draw only a subset of shgroups. Used in special situations as grease pencil strokes */ +void DRW_draw_pass_subset(DRWPass *pass, DRWShadingGroup *start_group, DRWShadingGroup *end_group) +{ + drw_draw_pass_ex(pass, start_group, end_group); +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_manager_profiling.c b/source/blender/draw/intern/draw_manager_profiling.c index f9fbbac2e2e..d2ed22c57b7 100644 --- a/source/blender/draw/intern/draw_manager_profiling.c +++ b/source/blender/draw/intern/draw_manager_profiling.c @@ -32,7 +32,12 @@ #include "MEM_guardedalloc.h" +#include "draw_manager.h" + #include "GPU_glew.h" +#include "GPU_texture.h" + +#include "UI_resources.h" #include "WM_api.h" #include "WM_types.h" @@ -198,14 +203,127 @@ void DRW_stats_reset(void) } } +static void draw_stat_5row(rcti *rect, int u, int v, const char *txt, const int size) +{ + BLF_draw_default_ascii(rect->xmin + (1 + u * 5) * U.widget_unit, + rect->ymax - (3 + v) * U.widget_unit, 0.0f, + txt, size); +} + +static void draw_stat(rcti *rect, int u, int v, const char *txt, const int size) +{ + BLF_draw_default_ascii(rect->xmin + (1 + u) * U.widget_unit, + rect->ymax - (3 + v) * U.widget_unit, 0.0f, + txt, size); +} + void DRW_stats_draw(rcti *rect) { char stat_string[64]; int lvl_index[MAX_NESTED_TIMER]; - int v = 0; + int v = 0, u = 0; + + double init_tot_time = 0.0, background_tot_time = 0.0, render_tot_time = 0.0, tot_time = 0.0; + + int fontid = BLF_default(); + UI_FontThemeColor(fontid, TH_TEXT_HI); + BLF_enable(fontid, BLF_SHADOW); + BLF_shadow(fontid, 5, (const float[4]){0.0f, 0.0f, 0.0f, 0.75f}); + BLF_shadow_offset(fontid, 0, -1); + + BLF_batch_draw_begin(); + + /* ------------------------------------------ */ + /* ---------------- CPU stats --------------- */ + /* ------------------------------------------ */ + /* Label row */ + char col_label[32]; + sprintf(col_label, "Engine"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Init"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Background"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Render"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + sprintf(col_label, "Total (w/o cache)"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + v++; + + /* Engines rows */ + char time_to_txt[16]; + for (LinkData *link = DST.enabled_engines.first; link; link = link->next) { + u = 0; + DrawEngineType *engine = link->data; + ViewportEngineData *data = drw_viewport_engine_data_ensure(engine); + + draw_stat_5row(rect, u++, v, engine->idname, sizeof(engine->idname)); + + init_tot_time += data->init_time; + sprintf(time_to_txt, "%.2fms", data->init_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + background_tot_time += data->background_time; + sprintf(time_to_txt, "%.2fms", data->background_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + render_tot_time += data->render_time; + sprintf(time_to_txt, "%.2fms", data->render_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + + tot_time += data->init_time + data->background_time + data->render_time; + sprintf(time_to_txt, "%.2fms", data->init_time + data->background_time + data->render_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + v++; + } - BLI_snprintf(stat_string, sizeof(stat_string), "GPU Render Stats"); - BLF_draw_default_ascii(rect->xmin + 1 * U.widget_unit, rect->ymax - v++ * U.widget_unit, 0.0f, stat_string, sizeof(stat_string)); + /* Totals row */ + u = 0; + sprintf(col_label, "Sub Total"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + sprintf(time_to_txt, "%.2fms", init_tot_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", background_tot_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", render_tot_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + sprintf(time_to_txt, "%.2fms", tot_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + v += 2; + + u = 0; + double *cache_time = GPU_viewport_cache_time_get(DST.viewport); + sprintf(col_label, "Cache Time"); + draw_stat_5row(rect, u++, v, col_label, sizeof(col_label)); + sprintf(time_to_txt, "%.2fms", *cache_time); + draw_stat_5row(rect, u++, v, time_to_txt, sizeof(time_to_txt)); + v += 2; + + /* ------------------------------------------ */ + /* ---------------- GPU stats --------------- */ + /* ------------------------------------------ */ + + /* Memory Stats */ + unsigned int tex_mem = GPU_texture_memory_usage_get(); + unsigned int vbo_mem = GWN_vertbuf_get_memory_usage(); + + sprintf(stat_string, "GPU Memory"); + draw_stat(rect, 0, v, stat_string, sizeof(stat_string)); + sprintf(stat_string, "%.2fMB", (double)(tex_mem + vbo_mem) / 1000000.0); + draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string)); + sprintf(stat_string, "Textures"); + draw_stat(rect, 1, v, stat_string, sizeof(stat_string)); + sprintf(stat_string, "%.2fMB", (double)tex_mem / 1000000.0); + draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string)); + sprintf(stat_string, "Meshes"); + draw_stat(rect, 1, v, stat_string, sizeof(stat_string)); + sprintf(stat_string, "%.2fMB", (double)vbo_mem / 1000000.0); + draw_stat_5row(rect, 1, v++, stat_string, sizeof(stat_string)); + v += 1; + + /* GPU Timings */ + BLI_snprintf(stat_string, sizeof(stat_string), "GPU Render Timings"); + draw_stat(rect, 0, v++, stat_string, sizeof(stat_string)); for (int i = 0; i < DTP.timer_increment; ++i) { double time_ms, time_percent; @@ -232,11 +350,14 @@ void DRW_stats_draw(rcti *rect) time_percent = MIN2(time_percent, 100.0); BLI_snprintf(stat_string, sizeof(stat_string), "%s", timer->name); - BLF_draw_default_ascii(rect->xmin + (1 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string)); + draw_stat(rect, 0 + timer->lvl, v, stat_string, sizeof(stat_string)); BLI_snprintf(stat_string, sizeof(stat_string), "%.2fms", time_ms); - BLF_draw_default_ascii(rect->xmin + (13 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string)); + draw_stat(rect, 12 + timer->lvl, v, stat_string, sizeof(stat_string)); BLI_snprintf(stat_string, sizeof(stat_string), "%.0f", time_percent); - BLF_draw_default_ascii(rect->xmin + (17 + timer->lvl) * U.widget_unit, rect->ymax - v * U.widget_unit, 0.0f, stat_string, sizeof(stat_string)); + draw_stat(rect, 16 + timer->lvl, v, stat_string, sizeof(stat_string)); v++; } -}
\ No newline at end of file + + BLF_batch_draw_end(); + BLF_disable(fontid, BLF_SHADOW); +} diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c new file mode 100644 index 00000000000..814109ee1e9 --- /dev/null +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -0,0 +1,387 @@ +/* + * 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_shader.c + * \ingroup draw + */ + +#include "draw_manager.h" + +#include "DNA_world_types.h" +#include "DNA_material_types.h" + +#include "BLI_listbase.h" +#include "BLI_string.h" +#include "BLI_string_utils.h" +#include "BLI_threads.h" +#include "BLI_task.h" + +#include "BKE_global.h" +#include "BKE_main.h" + +#include "GPU_shader.h" +#include "GPU_material.h" + +#include "WM_api.h" +#include "WM_types.h" + +extern char datatoc_gpu_shader_2D_vert_glsl[]; +extern char datatoc_gpu_shader_3D_vert_glsl[]; +extern char datatoc_common_fullscreen_vert_glsl[]; + + +/* -------------------------------------------------------------------- */ + +/** \name Deferred Compilation (DRW_deferred) + * + * Since compiling shader can take a long time, we do it in a non blocking + * manner in another thread. + * + * \{ */ + +typedef struct DRWDeferredShader { + struct DRWDeferredShader *prev, *next; + + GPUMaterial *mat; + char *vert, *geom, *frag, *defs; +} DRWDeferredShader; + +typedef struct DRWShaderCompiler { + ListBase queue; /* DRWDeferredShader */ + SpinLock list_lock; + + DRWDeferredShader *mat_compiling; + ThreadMutex compilation_lock; + + void *ogl_context; + + int shaders_done; /* To compute progress. */ +} DRWShaderCompiler; + +static void drw_deferred_shader_free(DRWDeferredShader *dsh) +{ + /* Make sure it is not queued before freeing. */ + MEM_SAFE_FREE(dsh->vert); + MEM_SAFE_FREE(dsh->geom); + MEM_SAFE_FREE(dsh->frag); + MEM_SAFE_FREE(dsh->defs); + + MEM_freeN(dsh); +} + +static void drw_deferred_shader_queue_free(ListBase *queue) +{ + DRWDeferredShader *dsh; + while((dsh = BLI_pophead(queue))) { + drw_deferred_shader_free(dsh); + } +} + +static void drw_deferred_shader_compilation_exec(void *custom_data, short *stop, short *do_update, float *progress) +{ + DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data; + void *ogl_context = comp->ogl_context; + + WM_opengl_context_activate(ogl_context); + + while (true) { + BLI_spin_lock(&comp->list_lock); + + if (*stop != 0) { + /* We don't want user to be able to cancel the compilation + * but wm can kill the task if we are closing blender. */ + BLI_spin_unlock(&comp->list_lock); + break; + } + + /* Pop tail because it will be less likely to lock the main thread + * if all GPUMaterials are to be freed (see DRW_deferred_shader_remove()). */ + comp->mat_compiling = BLI_poptail(&comp->queue); + if (comp->mat_compiling == NULL) { + /* No more Shader to compile. */ + BLI_spin_unlock(&comp->list_lock); + break; + } + + comp->shaders_done++; + int total = BLI_listbase_count(&comp->queue) + comp->shaders_done; + + BLI_mutex_lock(&comp->compilation_lock); + BLI_spin_unlock(&comp->list_lock); + + /* Do the compilation. */ + GPU_material_generate_pass( + comp->mat_compiling->mat, + comp->mat_compiling->vert, + comp->mat_compiling->geom, + comp->mat_compiling->frag, + comp->mat_compiling->defs); + + *progress = (float)comp->shaders_done / (float)total; + *do_update = true; + + glFlush(); + BLI_mutex_unlock(&comp->compilation_lock); + + drw_deferred_shader_free(comp->mat_compiling); + } + + WM_opengl_context_release(ogl_context); +} + +static void drw_deferred_shader_compilation_free(void *custom_data) +{ + DRWShaderCompiler *comp = (DRWShaderCompiler *)custom_data; + + drw_deferred_shader_queue_free(&comp->queue); + + BLI_spin_end(&comp->list_lock); + BLI_mutex_end(&comp->compilation_lock); + + if (comp->ogl_context) { + /* Only destroy if the job owns the context. */ + WM_opengl_context_dispose(comp->ogl_context); + } + + MEM_freeN(comp); +} + +static void drw_deferred_shader_add( + GPUMaterial *mat, const char *vert, const char *geom, const char *frag_lib, const char *defines) +{ + /* Do not deferre the compilation if we are rendering for image. */ + if (DRW_state_is_image_render()) { + /* Double checking that this GPUMaterial is not going to be + * compiled by another thread. */ + DRW_deferred_shader_remove(mat); + GPU_material_generate_pass(mat, vert, geom, frag_lib, defines); + return; + } + + DRWDeferredShader *dsh = MEM_callocN(sizeof(DRWDeferredShader), "Deferred Shader"); + + dsh->mat = mat; + if (vert) dsh->vert = BLI_strdup(vert); + if (geom) dsh->geom = BLI_strdup(geom); + if (frag_lib) dsh->frag = BLI_strdup(frag_lib); + if (defines) dsh->defs = BLI_strdup(defines); + + BLI_assert(DST.draw_ctx.evil_C); + wmWindowManager *wm = CTX_wm_manager(DST.draw_ctx.evil_C); + wmWindow *win = CTX_wm_window(DST.draw_ctx.evil_C); + Scene *scene = DST.draw_ctx.scene; + + /* Get the running job or a new one if none is running. Can only have one job per type & owner. */ + wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation", + WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION); + + DRWShaderCompiler *old_comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job); + + DRWShaderCompiler *comp = MEM_callocN(sizeof(DRWShaderCompiler), "DRWShaderCompiler"); + BLI_spin_init(&comp->list_lock); + BLI_mutex_init(&comp->compilation_lock); + + if (old_comp) { + BLI_spin_lock(&old_comp->list_lock); + BLI_movelisttolist(&comp->queue, &old_comp->queue); + BLI_spin_unlock(&old_comp->list_lock); + /* Do not recreate context, just pass ownership. */ + comp->ogl_context = old_comp->ogl_context; + old_comp->ogl_context = NULL; + } + + BLI_addtail(&comp->queue, dsh); + + /* Create only one context. */ + if (comp->ogl_context == NULL) { + comp->ogl_context = WM_opengl_context_create(); + WM_opengl_context_activate(DST.ogl_context); + } + + WM_jobs_customdata_set(wm_job, comp, drw_deferred_shader_compilation_free); + WM_jobs_timer(wm_job, 0.1, NC_MATERIAL | ND_SHADING_DRAW, 0); + WM_jobs_callbacks(wm_job, drw_deferred_shader_compilation_exec, NULL, NULL, NULL); + WM_jobs_start(wm, wm_job); +} + +void DRW_deferred_shader_remove(GPUMaterial *mat) +{ + Scene *scene = GPU_material_scene(mat); + + for (wmWindowManager *wm = G.main->wm.first; wm; wm = wm->id.next) { + if (WM_jobs_test(wm, scene, WM_JOB_TYPE_SHADER_COMPILATION) == false) { + /* No job running, do not create a new one by calling WM_jobs_get. */ + continue; + } + for (wmWindow *win = wm->windows.first; win; win = win->next) { + wmJob *wm_job = WM_jobs_get(wm, win, scene, "Shaders Compilation", + WM_JOB_PROGRESS | WM_JOB_SUSPEND, WM_JOB_TYPE_SHADER_COMPILATION); + + DRWShaderCompiler *comp = (DRWShaderCompiler *)WM_jobs_customdata_get(wm_job); + if (comp != NULL) { + BLI_spin_lock(&comp->list_lock); + DRWDeferredShader *dsh; + dsh = (DRWDeferredShader *)BLI_findptr(&comp->queue, mat, offsetof(DRWDeferredShader, mat)); + if (dsh) { + BLI_remlink(&comp->queue, dsh); + } + + /* Wait for compilation to finish */ + if (comp->mat_compiling != NULL) { + if (comp->mat_compiling->mat == mat) { + BLI_mutex_lock(&comp->compilation_lock); + BLI_mutex_unlock(&comp->compilation_lock); + } + } + BLI_spin_unlock(&comp->list_lock); + + if (dsh) { + drw_deferred_shader_free(dsh); + } + } + } + } +} + +/** \} */ + +/* -------------------------------------------------------------------- */ + +GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, const char *defines) +{ + return GPU_shader_create(vert, frag, geom, NULL, defines); +} + +GPUShader *DRW_shader_create_with_lib( + const char *vert, const char *geom, const char *frag, const char *lib, const char *defines) +{ + GPUShader *sh; + char *vert_with_lib = NULL; + char *frag_with_lib = NULL; + char *geom_with_lib = NULL; + + vert_with_lib = BLI_string_joinN(lib, vert); + frag_with_lib = BLI_string_joinN(lib, frag); + if (geom) { + geom_with_lib = BLI_string_joinN(lib, geom); + } + + sh = GPU_shader_create(vert_with_lib, frag_with_lib, geom_with_lib, NULL, defines); + + MEM_freeN(vert_with_lib); + MEM_freeN(frag_with_lib); + if (geom) { + MEM_freeN(geom_with_lib); + } + + return sh; +} + +GPUShader *DRW_shader_create_2D(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_2D_vert_glsl, frag, NULL, NULL, defines); +} + +GPUShader *DRW_shader_create_3D(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_gpu_shader_3D_vert_glsl, frag, NULL, NULL, defines); +} + +GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *defines) +{ + return GPU_shader_create(datatoc_common_fullscreen_vert_glsl, frag, NULL, NULL, defines); +} + +GPUShader *DRW_shader_create_3D_depth_only(void) +{ + return GPU_shader_get_builtin_shader(GPU_SHADER_3D_DEPTH_ONLY); +} + +GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, int options) +{ + GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); + if (DRW_state_is_image_render()) { + if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) { + /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX + * with the shader code and we will resume the compilation from there. */ + return NULL; + } + } + return mat; +} + +GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, int options) +{ + GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); + if (DRW_state_is_image_render()) { + if (mat != NULL && GPU_material_status(mat) == GPU_MAT_QUEUED) { + /* XXX Hack : we return NULL so that the engine will call DRW_shader_create_from_XXX + * with the shader code and we will resume the compilation from there. */ + return NULL; + } + } + return mat; +} + +GPUMaterial *DRW_shader_create_from_world( + struct Scene *scene, World *wo, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat = NULL; + if (DRW_state_is_image_render()) { + mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); + } + + if (mat == NULL) { + mat = GPU_material_from_nodetree( + scene, wo->nodetree, &wo->gpumaterial, engine_type, options, + vert, geom, frag_lib, defines, true); + } + + drw_deferred_shader_add(mat, vert, geom, frag_lib, defines); + + return mat; +} + +GPUMaterial *DRW_shader_create_from_material( + struct Scene *scene, Material *ma, const void *engine_type, int options, + const char *vert, const char *geom, const char *frag_lib, const char *defines) +{ + GPUMaterial *mat = NULL; + if (DRW_state_is_image_render()) { + mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); + } + + if (mat == NULL) { + mat = GPU_material_from_nodetree( + scene, ma->nodetree, &ma->gpumaterial, engine_type, options, + vert, geom, frag_lib, defines, true); + } + + drw_deferred_shader_add(mat, vert, geom, frag_lib, defines); + + return mat; +} + +void DRW_shader_free(GPUShader *shader) +{ + GPU_shader_free(shader); +} diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c new file mode 100644 index 00000000000..65856a6bf5c --- /dev/null +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -0,0 +1,237 @@ +/* + * 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_texture.c + * \ingroup draw + */ + +#include "draw_manager.h" + +void drw_texture_get_format( + DRWTextureFormat format, bool is_framebuffer, + GPUTextureFormat *r_data_type, int *r_channels, bool *r_is_depth) +{ + /* Some formats do not work with framebuffers. */ + if (is_framebuffer) { + switch (format) { + /* Only add formats that are COMPATIBLE with FB. + * Generally they are multiple of 16bit. */ + case DRW_TEX_R_16: + case DRW_TEX_R_16I: + case DRW_TEX_R_32: + case DRW_TEX_RG_8: + case DRW_TEX_RG_16: + case DRW_TEX_RG_16I: + case DRW_TEX_RG_32: + case DRW_TEX_RGBA_8: + case DRW_TEX_RGBA_16: + case DRW_TEX_RGBA_32: + case DRW_TEX_DEPTH_16: + case DRW_TEX_DEPTH_24: + case DRW_TEX_DEPTH_24_STENCIL_8: + case DRW_TEX_DEPTH_32: + case DRW_TEX_RGB_11_11_10: + break; + default: + BLI_assert(false && "Texture format unsupported as render target!"); + *r_channels = 4; + *r_data_type = GPU_RGBA8; + *r_is_depth = false; + return; + } + } + + switch (format) { + case DRW_TEX_RGBA_8: *r_data_type = GPU_RGBA8; break; + case DRW_TEX_RGBA_16: *r_data_type = GPU_RGBA16F; break; + case DRW_TEX_RGBA_32: *r_data_type = GPU_RGBA32F; break; + case DRW_TEX_RGB_16: *r_data_type = GPU_RGB16F; break; + case DRW_TEX_RGB_11_11_10: *r_data_type = GPU_R11F_G11F_B10F; break; + case DRW_TEX_RG_8: *r_data_type = GPU_RG8; break; + case DRW_TEX_RG_16: *r_data_type = GPU_RG16F; break; + case DRW_TEX_RG_16I: *r_data_type = GPU_RG16I; break; + case DRW_TEX_RG_32: *r_data_type = GPU_RG32F; break; + case DRW_TEX_R_8: *r_data_type = GPU_R8; break; + case DRW_TEX_R_16: *r_data_type = GPU_R16F; break; + case DRW_TEX_R_16I: *r_data_type = GPU_R16I; break; + case DRW_TEX_R_32: *r_data_type = GPU_R32F; break; +#if 0 + case DRW_TEX_RGB_8: *r_data_type = GPU_RGB8; break; + case DRW_TEX_RGB_32: *r_data_type = GPU_RGB32F; break; +#endif + case DRW_TEX_DEPTH_16: *r_data_type = GPU_DEPTH_COMPONENT16; break; + case DRW_TEX_DEPTH_24: *r_data_type = GPU_DEPTH_COMPONENT24; break; + case DRW_TEX_DEPTH_24_STENCIL_8: *r_data_type = GPU_DEPTH24_STENCIL8; break; + case DRW_TEX_DEPTH_32: *r_data_type = GPU_DEPTH_COMPONENT32F; break; + default : + /* file type not supported you must uncomment it from above */ + BLI_assert(false); + break; + } + + switch (format) { + case DRW_TEX_RGBA_8: + case DRW_TEX_RGBA_16: + case DRW_TEX_RGBA_32: + *r_channels = 4; + break; + case DRW_TEX_RGB_8: + case DRW_TEX_RGB_16: + case DRW_TEX_RGB_32: + case DRW_TEX_RGB_11_11_10: + *r_channels = 3; + break; + case DRW_TEX_RG_8: + case DRW_TEX_RG_16: + case DRW_TEX_RG_16I: + case DRW_TEX_RG_32: + *r_channels = 2; + break; + default: + *r_channels = 1; + break; + } + + if (r_is_depth) { + *r_is_depth = ELEM(format, DRW_TEX_DEPTH_16, DRW_TEX_DEPTH_24, DRW_TEX_DEPTH_24_STENCIL_8); + } +} + +void drw_texture_set_parameters(GPUTexture *tex, DRWTextureFlag flags) +{ + GPU_texture_bind(tex, 0); + if (flags & DRW_TEX_MIPMAP) { + GPU_texture_mipmap_mode(tex, true, flags & DRW_TEX_FILTER); + GPU_texture_generate_mipmap(tex); + } + else { + GPU_texture_filter_mode(tex, flags & DRW_TEX_FILTER); + } + GPU_texture_wrap_mode(tex, flags & DRW_TEX_WRAP); + GPU_texture_compare_mode(tex, flags & DRW_TEX_COMPARE); + GPU_texture_unbind(tex); +} + +GPUTexture *DRW_texture_create_1D(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, false, &data_type, &channels, NULL); + tex = GPU_texture_create_1D_custom(w, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +GPUTexture *DRW_texture_create_2D(int w, int h, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, false, &data_type, &channels, NULL); + tex = GPU_texture_create_2D_custom(w, h, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +GPUTexture *DRW_texture_create_2D_array( + int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, false, &data_type, &channels, NULL); + tex = GPU_texture_create_2D_array_custom(w, h, d, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +GPUTexture *DRW_texture_create_3D( + int w, int h, int d, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, false, &data_type, &channels, NULL); + tex = GPU_texture_create_3D_custom(w, h, d, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + +GPUTexture *DRW_texture_create_cube(int w, DRWTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex; + GPUTextureFormat data_type; + int channels; + + drw_texture_get_format(format, false, &data_type, &channels, NULL); + tex = GPU_texture_create_cube_custom(w, channels, data_type, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + 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); + GPU_texture_generate_mipmap(tex); + GPU_texture_unbind(tex); +} + +void DRW_texture_free(GPUTexture *tex) +{ + GPU_texture_free(tex); +} diff --git a/source/blender/draw/intern/draw_view.c b/source/blender/draw/intern/draw_view.c index 391c29e511f..c65ed55561e 100644 --- a/source/blender/draw/intern/draw_view.c +++ b/source/blender/draw/intern/draw_view.c @@ -611,20 +611,20 @@ void DRW_draw_background(void) /* **************************** 3D Cursor ******************************** */ -static bool is_cursor_visible(Scene *scene, ViewLayer *view_layer) +static bool is_cursor_visible(const DRWContextState *draw_ctx, Scene *scene, ViewLayer *view_layer) { Object *ob = OBACT(view_layer); /* don't draw cursor in paint modes, but with a few exceptions */ - if (ob && ob->mode & OB_MODE_ALL_PAINT) { + if (ob && draw_ctx->object_mode & OB_MODE_ALL_PAINT) { /* exception: object is in weight paint and has deforming armature in pose mode */ - if (ob->mode & OB_MODE_WEIGHT_PAINT) { + if (draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) { if (BKE_object_pose_armature_get(ob) != NULL) { return true; } } /* exception: object in texture paint mode, clone brush, use_clone_layer disabled */ - else if (ob->mode & OB_MODE_TEXTURE_PAINT) { + else if (draw_ctx->object_mode & OB_MODE_TEXTURE_PAINT) { const Paint *p = BKE_paint_get_active(scene, view_layer); if (p && p->brush && p->brush->imagepaint_tool == PAINT_TOOL_CLONE) { @@ -645,7 +645,7 @@ void DRW_draw_cursor(void) { const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; + ARegion *ar = draw_ctx->ar; Scene *scene = draw_ctx->scene; ViewLayer *view_layer = draw_ctx->view_layer; @@ -654,62 +654,19 @@ void DRW_draw_cursor(void) glDisable(GL_DEPTH_TEST); glLineWidth(1.0f); - if (is_cursor_visible(scene, view_layer)) { - float *co = ED_view3d_cursor3d_get(scene, v3d); - unsigned char crosshair_color[3]; - - const float f5 = 0.25f; - const float f10 = 0.5f; - const float f20 = 1.0f; - - Gwn_VertFormat *format = immVertexFormat(); - unsigned int pos = GWN_vertformat_attr_add(format, "pos", GWN_COMP_F32, 2, GWN_FETCH_FLOAT); - unsigned int color = GWN_vertformat_attr_add(format, "color", GWN_COMP_U8, 3, GWN_FETCH_INT_TO_FLOAT_UNIT); - unsigned int wpos = GWN_vertformat_attr_add(format, "world_pos", GWN_COMP_F32, 3, GWN_FETCH_FLOAT); + if (is_cursor_visible(draw_ctx, scene, view_layer)) { + int co[2]; + if (ED_view3d_project_int_global(ar, ED_view3d_cursor3d_get(scene, v3d), co, V3D_PROJ_TEST_NOP) == V3D_PROJ_RET_OK) { - /* XXX Using instance shader without instance */ - immBindBuiltinProgram(GPU_SHADER_3D_SCREENSPACE_VARIYING_COLOR); - immUniform1f("size", U.widget_unit); - immUniform1f("pixel_size", *DRW_viewport_pixelsize_get()); - immUniformArray3fv("screen_vecs", DRW_viewport_screenvecs_get(), 2); - immUniformMatrix4fv("ViewProjectionMatrix", rv3d->persmat); + ED_region_pixelspace(ar); + gpuTranslate2f(co[0], co[1]); + gpuScale2f(U.widget_unit, U.widget_unit); - const int segments = 16; - - immBegin(GWN_PRIM_LINE_LOOP, segments); - immAttrib3fv(wpos, co); - - for (int i = 0; i < segments; ++i) { - float angle = (float)(2 * M_PI) * ((float)i / (float)segments); - float x = f10 * cosf(angle); - float y = f10 * sinf(angle); - - if (i % 2 == 0) - immAttrib3ub(color, 255, 0, 0); - else - immAttrib3ub(color, 255, 255, 255); - - immVertex2f(pos, x, y); + Gwn_Batch *cursor_batch = DRW_cache_cursor_get(); + GPUShader *shader = GPU_shader_get_builtin_shader(GPU_SHADER_2D_FLAT_COLOR); + GWN_batch_program_set(cursor_batch, GPU_shader_get_program(shader), GPU_shader_get_interface(shader)); + GWN_batch_draw(cursor_batch); } - immEnd(); - - UI_GetThemeColor3ubv(TH_VIEW_OVERLAY, crosshair_color); - - immBegin(GWN_PRIM_LINES, 8); - immAttrib3ubv(color, crosshair_color); - immAttrib3fv(wpos, co); - - immVertex2f(pos, -f20, 0); - immVertex2f(pos, -f5, 0); - immVertex2f(pos, +f5, 0); - immVertex2f(pos, +f20, 0); - immVertex2f(pos, 0, -f20); - immVertex2f(pos, 0, -f5); - immVertex2f(pos, 0, +f5); - immVertex2f(pos, 0, +f20); - immEnd(); - - immUnbindProgram(); } } diff --git a/source/blender/draw/modes/edit_armature_mode.c b/source/blender/draw/modes/edit_armature_mode.c index 4deb4f86692..3c0c33b1daa 100644 --- a/source/blender/draw/modes/edit_armature_mode.c +++ b/source/blender/draw/modes/edit_armature_mode.c @@ -154,4 +154,5 @@ DrawEngineType draw_engine_edit_armature_type = { NULL, &EDIT_ARMATURE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_curve_mode.c b/source/blender/draw/modes/edit_curve_mode.c index ec12f7570c2..73a4fb1e9e6 100644 --- a/source/blender/draw/modes/edit_curve_mode.c +++ b/source/blender/draw/modes/edit_curve_mode.c @@ -229,12 +229,11 @@ static void EDIT_CURVE_cache_populate(void *vedata, Object *ob) EDIT_CURVE_StorageList *stl = ((EDIT_CURVE_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); const Scene *scene = draw_ctx->scene; - const Object *obedit = scene->obedit; UNUSED_VARS(psl, stl); if (ob->type == OB_CURVE) { - if (ob == obedit) { + if (ob == draw_ctx->object_edit) { Curve *cu = ob->data; /* Get geometry cache */ struct Gwn_Batch *geom; @@ -347,4 +346,5 @@ DrawEngineType draw_engine_edit_curve_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_CURVE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_groom_mode.c b/source/blender/draw/modes/edit_groom_mode.c index 3644fe16691..d12f918c0bc 100644 --- a/source/blender/draw/modes/edit_groom_mode.c +++ b/source/blender/draw/modes/edit_groom_mode.c @@ -195,7 +195,7 @@ static void EDIT_GROOM_cache_populate(void *vedata, Object *ob) EDIT_GROOM_StorageList *stl = ((EDIT_GROOM_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; + Object *obedit = draw_ctx->object_edit; GroomEditSettings *editsettings = &scene->toolsettings->groom_edit_settings; UNUSED_VARS(psl); diff --git a/source/blender/draw/modes/edit_lattice_mode.c b/source/blender/draw/modes/edit_lattice_mode.c index ff4c557326e..0268f4eb453 100644 --- a/source/blender/draw/modes/edit_lattice_mode.c +++ b/source/blender/draw/modes/edit_lattice_mode.c @@ -188,13 +188,11 @@ static void EDIT_LATTICE_cache_populate(void *vedata, Object *ob) EDIT_LATTICE_PassList *psl = ((EDIT_LATTICE_Data *)vedata)->psl; EDIT_LATTICE_StorageList *stl = ((EDIT_LATTICE_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; UNUSED_VARS(psl); if (ob->type == OB_LATTICE) { - if (ob == obedit) { + if (ob == draw_ctx->object_edit) { /* Get geometry cache */ struct Gwn_Batch *geom; @@ -294,4 +292,5 @@ DrawEngineType draw_engine_edit_lattice_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_LATTICE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_mesh_mode.c b/source/blender/draw/modes/edit_mesh_mode.c index 1a8c03e3933..4bd69941809 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); @@ -406,9 +408,9 @@ static void EDIT_MESH_cache_init(void *vedata) DRWShadingGroup *mix_shgrp = DRW_shgroup_create(e_data.overlay_mix_sh, psl->mix_occlude); DRW_shgroup_call_add(mix_shgrp, quad, NULL); DRW_shgroup_uniform_float(mix_shgrp, "alpha", &backwire_opacity, 1); - DRW_shgroup_uniform_buffer(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx); - DRW_shgroup_uniform_buffer(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx); - DRW_shgroup_uniform_buffer(mix_shgrp, "sceneDepth", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireColor", &e_data.occlude_wire_color_tx); + DRW_shgroup_uniform_texture_ref(mix_shgrp, "wireDepth", &e_data.occlude_wire_depth_tx); + DRW_shgroup_uniform_texture_ref(mix_shgrp, "sceneDepth", &dtxl->depth); } } @@ -443,11 +445,10 @@ static void EDIT_MESH_cache_populate(void *vedata, Object *ob) const DRWContextState *draw_ctx = DRW_context_state_get(); View3D *v3d = draw_ctx->v3d; Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; struct Gwn_Batch *geom; if (ob->type == OB_MESH) { - if (ob == obedit) { + if (ob == draw_ctx->object_edit) { const Mesh *me = ob->data; IDProperty *ces_mode_ed = BKE_layer_collection_engine_evaluated_get(ob, COLLECTION_MODE_EDIT, ""); bool do_occlude_wire = BKE_collection_engine_property_value_get_bool(ces_mode_ed, "show_occlude_wire"); @@ -524,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); @@ -535,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); @@ -610,4 +596,5 @@ DrawEngineType draw_engine_edit_mesh_type = { NULL, &EDIT_MESH_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_metaball_mode.c b/source/blender/draw/modes/edit_metaball_mode.c index a83f5ae33bc..bcabeef5bc3 100644 --- a/source/blender/draw/modes/edit_metaball_mode.c +++ b/source/blender/draw/modes/edit_metaball_mode.c @@ -119,11 +119,11 @@ static void EDIT_METABALL_cache_init(void *vedata) psl->pass = DRW_pass_create("My Pass", state); /* Create a shadingGroup using a function in draw_common.c or custom one */ - stl->g_data->group = shgroup_instance_mball_helpers(psl->pass, DRW_cache_screenspace_circle_get()); + stl->g_data->group = shgroup_instance_mball_handles(psl->pass, DRW_cache_screenspace_circle_get()); } } -static void EDIT_METABALL_cache_populate_radius_visualization( +static void EDIT_METABALL_cache_populate_radius( DRWShadingGroup *group, MetaElem *ml, const float scale_xform[3][4], const float *radius, const int selection_id) { @@ -142,7 +142,7 @@ static void EDIT_METABALL_cache_populate_radius_visualization( DRW_shgroup_call_dynamic_add(group, scale_xform, radius, color); } -static void EDIT_METABALL_cache_populate_stiffness_visualization( +static void EDIT_METABALL_cache_populate_stiffness( DRWShadingGroup *group, MetaElem *ml, const float scale_xform[3][4], const float *radius, const int selection_id) { @@ -169,11 +169,9 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob) if (ob->type == OB_MBALL) { const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; DRWShadingGroup *group = stl->g_data->group; - if (ob == obedit) { + if (ob == draw_ctx->object_edit) { MetaBall *mb = ob->data; const bool is_select = DRW_state_is_select(); @@ -181,13 +179,13 @@ static void EDIT_METABALL_cache_populate(void *vedata, Object *ob) int selection_id = 0; for (MetaElem *ml = mb->editelems->first; ml != NULL; ml = ml->next) { - BKE_mball_element_calc_display_m3x4(ml->draw_scale_xform, ob->obmat, &ml->x); + BKE_mball_element_calc_scale_xform(ml->draw_scale_xform, ob->obmat, &ml->x); ml->draw_stiffness_radius = ml->rad * atanf(ml->s) / (float)M_PI_2; - EDIT_METABALL_cache_populate_radius_visualization( + EDIT_METABALL_cache_populate_radius( group, ml, ml->draw_scale_xform, &ml->rad, is_select ? ++selection_id : -1); - EDIT_METABALL_cache_populate_stiffness_visualization( + EDIT_METABALL_cache_populate_stiffness( group, ml, ml->draw_scale_xform, &ml->draw_stiffness_radius, is_select ? ++selection_id : -1); } } @@ -248,4 +246,5 @@ DrawEngineType draw_engine_edit_metaball_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_METABALL_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_surface_mode.c b/source/blender/draw/modes/edit_surface_mode.c index 4e60c4abff5..8f0371925db 100644 --- a/source/blender/draw/modes/edit_surface_mode.c +++ b/source/blender/draw/modes/edit_surface_mode.c @@ -266,4 +266,5 @@ DrawEngineType draw_engine_edit_surface_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_SURFACE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/edit_text_mode.c b/source/blender/draw/modes/edit_text_mode.c index b375bad84b5..43c4a356279 100644 --- a/source/blender/draw/modes/edit_text_mode.c +++ b/source/blender/draw/modes/edit_text_mode.c @@ -190,13 +190,11 @@ static void EDIT_TEXT_cache_populate(void *vedata, Object *ob) EDIT_TEXT_PassList *psl = ((EDIT_TEXT_Data *)vedata)->psl; EDIT_TEXT_StorageList *stl = ((EDIT_TEXT_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - Object *obedit = scene->obedit; UNUSED_VARS(psl, stl); if (ob->type == OB_FONT) { - if (ob == obedit) { + if (ob == draw_ctx->object_edit) { const Curve *cu = ob->data; /* Get geometry cache */ struct Gwn_Batch *geom; @@ -309,4 +307,5 @@ DrawEngineType draw_engine_edit_text_type = { NULL, /* draw_background but not needed by mode engines */ &EDIT_TEXT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/object_mode.c b/source/blender/draw/modes/object_mode.c index 091edf10435..52db4092fbc 100644 --- a/source/blender/draw/modes/object_mode.c +++ b/source/blender/draw/modes/object_mode.c @@ -34,7 +34,7 @@ #include "DNA_mesh_types.h" #include "DNA_meta_types.h" #include "DNA_modifier_types.h" -#include "DNA_object_force.h" +#include "DNA_object_force_types.h" #include "DNA_lightprobe_types.h" #include "DNA_particle_types.h" #include "DNA_view3d_types.h" @@ -59,6 +59,8 @@ #include "GPU_shader.h" #include "GPU_texture.h" +#include "MEM_guardedalloc.h" + #include "UI_resources.h" #include "draw_mode_engines.h" @@ -80,12 +82,12 @@ extern char datatoc_object_empty_image_frag_glsl[]; extern char datatoc_object_empty_image_vert_glsl[]; extern char datatoc_object_lightprobe_grid_vert_glsl[]; extern char datatoc_object_particle_prim_vert_glsl[]; -extern char datatoc_object_particle_prim_frag_glsl[]; extern char datatoc_object_particle_dot_vert_glsl[]; extern char datatoc_object_particle_dot_frag_glsl[]; extern char datatoc_common_globals_lib_glsl[]; extern char datatoc_common_fxaa_lib_glsl[]; -extern char datatoc_gpu_shader_fullscreen_vert_glsl[]; +extern char datatoc_gpu_shader_flat_color_frag_glsl[]; +extern char datatoc_common_fullscreen_vert_glsl[]; extern char datatoc_gpu_shader_uniform_color_frag_glsl[]; /* *********** LISTS *********** */ @@ -109,8 +111,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 { @@ -159,7 +162,7 @@ typedef struct OBJECT_PrivateData { DRWShadingGroup *probe_grid; /* MetaBalls */ - DRWShadingGroup *mball_circle; + DRWShadingGroup *mball_handle; /* Lamps */ DRWShadingGroup *lamp_center; @@ -218,12 +221,25 @@ typedef struct OBJECT_PrivateData { DRWShadingGroup *wire_select_group; DRWShadingGroup *wire_transform; + /* Points */ + DRWShadingGroup *points; + DRWShadingGroup *points_active; + DRWShadingGroup *points_active_group; + DRWShadingGroup *points_select; + DRWShadingGroup *points_select_group; + DRWShadingGroup *points_transform; + /* Hair Systems */ DRWShadingGroup *hair_verts; DRWShadingGroup *hair_edges; } OBJECT_PrivateData; /* Transient data */ static struct { + /* Instance Data format */ + struct Gwn_VertFormat *particle_format; + struct Gwn_VertFormat *empty_image_format; + struct Gwn_VertFormat *empty_image_wire_format; + /* fullscreen shaders */ GPUShader *outline_resolve_sh; GPUShader *outline_resolve_aa_sh; @@ -276,23 +292,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); + + GPU_framebuffer_ensure_config(&fbl->outlines_fb, { + GPU_ATTACHMENT_TEXTURE(e_data.outlines_depth_tx), + GPU_ATTACHMENT_TEXTURE(e_data.outlines_color_tx) + }); - DRW_framebuffer_init( - &fbl->outlines, &draw_engine_object_type, - (int)viewport_size[0], (int)viewport_size[1], - tex, 2); + GPU_framebuffer_ensure_config(&fbl->expand_fb, { + GPU_ATTACHMENT_NONE, + 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); + 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) { @@ -301,7 +325,7 @@ static void OBJECT_engine_init(void *vedata) if (!e_data.outline_resolve_aa_sh) { e_data.outline_resolve_aa_sh = DRW_shader_create_with_lib( - datatoc_gpu_shader_fullscreen_vert_glsl, NULL, + datatoc_common_fullscreen_vert_glsl, NULL, datatoc_object_outline_resolve_frag_glsl, datatoc_common_fxaa_lib_glsl, "#define FXAA_ALPHA\n" @@ -340,12 +364,12 @@ static void OBJECT_engine_init(void *vedata) if (!e_data.part_prim_sh) { e_data.part_prim_sh = DRW_shader_create( - datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl, NULL); + datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, NULL); } if (!e_data.part_axis_sh) { e_data.part_axis_sh = DRW_shader_create( - datatoc_object_particle_prim_vert_glsl, NULL, datatoc_object_particle_prim_frag_glsl, + datatoc_object_particle_prim_vert_glsl, NULL, datatoc_gpu_shader_flat_color_frag_glsl, "#define USE_AXIS\n"); } @@ -540,6 +564,9 @@ static void OBJECT_engine_init(void *vedata) static void OBJECT_engine_free(void) { + MEM_SAFE_FREE(e_data.particle_format); + MEM_SAFE_FREE(e_data.empty_image_format); + MEM_SAFE_FREE(e_data.empty_image_wire_format); DRW_SHADER_FREE_SAFE(e_data.outline_resolve_sh); DRW_SHADER_FREE_SAFE(e_data.outline_resolve_aa_sh); DRW_SHADER_FREE_SAFE(e_data.outline_detect_sh); @@ -570,6 +597,15 @@ static DRWShadingGroup *shgroup_wire(DRWPass *pass, const float col[4], GPUShade return grp; } +/* currently same as 'shgroup_outline', new function to avoid confustion */ +static DRWShadingGroup *shgroup_points(DRWPass *pass, const float col[4], GPUShader *sh) +{ + DRWShadingGroup *grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_vec4(grp, "color", col, 1); + + return grp; +} + static DRWShadingGroup *shgroup_theme_id_to_outline_or( OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback) { @@ -604,6 +640,23 @@ static DRWShadingGroup *shgroup_theme_id_to_wire_or( } } +static DRWShadingGroup *shgroup_theme_id_to_point_or( + OBJECT_StorageList *stl, int theme_id, DRWShadingGroup *fallback) +{ + switch (theme_id) { + case TH_ACTIVE: + return stl->g_data->points_active; + case TH_SELECT: + return stl->g_data->points_select; + case TH_GROUP_ACTIVE: + return stl->g_data->points_select_group; + case TH_TRANSFORM: + return stl->g_data->points_transform; + default: + return fallback; + } +} + static void image_calc_aspect(Image *ima, ImageUser *iuser, float r_image_aspect[2]) { float ima_x, ima_y; @@ -672,14 +725,16 @@ static void DRW_shgroup_empty_image( image_calc_aspect(ob->data, ob->iuser, empty_image_data->image_aspect); if (tex) { + DRW_shgroup_instance_format(e_data.empty_image_format, { + {"objectColor" , DRW_ATTRIB_FLOAT, 4}, + {"size" , DRW_ATTRIB_FLOAT, 1}, + {"offset" , DRW_ATTRIB_FLOAT, 2}, + {"InstanceModelMatrix" , DRW_ATTRIB_FLOAT, 16}, + }); + struct Gwn_Batch *geom = DRW_cache_image_plane_get(); DRWShadingGroup *grp = DRW_shgroup_instance_create( - e_data.object_empty_image_sh, psl->non_meshes, geom); - DRW_shgroup_attrib_float(grp, "objectColor", 4); - DRW_shgroup_attrib_float(grp, "size", 1); - DRW_shgroup_attrib_float(grp, "offset", 2); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); - + e_data.object_empty_image_sh, psl->non_meshes, geom, e_data.empty_image_format); DRW_shgroup_uniform_texture(grp, "image", tex); DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1); @@ -690,14 +745,16 @@ static void DRW_shgroup_empty_image( } { + DRW_shgroup_instance_format(e_data.empty_image_wire_format, { + {"objectColor" , DRW_ATTRIB_FLOAT, 4}, + {"size" , DRW_ATTRIB_FLOAT, 1}, + {"offset" , DRW_ATTRIB_FLOAT, 2}, + {"InstanceModelMatrix" , DRW_ATTRIB_FLOAT, 16} + }); + struct Gwn_Batch *geom = DRW_cache_image_plane_wire_get(); DRWShadingGroup *grp = DRW_shgroup_instance_create( - e_data.object_empty_image_wire_sh, psl->non_meshes, geom); - DRW_shgroup_attrib_float(grp, "color", 3); - DRW_shgroup_attrib_float(grp, "size", 1); - DRW_shgroup_attrib_float(grp, "offset", 2); - DRW_shgroup_attrib_float(grp, "InstanceModelMatrix", 16); - + e_data.object_empty_image_wire_sh, psl->non_meshes, geom, e_data.empty_image_wire_format); DRW_shgroup_uniform_vec2(grp, "aspect", empty_image_data->image_aspect, 1); empty_image_data->shgrp_wire = grp; @@ -774,23 +831,23 @@ static void OBJECT_cache_init(void *vedata) psl->outlines_search = DRW_pass_create("Outlines Detect Pass", state); DRWShadingGroup *grp = DRW_shgroup_create(e_data.outline_detect_sh, psl->outlines_search); - DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_color_tx); - DRW_shgroup_uniform_buffer(grp, "outlineDepth", &e_data.outlines_depth_tx); - DRW_shgroup_uniform_buffer(grp, "sceneDepth", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_color_tx); + DRW_shgroup_uniform_texture_ref(grp, "outlineDepth", &e_data.outlines_depth_tx); + DRW_shgroup_uniform_texture_ref(grp, "sceneDepth", &dtxl->depth); DRW_shgroup_uniform_float(grp, "alphaOcclu", &alphaOcclu, 1); DRW_shgroup_call_add(grp, quad, NULL); psl->outlines_expand = DRW_pass_create("Outlines Expand Pass", state); grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_expand); - DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_blur_tx); + DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_blur_tx); DRW_shgroup_uniform_bool(grp, "doExpand", &bTrue, 1); DRW_shgroup_call_add(grp, quad, NULL); psl->outlines_bleed = DRW_pass_create("Outlines Bleed Pass", state); grp = DRW_shgroup_create(e_data.outline_fade_sh, psl->outlines_bleed); - DRW_shgroup_uniform_buffer(grp, "outlineColor", &e_data.outlines_color_tx); + DRW_shgroup_uniform_texture_ref(grp, "outlineColor", &e_data.outlines_color_tx); DRW_shgroup_uniform_bool(grp, "doExpand", &bFalse, 1); DRW_shgroup_call_add(grp, quad, NULL); } @@ -802,7 +859,7 @@ static void OBJECT_cache_init(void *vedata) struct Gwn_Batch *quad = DRW_cache_fullscreen_quad_get(); DRWShadingGroup *grp = DRW_shgroup_create(e_data.outline_resolve_aa_sh, psl->outlines_resolve); - DRW_shgroup_uniform_buffer(grp, "outlineBluredColor", &e_data.outlines_blur_tx); + DRW_shgroup_uniform_texture_ref(grp, "outlineBluredColor", &e_data.outlines_blur_tx); DRW_shgroup_uniform_vec2(grp, "rcpDimensions", e_data.inv_viewport_size, 1); DRW_shgroup_call_add(grp, quad, NULL); } @@ -827,7 +884,7 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_uniform_float(grp, "gridOneOverLogSubdiv", &e_data.grid_settings[4], 1); DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo); DRW_shgroup_uniform_vec2(grp, "viewportSize", DRW_viewport_size_get(), 1); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_call_add(grp, quad, mat); grp = DRW_shgroup_create(e_data.grid_sh, psl->grid); @@ -835,7 +892,7 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.grid_normal, 1); DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.grid_axes, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_call_add(grp, quad, mat); grp = DRW_shgroup_create(e_data.grid_sh, psl->grid); @@ -843,7 +900,7 @@ static void OBJECT_cache_init(void *vedata) DRW_shgroup_uniform_vec3(grp, "planeNormal", e_data.zplane_normal, 1); DRW_shgroup_uniform_vec3(grp, "planeAxes", e_data.zplane_axes, 1); DRW_shgroup_uniform_block(grp, "globalsBlock", globals_ubo); - DRW_shgroup_uniform_buffer(grp, "depthBuffer", &dtxl->depth); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); DRW_shgroup_call_add(grp, quad, mat); } @@ -976,11 +1033,30 @@ static void OBJECT_cache_init(void *vedata) stl->g_data->wire_active_group = shgroup_wire(psl->non_meshes, ts.colorGroupActive, sh); } + + { + GPUShader *sh = GPU_shader_get_builtin_shader(GPU_SHADER_3D_POINT_FIXED_SIZE_UNIFORM_COLOR); + + /* Unselected */ + stl->g_data->points = shgroup_points(psl->non_meshes, ts.colorWire, sh); + + /* Select */ + stl->g_data->points_select = shgroup_points(psl->non_meshes, ts.colorSelect, sh); + stl->g_data->points_select_group = shgroup_points(psl->non_meshes, ts.colorGroupActive, sh); + + /* Transform */ + stl->g_data->points_transform = shgroup_points(psl->non_meshes, ts.colorTransform, sh); + + /* Active */ + stl->g_data->points_active = shgroup_points(psl->non_meshes, ts.colorActive, sh); + stl->g_data->points_active_group = shgroup_points(psl->non_meshes, ts.colorGroupActive, sh); + } + { - /* Metaballs Helpers */ + /* Metaballs Handles */ struct Gwn_Batch *geom; geom = DRW_cache_screenspace_circle_get(); - stl->g_data->mball_circle = shgroup_instance_mball_helpers(psl->non_meshes, geom); + stl->g_data->mball_handle = shgroup_instance_mball_handles(psl->non_meshes, geom); } { @@ -1130,7 +1206,7 @@ static void OBJECT_cache_init(void *vedata) } } -static void DRW_shgroup_mball_helpers(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer) +static void DRW_shgroup_mball_handles(OBJECT_StorageList *stl, Object *ob, ViewLayer *view_layer) { MetaBall *mb = ob->data; @@ -1139,8 +1215,8 @@ static void DRW_shgroup_mball_helpers(OBJECT_StorageList *stl, Object *ob, ViewL for (MetaElem *ml = mb->elems.first; ml != NULL; ml = ml->next) { /* draw radius */ - BKE_mball_element_calc_display_m3x4(ml->draw_scale_xform, ob->obmat, &ml->x); - DRW_shgroup_call_dynamic_add(stl->g_data->mball_circle, ml->draw_scale_xform, &ml->rad, color); + BKE_mball_element_calc_scale_xform(ml->draw_scale_xform, ob->obmat, &ml->x); + DRW_shgroup_call_dynamic_add(stl->g_data->mball_handle, ml->draw_scale_xform, &ml->rad, color); } } @@ -1151,15 +1227,22 @@ static void DRW_shgroup_lamp(OBJECT_StorageList *stl, Object *ob, ViewLayer *vie int theme_id = DRW_object_wire_theme_get(ob, view_layer, &color); static float zero = 0.0f; - float **la_mats = (float **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL); - if (*la_mats == NULL) { - /* we need 2 matrices */ - *la_mats = MEM_mallocN(sizeof(float) * 16 * 2, "Lamp Object Mode Matrices"); - } + typedef struct LampEngineData { + ObjectEngineData engine_data; + float shape_mat[4][4]; + float spot_blend_mat[4][4]; + } LampEngineData; - float (*shapemat)[4], (*spotblendmat)[4]; - shapemat = (float (*)[4])(*la_mats); - spotblendmat = (float (*)[4])(*la_mats + 16); + LampEngineData *lamp_engine_data = + (LampEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_object_type, + sizeof(LampEngineData), + NULL, + NULL); + + float (*shapemat)[4] = lamp_engine_data->shape_mat; + float (*spotblendmat)[4] = lamp_engine_data->spot_blend_mat; /* Don't draw the center if it's selected or active */ if (theme_id == TH_GROUP) @@ -1257,7 +1340,8 @@ static void DRW_shgroup_camera(OBJECT_StorageList *stl, Object *ob, ViewLayer *v RegionView3D *rv3d = draw_ctx->rv3d; Camera *cam = ob->data; - const bool is_active = (ob == v3d->camera); + const Object *camera_object = DEG_get_evaluated_object(draw_ctx->depsgraph, v3d->camera); + const bool is_active = (ob == camera_object); const bool look_through = (is_active && (rv3d->persp == RV3D_CAMOB)); float *color; DRW_object_wire_theme_get(ob, view_layer, &color); @@ -1491,6 +1575,8 @@ static void DRW_shgroup_speaker(OBJECT_StorageList *stl, Object *ob, ViewLayer * } typedef struct OBJECT_LightProbeEngineData { + ObjectEngineData engine_data; + float prb_mats[6][4][4]; float probe_cube_mat[4][4]; float draw_size; @@ -1498,6 +1584,7 @@ typedef struct OBJECT_LightProbeEngineData { float increment_y[3]; float increment_z[3]; float corner[3]; + unsigned int cell_count; } OBJECT_LightProbeEngineData; static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl, Object *ob, ViewLayer *view_layer) @@ -1508,13 +1595,13 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0); DRW_object_wire_theme_get(ob, view_layer, &color); - OBJECT_LightProbeEngineData *prb_data; - OBJECT_LightProbeEngineData **prb_data_pt = (OBJECT_LightProbeEngineData **)DRW_object_engine_data_ensure(ob, &draw_engine_object_type, NULL); - if (*prb_data_pt == NULL) { - *prb_data_pt = MEM_mallocN(sizeof(OBJECT_LightProbeEngineData), "Probe Clip distances Matrices"); - } - - prb_data = *prb_data_pt; + OBJECT_LightProbeEngineData *prb_data = + (OBJECT_LightProbeEngineData *)DRW_object_engine_data_ensure( + ob, + &draw_engine_object_type, + sizeof(OBJECT_LightProbeEngineData), + NULL, + NULL); if ((DRW_state_is_select() || do_outlines) && ((prb->flag & LIGHTPROBE_FLAG_SHOW_DATA) != 0)) { @@ -1551,8 +1638,8 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl mul_m4_v3(ob->obmat, prb_data->increment_z); sub_v3_v3(prb_data->increment_z, prb_data->corner); - DRWShadingGroup *grp = DRW_shgroup_instance_create(e_data.lightprobe_grid_sh, psl->lightprobes, DRW_cache_sphere_get()); - DRW_shgroup_set_instance_count(grp, prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z); + prb_data->cell_count = prb->grid_resolution_x * prb->grid_resolution_y * prb->grid_resolution_z; + DRWShadingGroup *grp = DRW_shgroup_create(e_data.lightprobe_grid_sh, psl->lightprobes); DRW_shgroup_uniform_vec4(grp, "color", color, 1); DRW_shgroup_uniform_vec3(grp, "corner", prb_data->corner, 1); DRW_shgroup_uniform_vec3(grp, "increment_x", prb_data->increment_x, 1); @@ -1560,6 +1647,7 @@ static void DRW_shgroup_lightprobe(OBJECT_StorageList *stl, OBJECT_PassList *psl DRW_shgroup_uniform_vec3(grp, "increment_z", prb_data->increment_z, 1); DRW_shgroup_uniform_ivec3(grp, "grid_resolution", &prb->grid_resolution_x, 1); DRW_shgroup_uniform_float(grp, "sphere_size", &prb->data_draw_size, 1); + DRW_shgroup_call_instances_add(grp, DRW_cache_sphere_get(), NULL, &prb_data->cell_count); } else if (prb->type == LIGHTPROBE_TYPE_CUBE) { prb_data->draw_size = prb->data_draw_size * 0.1f; @@ -1751,12 +1839,15 @@ static void OBJECT_cache_populate_particles(Object *ob, unit_m4(mat); if (draw_as != PART_DRAW_PATH) { - struct Gwn_Batch *geom = DRW_cache_particles_get_dots(psys); + struct Gwn_Batch *geom = DRW_cache_particles_get_dots(ob, psys); DRWShadingGroup *shgrp = NULL; static int screen_space[2] = {0, 1}; static float def_prim_col[3] = {0.5f, 0.5f, 0.5f}; static float def_sec_col[3] = {1.0f, 1.0f, 1.0f}; + /* Dummy particle format for instancing to work. */ + DRW_shgroup_instance_format(e_data.particle_format, {{"dummy", DRW_ATTRIB_FLOAT, 1}}); + Material *ma = give_current_material(ob, part->omat); switch (draw_as) { @@ -1771,21 +1862,24 @@ static void OBJECT_cache_populate_particles(Object *ob, break; case PART_DRAW_CROSS: shgrp = DRW_shgroup_instance_create( - e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CROSS)); + e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CROSS), + e_data.particle_format); DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp); DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1); DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1); break; case PART_DRAW_CIRC: shgrp = DRW_shgroup_instance_create( - e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CIRC)); + e_data.part_prim_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_CIRC), + e_data.particle_format); DRW_shgroup_uniform_texture(shgrp, "ramp", globals_ramp); DRW_shgroup_uniform_vec3(shgrp, "color", ma ? &ma->r : def_prim_col, 1); DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[1], 1); break; case PART_DRAW_AXIS: shgrp = DRW_shgroup_instance_create( - e_data.part_axis_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_AXIS)); + e_data.part_axis_sh, psl->particle, DRW_cache_particles_get_prim(PART_DRAW_AXIS), + e_data.particle_format); DRW_shgroup_uniform_int(shgrp, "screen_space", &screen_space[0], 1); break; default: @@ -1808,7 +1902,6 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) OBJECT_PassList *psl = ((OBJECT_Data *)vedata)->psl; OBJECT_StorageList *stl = ((OBJECT_Data *)vedata)->stl; const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; ViewLayer *view_layer = draw_ctx->view_layer; View3D *v3d = draw_ctx->v3d; int theme_id = TH_UNDEFINED; @@ -1828,14 +1921,13 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) bool do_outlines = ((ob->base_flag & BASE_SELECTED) != 0); if (do_outlines) { - Object *obedit = scene->obedit; - if (ob != obedit && !((ob == draw_ctx->obact) && (ob->mode & OB_MODE_ALL_PAINT))) { + if ((ob != draw_ctx->object_edit) && !((ob == draw_ctx->obact) && (draw_ctx->object_mode & OB_MODE_ALL_PAINT))) { struct Gwn_Batch *geom = DRW_cache_object_surface_get(ob); if (geom) { theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); DRWShadingGroup *shgroup = shgroup_theme_id_to_outline_or(stl, theme_id, NULL); if (shgroup != NULL) { - DRW_shgroup_call_add(shgroup, geom, ob->obmat); + DRW_shgroup_call_object_add(shgroup, geom, ob); } } } @@ -1844,18 +1936,30 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) switch (ob->type) { case OB_MESH: { - Mesh *me = ob->data; - if (me->totpoly == 0) { - Object *obedit = scene->obedit; - if (ob != obedit) { - struct Gwn_Batch *geom = DRW_cache_mesh_edges_get(ob); - if (geom) { - if (theme_id == TH_UNDEFINED) { - theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + if (ob != draw_ctx->object_edit) { + Mesh *me = ob->data; + if (me->totpoly == 0) { + if (me->totedge == 0) { + struct Gwn_Batch *geom = DRW_cache_mesh_verts_get(ob); + if (geom) { + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + + DRWShadingGroup *shgroup = shgroup_theme_id_to_point_or(stl, theme_id, stl->g_data->points); + DRW_shgroup_call_object_add(shgroup, geom, ob); + } + } + else { + struct Gwn_Batch *geom = DRW_cache_mesh_edges_get(ob); + if (geom) { + if (theme_id == TH_UNDEFINED) { + theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); + } + + DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire); + DRW_shgroup_call_object_add(shgroup, geom, ob); } - - DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire); - DRW_shgroup_call_add(shgroup, geom, ob->obmat); } } } @@ -1865,44 +1969,40 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) break; case OB_LATTICE: { - Object *obedit = scene->obedit; - if (ob != obedit) { + if (ob != draw_ctx->object_edit) { struct Gwn_Batch *geom = DRW_cache_lattice_wire_get(ob, false); if (theme_id == TH_UNDEFINED) { theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); } DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire); - DRW_shgroup_call_add(shgroup, geom, ob->obmat); + DRW_shgroup_call_object_add(shgroup, geom, ob); } break; } case OB_CURVE: { - Object *obedit = scene->obedit; - if (ob != obedit) { + if (ob != draw_ctx->object_edit) { struct Gwn_Batch *geom = DRW_cache_curve_edge_wire_get(ob); if (theme_id == TH_UNDEFINED) { theme_id = DRW_object_wire_theme_get(ob, view_layer, NULL); } DRWShadingGroup *shgroup = shgroup_theme_id_to_wire_or(stl, theme_id, stl->g_data->wire); - DRW_shgroup_call_add(shgroup, geom, ob->obmat); + DRW_shgroup_call_object_add(shgroup, geom, ob); } break; } case OB_MBALL: { - Object *obedit = scene->obedit; - if (ob != obedit) { - DRW_shgroup_mball_helpers(stl, ob, view_layer); + if (ob != draw_ctx->object_edit) { + DRW_shgroup_mball_handles(stl, ob, view_layer); } break; } case OB_GROOM: { - Object *obedit = scene->obedit; - if (ob != obedit) { + if (ob != draw_ctx->object_edit) { Groom *groom = ob->data; struct Gwn_Batch *geom = DRW_cache_groom_wire_get(ob); if (theme_id == TH_UNDEFINED) { @@ -1956,7 +2056,7 @@ static void OBJECT_cache_populate(void *vedata, Object *ob) { FurModifierData *fmd = (FurModifierData*)md; - if (!modifier_isEnabled(scene, md, eModifierMode_Realtime)) + if (!modifier_isEnabled(draw_ctx->scene, md, eModifierMode_Realtime)) { continue; } @@ -2008,38 +2108,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()) { @@ -2064,9 +2153,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 */ @@ -2102,4 +2191,5 @@ DrawEngineType draw_engine_object_type = { NULL, &OBJECT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/paint_texture_mode.c b/source/blender/draw/modes/paint_texture_mode.c index b49da0cba2f..2a5eabd08fa 100644 --- a/source/blender/draw/modes/paint_texture_mode.c +++ b/source/blender/draw/modes/paint_texture_mode.c @@ -414,4 +414,5 @@ DrawEngineType draw_engine_paint_texture_type = { NULL, /* draw_background but not needed by mode engines */ &PAINT_TEXTURE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/paint_vertex_mode.c b/source/blender/draw/modes/paint_vertex_mode.c index e430fca5742..835fefdee26 100644 --- a/source/blender/draw/modes/paint_vertex_mode.c +++ b/source/blender/draw/modes/paint_vertex_mode.c @@ -213,4 +213,5 @@ DrawEngineType draw_engine_paint_vertex_type = { NULL, &PAINT_VERTEX_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/paint_weight_mode.c b/source/blender/draw/modes/paint_weight_mode.c index e139b4af97f..3cc2ad63ed4 100644 --- a/source/blender/draw/modes/paint_weight_mode.c +++ b/source/blender/draw/modes/paint_weight_mode.c @@ -251,4 +251,5 @@ DrawEngineType draw_engine_paint_weight_type = { NULL, &PAINT_WEIGHT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/particle_mode.c b/source/blender/draw/modes/particle_mode.c index 6a3e53a72c2..f92505a8778 100644 --- a/source/blender/draw/modes/particle_mode.c +++ b/source/blender/draw/modes/particle_mode.c @@ -200,7 +200,7 @@ static void PARTICLE_draw_scene(void *vedata) DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - UNUSED_VARS(fbl, dfbl, dtxl); + UNUSED_VARS(fbl, dfbl, dtxl, psl); /* Show / hide entire passes, swap framebuffers ... whatever you fancy */ /* @@ -212,7 +212,7 @@ static void PARTICLE_draw_scene(void *vedata) */ /* ... or just render passes on default framebuffer. */ - DRW_draw_pass(psl->pass); + //DRW_draw_pass(psl->pass); /* If you changed framebuffer, double check you rebind * the default one with its textures attached before finishing */ @@ -261,4 +261,5 @@ DrawEngineType draw_engine_particle_type = { NULL, /* draw_background but not needed by mode engines */ &PARTICLE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/pose_mode.c b/source/blender/draw/modes/pose_mode.c index 1c2acd56085..749c3e71368 100644 --- a/source/blender/draw/modes/pose_mode.c +++ b/source/blender/draw/modes/pose_mode.c @@ -136,14 +136,16 @@ static void POSE_cache_populate(void *vedata, Object *ob) */ bool DRW_pose_mode_armature(Object *ob, Object *active_ob) { + const DRWContextState *draw_ctx = DRW_context_state_get(); + /* Pode armature is handled by pose mode engine. */ - if ((ob == active_ob) && ((ob->mode & OB_MODE_POSE) != 0)) { + if ((ob == active_ob) && ((draw_ctx->object_mode & OB_MODE_POSE) != 0)) { return true; } /* Armature parent is also handled by pose mode engine. */ - if ((active_ob != NULL) && ((active_ob->mode & OB_MODE_WEIGHT_PAINT) != 0)) { - if (active_ob->parent == ob) { + if ((active_ob != NULL) && ((draw_ctx->object_mode & OB_MODE_WEIGHT_PAINT) != 0)) { + if (ob == draw_ctx->object_pose) { return true; } } @@ -195,4 +197,5 @@ DrawEngineType draw_engine_pose_type = { NULL, &POSE_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/sculpt_mode.c b/source/blender/draw/modes/sculpt_mode.c index d9f1f5ebe91..65f4653591f 100644 --- a/source/blender/draw/modes/sculpt_mode.c +++ b/source/blender/draw/modes/sculpt_mode.c @@ -193,12 +193,8 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) if (ob->type == OB_MESH) { const DRWContextState *draw_ctx = DRW_context_state_get(); - EvaluationContext eval_ctx; - - CTX_data_eval_ctx(draw_ctx->evil_C, &eval_ctx); if (ob->sculpt && (ob == draw_ctx->obact)) { - /* XXX, needed for dyntopo-undo (which clears). * probably depsgraph should handlle? in 2.7x getting derived-mesh does this (mesh_build_data) */ if (ob->sculpt->pbvh == NULL) { @@ -206,7 +202,7 @@ static void SCULPT_cache_populate(void *vedata, Object *ob) * but this avoids waiting on first stroke) */ Scene *scene = draw_ctx->scene; - BKE_sculpt_update_mesh_elements(&eval_ctx, scene, scene->toolsettings->sculpt, ob, false, false); + BKE_sculpt_update_mesh_elements(&draw_ctx->eval_ctx, scene, scene->toolsettings->sculpt, ob, false, false); } PBVH *pbvh = ob->sculpt->pbvh; @@ -302,4 +298,5 @@ DrawEngineType draw_engine_sculpt_type = { NULL, /* draw_background but not needed by mode engines */ &SCULPT_draw_scene, NULL, + NULL, }; diff --git a/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl new file mode 100644 index 00000000000..fc5cc1cdcc3 --- /dev/null +++ b/source/blender/draw/modes/shaders/common_fullscreen_vert.glsl @@ -0,0 +1,10 @@ + +in vec2 pos; +in vec2 uvs; +out vec4 uvcoordsvar; + +void main() +{ + uvcoordsvar = vec4(uvs, 0.0, 0.0); + gl_Position = vec4(pos, 0.0, 1.0); +} diff --git a/source/blender/draw/modes/shaders/common_view_lib.glsl b/source/blender/draw/modes/shaders/common_view_lib.glsl new file mode 100644 index 00000000000..d261d263a6f --- /dev/null +++ b/source/blender/draw/modes/shaders/common_view_lib.glsl @@ -0,0 +1,14 @@ +/* keep in sync with DRWManager.view_data */ +layout(std140) uniform viewBlock { + /* Same order as DRWViewportMatrixType */ + mat4 ViewProjectionMatrix; + mat4 ViewProjectionMatrixInverse; + mat4 ViewMatrix; + mat4 ViewMatrixInverse; + mat4 ProjectionMatrix; + mat4 ProjectionMatrixInverse; + + vec4 CameraTexCoFactors; + + vec4 clipPlanes[2]; +}; diff --git a/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl b/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl deleted file mode 100644 index aa455a85cf0..00000000000 --- a/source/blender/draw/modes/shaders/object_particle_prim_frag.glsl +++ /dev/null @@ -1,9 +0,0 @@ - -flat in vec4 finalColor; - -out vec4 fragColor; - -void main() -{ - fragColor = finalColor; -} |