Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/draw')
-rw-r--r--source/blender/draw/CMakeLists.txt14
-rw-r--r--source/blender/draw/DRW_engine.h24
-rw-r--r--source/blender/draw/engines/basic/basic_engine.c59
-rw-r--r--source/blender/draw/engines/clay/clay_engine.c529
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_copy.glsl10
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_frag.glsl81
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_fxaa.glsl18
-rw-r--r--source/blender/draw/engines/clay/shaders/clay_prepass_frag.glsl44
-rw-r--r--source/blender/draw/engines/clay/shaders/ssao_alchemy.glsl6
-rw-r--r--source/blender/draw/engines/eevee/eevee_bloom.c95
-rw-r--r--source/blender/draw/engines/eevee/eevee_data.c103
-rw-r--r--source/blender/draw/engines/eevee/eevee_depth_of_field.c120
-rw-r--r--source/blender/draw/engines/eevee/eevee_effects.c217
-rw-r--r--source/blender/draw/engines/eevee/eevee_engine.c221
-rw-r--r--source/blender/draw/engines/eevee/eevee_lightprobes.c670
-rw-r--r--source/blender/draw/engines/eevee/eevee_lights.c381
-rw-r--r--source/blender/draw/engines/eevee/eevee_materials.c376
-rw-r--r--source/blender/draw/engines/eevee/eevee_mist.c139
-rw-r--r--source/blender/draw/engines/eevee/eevee_motion_blur.c50
-rw-r--r--source/blender/draw/engines/eevee/eevee_occlusion.c129
-rw-r--r--source/blender/draw/engines/eevee/eevee_private.h208
-rw-r--r--source/blender/draw/engines/eevee/eevee_render.c562
-rw-r--r--source/blender/draw/engines/eevee/eevee_screen_raytrace.c114
-rw-r--r--source/blender/draw/engines/eevee/eevee_subsurface.c254
-rw-r--r--source/blender/draw/engines/eevee/eevee_temporal_sampling.c154
-rw-r--r--source/blender/draw/engines/eevee/eevee_volumes.c155
-rw-r--r--source/blender/draw/engines/eevee/shaders/bsdf_common_lib.glsl176
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_gtao_frag.glsl3
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_minmaxz_frag.glsl9
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_mist_frag.glsl31
-rw-r--r--source/blender/draw/engines/eevee/shaders/effect_subsurface_frag.glsl18
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_grid_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_frag.glsl1
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_display_vert.glsl2
-rw-r--r--source/blender/draw/engines/eevee/shaders/lightprobe_planar_downsample_geom.glsl6
-rw-r--r--source/blender/draw/engines/eevee/shaders/lit_surface_vert.glsl5
-rw-r--r--source/blender/draw/engines/eevee/shaders/prepass_vert.glsl10
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_store_frag.glsl145
-rw-r--r--source/blender/draw/engines/eevee/shaders/shadow_vert.glsl4
-rw-r--r--source/blender/draw/engines/external/external_engine.c1
-rw-r--r--source/blender/draw/intern/DRW_render.h169
-rw-r--r--source/blender/draw/intern/draw_armature.c4
-rw-r--r--source/blender/draw/intern/draw_cache.c118
-rw-r--r--source/blender/draw/intern/draw_cache.h5
-rw-r--r--source/blender/draw/intern/draw_cache_impl.h2
-rw-r--r--source/blender/draw/intern/draw_cache_impl_mesh.c59
-rw-r--r--source/blender/draw/intern/draw_cache_impl_particles.c494
-rw-r--r--source/blender/draw/intern/draw_common.c187
-rw-r--r--source/blender/draw/intern/draw_common.h6
-rw-r--r--source/blender/draw/intern/draw_hair.c2
-rw-r--r--source/blender/draw/intern/draw_instance_data.c249
-rw-r--r--source/blender/draw/intern/draw_instance_data.h19
-rw-r--r--source/blender/draw/intern/draw_manager.c3236
-rw-r--r--source/blender/draw/intern/draw_manager.h358
-rw-r--r--source/blender/draw/intern/draw_manager_data.c935
-rw-r--r--source/blender/draw/intern/draw_manager_exec.c1170
-rw-r--r--source/blender/draw/intern/draw_manager_profiling.c135
-rw-r--r--source/blender/draw/intern/draw_manager_shader.c387
-rw-r--r--source/blender/draw/intern/draw_manager_texture.c237
-rw-r--r--source/blender/draw/intern/draw_view.c73
-rw-r--r--source/blender/draw/modes/edit_armature_mode.c1
-rw-r--r--source/blender/draw/modes/edit_curve_mode.c4
-rw-r--r--source/blender/draw/modes/edit_groom_mode.c2
-rw-r--r--source/blender/draw/modes/edit_lattice_mode.c5
-rw-r--r--source/blender/draw/modes/edit_mesh_mode.c49
-rw-r--r--source/blender/draw/modes/edit_metaball_mode.c17
-rw-r--r--source/blender/draw/modes/edit_surface_mode.c1
-rw-r--r--source/blender/draw/modes/edit_text_mode.c5
-rw-r--r--source/blender/draw/modes/object_mode.c322
-rw-r--r--source/blender/draw/modes/paint_texture_mode.c1
-rw-r--r--source/blender/draw/modes/paint_vertex_mode.c1
-rw-r--r--source/blender/draw/modes/paint_weight_mode.c1
-rw-r--r--source/blender/draw/modes/particle_mode.c5
-rw-r--r--source/blender/draw/modes/pose_mode.c9
-rw-r--r--source/blender/draw/modes/sculpt_mode.c7
-rw-r--r--source/blender/draw/modes/shaders/common_fullscreen_vert.glsl10
-rw-r--r--source/blender/draw/modes/shaders/common_view_lib.glsl14
-rw-r--r--source/blender/draw/modes/shaders/object_particle_prim_frag.glsl9
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 = &half;
- }
+ 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 = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ 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 = &half;
+ *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 = &half;
+ break;
+ }
+ case GPU_MAT_FAILED:
+ default:
+ color_p = error_col;
+ metal_p = spec_p = rough_p = &half;
+ 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(&params);
- /* 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(&params, draw_ctx->depsgraph, v3d, rv3d);
+ BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
+ }
+ else {
BKE_camera_params_from_object(&params, &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(&params, scene->r.xsch, scene->r.ysch, scene->r.xasp, scene->r.yasp);
}
- BKE_camera_params_compute_viewplane(&params, ar->winx, ar->winy, 1.0f, 1.0f);
BKE_camera_params_compute_matrix(&params);
/* 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;
-}