diff options
author | Julian Eisel <julian@blender.org> | 2020-03-12 17:58:03 +0300 |
---|---|---|
committer | Julian Eisel <julian@blender.org> | 2020-03-12 17:58:03 +0300 |
commit | b86be9b2145458037fd0b17433b7af0efa7b6472 (patch) | |
tree | f333625555402992ebb35d258f93eda1130389e6 /source/blender | |
parent | 00f83ec125207e90bf180b3eb7752d8cb6482a86 (diff) | |
parent | cb6cec904fa14ce0ab10a2a53af5c936d56376cf (diff) |
Merge branch 'temp-openxr-ghostxr' into temp-openxr-blenderside
Diffstat (limited to 'source/blender')
210 files changed, 6747 insertions, 6740 deletions
diff --git a/source/blender/blendthumb/CMakeLists.txt b/source/blender/blendthumb/CMakeLists.txt index 6c786dfcc7a..0b1ce5149da 100644 --- a/source/blender/blendthumb/CMakeLists.txt +++ b/source/blender/blendthumb/CMakeLists.txt @@ -28,6 +28,8 @@ set(SRC src/Dll.cpp ) +set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "${CMAKE_SHARED_LINKER_FLAGS_DEBUG} /nodefaultlib:MSVCRT.lib") + add_library(BlendThumb SHARED ${SRC}) target_link_libraries(BlendThumb ${ZLIB_LIBRARIES}) diff --git a/source/blender/blendthumb/src/Dll.cpp b/source/blender/blendthumb/src/Dll.cpp index 08b3d253be8..fec792ebfeb 100644 --- a/source/blender/blendthumb/src/Dll.cpp +++ b/source/blender/blendthumb/src/Dll.cpp @@ -159,7 +159,8 @@ struct REGISTRY_ENTRY { PCWSTR pszKeyName; PCWSTR pszValueName; DWORD dwValueType; - PCWSTR pszData; + PCWSTR pszData; // These two fields could/should have been a union, but C++ + DWORD dwData; // only lets you initalize the first field in a union. }; // Creates a registry key (if needed) and sets the default value of the key @@ -187,7 +188,7 @@ HRESULT CreateRegKeyAndSetValue(const REGISTRY_ENTRY *pRegistryEntry) break; case REG_DWORD: size = sizeof(DWORD); - data = (DWORD)pRegistryEntry->pszData; + data = pRegistryEntry->dwData; lpData = (BYTE *)&data; break; default: @@ -235,6 +236,7 @@ STDAPI DllRegisterServer() L"Software\\Classes\\.blend\\", L"Treatment", REG_DWORD, + 0, 0}, // doesn't appear to do anything... {HKEY_CURRENT_USER, L"Software\\Classes\\.blend\\ShellEx\\{e357fccd-a995-4576-b01f-234630154e96}", diff --git a/source/blender/blenfont/intern/blf.c b/source/blender/blenfont/intern/blf.c index 725c4c0712d..5664b9ae0a0 100644 --- a/source/blender/blenfont/intern/blf.c +++ b/source/blender/blenfont/intern/blf.c @@ -47,11 +47,9 @@ #include "IMB_colormanagement.h" -#ifndef BLF_STANDALONE -# include "GPU_shader.h" -# include "GPU_matrix.h" -# include "GPU_immediate.h" -#endif +#include "GPU_shader.h" +#include "GPU_matrix.h" +#include "GPU_immediate.h" #include "blf_internal_types.h" #include "blf_internal.h" diff --git a/source/blender/blenfont/intern/blf_font.c b/source/blender/blenfont/intern/blf_font.c index f0afe184233..0f75d9b5ab0 100644 --- a/source/blender/blenfont/intern/blf_font.c +++ b/source/blender/blenfont/intern/blf_font.c @@ -230,8 +230,10 @@ void blf_batch_draw(void) GPU_blend_set_func_separate( GPU_SRC_ALPHA, GPU_ONE_MINUS_SRC_ALPHA, GPU_ONE, GPU_ONE_MINUS_SRC_ALPHA); +#ifndef BLF_STANDALONE /* We need to flush widget base first to ensure correct ordering. */ UI_widgetbase_draw_cache_flush(); +#endif GPUTexture *texture = blf_batch_cache_texture_load(); GPU_texture_bind(texture, 0); diff --git a/source/blender/blenfont/intern/blf_glyph.c b/source/blender/blenfont/intern/blf_glyph.c index 3ab6814c531..3270eec58f9 100644 --- a/source/blender/blenfont/intern/blf_glyph.c +++ b/source/blender/blenfont/intern/blf_glyph.c @@ -46,10 +46,8 @@ #include "BLF_api.h" -#ifndef BLF_STANDALONE -# include "GPU_immediate.h" -# include "GPU_extensions.h" -#endif +#include "GPU_immediate.h" +#include "GPU_extensions.h" #include "blf_internal_types.h" #include "blf_internal.h" diff --git a/source/blender/blenkernel/BKE_lib_query.h b/source/blender/blenkernel/BKE_lib_query.h index b12803b1603..f3e15529f77 100644 --- a/source/blender/blenkernel/BKE_lib_query.h +++ b/source/blender/blenkernel/BKE_lib_query.h @@ -55,14 +55,14 @@ enum { IDWALK_CB_INDIRECT_USAGE = (1 << 2), /** - * That ID is used as mere sub-data by its owner - * (only case currently: those f***ing nodetrees in materials etc.). - * This means callback shall not *do* anything, - * only use this as informative data if it needs it. + * That ID is used as mere sub-data by its owner (only case currently: those root nodetrees in + * materials etc., and the Scene's master collections). + * This means callback shall not *do* anything, only use this as informative data if it needs it. */ - IDWALK_CB_PRIVATE = (1 << 3), + IDWALK_CB_EMBEDDED = (1 << 3), - /** That ID is not really used by its owner, it's just an internal hint/helper. + /** + * That ID is not really used by its owner, it's just an internal hint/helper. * This addresses Their Highest Ugliness the 'from' pointers: Object->from_proxy and Key->from. * How to handle that kind of cases totally depends on what caller code is doing... */ IDWALK_CB_LOOPBACK = (1 << 4), @@ -89,11 +89,15 @@ enum { typedef struct LibraryIDLinkCallbackData { void *user_data; - /* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a - * private one. */ + /** + * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is an + * embedded one. + */ struct ID *id_owner; - /* ID from which the current ID pointer is being processed. It may be a 'private' ID like master - * collection or root node tree. */ + /** + * ID from which the current ID pointer is being processed. It may be an embedded ID like master + * collection or root node tree. + */ struct ID *id_self; struct ID **id_pointer; int cb_flag; @@ -112,6 +116,8 @@ enum { IDWALK_READONLY = (1 << 0), IDWALK_RECURSE = (1 << 1), /* Also implies IDWALK_READONLY. */ IDWALK_INCLUDE_UI = (1 << 2), /* Include UI pointers (from WM and screens editors). */ + /** Do not process ID pointers inside embedded IDs. Needed by depsgraph processing e.g. */ + IDWALK_IGNORE_EMBEDDED_ID = (1 << 3), IDWALK_NO_INDIRECT_PROXY_DATA_USAGE = (1 << 8), /* Ugly special case :(((( */ }; diff --git a/source/blender/blenkernel/BKE_node.h b/source/blender/blenkernel/BKE_node.h index 6f1f68e1ef2..ed36d3892ac 100644 --- a/source/blender/blenkernel/BKE_node.h +++ b/source/blender/blenkernel/BKE_node.h @@ -391,9 +391,6 @@ struct bNodeTree *ntreeCopyTree_ex(const struct bNodeTree *ntree, struct Main *bmain, const bool do_id_user); struct bNodeTree *ntreeCopyTree(struct Main *bmain, const struct bNodeTree *ntree); -/* node->id user count */ -void ntreeUserIncrefID(struct bNodeTree *ntree); -void ntreeUserDecrefID(struct bNodeTree *ntree); struct bNodeTree **BKE_ntree_ptr_from_id(struct ID *id); struct bNodeTree *ntreeFromID(struct ID *id); diff --git a/source/blender/blenkernel/BKE_ocean.h b/source/blender/blenkernel/BKE_ocean.h index 3ba6486e6c5..d3ac825039d 100644 --- a/source/blender/blenkernel/BKE_ocean.h +++ b/source/blender/blenkernel/BKE_ocean.h @@ -84,6 +84,9 @@ void BKE_ocean_init(struct Ocean *o, float alignment, float depth, float time, + int spectrum, + float fetch_jonswap, + float sharpen_peak_jonswap, short do_height_field, short do_chop, short do_normals, @@ -122,6 +125,11 @@ void BKE_ocean_cache_eval_ij(struct OceanCache *och, struct OceanResult *ocr, in void BKE_ocean_free_cache(struct OceanCache *och); void BKE_ocean_free_modifier_cache(struct OceanModifierData *omd); +/* ocean_spectrum.c */ +float BLI_ocean_spectrum_piersonmoskowitz(const struct Ocean *oc, const float kx, const float kz); +float BLI_ocean_spectrum_texelmarsenarsloe(const struct Ocean *oc, const float kx, const float kz); +float BLI_ocean_spectrum_jonswap(const struct Ocean *oc, const float kx, const float kz); + #ifdef __cplusplus } #endif diff --git a/source/blender/blenkernel/BKE_scene.h b/source/blender/blenkernel/BKE_scene.h index 90e5459b599..8018178fcee 100644 --- a/source/blender/blenkernel/BKE_scene.h +++ b/source/blender/blenkernel/BKE_scene.h @@ -215,6 +215,7 @@ int BKE_scene_multiview_num_videos_get(const struct RenderData *rd); void BKE_scene_allocate_depsgraph_hash(struct Scene *scene); void BKE_scene_ensure_depsgraph_hash(struct Scene *scene); void BKE_scene_free_depsgraph_hash(struct Scene *scene); +void BKE_scene_free_view_layer_depsgraph(struct Scene *scene, struct ViewLayer *view_layer); struct Depsgraph *BKE_scene_get_depsgraph(struct Main *bmain, struct Scene *scene, diff --git a/source/blender/blenkernel/BKE_screen.h b/source/blender/blenkernel/BKE_screen.h index a6ed1274f19..2231cc36861 100644 --- a/source/blender/blenkernel/BKE_screen.h +++ b/source/blender/blenkernel/BKE_screen.h @@ -190,6 +190,8 @@ typedef struct ARegionType { /* return without drawing. * lock is set by region definition, and copied to do_lock by render. can become flag. */ short do_lock, lock; + /** Don't handle gizmos events behind #uiBlock's with #UI_BLOCK_CLIP_EVENTS flag set. */ + bool clip_gizmo_events_by_ui; /* call cursor function on each move event */ short event_cursor; } ARegionType; diff --git a/source/blender/blenkernel/BKE_shrinkwrap.h b/source/blender/blenkernel/BKE_shrinkwrap.h index 5edde7441de..83129bed5f7 100644 --- a/source/blender/blenkernel/BKE_shrinkwrap.h +++ b/source/blender/blenkernel/BKE_shrinkwrap.h @@ -170,7 +170,7 @@ void BKE_shrinkwrap_snap_point_to_surface(const struct ShrinkwrapTreeData *tree, float r_point_co[3]); /* - * NULL initializers to local data + * NULL initializes to local data */ #define NULL_ShrinkwrapCalcData \ { \ diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt index 22123f05cab..135168a6de4 100644 --- a/source/blender/blenkernel/CMakeLists.txt +++ b/source/blender/blenkernel/CMakeLists.txt @@ -178,6 +178,7 @@ set(SRC intern/object_facemap.c intern/object_update.c intern/ocean.c + intern/ocean_spectrum.c intern/outliner_treehash.c intern/packedFile.c intern/paint.c diff --git a/source/blender/blenkernel/intern/armature.c b/source/blender/blenkernel/intern/armature.c index 0580ad55e43..c23cb9231d7 100644 --- a/source/blender/blenkernel/intern/armature.c +++ b/source/blender/blenkernel/intern/armature.c @@ -1008,12 +1008,12 @@ void BKE_pchan_bbone_handles_compute(const BBoneSplineParameters *param, * - These properties allow users to hand-animate the * bone curve/shape, without having to resort to using * extra bones - * - The "bone" level offsets are for defining the restpose + * - The "bone" level offsets are for defining the rest-pose * shape of the bone (e.g. for curved eyebrows for example). * -> In the viewport, it's needed to define what the rest pose * looks like * -> For "rest == 0", we also still need to have it present - * so that we can "cancel out" this restpose when it comes + * so that we can "cancel out" this rest-pose when it comes * time to deform some geometry, it won't cause double transforms. * - The "pchan" level offsets are the ones that animators actually * end up animating diff --git a/source/blender/blenkernel/intern/brush.c b/source/blender/blenkernel/intern/brush.c index 74c492573b1..67e9feac0cf 100644 --- a/source/blender/blenkernel/intern/brush.c +++ b/source/blender/blenkernel/intern/brush.c @@ -443,7 +443,7 @@ void BKE_gpencil_brush_preset_set(Main *bmain, Brush *brush, const short type) brush->gpencil_settings->active_smooth = ACTIVE_SMOOTH; brush->gpencil_settings->draw_angle = 0.0f; brush->gpencil_settings->draw_angle_factor = 0.0f; - brush->gpencil_settings->hardeness = 0.211f; + brush->gpencil_settings->hardeness = 0.9f; copy_v2_fl(brush->gpencil_settings->aspect_ratio, 1.0f); brush->gpencil_tool = GPAINT_TOOL_DRAW; diff --git a/source/blender/blenkernel/intern/collection.c b/source/blender/blenkernel/intern/collection.c index 5c4636db728..d9954323594 100644 --- a/source/blender/blenkernel/intern/collection.c +++ b/source/blender/blenkernel/intern/collection.c @@ -89,7 +89,7 @@ static void collection_copy_data(Main *bmain, ID *id_dst, const ID *id_src, cons const Collection *collection_src = (const Collection *)id_src; BLI_assert(((collection_src->flag & COLLECTION_IS_MASTER) != 0) == - ((collection_src->id.flag & LIB_PRIVATE_DATA) != 0)); + ((collection_src->id.flag & LIB_EMBEDDED_DATA) != 0)); /* Do not copy collection's preview (same behavior as for objects). */ if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0 && false) { /* XXX TODO temp hack */ @@ -366,7 +366,7 @@ Collection *BKE_collection_duplicate(Main *bmain, const bool do_obdata) { /* It's not allowed to copy the master collection. */ - BLI_assert((collection->id.flag & LIB_PRIVATE_DATA) == 0); + BLI_assert((collection->id.flag & LIB_EMBEDDED_DATA) == 0); BLI_assert((collection->flag & COLLECTION_IS_MASTER) == 0); if (collection->flag & COLLECTION_IS_MASTER) { return NULL; @@ -514,7 +514,7 @@ Collection *BKE_collection_master_add() /* Not an actual datablock, but owned by scene. */ Collection *master_collection = MEM_callocN(sizeof(Collection), "Master Collection"); STRNCPY(master_collection->id.name, "GRMaster Collection"); - master_collection->id.flag |= LIB_PRIVATE_DATA; + master_collection->id.flag |= LIB_EMBEDDED_DATA; master_collection->flag |= COLLECTION_IS_MASTER; return master_collection; } diff --git a/source/blender/blenkernel/intern/fluid.c b/source/blender/blenkernel/intern/fluid.c index 03c9cc7d151..9919a0d7385 100644 --- a/source/blender/blenkernel/intern/fluid.c +++ b/source/blender/blenkernel/intern/fluid.c @@ -2741,7 +2741,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, } /* Optimization: Static liquid flow objects don't need emission computation after first * frame. - * TODO (sebbas): Also do not use static mode if inital velocities are enabled. */ + * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ if (mfs->type == FLUID_FLOW_TYPE_LIQUID && is_static && !is_first_frame && !use_velocity) { continue; } @@ -2961,7 +2961,7 @@ static void update_flowsfluids(struct Depsgraph *depsgraph, if (is_liquid && !is_first_frame) { /* Skip static liquid objects that are not on the first frame. - * TODO (sebbas): Also do not use static mode if inital velocities are enabled. */ + * TODO (sebbas): Also do not use static mode if initial velocities are enabled. */ if (is_static && !use_velocity) { continue; } @@ -3222,7 +3222,7 @@ static Mesh *create_liquid_geometry(FluidDomainSettings *mds, Mesh *orgmesh, Obj float cell_size_scaled[3]; /* Assign material + flags to new mesh. - * If there are no faces in original mesj, keep materials and flags unchanged. */ + * If there are no faces in original mesh, keep materials and flags unchanged. */ MPoly *mpoly; MPoly mp_example = {0}; mpoly = orgmesh->mpoly; diff --git a/source/blender/blenkernel/intern/image.c b/source/blender/blenkernel/intern/image.c index 7a697f19b8b..4220408749a 100644 --- a/source/blender/blenkernel/intern/image.c +++ b/source/blender/blenkernel/intern/image.c @@ -3023,7 +3023,7 @@ Image *BKE_image_ensure_viewer(Main *bmain, int type, const char *name) /* happens on reload, imagewindow cannot be image user when hidden*/ if (ima->id.us == 0) { - id_us_plus(&ima->id); + id_us_ensure_real(&ima->id); } return ima; diff --git a/source/blender/blenkernel/intern/lib_id.c b/source/blender/blenkernel/intern/lib_id.c index 919f249eea6..c342185d0b8 100644 --- a/source/blender/blenkernel/intern/lib_id.c +++ b/source/blender/blenkernel/intern/lib_id.c @@ -340,7 +340,7 @@ static int lib_id_expand_local_cb(LibraryIDLinkCallbackData *cb_data) ID *id_self = cb_data->id_self; ID **id_pointer = cb_data->id_pointer; int const cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } @@ -1148,7 +1148,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori ID *new_id = *r_newid; int flag = orig_flag; - const bool is_private_id_data = (id->flag & LIB_PRIVATE_DATA) != 0; + const bool is_private_id_data = (id->flag & LIB_EMBEDDED_DATA) != 0; BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || bmain != NULL); BLI_assert((flag & LIB_ID_CREATE_NO_MAIN) != 0 || (flag & LIB_ID_CREATE_NO_ALLOCATE) == 0); @@ -1167,7 +1167,7 @@ void BKE_libblock_copy_ex(Main *bmain, const ID *id, ID **r_newid, const int ori } /* The id->flag bits to copy over. */ - const int copy_idflag_mask = LIB_PRIVATE_DATA; + const int copy_idflag_mask = LIB_EMBEDDED_DATA; if ((flag & LIB_ID_CREATE_NO_ALLOCATE) != 0) { /* r_newid already contains pointer to allocated memory. */ @@ -1744,7 +1744,7 @@ static void library_make_local_copying_check(ID *id, } /* Shapekeys are considered 'private' to their owner ID here, and never tagged - * (since they cannot be linked), * so we have to switch effective parent to their owner. + * (since they cannot be linked), so we have to switch effective parent to their owner. */ if (GS(par_id->name) == ID_KE) { par_id = ((Key *)par_id)->from; diff --git a/source/blender/blenkernel/intern/lib_query.c b/source/blender/blenkernel/intern/lib_query.c index ee27d0e546d..41d938e897d 100644 --- a/source/blender/blenkernel/intern/lib_query.c +++ b/source/blender/blenkernel/intern/lib_query.c @@ -137,11 +137,15 @@ enum { typedef struct LibraryForeachIDData { Main *bmain; - /* 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a - * private one. */ + /** + * 'Real' ID, the one that might be in bmain, only differs from self_id when the later is a + * private one. + */ ID *owner_id; - /* ID from which the current ID pointer is being processed. It may be a 'private' ID like master - * collection or root node tree. */ + /** + * ID from which the current ID pointer is being processed. It may be an embedded ID like master + * collection or root node tree. + */ ID *self_id; int flag; @@ -343,8 +347,8 @@ static void library_foreach_layer_collection(LibraryForeachIDData *data, ListBas /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad * anyway... */ const int cb_flag = (lc->collection != NULL && - (lc->collection->id.flag & LIB_PRIVATE_DATA) != 0) ? - IDWALK_CB_PRIVATE : + (lc->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : IDWALK_CB_NOP; FOREACH_CALLBACK_INVOKE(data, lc->collection, cb_flag); library_foreach_layer_collection(data, &lc->layer_collections); @@ -367,8 +371,8 @@ static void library_foreach_collection(LibraryForeachIDData *data, Collection *c /* XXX This is very weak. The whole idea of keeping pointers to private IDs is very bad * anyway... */ const int cb_flag = ((parent->collection != NULL && - (parent->collection->id.flag & LIB_PRIVATE_DATA) != 0) ? - IDWALK_CB_PRIVATE : + (parent->collection->id.flag & LIB_EMBEDDED_DATA) != 0) ? + IDWALK_CB_EMBEDDED : IDWALK_CB_NOP); FOREACH_CALLBACK_INVOKE( data, parent->collection, IDWALK_CB_NEVER_SELF | IDWALK_CB_LOOPBACK | cb_flag); @@ -484,13 +488,13 @@ static void library_foreach_screen_area(LibraryForeachIDData *data, ScrArea *are FOREACH_CALLBACK_INVOKE_ID(data, snode->from, IDWALK_CB_NOP); FOREACH_CALLBACK_INVOKE( - data, snode->nodetree, is_private_nodetree ? IDWALK_CB_PRIVATE : IDWALK_CB_USER); + data, snode->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_USER); for (path = snode->treepath.first; path; path = path->next) { if (path == snode->treepath.first) { /* first nodetree in path is same as snode->nodetree */ FOREACH_CALLBACK_INVOKE( - data, path->nodetree, is_private_nodetree ? IDWALK_CB_PRIVATE : IDWALK_CB_NOP); + data, path->nodetree, is_private_nodetree ? IDWALK_CB_EMBEDDED : IDWALK_CB_NOP); } else { FOREACH_CALLBACK_INVOKE(data, path->nodetree, IDWALK_CB_USER); @@ -527,10 +531,13 @@ static void library_foreach_ID_as_subdata_link(ID **id_pp, { /* Needed e.g. for callbacks handling relationships... This call shall be absolutely readonly. */ ID *id = *id_pp; - FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_PRIVATE); + FOREACH_CALLBACK_INVOKE_ID_PP(data, id_pp, IDWALK_CB_EMBEDDED); BLI_assert(id == *id_pp); - if (flag & IDWALK_RECURSE) { + if (flag & IDWALK_IGNORE_EMBEDDED_ID) { + /* Do Nothing. */ + } + else if (flag & IDWALK_RECURSE) { /* Defer handling into main loop, recursively calling BKE_library_foreach_ID_link in * IDWALK_RECURSE case is troublesome, see T49553. */ /* XXX note that this breaks the 'owner id' thing now, we likely want to handle that @@ -583,7 +590,12 @@ static void library_foreach_ID_link(Main *bmain, for (; id != NULL; id = (flag & IDWALK_RECURSE) ? BLI_LINKSTACK_POP(data.ids_todo) : NULL) { data.self_id = id; - data.owner_id = (id->flag & LIB_PRIVATE_DATA) ? id_owner : data.self_id; + /* Note that we may call this functions sometime directly on an embedded ID, without any + * knowledge of the owner ID then. + * While not great, and that should be probably sanitized at some point, we cal live with it + * for now. */ + data.owner_id = ((id->flag & LIB_EMBEDDED_DATA) != 0 && id_owner != NULL) ? id_owner : + data.self_id; /* inherit_data is non-NULL when this function is called for some sub-data ID * (like root nodetree of a material). diff --git a/source/blender/blenkernel/intern/lib_remap.c b/source/blender/blenkernel/intern/lib_remap.c index d4b7696074a..1a22a6e6f79 100644 --- a/source/blender/blenkernel/intern/lib_remap.c +++ b/source/blender/blenkernel/intern/lib_remap.c @@ -68,7 +68,7 @@ typedef struct IDRemap { ID *old_id; ID *new_id; /** The ID in which we are replacing old_id by new_id usages. */ - ID *id; + ID *id_owner; short flag; /* 'Output' data. */ @@ -94,16 +94,21 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } + ID *id_owner = cb_data->id_owner; ID *id_self = cb_data->id_self; ID **id_p = cb_data->id_pointer; IDRemap *id_remap_data = cb_data->user_data; ID *old_id = id_remap_data->old_id; ID *new_id = id_remap_data->new_id; - ID *id = id_remap_data->id; + + /* Those asserts ensure the general sanity of ID tags regarding 'embedded' ID data (root + * nodetrees and co). */ + BLI_assert(id_owner == id_remap_data->id_owner); + BLI_assert(id_self == id_owner || (id_self->flag & LIB_EMBEDDED_DATA) != 0); if (!old_id) { /* Used to cleanup all IDs used by a specific one. */ BLI_assert(!new_id); @@ -123,9 +128,10 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) /* Note: proxy usage implies LIB_TAG_EXTERN, so on this aspect it is direct, * on the other hand since they get reset to lib data on file open/reload it is indirect too. * Edit Mode is also a 'skip direct' case. */ - const bool is_obj = (GS(id->name) == ID_OB); - const bool is_obj_proxy = (is_obj && (((Object *)id)->proxy || ((Object *)id)->proxy_group)); - const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id)); + const bool is_obj = (GS(id_owner->name) == ID_OB); + const bool is_obj_proxy = (is_obj && + (((Object *)id_owner)->proxy || ((Object *)id_owner)->proxy_group)); + const bool is_obj_editmode = (is_obj && BKE_object_is_in_editmode((Object *)id_owner)); const bool is_never_null = ((cb_flag & IDWALK_CB_NEVER_NULL) && (new_id == NULL) && (id_remap_data->flag & ID_REMAP_FORCE_NEVER_NULL_USAGE) == 0); const bool skip_reference = (id_remap_data->flag & ID_REMAP_SKIP_OVERRIDE_LIBRARY) != 0; @@ -149,19 +155,19 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) if ((id_remap_data->flag & ID_REMAP_FLAG_NEVER_NULL_USAGE) && (cb_flag & IDWALK_CB_NEVER_NULL)) { - id->tag |= LIB_TAG_DOIT; + id_owner->tag |= LIB_TAG_DOIT; } /* Special hack in case it's Object->data and we are in edit mode, and new_id is not NULL * (otherwise, we follow common NEVER_NULL flags). * (skipped_indirect too). */ if ((is_never_null && skip_never_null) || - (is_obj_editmode && (((Object *)id)->data == *id_p) && new_id != NULL) || + (is_obj_editmode && (((Object *)id_owner)->data == *id_p) && new_id != NULL) || (skip_indirect && is_indirect) || (is_reference && skip_reference)) { if (is_indirect) { id_remap_data->skipped_indirect++; if (is_obj) { - Object *ob = (Object *)id; + Object *ob = (Object *)id_owner; if (ob->data == *id_p && ob->proxy != NULL) { /* And another 'Proudly brought to you by Proxy Hell' hack! * This will allow us to avoid clearing 'LIB_EXTERN' flag of obdata of proxies... */ @@ -189,6 +195,11 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) DEG_id_tag_update_ex(id_remap_data->bmain, id_self, ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + if (id_self != id_owner) { + DEG_id_tag_update_ex(id_remap_data->bmain, + id_owner, + ID_RECALC_COPY_ON_WRITE | ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY); + } } if (cb_flag & IDWALK_CB_USER) { /* NOTE: We don't user-count IDs which are not in the main database. @@ -215,7 +226,7 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) } /* We need to remap proxy_from pointer of remapped proxy... sigh. */ if (is_obj_proxy && new_id != NULL) { - Object *ob = (Object *)id; + Object *ob = (Object *)id_owner; if (ob->proxy == (Object *)new_id) { ob->proxy->proxy_from = ob; } @@ -228,11 +239,11 @@ static int foreach_libblock_remap_callback(LibraryIDLinkCallbackData *cb_data) static void libblock_remap_data_preprocess(IDRemap *r_id_remap_data) { - switch (GS(r_id_remap_data->id->name)) { + switch (GS(r_id_remap_data->id_owner->name)) { case ID_OB: { ID *old_id = r_id_remap_data->old_id; if (!old_id || GS(old_id->name) == ID_AR) { - Object *ob = (Object *)r_id_remap_data->id; + Object *ob = (Object *)r_id_remap_data->id_owner; /* Object's pose holds reference to armature bones... sic */ /* Note that in theory, we should have to bother about * linked/non-linked/never-null/etc. flags/states. @@ -371,7 +382,7 @@ static void libblock_remap_data( r_id_remap_data->bmain = bmain; r_id_remap_data->old_id = old_id; r_id_remap_data->new_id = new_id; - r_id_remap_data->id = NULL; + r_id_remap_data->id_owner = NULL; r_id_remap_data->flag = remap_flags; r_id_remap_data->status = 0; r_id_remap_data->skipped_direct = 0; @@ -382,7 +393,7 @@ static void libblock_remap_data( #ifdef DEBUG_PRINT printf("\tchecking id %s (%p, %p)\n", id->name, id, id->lib); #endif - r_id_remap_data->id = id; + r_id_remap_data->id_owner = id; libblock_remap_data_preprocess(r_id_remap_data); BKE_library_foreach_ID_link( NULL, id, foreach_libblock_remap_callback, (void *)r_id_remap_data, foreach_id_flags); @@ -398,7 +409,7 @@ static void libblock_remap_data( /* Note that we cannot skip indirect usages of old_id here (if requested), * we still need to check it for the user count handling... * XXX No more true (except for debug usage of those skipping counters). */ - r_id_remap_data->id = id_curr; + r_id_remap_data->id_owner = id_curr; libblock_remap_data_preprocess(r_id_remap_data); BKE_library_foreach_ID_link(NULL, id_curr, @@ -642,7 +653,7 @@ void BKE_libblock_relink_ex( static int id_relink_to_newid_looper(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } diff --git a/source/blender/blenkernel/intern/main_idmap.c b/source/blender/blenkernel/intern/main_idmap.c index 26eb0b681a1..8b83482d685 100644 --- a/source/blender/blenkernel/intern/main_idmap.c +++ b/source/blender/blenkernel/intern/main_idmap.c @@ -124,6 +124,8 @@ struct IDNameLib_Map *BKE_main_idmap_create(struct Main *bmain, const bool existing_key = BLI_ghash_ensure_p( id_map->uuid_map, POINTER_FROM_UINT(id->session_uuid), &id_ptr_v); BLI_assert(existing_key == false); + UNUSED_VARS_NDEBUG(existing_key); + *id_ptr_v = id; } FOREACH_MAIN_ID_END; diff --git a/source/blender/blenkernel/intern/node.c b/source/blender/blenkernel/intern/node.c index 1feb20ec272..8ddb78bcc17 100644 --- a/source/blender/blenkernel/intern/node.c +++ b/source/blender/blenkernel/intern/node.c @@ -1654,7 +1654,7 @@ bNodeTree *ntreeAddTree(Main *bmain, const char *name, const char *idname) } else { ntree = MEM_callocN(sizeof(bNodeTree), "new node tree"); - ntree->id.flag |= LIB_PRIVATE_DATA; + ntree->id.flag |= LIB_EMBEDDED_DATA; *((short *)ntree->id.name) = ID_NT; BLI_strncpy(ntree->id.name + 2, name, sizeof(ntree->id.name)); } @@ -1682,21 +1682,6 @@ bNodeTree *ntreeCopyTree(Main *bmain, const bNodeTree *ntree) return ntreeCopyTree_ex(ntree, bmain, true); } -void ntreeUserIncrefID(bNodeTree *ntree) -{ - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - id_us_plus(node->id); - } -} -void ntreeUserDecrefID(bNodeTree *ntree) -{ - bNode *node; - for (node = ntree->nodes.first; node; node = node->next) { - id_us_min(node->id); - } -} - /* *************** Node Preview *********** */ /* XXX this should be removed eventually ... diff --git a/source/blender/blenkernel/intern/ocean.c b/source/blender/blenkernel/intern/ocean.c index c27fb59835f..26485d10fbd 100644 --- a/source/blender/blenkernel/intern/ocean.c +++ b/source/blender/blenkernel/intern/ocean.c @@ -38,11 +38,11 @@ #include "BLI_path_util.h" #include "BLI_rand.h" #include "BLI_task.h" -#include "BLI_threads.h" #include "BLI_utildefines.h" #include "BKE_image.h" #include "BKE_ocean.h" +#include "ocean_intern.h" #include "IMB_imbuf.h" #include "IMB_imbuf_types.h" @@ -54,95 +54,6 @@ #ifdef WITH_OCEANSIM /* Ocean code */ -# include "fftw3.h" - -# define GRAVITY 9.81f - -typedef struct Ocean { - /* ********* input parameters to the sim ********* */ - float _V; - float _l; - float _w; - float _A; - float _damp_reflections; - float _wind_alignment; - float _depth; - - float _wx; - float _wz; - - float _L; - - /* dimensions of computational grid */ - int _M; - int _N; - - /* spatial size of computational grid */ - float _Lx; - float _Lz; - - float normalize_factor; /* init w */ - float time; - - short _do_disp_y; - short _do_normals; - short _do_chop; - short _do_jacobian; - - /* mutex for threaded texture access */ - ThreadRWMutex oceanmutex; - - /* ********* sim data arrays ********* */ - - /* two dimensional arrays of complex */ - fftw_complex *_fft_in; /* init w sim w */ - fftw_complex *_fft_in_x; /* init w sim w */ - fftw_complex *_fft_in_z; /* init w sim w */ - fftw_complex *_fft_in_jxx; /* init w sim w */ - fftw_complex *_fft_in_jzz; /* init w sim w */ - fftw_complex *_fft_in_jxz; /* init w sim w */ - fftw_complex *_fft_in_nx; /* init w sim w */ - fftw_complex *_fft_in_nz; /* init w sim w */ - fftw_complex *_htilda; /* init w sim w (only once) */ - - /* fftw "plans" */ - fftw_plan _disp_y_plan; /* init w sim r */ - fftw_plan _disp_x_plan; /* init w sim r */ - fftw_plan _disp_z_plan; /* init w sim r */ - fftw_plan _N_x_plan; /* init w sim r */ - fftw_plan _N_z_plan; /* init w sim r */ - fftw_plan _Jxx_plan; /* init w sim r */ - fftw_plan _Jxz_plan; /* init w sim r */ - fftw_plan _Jzz_plan; /* init w sim r */ - - /* two dimensional arrays of float */ - double *_disp_y; /* init w sim w via plan? */ - double *_N_x; /* init w sim w via plan? */ - /* all member of this array has same values, - * so convert this array to a float to reduce memory usage (MEM01). */ - /*float * _N_y; */ - double _N_y; /* sim w ********* can be rearranged? */ - double *_N_z; /* init w sim w via plan? */ - double *_disp_x; /* init w sim w via plan? */ - double *_disp_z; /* init w sim w via plan? */ - - /* two dimensional arrays of float */ - /* Jacobian and minimum eigenvalue */ - double *_Jxx; /* init w sim w */ - double *_Jzz; /* init w sim w */ - double *_Jxz; /* init w sim w */ - - /* one dimensional float array */ - float *_kx; /* init w sim r */ - float *_kz; /* init w sim r */ - - /* two dimensional complex array */ - fftw_complex *_h0; /* init w sim r */ - fftw_complex *_h0_minus; /* init w sim r */ - - /* two dimensional float array */ - float *_k; /* init w sim r */ -} Ocean; static float nextfr(RNG *rng, float min, float max) { @@ -285,7 +196,7 @@ float BKE_ocean_jminus_to_foam(float jminus, float coverage) { float foam = jminus * -0.005f + coverage; CLAMP(foam, 0.0f, 1.0f); - return foam * foam; + return foam; } void BKE_ocean_eval_uv(struct Ocean *oc, struct OceanResult *ocr, float u, float v) @@ -893,6 +804,9 @@ void BKE_ocean_init_from_modifier(struct Ocean *ocean, struct OceanModifierData omd->wave_alignment, omd->depth, omd->time, + omd->spectrum, + omd->fetch_jonswap, + omd->sharpen_peak_jonswap, do_heightfield, do_chop, do_normals, @@ -913,6 +827,9 @@ void BKE_ocean_init(struct Ocean *o, float alignment, float depth, float time, + int spectrum, + float fetch_jonswap, + float sharpen_peak_jonswap, short do_height_field, short do_chop, short do_normals, @@ -940,6 +857,13 @@ void BKE_ocean_init(struct Ocean *o, o->_L = V * V / GRAVITY; /* largest wave for a given velocity V */ o->time = time; + /* Spectrum to use. */ + o->_spectrum = spectrum; + + /* Common JONSWAP parameters. */ + o->_fetch_jonswap = fetch_jonswap; + o->_sharpen_peak_jonswap = sharpen_peak_jonswap; + o->_do_disp_y = do_height_field; o->_do_normals = do_normals; o->_do_chop = do_chop; @@ -1001,10 +925,46 @@ void BKE_ocean_init(struct Ocean *o, fftw_complex r1r2; init_complex(r1r2, r1, r2); - mul_complex_f( - o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); - mul_complex_f( - o->_h0_minus[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); + switch (o->_spectrum) { + case MOD_OCEAN_SPECTRUM_JONSWAP: + mul_complex_f(o->_h0[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_jonswap(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f( + o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_jonswap(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); + break; + case MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE: + mul_complex_f( + o->_h0[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f( + o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_texelmarsenarsloe(o, -o->_kx[i], -o->_kz[j]) / + 2.0f))); + break; + case MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ: + mul_complex_f( + o->_h0[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f( + o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(BLI_ocean_spectrum_piersonmoskowitz(o, -o->_kx[i], -o->_kz[j]) / + 2.0f))); + break; + default: + mul_complex_f( + o->_h0[i * o->_N + j], r1r2, (float)(sqrt(Ph(o, o->_kx[i], o->_kz[j]) / 2.0f))); + mul_complex_f(o->_h0_minus[i * o->_N + j], + r1r2, + (float)(sqrt(Ph(o, -o->_kx[i], -o->_kz[j]) / 2.0f))); + break; + } } } @@ -1517,12 +1477,6 @@ void BKE_ocean_bake(struct Ocean *o, #else /* WITH_OCEANSIM */ -/* stub */ -typedef struct Ocean { - /* need some data here, C does not allow empty struct */ - int stub; -} Ocean; - float BKE_ocean_jminus_to_foam(float UNUSED(jminus), float UNUSED(coverage)) { return 0.0f; @@ -1591,6 +1545,9 @@ void BKE_ocean_init(struct Ocean *UNUSED(o), float UNUSED(alignment), float UNUSED(depth), float UNUSED(time), + int UNUSED(spectrum), + float UNUSED(fetch_jonswap), + float UNUSED(sharpen_peak_jonswap), short UNUSED(do_height_field), short UNUSED(do_chop), short UNUSED(do_normals), diff --git a/source/blender/blenkernel/intern/ocean_intern.h b/source/blender/blenkernel/intern/ocean_intern.h new file mode 100644 index 00000000000..7da88419219 --- /dev/null +++ b/source/blender/blenkernel/intern/ocean_intern.h @@ -0,0 +1,137 @@ +/* + * 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. + */ + +#ifndef __BKE_OCEAN_INTERN_H__ +#define __BKE_OCEAN_INTERN_H__ + +/** \file + * \ingroup bli + */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef WITH_OCEANSIM +# include "BLI_threads.h" +# include "fftw3.h" +# define GRAVITY 9.81f + +typedef struct Ocean { + /* ********* input parameters to the sim ********* */ + float _V; + float _l; + float _w; + float _A; + float _damp_reflections; + float _wind_alignment; + float _depth; + + float _wx; + float _wz; + + float _L; + + /* dimensions of computational grid */ + int _M; + int _N; + + /* spatial size of computational grid */ + float _Lx; + float _Lz; + + float normalize_factor; /* init w */ + float time; + + short _do_disp_y; + short _do_normals; + short _do_chop; + short _do_jacobian; + + /* Which spectral model we are using. */ + int _spectrum; + + /* JONSWAP common parameters. */ + float _fetch_jonswap; + float _sharpen_peak_jonswap; + + /* mutex for threaded texture access */ + ThreadRWMutex oceanmutex; + + /* ********* sim data arrays ********* */ + + /* two dimensional arrays of complex */ + fftw_complex *_fft_in; /* init w sim w */ + fftw_complex *_fft_in_x; /* init w sim w */ + fftw_complex *_fft_in_z; /* init w sim w */ + fftw_complex *_fft_in_jxx; /* init w sim w */ + fftw_complex *_fft_in_jzz; /* init w sim w */ + fftw_complex *_fft_in_jxz; /* init w sim w */ + fftw_complex *_fft_in_nx; /* init w sim w */ + fftw_complex *_fft_in_nz; /* init w sim w */ + fftw_complex *_htilda; /* init w sim w (only once) */ + + /* fftw "plans" */ + fftw_plan _disp_y_plan; /* init w sim r */ + fftw_plan _disp_x_plan; /* init w sim r */ + fftw_plan _disp_z_plan; /* init w sim r */ + fftw_plan _N_x_plan; /* init w sim r */ + fftw_plan _N_z_plan; /* init w sim r */ + fftw_plan _Jxx_plan; /* init w sim r */ + fftw_plan _Jxz_plan; /* init w sim r */ + fftw_plan _Jzz_plan; /* init w sim r */ + + /* two dimensional arrays of float */ + double *_disp_y; /* init w sim w via plan? */ + double *_N_x; /* init w sim w via plan? */ + /* all member of this array has same values, + * so convert this array to a float to reduce memory usage (MEM01). */ + /*float * _N_y; */ + double _N_y; /* sim w ********* can be rearranged? */ + double *_N_z; /* init w sim w via plan? */ + double *_disp_x; /* init w sim w via plan? */ + double *_disp_z; /* init w sim w via plan? */ + + /* two dimensional arrays of float */ + /* Jacobian and minimum eigenvalue */ + double *_Jxx; /* init w sim w */ + double *_Jzz; /* init w sim w */ + double *_Jxz; /* init w sim w */ + + /* one dimensional float array */ + float *_kx; /* init w sim r */ + float *_kz; /* init w sim r */ + + /* two dimensional complex array */ + fftw_complex *_h0; /* init w sim r */ + fftw_complex *_h0_minus; /* init w sim r */ + + /* two dimensional float array */ + float *_k; /* init w sim r */ +} Ocean; +#else +/* stub */ +typedef struct Ocean { + /* need some data here, C does not allow empty struct */ + int stub; +} Ocean; +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/source/blender/blenkernel/intern/ocean_spectrum.c b/source/blender/blenkernel/intern/ocean_spectrum.c new file mode 100644 index 00000000000..93018f4a5b0 --- /dev/null +++ b/source/blender/blenkernel/intern/ocean_spectrum.c @@ -0,0 +1,224 @@ +/* + * 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. + */ + +/** \file + * \ingroup bke + */ + +#include "BLI_math.h" +#include "BKE_ocean.h" +#include "ocean_intern.h" + +#ifdef WITH_OCEANSIM + +/* -------------------------------------------------------------------- */ +/** \name Ocean Spectrum from EncinoWaves + * \{ */ + +/* + * Original code from EncinoWaves project Copyright (c) 2015 Christopher Jon Horvath + * Modifications made to work within blender. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + */ + +/** + * alpha_beta_spectrum is a common algorithm for the Pierson-Moskowitz, JONSWAP and TMA models. + * This is a modified implementation from the EncinoWaves project. + */ +static float alpha_beta_spectrum(const float alpha, + const float beta, + const float gamma, + const float omega, + const float peakomega) +{ + return (alpha * sqrt(gamma) / pow(omega, 5.0)) * exp(-beta * pow(peakomega / omega, 4.0)); +} + +static float peak_sharpen(const float omega, const float m_peakomega, const float m_gamma) +{ + const float peak_sharpening_sigma = (omega < m_peakomega) ? 0.07 : 0.09; + const float peak_sharpening = pow( + m_gamma, exp(-sqrt((omega - m_peakomega) / (peak_sharpening_sigma * m_peakomega)) / 2.0)); + + return peak_sharpening; +} + +/** + * Spectrum-type independent modifications. + */ +static float ocean_spectrum_wind_and_damp(const Ocean *oc, + const float kx, + const float kz, + const float val) +{ + const float k2 = kx * kx + kz * kz; + const float k_mag_inv = 1.0f / k2; + const float k_dot_w = (kx * k_mag_inv * oc->_wx) + (kz * k_mag_inv * oc->_wz); + + /* Bias towards wind dir. */ + float newval = val * pow(fabs(k_dot_w), oc->_wind_alignment); + + /* Eliminate wavelengths smaller than cutoff. */ + /* val *= exp(-k2 * m_cutoff); */ + + /* Reduce reflected waves. */ + if (k_dot_w < 0.0f) { + if (oc->_wind_alignment > 0.0) { + newval *= oc->_damp_reflections; + } + } + + return newval; +} + +static float jonswap(const Ocean *oc, const float k2) +{ + /* Get our basic JONSWAP value from #alpha_beta_spectrum. */ + const float k_mag = sqrt(k2); + + const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth); + const float omega = sqrt(m_omega); + + const float m_fetch = oc->_fetch_jonswap; + + /* Strictly, this should be a random value from a Gaussian (mean 3.3, variance 0.67), + * clamped 1.0 to 6.0. */ + float m_gamma = oc->_sharpen_peak_jonswap; + if (m_gamma < 1.0) { + m_gamma = 1.00; + } + if (m_gamma > 6.0) { + m_gamma = 6.0; + } + + const float m_windspeed = oc->_V; + + const float m_dimensionlessFetch = fabs(GRAVITY * m_fetch / sqrt(m_windspeed)); + const float m_alpha = 0.076 * pow(m_dimensionlessFetch, -0.22); + + const float m_tau = M_PI * 2; + const float m_peakomega = m_tau * 3.5 * fabs(GRAVITY / oc->_V) * + pow(m_dimensionlessFetch, -0.33); + + const float beta = 1.25f; + + float val = alpha_beta_spectrum(m_alpha, beta, GRAVITY, omega, m_peakomega); + + /* Peak sharpening */ + val *= peak_sharpen(m_omega, m_peakomega, m_gamma); + + return val; +} + +/** + * Pierson-Moskowitz model, 1964, assumes waves reach equilibrium with wind. + * Model is intended for large area 'fully developed' sea, where winds have been steadily blowing + * for days over an area that includes hundreds of wavelengths on a side. + */ +float BLI_ocean_spectrum_piersonmoskowitz(const Ocean *oc, const float kx, const float kz) +{ + const float k2 = kx * kx + kz * kz; + + if (k2 == 0.0f) { + /* No DC component. */ + return 0.0f; + } + + /* Get Pierson-Moskowitz value from #alpha_beta_spectrum. */ + const float peak_omega_PM = 0.87f * GRAVITY / oc->_V; + + const float k_mag = sqrt(k2); + const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth); + + const float omega = sqrt(m_omega); + const float alpha = 0.0081f; + const float beta = 1.291f; + + float val = alpha_beta_spectrum(alpha, beta, GRAVITY, omega, peak_omega_PM); + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + return val; +} + +/** + * TMA extends the JONSWAP spectrum. + * This spectral model is best suited to shallow water. + */ +float BLI_ocean_spectrum_texelmarsenarsloe(const Ocean *oc, const float kx, const float kz) +{ + const float k2 = kx * kx + kz * kz; + + if (k2 == 0.0f) { + /* No DC component. */ + return 0.0f; + } + + float val = jonswap(oc, k2); + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + /* TMA modifications to JONSWAP. */ + const float m_depth = oc->_depth; + const float gain = sqrt(m_depth / GRAVITY); + + const float k_mag = sqrt(k2); + + const float m_omega = GRAVITY * k_mag * tanh(k_mag * oc->_depth); + const float omega = sqrt(m_omega); + + const float kitaigorodskiiDepth_wh = omega * gain; + const float kitaigorodskiiDepth = 0.5 + (0.5 * tanh(1.8 * (kitaigorodskiiDepth_wh - 1.125))); + + val *= kitaigorodskiiDepth; + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + return val; +} + +/** + * Hasselmann et al, 1973. This model extends the Pierson-Moskowitz model with a peak sharpening + * function This enhancement is an artificial construct to address the problem that the wave + * spectrum is never fully developed. + * + * The fetch parameter represents the distance from a lee shore, + * called the fetch, or the distance over which the wind blows with constant velocity. + */ +float BLI_ocean_spectrum_jonswap(const Ocean *oc, const float kx, const float kz) +{ + const float k2 = kx * kx + kz * kz; + + if (k2 == 0.0f) { + /* No DC component. */ + return 0.0f; + } + + float val = jonswap(oc, k2); + + val = ocean_spectrum_wind_and_damp(oc, kx, kz, val); + + return val; +} + +/** \} */ + +#endif /* WITH_OCEANSIM */ diff --git a/source/blender/blenkernel/intern/pointcache.c b/source/blender/blenkernel/intern/pointcache.c index 90a4a2dee23..b0163436cc4 100644 --- a/source/blender/blenkernel/intern/pointcache.c +++ b/source/blender/blenkernel/intern/pointcache.c @@ -1953,8 +1953,8 @@ static bool foreach_object_ptcache( if (!foreach_object_modifier_ptcache(object, callback, callback_user_data)) { return false; } - /* Consider all object in dupli groups to be part of the same object, - * for baking with linking dupligroups. Once we have better overrides + /* Consider all object in dupli-groups to be part of the same object, + * for baking with linking dupli-groups. Once we have better overrides * this can be revisited so users select the local objects directly. */ if (scene != NULL && (duplis-- > 0) && (object->instance_collection != NULL)) { FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (object->instance_collection, current_object) { diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c index 37049014ef7..6ca14ec9197 100644 --- a/source/blender/blenkernel/intern/scene.c +++ b/source/blender/blenkernel/intern/scene.c @@ -395,9 +395,9 @@ static void scene_free_data(ID *id) scene->master_collection = NULL; } - if (scene->eevee.light_cache) { - EEVEE_lightcache_free(scene->eevee.light_cache); - scene->eevee.light_cache = NULL; + if (scene->eevee.light_cache_data) { + EEVEE_lightcache_free(scene->eevee.light_cache_data); + scene->eevee.light_cache_data = NULL; } if (scene->display.shading.prop) { @@ -583,7 +583,7 @@ void BKE_scene_copy_data_eevee(Scene *sce_dst, const Scene *sce_src) { /* Copy eevee data between scenes. */ sce_dst->eevee = sce_src->eevee; - sce_dst->eevee.light_cache = NULL; + sce_dst->eevee.light_cache_data = NULL; sce_dst->eevee.light_cache_info[0] = '\0'; /* TODO Copy the cache. */ } @@ -2057,6 +2057,14 @@ void BKE_scene_free_depsgraph_hash(Scene *scene) scene->depsgraph_hash = NULL; } +void BKE_scene_free_view_layer_depsgraph(Scene *scene, ViewLayer *view_layer) +{ + if (scene->depsgraph_hash != NULL) { + DepsgraphKey key = {view_layer}; + BLI_ghash_remove(scene->depsgraph_hash, &key, depsgraph_key_free, depsgraph_key_value_free); + } +} + /* Query depsgraph for a specific contexts. */ Depsgraph *BKE_scene_get_depsgraph(Main *bmain, Scene *scene, ViewLayer *view_layer, bool allocate) diff --git a/source/blender/blenkernel/intern/tracking.c b/source/blender/blenkernel/intern/tracking.c index f1243330567..a9bd1d17567 100644 --- a/source/blender/blenkernel/intern/tracking.c +++ b/source/blender/blenkernel/intern/tracking.c @@ -621,7 +621,7 @@ MovieTrackingTrack *BKE_tracking_track_duplicate(MovieTrackingTrack *track) new_track->markers = MEM_dupallocN(new_track->markers); - /* Orevent duplicate from being used for 2D stabilization. + /* Prevent duplicate from being used for 2D stabilization. * If necessary, it shall be added explicitly. */ new_track->flag &= ~TRACK_USE_2D_STAB; diff --git a/source/blender/blenlib/intern/BLI_memblock.c b/source/blender/blenlib/intern/BLI_memblock.c index ee9ea15835b..b532202ebaa 100644 --- a/source/blender/blenlib/intern/BLI_memblock.c +++ b/source/blender/blenlib/intern/BLI_memblock.c @@ -191,10 +191,14 @@ void *BLI_memblock_iterstep(BLI_memblock_iter *iter) return ptr; } -/* Direct access. elem is element index inside the chosen chunk. */ +/* Direct access. elem is element index inside the chosen chunk. + * Double usage: You can set chunk to 0 and set the absolute elem index. + * The correct chunk will be retrieve. */ void *BLI_memblock_elem_get(BLI_memblock *mblk, int chunk, int elem) { BLI_assert(chunk < mblk->chunk_len); - BLI_assert(elem < (mblk->chunk_size / mblk->elem_size)); + int elem_per_chunk = mblk->chunk_size / mblk->elem_size; + chunk += elem / elem_per_chunk; + elem = elem % elem_per_chunk; return (char *)(mblk->chunk_list[chunk]) + mblk->elem_size * elem; } diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c index 7e17d1235fe..3059caf83f1 100644 --- a/source/blender/blenloader/intern/readfile.c +++ b/source/blender/blenloader/intern/readfile.c @@ -157,6 +157,8 @@ #include "RE_engine.h" +#include "engines/eevee/eevee_lightcache.h" + #include "readfile.h" #include <errno.h> @@ -1852,8 +1854,8 @@ void blo_make_scene_pointer_map(FileData *fd, Main *oldmain) fd->scenemap = oldnewmap_new(); for (; sce; sce = sce->id.next) { - if (sce->eevee.light_cache) { - struct LightCache *light_cache = sce->eevee.light_cache; + if (sce->eevee.light_cache_data) { + struct LightCache *light_cache = sce->eevee.light_cache_data; oldnewmap_insert(fd->scenemap, light_cache, light_cache, 0); } } @@ -1873,7 +1875,7 @@ void blo_end_scene_pointer_map(FileData *fd, Main *oldmain) } for (; sce; sce = sce->id.next) { - sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data); } } @@ -5439,7 +5441,8 @@ static void direct_link_modifiers(FileData *fd, ListBase *lb, Object *ob) mmd->domain->fluid = NULL; mmd->domain->fluid_mutex = BLI_rw_mutex_alloc(); - mmd->domain->tex = NULL; + mmd->domain->tex_density = NULL; + mmd->domain->tex_color = NULL; mmd->domain->tex_shadow = NULL; mmd->domain->tex_flame = NULL; mmd->domain->tex_flame_coba = NULL; @@ -6926,19 +6929,20 @@ static void direct_link_scene(FileData *fd, Scene *sce) if (fd->memfile) { /* If it's undo try to recover the cache. */ if (fd->scenemap) { - sce->eevee.light_cache = newsceadr(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newsceadr(fd, sce->eevee.light_cache_data); } else { - sce->eevee.light_cache = NULL; + sce->eevee.light_cache_data = NULL; } } else { /* else try to read the cache from file. */ - sce->eevee.light_cache = newdataadr(fd, sce->eevee.light_cache); - if (sce->eevee.light_cache) { - direct_link_lightcache(fd, sce->eevee.light_cache); + sce->eevee.light_cache_data = newdataadr(fd, sce->eevee.light_cache_data); + if (sce->eevee.light_cache_data) { + direct_link_lightcache(fd, sce->eevee.light_cache_data); } } + EEVEE_lightcache_info_update(&sce->eevee); direct_link_view3dshading(fd, &sce->display.shading); @@ -7791,7 +7795,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; ID **id_pointer = cb_data->id_pointer; - if (cb_flag & IDWALK_CB_PRIVATE || *id_pointer == NULL) { + if (cb_flag & IDWALK_CB_EMBEDDED || *id_pointer == NULL) { return IDWALK_RET_NOP; } @@ -7802,7 +7806,7 @@ static int lib_link_main_data_restore_cb(LibraryIDLinkCallbackData *cb_data) Collection *collection = (Collection *)*id_pointer; if (collection->flag & COLLECTION_IS_MASTER) { /* We should never reach that point anymore, since master collection private ID should be - * properly tagged with IDWALK_CB_PRIVATE. */ + * properly tagged with IDWALK_CB_EMBEDDED. */ BLI_assert(0); return IDWALK_RET_NOP; } diff --git a/source/blender/blenloader/intern/versioning_280.c b/source/blender/blenloader/intern/versioning_280.c index 34041b0ca22..0ce32d234a8 100644 --- a/source/blender/blenloader/intern/versioning_280.c +++ b/source/blender/blenloader/intern/versioning_280.c @@ -4091,7 +4091,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) FOREACH_MAIN_ID_BEGIN (bmain, id) { bNodeTree *ntree = ntreeFromID(id); if (ntree) { - ntree->id.flag |= LIB_PRIVATE_DATA; + ntree->id.flag |= LIB_EMBEDDED_DATA; } } FOREACH_MAIN_ID_END; @@ -4108,7 +4108,7 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) /* Older files do not have a master collection, which is then added through * `BKE_collection_master_add()`, so everything is fine. */ if (scene->master_collection != NULL) { - scene->master_collection->id.flag |= LIB_PRIVATE_DATA; + scene->master_collection->id.flag |= LIB_EMBEDDED_DATA; } } } @@ -4851,6 +4851,18 @@ void blo_do_versions_280(FileData *fd, Library *UNUSED(lib), Main *bmain) */ { /* Keep this block, even when empty. */ + + if (!DNA_struct_elem_find(fd->filesdna, "OceanModifierData", "float", "fetch_jonswap")) { + for (Object *object = bmain->objects.first; object != NULL; object = object->id.next) { + for (ModifierData *md = object->modifiers.first; md; md = md->next) { + if (md->type == eModifierType_Ocean) { + OceanModifierData *omd = (OceanModifierData *)md; + omd->fetch_jonswap = 120.0f; + } + } + } + } + if (!DNA_struct_find(fd->filesdna, "XrSessionSettings")) { for (wmWindowManager *wm = bmain->wm.first; wm; wm = wm->id.next) { const View3D *v3d_default = DNA_struct_default_get(View3D); diff --git a/source/blender/blenloader/intern/writefile.c b/source/blender/blenloader/intern/writefile.c index 81df00ebdef..a9c5008062b 100644 --- a/source/blender/blenloader/intern/writefile.c +++ b/source/blender/blenloader/intern/writefile.c @@ -2767,9 +2767,9 @@ static void write_scene(WriteData *wd, Scene *sce) } /* Eevee Lightcache */ - if (sce->eevee.light_cache && !wd->use_memfile) { - writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache); - write_lightcache(wd, sce->eevee.light_cache); + if (sce->eevee.light_cache_data && !wd->use_memfile) { + writestruct(wd, DATA, LightCache, 1, sce->eevee.light_cache_data); + write_lightcache(wd, sce->eevee.light_cache_data); } write_view3dshading(wd, &sce->display.shading); diff --git a/source/blender/blentranslation/msgfmt/CMakeLists.txt b/source/blender/blentranslation/msgfmt/CMakeLists.txt index 147c375aa6e..350473fa195 100644 --- a/source/blender/blentranslation/msgfmt/CMakeLists.txt +++ b/source/blender/blentranslation/msgfmt/CMakeLists.txt @@ -37,6 +37,10 @@ if(APPLE) set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${PLATFORM_LINKFLAGS}") endif() +if(WIN32) + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "${CMAKE_EXE_LINKER_FLAGS_DEBUG} /nodefaultlib:MSVCRT.lib") +endif() + add_executable(msgfmt ${SRC}) target_link_libraries(msgfmt bf_blenlib) diff --git a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc index 01d84f6b5d8..c512300200e 100644 --- a/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc +++ b/source/blender/depsgraph/intern/builder/deg_builder_nodes.cc @@ -319,6 +319,18 @@ void DepsgraphNodeBuilder::begin_build() * them for new ID nodes. */ id_info_hash_ = BLI_ghash_ptr_new("Depsgraph id hash"); for (IDNode *id_node : graph_->id_nodes) { + /* It is possible that the ID does not need to have CoW version in which case id_cow is the + * same as id_orig. Additionally, such ID might have been removed, which makes the check + * for whether id_cow is expanded to access freed memory. In orderr to deal with this we + * check whether CoW is needed based on a scalar value which does not lead to access of + * possibly deleted memory. + * Additionally, this saves some space in the map by skipping mapping for datablocks which + * do not need CoW, */ + if (!deg_copy_on_write_is_needed(id_node->id_type)) { + id_node->id_cow = nullptr; + continue; + } + IDInfo *id_info = (IDInfo *)MEM_mallocN(sizeof(IDInfo), "depsgraph id info"); if (deg_copy_on_write_is_expanded(id_node->id_cow) && id_node->id_orig != id_node->id_cow) { id_info->id_cow = id_node->id_cow; diff --git a/source/blender/depsgraph/intern/eval/deg_eval.cc b/source/blender/depsgraph/intern/eval/deg_eval.cc index df61a1416bd..1296c87bbb0 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval.cc @@ -37,6 +37,7 @@ #include "DNA_object_types.h" #include "DNA_scene_types.h" +#include "DNA_node_types.h" #include "DEG_depsgraph.h" #include "DEG_depsgraph_query.h" @@ -343,11 +344,13 @@ void depsgraph_ensure_view_layer(Depsgraph *graph) * - It was tagged for update of CoW component. * This allows us to have proper view layer pointer. */ Scene *scene_cow = graph->scene_cow; - if (!deg_copy_on_write_is_expanded(&scene_cow->id) || - scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) { - const IDNode *id_node = graph->find_id_node(&graph->scene->id); - deg_update_copy_on_write_datablock(graph, id_node); + if (deg_copy_on_write_is_expanded(&scene_cow->id) && + (scene_cow->id.recalc & ID_RECALC_COPY_ON_WRITE) == 0) { + return; } + + const IDNode *scene_id_node = graph->find_id_node(&graph->scene->id); + deg_update_copy_on_write_datablock(graph, scene_id_node); } } // namespace diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc index 1841f5f024f..d8ce590c611 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.cc @@ -804,7 +804,7 @@ void update_id_after_copy(const Depsgraph *depsgraph, Scene *scene_cow = (Scene *)id_cow; const Scene *scene_orig = (const Scene *)id_orig; scene_cow->toolsettings = scene_orig->toolsettings; - scene_cow->eevee.light_cache = scene_orig->eevee.light_cache; + scene_cow->eevee.light_cache_data = scene_orig->eevee.light_cache_data; scene_setup_view_layers_after_remap(depsgraph, id_node, reinterpret_cast<Scene *>(id_cow)); update_scene_orig_pointers(scene_orig, scene_cow); break; @@ -914,8 +914,11 @@ ID *deg_expand_copy_on_write_datablock(const Depsgraph *depsgraph, user_data.depsgraph = depsgraph; user_data.node_builder = node_builder; user_data.create_placeholders = create_placeholders; - BKE_library_foreach_ID_link( - nullptr, id_cow, foreach_libblock_remap_callback, (void *)&user_data, IDWALK_NOP); + BKE_library_foreach_ID_link(nullptr, + id_cow, + foreach_libblock_remap_callback, + (void *)&user_data, + IDWALK_IGNORE_EMBEDDED_ID); /* Correct or tweak some pointers which are not taken care by foreach * from above. */ update_id_after_copy(depsgraph, id_node, id_orig, id_cow); @@ -1000,7 +1003,7 @@ void discard_scene_pointers(ID *id_cow) { Scene *scene_cow = (Scene *)id_cow; scene_cow->toolsettings = nullptr; - scene_cow->eevee.light_cache = nullptr; + scene_cow->eevee.light_cache_data = nullptr; } /* nullptr-ify all edit mode pointers which points to data from @@ -1113,6 +1116,11 @@ bool deg_copy_on_write_is_expanded(const ID *id_cow) bool deg_copy_on_write_is_needed(const ID *id_orig) { const ID_Type id_type = GS(id_orig->name); + return deg_copy_on_write_is_needed(id_type); +} + +bool deg_copy_on_write_is_needed(const ID_Type id_type) +{ return ID_TYPE_IS_COW(id_type); } diff --git a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h index 1992c80e036..05464d11f13 100644 --- a/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h +++ b/source/blender/depsgraph/intern/eval/deg_eval_copy_on_write.h @@ -25,6 +25,8 @@ #include <stddef.h> +#include "DNA_ID.h" + struct ID; /* Uncomment this to have verbose log about original and CoW pointers @@ -94,5 +96,6 @@ bool deg_copy_on_write_is_expanded(const struct ID *id_cow); * This includes images. */ bool deg_copy_on_write_is_needed(const ID *id_orig); +bool deg_copy_on_write_is_needed(const ID_Type id_type); } // namespace DEG diff --git a/source/blender/depsgraph/intern/node/deg_node_id.cc b/source/blender/depsgraph/intern/node/deg_node_id.cc index 0fbf658ceb3..cd25cc14069 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.cc +++ b/source/blender/depsgraph/intern/node/deg_node_id.cc @@ -103,6 +103,7 @@ void IDNode::init(const ID *id, const char *UNUSED(subdata)) { BLI_assert(id != nullptr); /* Store ID-pointer. */ + id_type = GS(id->name); id_orig = (ID *)id; eval_flags = 0; previous_eval_flags = 0; diff --git a/source/blender/depsgraph/intern/node/deg_node_id.h b/source/blender/depsgraph/intern/node/deg_node_id.h index 886c25b5a4e..6eea31ebff9 100644 --- a/source/blender/depsgraph/intern/node/deg_node_id.h +++ b/source/blender/depsgraph/intern/node/deg_node_id.h @@ -25,6 +25,7 @@ #include "intern/node/deg_node.h" #include "BLI_sys_types.h" +#include "DNA_ID.h" struct GHash; @@ -73,6 +74,10 @@ struct IDNode : public Node { IDComponentsMask get_visible_components_mask() const; /* ID Block referenced. */ + /* Type of the ID stored separately, so it's possible to perform check whether CoW is needed + * without de-referencing the id_cow (which is not safe when ID is NOT covered by CoW and has + * been deleted from the main database.) */ + ID_Type id_type; ID *id_orig; ID *id_cow; diff --git a/source/blender/draw/CMakeLists.txt b/source/blender/draw/CMakeLists.txt index 1f04739644e..a1213be4be0 100644 --- a/source/blender/draw/CMakeLists.txt +++ b/source/blender/draw/CMakeLists.txt @@ -97,19 +97,18 @@ set(SRC engines/eevee/eevee_subsurface.c engines/eevee/eevee_temporal_sampling.c engines/eevee/eevee_volumes.c - engines/workbench/solid_mode.c - engines/workbench/transparent_mode.c engines/workbench/workbench_data.c - engines/workbench/workbench_deferred.c - engines/workbench/workbench_effect_aa.c + engines/workbench/workbench_effect_antialiasing.c + engines/workbench/workbench_effect_cavity.c engines/workbench/workbench_effect_dof.c - engines/workbench/workbench_effect_fxaa.c - engines/workbench/workbench_effect_taa.c + engines/workbench/workbench_effect_outline.c engines/workbench/workbench_engine.c - engines/workbench/workbench_forward.c engines/workbench/workbench_materials.c + engines/workbench/workbench_opaque.c engines/workbench/workbench_render.c - engines/workbench/workbench_studiolight.c + engines/workbench/workbench_shader.c + engines/workbench/workbench_shadow.c + engines/workbench/workbench_transparent.c engines/workbench/workbench_volume.c engines/external/external_engine.c engines/gpencil/gpencil_antialiasing.c @@ -231,6 +230,7 @@ data_to_c_simple(engines/eevee/shaders/btdf_lut_frag.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_common_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/irradiance_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/octahedron_lib.glsl SRC) +data_to_c_simple(engines/eevee/shaders/cubemap_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/bsdf_sampling_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/raytrace_lib.glsl SRC) data_to_c_simple(engines/eevee/shaders/renderpass_postprocess_frag.glsl SRC) @@ -247,28 +247,32 @@ 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(engines/workbench/shaders/workbench_cavity_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_cavity_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_common_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_composite_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_data_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_deferred_composite_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_deferred_background_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_cavity_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_dof_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_effect_fxaa_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_outline_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_effect_smaa_vert.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_effect_taa_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_forward_composite_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_forward_depth_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_ghost_resolve_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_object_outline_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_curvature_lib.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_image_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_matcap_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_material_lib.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_merge_infront_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_prepass_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_prepass_hair_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_prepass_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_shader_interface_lib.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_shadow_caps_geom.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_shadow_debug_frag.glsl SRC) -data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_shadow_geom.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_shadow_vert.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_transparent_accum_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_transparent_resolve_frag.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_volume_frag.glsl SRC) +data_to_c_simple(engines/workbench/shaders/workbench_volume_vert.glsl SRC) data_to_c_simple(engines/workbench/shaders/workbench_world_light_lib.glsl SRC) data_to_c_simple(intern/shaders/common_colormanagement_lib.glsl SRC) diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.c b/source/blender/draw/engines/eevee/eevee_lightcache.c index 2b11a608bd0..35a45cc97f4 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.c +++ b/source/blender/draw/engines/eevee/eevee_lightcache.c @@ -42,6 +42,7 @@ #include "eevee_private.h" #include "GPU_context.h" +#include "GPU_extensions.h" #include "WM_api.h" #include "WM_types.h" @@ -195,6 +196,16 @@ static uint eevee_lightcache_memsize_get(LightCache *lcache) return size; } +static bool eevee_lightcache_version_check(LightCache *lcache) +{ + switch (lcache->type) { + case LIGHTCACHE_TYPE_STATIC: + return lcache->version == LIGHTCACHE_STATIC_VERSION; + default: + return false; + } +} + static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) { int total_irr_samples = 0; @@ -208,9 +219,23 @@ static int eevee_lightcache_irradiance_sample_count(LightCache *lcache) void EEVEE_lightcache_info_update(SceneEEVEE *eevee) { - LightCache *lcache = eevee->light_cache; + LightCache *lcache = eevee->light_cache_data; if (lcache != NULL) { + if (!eevee_lightcache_version_check(lcache)) { + BLI_strncpy(eevee->light_cache_info, + TIP_("Incompatible Light cache version, please bake again"), + sizeof(eevee->light_cache_info)); + return; + } + + if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) { + BLI_strncpy(eevee->light_cache_info, + TIP_("Error: Light cache is too big for your GPU to be loaded"), + sizeof(eevee->light_cache_info)); + return; + } + if (lcache->flag & LIGHTCACHE_BAKING) { BLI_strncpy( eevee->light_cache_info, TIP_("Baking light cache"), sizeof(eevee->light_cache_info)); @@ -266,8 +291,8 @@ static bool EEVEE_lightcache_validate(const LightCache *light_cache, (irr_size[2] == light_cache->grid_tx.tex_size[2]) && (grid_len == light_cache->grid_len)) { int mip_len = log2_floor_u(cube_res) - MIN_CUBE_LOD_LEVEL; if ((cube_res == light_cache->cube_tx.tex_size[0]) && - (cube_len == light_cache->cube_tx.tex_size[2]) && (cube_len == light_cache->cube_len) && - (mip_len == light_cache->mips_len)) { + (cube_len == light_cache->cube_tx.tex_size[2] / 6) && + (cube_len == light_cache->cube_len) && (mip_len == light_cache->mips_len)) { return true; } } @@ -283,6 +308,9 @@ LightCache *EEVEE_lightcache_create(const int grid_len, { LightCache *light_cache = MEM_callocN(sizeof(LightCache), "LightCache"); + light_cache->version = LIGHTCACHE_STATIC_VERSION; + light_cache->type = LIGHTCACHE_TYPE_STATIC; + light_cache->cube_data = MEM_callocN(sizeof(EEVEE_LightProbe) * cube_len, "EEVEE_LightProbe"); light_cache->grid_data = MEM_callocN(sizeof(EEVEE_LightGrid) * grid_len, "EEVEE_LightGrid"); @@ -292,13 +320,26 @@ LightCache *EEVEE_lightcache_create(const int grid_len, light_cache->grid_tx.tex_size[1] = irr_size[1]; light_cache->grid_tx.tex_size[2] = irr_size[2]; - light_cache->cube_tx.tex = DRW_texture_create_2d_array( - cube_size, cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + int mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL; + + if (GPU_arb_texture_cube_map_array_is_supported()) { + light_cache->cube_tx.tex = DRW_texture_create_cube_array( + cube_size, cube_len, GPU_R11F_G11F_B10F, DRW_TEX_FILTER | DRW_TEX_MIPMAP, NULL); + } + else { + light_cache->cube_tx.tex = DRW_texture_create_2d_array(cube_size, + cube_size, + cube_len * 6, + GPU_R11F_G11F_B10F, + DRW_TEX_FILTER | DRW_TEX_MIPMAP, + NULL); + } + light_cache->cube_tx.tex_size[0] = cube_size; light_cache->cube_tx.tex_size[1] = cube_size; - light_cache->cube_tx.tex_size[2] = cube_len; + light_cache->cube_tx.tex_size[2] = cube_len * 6; - light_cache->mips_len = log2_floor_u(cube_size) - MIN_CUBE_LOD_LEVEL; + light_cache->mips_len = mips_len; light_cache->vis_res = vis_size; light_cache->ref_res = cube_size; @@ -315,9 +356,19 @@ LightCache *EEVEE_lightcache_create(const int grid_len, return light_cache; } -void EEVEE_lightcache_load(LightCache *lcache) +static bool eevee_lightcache_static_load(LightCache *lcache) { - if (lcache->grid_tx.tex == NULL && lcache->grid_tx.data) { + /* We use fallback if a texture is not setup and there is no data to restore it. */ + if ((!lcache->grid_tx.tex && !lcache->grid_tx.data) || + (!lcache->cube_tx.tex && !lcache->cube_tx.data)) { + return false; + } + /* If cache is too big for this GPU. */ + if (lcache->cube_tx.tex_size[2] > GPU_max_texture_layers()) { + return false; + } + + if (lcache->grid_tx.tex == NULL) { lcache->grid_tx.tex = GPU_texture_create_nD(lcache->grid_tx.tex_size[0], lcache->grid_tx.tex_size[1], lcache->grid_tx.tex_size[2], @@ -333,17 +384,28 @@ void EEVEE_lightcache_load(LightCache *lcache) GPU_texture_unbind(lcache->grid_tx.tex); } - if (lcache->cube_tx.tex == NULL && lcache->cube_tx.data) { - lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0], - lcache->cube_tx.tex_size[1], - lcache->cube_tx.tex_size[2], - 2, - lcache->cube_tx.data, - GPU_R11F_G11F_B10F, - GPU_DATA_10_11_11_REV, - 0, - false, - NULL); + if (lcache->cube_tx.tex == NULL) { + if (GPU_arb_texture_cube_map_array_is_supported()) { + lcache->cube_tx.tex = GPU_texture_cube_create(lcache->cube_tx.tex_size[0], + lcache->cube_tx.tex_size[2] / 6, + lcache->cube_tx.data, + GPU_R11F_G11F_B10F, + GPU_DATA_10_11_11_REV, + NULL); + } + else { + lcache->cube_tx.tex = GPU_texture_create_nD(lcache->cube_tx.tex_size[0], + lcache->cube_tx.tex_size[1], + lcache->cube_tx.tex_size[2], + 2, + lcache->cube_tx.data, + GPU_R11F_G11F_B10F, + GPU_DATA_10_11_11_REV, + 0, + false, + NULL); + } + GPU_texture_bind(lcache->cube_tx.tex, 0); GPU_texture_mipmap_mode(lcache->cube_tx.tex, true, true); for (int mip = 0; mip < lcache->mips_len; mip++) { @@ -352,6 +414,25 @@ void EEVEE_lightcache_load(LightCache *lcache) } GPU_texture_unbind(lcache->cube_tx.tex); } + return true; +} + +bool EEVEE_lightcache_load(LightCache *lcache) +{ + if (lcache == NULL) { + return false; + } + + if (!eevee_lightcache_version_check(lcache)) { + return false; + } + + switch (lcache->type) { + case LIGHTCACHE_TYPE_STATIC: + return eevee_lightcache_static_load(lcache); + default: + return false; + } } static void eevee_lightbake_readback_irradiance(LightCache *lcache) @@ -457,7 +538,7 @@ static void eevee_lightbake_count_probes(EEVEE_LightBake *lbake) prb->grid_resolution_z; lbake->grid_len++; } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { + else if (prb->type == LIGHTPROBE_TYPE_CUBE && lbake->cube_len < EEVEE_PROBE_MAX) { lbake->cube_len++; } } @@ -491,8 +572,7 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) irradiance_pool_size_get(lbake->vis_res, lbake->total_irr_samples, lbake->irr_size); - lbake->ref_cube_res = octahedral_size_from_cubesize(lbake->rt_res); - + lbake->ref_cube_res = lbake->rt_res; lbake->cube_prb = MEM_callocN(sizeof(LightProbe *) * lbake->cube_len, "EEVEE Cube visgroup ptr"); lbake->grid_prb = MEM_callocN(sizeof(LightProbe *) * lbake->grid_len, "EEVEE Grid visgroup ptr"); @@ -506,12 +586,12 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) /* Ensure Light Cache is ready to accept new data. If not recreate one. * WARNING: All the following must be threadsafe. It's currently protected * by the DRW mutex. */ - lbake->lcache = eevee->light_cache; + lbake->lcache = eevee->light_cache_data; /* TODO validate irradiance and reflection cache independently... */ if (!EEVEE_lightcache_validate( lbake->lcache, lbake->cube_len, lbake->ref_cube_res, lbake->grid_len, lbake->irr_size)) { - eevee->light_cache = lbake->lcache = NULL; + eevee->light_cache_data = lbake->lcache = NULL; } if (lbake->lcache == NULL) { @@ -522,10 +602,10 @@ static void eevee_lightbake_create_resources(EEVEE_LightBake *lbake) lbake->lcache->vis_res = lbake->vis_res; lbake->own_light_cache = true; - eevee->light_cache = lbake->lcache; + eevee->light_cache_data = lbake->lcache; } - EEVEE_lightcache_load(eevee->light_cache); + EEVEE_lightcache_load(eevee->light_cache_data); lbake->lcache->flag |= LIGHTCACHE_BAKING; lbake->lcache->cube_len = 1; @@ -804,7 +884,7 @@ static void eevee_lightbake_render_world_sample(void *ved, void *user_data) EEVEE_ViewLayerData *sldata = EEVEE_view_layer_data_ensure(); EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; + LightCache *lcache = scene_eval->eevee.light_cache_data; float clamp = scene_eval->eevee.gi_glossy_clamp; float filter_quality = scene_eval->eevee.gi_filter_quality; @@ -920,7 +1000,7 @@ static void eevee_lightbake_render_grid_sample(void *ved, void *user_data) EEVEE_LightGrid *egrid = lbake->grid; LightProbe *prb = *lbake->probe; Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; + LightCache *lcache = scene_eval->eevee.light_cache_data; int grid_loc[3], sample_id, sample_offset, stride; float pos[3]; const bool is_last_bounce_sample = ((egrid->offset + lbake->grid_sample) == @@ -1002,7 +1082,7 @@ static void eevee_lightbake_render_probe_sample(void *ved, void *user_data) EEVEE_CommonUniformBuffer *common_data = &sldata->common_data; EEVEE_LightBake *lbake = (EEVEE_LightBake *)user_data; Scene *scene_eval = DEG_get_evaluated_scene(lbake->depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; + LightCache *lcache = scene_eval->eevee.light_cache_data; EEVEE_LightProbe *eprobe = lbake->cube; LightProbe *prb = *lbake->probe; float clamp = scene_eval->eevee.gi_glossy_clamp; @@ -1083,7 +1163,7 @@ static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake) { Depsgraph *depsgraph = lbake->depsgraph; Scene *scene_eval = DEG_get_evaluated_scene(depsgraph); - LightCache *lcache = scene_eval->eevee.light_cache; + LightCache *lcache = scene_eval->eevee.light_cache_data; /* At least one for the world */ int grid_len = 1; @@ -1106,7 +1186,7 @@ static void eevee_lightbake_gather_probes(EEVEE_LightBake *lbake) EEVEE_LightGrid *egrid = &lcache->grid_data[grid_len++]; EEVEE_lightprobes_grid_data_from_object(ob, egrid, &total_irr_samples); } - else if (prb->type == LIGHTPROBE_TYPE_CUBE) { + else if (prb->type == LIGHTPROBE_TYPE_CUBE && cube_len < EEVEE_PROBE_MAX) { lbake->cube_prb[cube_len] = prb; EEVEE_LightProbe *eprobe = &lcache->cube_data[cube_len++]; EEVEE_lightprobes_cube_data_from_object(ob, eprobe); @@ -1136,11 +1216,11 @@ void EEVEE_lightbake_update(void *custom_data) Scene *scene_orig = lbake->scene; /* If a new lightcache was created, free the old one and reference the new. */ - if (lbake->lcache && scene_orig->eevee.light_cache != lbake->lcache) { - if (scene_orig->eevee.light_cache != NULL) { - EEVEE_lightcache_free(scene_orig->eevee.light_cache); + if (lbake->lcache && scene_orig->eevee.light_cache_data != lbake->lcache) { + if (scene_orig->eevee.light_cache_data != NULL) { + EEVEE_lightcache_free(scene_orig->eevee.light_cache_data); } - scene_orig->eevee.light_cache = lbake->lcache; + scene_orig->eevee.light_cache_data = lbake->lcache; lbake->own_light_cache = false; } @@ -1182,6 +1262,12 @@ void EEVEE_lightbake_job(void *custom_data, short *stop, short *do_update, float lbake->do_update = do_update; lbake->progress = progress; + if (G.background) { + /* Make sure to init GL capabilities before counting probes. */ + eevee_lightbake_context_enable(lbake); + eevee_lightbake_context_disable(lbake); + } + /* Count lightprobes */ eevee_lightbake_count_probes(lbake); diff --git a/source/blender/draw/engines/eevee/eevee_lightcache.h b/source/blender/draw/engines/eevee/eevee_lightcache.h index ede2de13dce..0db36ce0c2e 100644 --- a/source/blender/draw/engines/eevee/eevee_lightcache.h +++ b/source/blender/draw/engines/eevee/eevee_lightcache.h @@ -60,7 +60,7 @@ struct LightCache *EEVEE_lightcache_create(const int grid_len, const int vis_size, const int irr_size[3]); void EEVEE_lightcache_free(struct LightCache *lcache); -void EEVEE_lightcache_load(struct LightCache *lcache); +bool EEVEE_lightcache_load(struct LightCache *lcache); void EEVEE_lightcache_info_update(struct SceneEEVEE *eevee); #endif /* __EEVEE_LIGHTCACHE_H__ */ diff --git a/source/blender/draw/engines/eevee/eevee_lightprobes.c b/source/blender/draw/engines/eevee/eevee_lightprobes.c index 4fbecfe3120..61ca2317572 100644 --- a/source/blender/draw/engines/eevee/eevee_lightprobes.c +++ b/source/blender/draw/engines/eevee/eevee_lightprobes.c @@ -37,6 +37,7 @@ #include "GPU_material.h" #include "GPU_texture.h" +#include "GPU_extensions.h" #include "DEG_depsgraph_query.h" @@ -171,32 +172,28 @@ void EEVEE_lightprobes_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) memset(stl->g_data->world_views, 0, sizeof(stl->g_data->world_views)); memset(stl->g_data->planar_views, 0, sizeof(stl->g_data->planar_views)); - /* Use fallback if we don't have gpu texture allocated an we cannot restore them. */ - bool use_fallback_lightcache = (scene_eval->eevee.light_cache == NULL) || - ((scene_eval->eevee.light_cache->grid_tx.tex == NULL) && - (scene_eval->eevee.light_cache->grid_tx.data == NULL)) || - ((scene_eval->eevee.light_cache->cube_tx.tex == NULL) && - (scene_eval->eevee.light_cache->cube_tx.data == NULL)); - - if (use_fallback_lightcache && (sldata->fallback_lightcache == NULL)) { + if (EEVEE_lightcache_load(scene_eval->eevee.light_cache_data)) { + stl->g_data->light_cache = scene_eval->eevee.light_cache_data; + } + else { + if (!sldata->fallback_lightcache) { #if defined(IRRADIANCE_SH_L2) - int grid_res = 4; + int grid_res = 4; #elif defined(IRRADIANCE_CUBEMAP) - int grid_res = 8; + int grid_res = 8; #elif defined(IRRADIANCE_HL2) - int grid_res = 4; + int grid_res = 4; #endif - int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution); - int vis_res = scene_eval->eevee.gi_visibility_resolution; - sldata->fallback_lightcache = EEVEE_lightcache_create( - 1, 1, cube_res, vis_res, (int[3]){grid_res, grid_res, 1}); + sldata->fallback_lightcache = EEVEE_lightcache_create( + 1, + 1, + scene_eval->eevee.gi_cubemap_resolution, + scene_eval->eevee.gi_visibility_resolution, + (int[3]){grid_res, grid_res, 1}); + } + stl->g_data->light_cache = sldata->fallback_lightcache; } - stl->g_data->light_cache = (use_fallback_lightcache) ? sldata->fallback_lightcache : - scene_eval->eevee.light_cache; - - EEVEE_lightcache_load(stl->g_data->light_cache); - if (!sldata->probes) { sldata->probes = MEM_callocN(sizeof(EEVEE_LightProbesInfo), "EEVEE_LightProbesInfo"); sldata->probe_ubo = DRW_uniformbuffer_create(sizeof(EEVEE_LightProbe) * MAX_PROBE, NULL); @@ -255,7 +252,7 @@ void EEVEE_lightbake_cache_init(EEVEE_ViewLayerData *sldata, grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); struct GPUBatch *geom = DRW_cache_fullscreen_quad_get(); - DRW_shgroup_call(grp, geom, NULL); + DRW_shgroup_call_instances(grp, NULL, geom, 6); } { @@ -508,8 +505,8 @@ void EEVEE_lightprobes_cache_add(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata EEVEE_LightProbesInfo *pinfo = sldata->probes; LightProbe *probe = (LightProbe *)ob->data; - if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= MAX_PROBE) || - (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= MAX_PROBE) || + if ((probe->type == LIGHTPROBE_TYPE_CUBE && pinfo->num_cube >= EEVEE_PROBE_MAX) || + (probe->type == LIGHTPROBE_TYPE_GRID && pinfo->num_grid >= EEVEE_PROBE_MAX) || (probe->type == LIGHTPROBE_TYPE_PLANAR && pinfo->num_planar >= MAX_PLANAR)) { printf("Too many probes in the view !!!\n"); return; @@ -762,7 +759,7 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved DRW_uniformbuffer_update(sldata->grid_ubo, &sldata->probes->grid_data); /* For shading, save max level of the octahedron map */ - sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len - 1.0f; + sldata->common_data.prb_lod_cube_max = (float)light_cache->mips_len; sldata->common_data.prb_lod_planar_max = (float)MAX_PLANAR_LOD_LEVEL; sldata->common_data.prb_irradiance_vis_size = light_cache->vis_res; sldata->common_data.prb_irradiance_smooth = square_f(scene_eval->eevee.gi_irradiance_smoothing); @@ -785,15 +782,15 @@ void EEVEE_lightprobes_cache_finish(EEVEE_ViewLayerData *sldata, EEVEE_Data *ved if (draw_ctx->scene->eevee.flag & SCE_EEVEE_GI_AUTOBAKE) { Scene *scene_orig = DEG_get_input_scene(draw_ctx->depsgraph); - if (scene_orig->eevee.light_cache != NULL) { + if (scene_orig->eevee.light_cache_data != NULL) { if (pinfo->do_grid_update) { - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID; + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID; } - /* If we update grid we need to update the cube-maps too. - * So always refresh cube-maps. */ - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; - /* Tag the light-cache to auto update. */ - scene_orig->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_AUTO; + /* If we update grid we need to update the cubemaps too. + * So always refresh cubemaps. */ + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; + /* Tag the lightcache to auto update. */ + scene_orig->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_AUTO; /* Use a notifier to trigger the operator after drawing. */ WM_event_add_notifier(draw_ctx->evil_C, NC_LIGHTPROBE, scene_orig); } @@ -1077,7 +1074,7 @@ void EEVEE_lightbake_filter_glossy(EEVEE_ViewLayerData *sldata, pinfo->texel_size = 1.0f / (float)mipsize; pinfo->padding_size = (i == maxlevel) ? 0 : (float)(1 << (maxlevel - i - 1)); pinfo->padding_size *= pinfo->texel_size; - pinfo->layer = probe_idx; + pinfo->layer = probe_idx * 6; pinfo->roughness = i / (float)maxlevel; pinfo->roughness *= pinfo->roughness; /* Disney Roughness */ pinfo->roughness *= pinfo->roughness; /* Distribute Roughness accros lod more evenly */ diff --git a/source/blender/draw/engines/eevee/eevee_lookdev.c b/source/blender/draw/engines/eevee/eevee_lookdev.c index 7be6fc2d030..a725a3583f3 100644 --- a/source/blender/draw/engines/eevee/eevee_lookdev.c +++ b/source/blender/draw/engines/eevee/eevee_lookdev.c @@ -76,7 +76,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, effects->lookdev_view = NULL; - if (LOOK_DEV_OVERLAY_ENABLED(v3d)) { + if (eevee_hdri_preview_overlay_enabled(v3d)) { /* Viewport / Spheres size. */ const rcti *rect; rcti fallback_rect; @@ -116,7 +116,7 @@ void EEVEE_lookdev_cache_init(EEVEE_Data *vedata, EEVEE_shaders_background_studiolight_sh_get(); const Scene *scene_eval = DEG_get_evaluated_scene(draw_ctx->depsgraph); - int cube_res = octahedral_size_from_cubesize(scene_eval->eevee.gi_cubemap_resolution); + int cube_res = scene_eval->eevee.gi_cubemap_resolution; /* If one of the component is missing we start from scratch. */ if ((stl->lookdev_grid_data == NULL) || (stl->lookdev_cube_data == NULL) || @@ -228,7 +228,7 @@ void EEVEE_lookdev_draw(EEVEE_Data *vedata) const DRWContextState *draw_ctx = DRW_context_state_get(); - if (psl->lookdev_diffuse_pass && LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) { + if (psl->lookdev_diffuse_pass && eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { /* Config renderer. */ EEVEE_CommonUniformBuffer *common = &sldata->common_data; common->la_num_light = 0; diff --git a/source/blender/draw/engines/eevee/eevee_materials.c b/source/blender/draw/engines/eevee/eevee_materials.c index a37c063adf6..230a0725493 100644 --- a/source/blender/draw/engines/eevee/eevee_materials.c +++ b/source/blender/draw/engines/eevee/eevee_materials.c @@ -89,6 +89,7 @@ extern char datatoc_common_hair_lib_glsl[]; extern char datatoc_common_view_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_lit_surface_frag_glsl[]; extern char datatoc_lit_surface_vert_glsl[]; extern char datatoc_raytrace_lib_glsl[]; @@ -618,6 +619,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_raytrace_lib_glsl, datatoc_ssr_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, @@ -641,6 +643,7 @@ void EEVEE_materials_init(EEVEE_ViewLayerData *sldata, datatoc_bsdf_common_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_ltc_lib_glsl, @@ -776,6 +779,7 @@ struct GPUMaterial *EEVEE_material_world_lightprobe_get(struct Scene *scene, Wor wo, engine, options, + false, e_data.vert_background_shader_str, NULL, e_data.frag_shader_lib, @@ -796,6 +800,7 @@ struct GPUMaterial *EEVEE_material_world_background_get(struct Scene *scene, Wor wo, engine, options, + false, e_data.vert_background_shader_str, NULL, e_data.frag_shader_lib, @@ -819,6 +824,7 @@ struct GPUMaterial *EEVEE_material_world_volume_get(struct Scene *scene, World * wo, engine, options, + true, e_data.vert_volume_shader_str, e_data.geom_volume_shader_str, e_data.volume_shader_lib, @@ -853,6 +859,7 @@ struct GPUMaterial *EEVEE_material_mesh_get(struct Scene *scene, ma, engine, options, + false, e_data.vert_shader_str, NULL, e_data.frag_shader_lib, @@ -880,6 +887,7 @@ struct GPUMaterial *EEVEE_material_mesh_volume_get(struct Scene *scene, Material ma, engine, options, + true, e_data.vert_volume_shader_str, e_data.geom_volume_shader_str, e_data.volume_shader_lib, @@ -916,6 +924,7 @@ struct GPUMaterial *EEVEE_material_mesh_depth_get(struct Scene *scene, ma, engine, options, + false, (is_shadow) ? e_data.vert_shadow_shader_str : e_data.vert_shader_str, NULL, @@ -945,6 +954,7 @@ struct GPUMaterial *EEVEE_material_hair_get(struct Scene *scene, Material *ma) ma, engine, options, + false, e_data.vert_shader_str, NULL, e_data.frag_shader_lib, @@ -1256,7 +1266,7 @@ void EEVEE_materials_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); } - if (LOOK_DEV_OVERLAY_ENABLED(draw_ctx->v3d)) { + if (eevee_hdri_preview_overlay_enabled(draw_ctx->v3d)) { DRWShadingGroup *shgrp; struct GPUBatch *sphere = DRW_cache_sphere_get(); @@ -1919,7 +1929,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, * to know if the material has a "volume nodetree". */ bool use_volume_material = (gpumat_array[0] && - GPU_material_use_domain_volume(gpumat_array[0])); + GPU_material_has_volume_output(gpumat_array[0])); if ((ob->dt >= OB_SOLID) || DRW_state_is_image_render()) { /* Get per-material split surface */ @@ -1968,7 +1978,7 @@ void EEVEE_materials_cache_populate(EEVEE_Data *vedata, /* Do not render surface if we are rendering a volume object * and do not have a surface closure. */ if (use_volume_material && - (gpumat_array[i] && !GPU_material_use_domain_surface(gpumat_array[i]))) { + (gpumat_array[i] && !GPU_material_has_surface_output(gpumat_array[i]))) { continue; } diff --git a/source/blender/draw/engines/eevee/eevee_private.h b/source/blender/draw/engines/eevee/eevee_private.h index 5ffea393e1f..0f084ba306b 100644 --- a/source/blender/draw/engines/eevee/eevee_private.h +++ b/source/blender/draw/engines/eevee/eevee_private.h @@ -78,6 +78,8 @@ extern struct DrawEngineType draw_engine_eevee_type; SHADER_IRRADIANCE /* clang-format on */ +#define EEVEE_PROBE_MAX min_ii(MAX_PROBE, GPU_max_texture_layers() / 6) + #define SWAP_DOUBLE_BUFFERS() \ { \ if (effects->swap_double_buffer) { \ @@ -123,9 +125,21 @@ extern struct DrawEngineType draw_engine_eevee_type; } \ ((void)0) -#define LOOK_DEV_OVERLAY_ENABLED(v3d) \ - ((v3d) && (v3d->shading.type == OB_MATERIAL) && ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && \ - (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV)) +BLI_INLINE bool eevee_hdri_preview_overlay_enabled(View3D *v3d) +{ + /* Only show the HDRI Preview in Shading Preview in the Viewport. */ + if (v3d == NULL || v3d->shading.type != OB_MATERIAL) { + return false; + } + + /* Only show the HDRI Preview when viewing the Combined render pass */ + if (v3d->shading.render_pass != SCE_PASS_COMBINED) { + return false; + } + + return ((v3d->flag2 & V3D_HIDE_OVERLAYS) == 0) && (v3d->overlay.flag & V3D_OVERLAY_LOOK_DEV); +} + #define USE_SCENE_LIGHT(v3d) \ ((!v3d) || \ ((v3d->shading.type == OB_MATERIAL) && (v3d->shading.flag & V3D_SHADING_SCENE_LIGHTS)) || \ @@ -137,19 +151,6 @@ extern struct DrawEngineType draw_engine_eevee_type; ((v3d->shading.flag & V3D_SHADING_SCENE_WORLD_RENDER) == 0)))) #define MIN_CUBE_LOD_LEVEL 3 - -BLI_INLINE int octahedral_size_from_cubesize(int cube_size) -{ - int cube_pixel_count = square_i(cube_size) * 6; - int octa_size = (int)ceilf(sqrtf(cube_pixel_count)); - int lod_count = log2_floor_u(octa_size) - MIN_CUBE_LOD_LEVEL; - /* Find lowest lod size and grow back to avoid having non matching mipsizes that would - * break trilinear interpolation. */ - octa_size /= 1 << lod_count; - octa_size *= 1 << lod_count; - return octa_size; -} - #define MAX_PLANAR_LOD_LEVEL 9 /* All the renderpasses that use the GPUMaterial for accumulation */ diff --git a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c index d231edf1383..e875187bdbf 100644 --- a/source/blender/draw/engines/eevee/eevee_screen_raytrace.c +++ b/source/blender/draw/engines/eevee/eevee_screen_raytrace.c @@ -54,6 +54,7 @@ extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_effect_ssr_frag_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; @@ -67,6 +68,7 @@ static struct GPUShader *eevee_effects_screen_raytrace_shader_get(int options) datatoc_bsdf_sampling_lib_glsl, datatoc_ambient_occlusion_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_lightprobe_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_effect_ssr_frag_glsl); diff --git a/source/blender/draw/engines/eevee/eevee_shaders.c b/source/blender/draw/engines/eevee/eevee_shaders.c index 2d91e4bb4bd..50b7c5c5f97 100644 --- a/source/blender/draw/engines/eevee/eevee_shaders.c +++ b/source/blender/draw/engines/eevee/eevee_shaders.c @@ -88,6 +88,7 @@ extern char datatoc_lightprobe_planar_downsample_vert_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lightprobe_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; /* Velocity Resolve */ extern char datatoc_effect_velocity_resolve_frag_glsl[]; @@ -196,6 +197,7 @@ GPUShader *EEVEE_shaders_background_studiolight_sh_get(void) { if (e_data.probe_background_studiolight_sh == NULL) { char *frag_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_lightprobe_lib_glsl, @@ -217,6 +219,7 @@ GPUShader *EEVEE_shaders_probe_cube_display_sh_get(void) { if (e_data.probe_cube_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, @@ -238,6 +241,7 @@ GPUShader *EEVEE_shaders_probe_grid_display_sh_get(void) { if (e_data.probe_grid_display_sh == NULL) { char *shader_str = BLI_string_joinN(datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_common_view_lib_glsl, datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, diff --git a/source/blender/draw/engines/eevee/eevee_subsurface.c b/source/blender/draw/engines/eevee/eevee_subsurface.c index 98e799acb5e..bab89a8a87b 100644 --- a/source/blender/draw/engines/eevee/eevee_subsurface.c +++ b/source/blender/draw/engines/eevee/eevee_subsurface.c @@ -41,6 +41,7 @@ extern char datatoc_common_uniforms_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_raytrace_lib_glsl[]; extern char datatoc_octahedron_lib_glsl[]; +extern char datatoc_cubemap_lib_glsl[]; extern char datatoc_bsdf_sampling_lib_glsl[]; extern char datatoc_bsdf_common_lib_glsl[]; extern char datatoc_effect_subsurface_frag_glsl[]; @@ -59,6 +60,7 @@ static void eevee_create_shader_subsurface(void) datatoc_bsdf_sampling_lib_glsl, datatoc_raytrace_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_lights_lib_glsl, datatoc_effect_translucency_frag_glsl); diff --git a/source/blender/draw/engines/eevee/eevee_volumes.c b/source/blender/draw/engines/eevee/eevee_volumes.c index d11e93bbc3f..8c1c72a3c20 100644 --- a/source/blender/draw/engines/eevee/eevee_volumes.c +++ b/source/blender/draw/engines/eevee/eevee_volumes.c @@ -72,6 +72,7 @@ extern char datatoc_bsdf_common_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_cubemap_lib_glsl[]; extern char datatoc_irradiance_lib_glsl[]; extern char datatoc_lights_lib_glsl[]; extern char datatoc_volumetric_accum_frag_glsl[]; @@ -99,6 +100,7 @@ static void eevee_create_shader_volumes(void) datatoc_common_uniforms_lib_glsl, datatoc_bsdf_common_lib_glsl, datatoc_octahedron_lib_glsl, + datatoc_cubemap_lib_glsl, datatoc_irradiance_lib_glsl, datatoc_lights_lib_glsl, datatoc_volumetric_lib_glsl); @@ -141,10 +143,10 @@ static void eevee_create_shader_volumes(void) e_data.volumetric_accum_sh = DRW_shader_create_fullscreen(datatoc_volumetric_accum_frag_glsl, NULL); - float color[4] = {1.0f, 1.0f, 1.0f, 1.0f}; - e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, color); + const float density[4] = {1.0f, 1.0f, 1.0f, 1.0f}; + e_data.dummy_density = DRW_texture_create_3d(1, 1, 1, GPU_RGBA8, DRW_TEX_WRAP, density); - float flame = 0.0f; + const float flame = 0.0f; e_data.dummy_flame = DRW_texture_create_3d(1, 1, 1, GPU_R8, DRW_TEX_WRAP, &flame); } @@ -351,7 +353,7 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) !LOOK_DEV_STUDIO_LIGHT_ENABLED(draw_ctx->v3d)) { struct GPUMaterial *mat = EEVEE_material_world_volume_get(scene, wo); - if (GPU_material_use_domain_volume(mat)) { + if (GPU_material_has_volume_output(mat)) { grp = DRW_shgroup_material_create(mat, psl->volumetric_world_ps); } @@ -367,9 +369,11 @@ void EEVEE_volumes_cache_init(EEVEE_ViewLayerData *sldata, EEVEE_Data *vedata) grp, "renderpass_block", EEVEE_material_default_render_pass_ubo_get(sldata)); /* Fix principle volumetric not working with world materials. */ - DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); - DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame); - DRW_shgroup_uniform_vec2_copy(grp, "unftemperature", (float[2]){0.0f, 1.0f}); + ListBase gpu_grids = GPU_material_volume_grids(mat); + for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; + gpu_grid = gpu_grid->next) { + DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density); + } DRW_shgroup_call_procedural_triangles(grp, NULL, common_data->vol_tex_size[2]); @@ -445,6 +449,7 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, DRW_shgroup_uniform_vec3(grp, "volumeOrcoLoc", texcoloc, 1); DRW_shgroup_uniform_vec3(grp, "volumeOrcoSize", texcosize, 1); + ListBase gpu_grids = GPU_material_volume_grids(mat); /* Smoke Simulation */ if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && (md = modifiers_findByType(ob, eModifierType_Fluid)) && @@ -476,10 +481,25 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, BLI_addtail(&e_data.smoke_domains, BLI_genericNodeN(mmd)); } - DRW_shgroup_uniform_texture_ref( - grp, "sampdensity", mds->tex ? &mds->tex : &e_data.dummy_density); - DRW_shgroup_uniform_texture_ref( - grp, "sampflame", mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame); + for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) { + if (STREQ(gpu_grid->name, "density")) { + DRW_shgroup_uniform_texture_ref(grp, + gpu_grid->sampler_name, + mds->tex_density ? &mds->tex_density : + &e_data.dummy_density); + } + else if (STREQ(gpu_grid->name, "color")) { + DRW_shgroup_uniform_texture_ref( + grp, gpu_grid->sampler_name, mds->tex_color ? &mds->tex_color : &e_data.dummy_density); + } + else if (STREQ(gpu_grid->name, "flame") || STREQ(gpu_grid->name, "temperature")) { + DRW_shgroup_uniform_texture_ref( + grp, gpu_grid->sampler_name, mds->tex_flame ? &mds->tex_flame : &e_data.dummy_flame); + } + else { + DRW_shgroup_uniform_texture_ref(grp, gpu_grid->sampler_name, &e_data.dummy_density); + } + } /* Constant Volume color. */ bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && @@ -489,13 +509,13 @@ void EEVEE_volumes_cache_object_add(EEVEE_ViewLayerData *sldata, grp, "volumeColor", (use_constant_color) ? mds->active_color : white, 1); /* Output is such that 0..1 maps to 0..1000K */ - DRW_shgroup_uniform_vec2(grp, "unftemperature", &mds->flame_ignition, 1); + DRW_shgroup_uniform_vec2(grp, "volumeTemperature", &mds->flame_ignition, 1); } else { - DRW_shgroup_uniform_texture(grp, "sampdensity", e_data.dummy_density); - DRW_shgroup_uniform_texture(grp, "sampflame", e_data.dummy_flame); + for (GPUMaterialVolumeGrid *gpu_grid = gpu_grids.first; gpu_grid; gpu_grid = gpu_grid->next) { + DRW_shgroup_uniform_texture(grp, gpu_grid->sampler_name, e_data.dummy_density); + } DRW_shgroup_uniform_vec3(grp, "volumeColor", white, 1); - DRW_shgroup_uniform_vec2(grp, "unftemperature", (float[2]){0.0f, 1.0f}, 1); } /* TODO Reduce to number of slices intersecting. */ diff --git a/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl new file mode 100644 index 00000000000..90272400915 --- /dev/null +++ b/source/blender/draw/engines/eevee/shaders/cubemap_lib.glsl @@ -0,0 +1,130 @@ + +#ifdef GPU_ARB_texture_cube_map_array + +# define textureLod_cubemapArray(tex, co, lod) textureLod(tex, co, lod) + +#else + +/* Fallback implementation for hardware not supporting cubemap arrays. */ +# define samplerCubeArray sampler2DArray + +float cubemap_face_index(vec3 P) +{ + vec3 aP = abs(P); + if (all(greaterThan(aP.xx, aP.yz))) { + return (P.x > 0.0) ? 0.0 : 1.0; + } + else if (all(greaterThan(aP.yy, aP.xz))) { + return (P.y > 0.0) ? 2.0 : 3.0; + } + else { + return (P.z > 0.0) ? 4.0 : 5.0; + } +} + +vec2 cubemap_face_coord(vec3 P, float face) +{ + if (face < 2.0) { + return (P.zy / P.x) * vec2(-0.5, -sign(P.x) * 0.5) + 0.5; + } + else if (face < 4.0) { + return (P.xz / P.y) * vec2(sign(P.y) * 0.5, 0.5) + 0.5; + } + else { + return (P.xy / P.z) * vec2(0.5, -sign(P.z) * 0.5) + 0.5; + } +} + +vec3 cubemap_adj_x(float face) +{ + bool y_axis = (face == 2.0 || face == 3.0); + return y_axis ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); +} + +vec3 cubemap_adj_y(float face) +{ + bool x_axis = (face < 2.0); + return x_axis ? vec3(0.0, 0.0, 1.0) : vec3(1.0, 0.0, 0.0); +} + +vec3 cubemap_adj_xy(float face) +{ + if (face < 2.0) { + return vec3(0.0, 1.0, 1.0); + } + else if (face < 4.0) { + return vec3(1.0, 0.0, 1.0); + } + else { + return vec3(1.0, 1.0, 0.0); + } +} + +vec4 cubemap_seamless(sampler2DArray tex, vec4 cubevec, float lod) +{ + /* Manual Cube map Layer indexing. */ + float face = cubemap_face_index(cubevec.xyz); + vec2 uv = cubemap_face_coord(cubevec.xyz, face); + vec3 coord = vec3(uv, cubevec.w * 6.0 + face); + + vec4 col = textureLod(tex, coord, lod); + + float cube_size = float(textureSize(tex, int(lod)).x); + + vec2 uv_border = (abs(uv - 0.5) + (0.5 / cube_size - 0.5)) * 2.0 * cube_size; + bvec2 border = greaterThan(uv_border, vec2(0.0)); + if (all(border)) { + /* Corners case. */ + vec3 cubevec_adj; + float face_adj; + /* Get the other face coords. */ + cubevec_adj = cubevec.xyz * cubemap_adj_x(face); + face_adj = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face_adj); + coord = vec3(uv, cubevec.w * 6.0 + face_adj); + vec4 col1 = textureLod(tex, coord, lod); + + /* Get the 3rd face coords. */ + cubevec_adj = cubevec.xyz * cubemap_adj_y(face); + face_adj = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face_adj); + coord = vec3(uv, cubevec.w * 6.0 + face_adj); + vec4 col2 = textureLod(tex, coord, lod); + + /* Mix all colors to get the corner color. */ + vec4 col3 = (col + col1 + col2) / 3.0; + + vec2 mix_fac = uv_border * 0.5; + return mix(mix(col, col2, mix_fac.x), mix(col1, col3, mix_fac.x), mix_fac.y); + } + else if (any(border)) { + /* Edges case. */ + /* Get the other face coords. */ + vec3 cubevec_adj = cubevec.xyz * cubemap_adj_xy(face); + face = cubemap_face_index(cubevec_adj); + /* Still use the original cubevec to get the outer texels or the face. */ + uv = cubemap_face_coord(cubevec.xyz, face); + coord = vec3(uv, cubevec.w * 6.0 + face); + + float mix_fac = max(uv_border.x, uv_border.y) * 0.5; + return mix(col, textureLod(tex, coord, lod), mix_fac); + } + else { + return col; + } +} + +vec4 textureLod_cubemapArray(sampler2DArray tex, vec4 cubevec, float lod) +{ + float lod1 = floor(lod); + float lod2 = ceil(lod); + + vec4 col_lod1 = cubemap_seamless(tex, cubevec, lod1); + vec4 col_lod2 = cubemap_seamless(tex, cubevec, lod2); + + return mix(col_lod1, col_lod2, lod - lod1); +} + +#endif diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl index a852dd47872..96fe94fc41e 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_cube_display_frag.glsl @@ -15,6 +15,5 @@ void main() vec3 view_nor = vec3(quadCoord, sqrt(max(0.0, 1.0 - dist_sqr))); vec3 world_ref = mat3(ViewMatrixInverse) * reflect(vec3(0.0, 0.0, -1.0), view_nor); - FragColor = vec4(textureLod_octahedron(probeCubes, vec4(world_ref, pid), 0.0, prbLodCubeMax).rgb, - 1.0); + FragColor = vec4(textureLod_cubemapArray(probeCubes, vec4(world_ref, pid), 0.0).rgb, 1.0); } diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl index 06c31272ecd..00eb3c7e200 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_filter_glossy_frag.glsl @@ -33,29 +33,9 @@ vec3 octahedral_to_cubemap_proj(vec2 co) void main() { - vec2 uvs = gl_FragCoord.xy * texelSize; - - /* Add a N pixel border to ensure filtering is correct - * for N mipmap levels. */ - uvs = (uvs - paddingSize) / (1.0 - 2.0 * paddingSize); - - /* edge mirroring : only mirror if directly adjacent - * (not diagonally adjacent) */ - vec2 m = abs(uvs - 0.5) + 0.5; - vec2 f = floor(m); - if (f.x - f.y != 0.0) { - uvs = 1.0 - uvs; - } - - /* clamp to [0-1] */ - uvs = fract(uvs); - - /* get cubemap vector */ - vec3 cubevec = octahedral_to_cubemap_proj(uvs); - vec3 N, T, B, V; - vec3 R = normalize(cubevec); + vec3 R = normalize(worldPosition); /* Isotropic assumption */ N = V = R; diff --git a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl index ab205b78274..6c6db88139b 100644 --- a/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/lightprobe_lib.glsl @@ -1,7 +1,7 @@ /* ----------- Uniforms --------- */ uniform sampler2DArray probePlanars; -uniform sampler2DArray probeCubes; +uniform samplerCubeArray probeCubes; /* ----------- Structures --------- */ @@ -172,15 +172,12 @@ vec3 probe_evaluate_cube(int pd_id, vec3 W, vec3 R, float roughness) float fac = saturate(original_roughness * 2.0 - 1.0); R = mix(intersection, R, fac * fac); - return textureLod_octahedron( - probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax, prbLodCubeMax) - .rgb; + return textureLod_cubemapArray(probeCubes, vec4(R, float(pd_id)), roughness * prbLodCubeMax).rgb; } vec3 probe_evaluate_world_spec(vec3 R, float roughness) { - return textureLod_octahedron(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax, prbLodCubeMax) - .rgb; + return textureLod_cubemapArray(probeCubes, vec4(R, 0.0), roughness * prbLodCubeMax).rgb; } vec3 probe_evaluate_planar( diff --git a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl index bfb6bc890ec..e05cc2719fa 100644 --- a/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl +++ b/source/blender/draw/engines/eevee/shaders/octahedron_lib.glsl @@ -18,21 +18,3 @@ vec2 mapping_octahedron(vec3 cubevec, vec2 texel_size) return uvs; } - -vec4 textureLod_octahedron(sampler2DArray tex, vec4 cubevec, float lod, float lod_max) -{ - vec2 texelSize = 1.0 / vec2(textureSize(tex, int(lod_max))); - - vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize); - - return textureLod(tex, vec3(uvs, cubevec.w), lod); -} - -vec4 texture_octahedron(sampler2DArray tex, vec4 cubevec) -{ - vec2 texelSize = 1.0 / vec2(textureSize(tex, 0)); - - vec2 uvs = mapping_octahedron(cubevec.xyz, texelSize); - - return texture(tex, vec3(uvs, cubevec.w)); -} diff --git a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c index 743171b09fb..3459685f504 100644 --- a/source/blender/draw/engines/gpencil/gpencil_cache_utils.c +++ b/source/blender/draw/engines/gpencil/gpencil_cache_utils.c @@ -61,7 +61,7 @@ GPENCIL_tObject *gpencil_object_cache_add(GPENCIL_PrivateData *pd, Object *ob) /* TODO: This does not work quite well if you use * strokes not aligned with the object axes. Maybe we could try to * compute the minimum axis of all strokes. But this would be more - * computationaly heavy and should go into the GPData evaluation. */ + * computationally heavy and should go into the GPData evaluation. */ BoundBox *bbox = BKE_object_boundbox_get(ob); /* Convert bbox to matrix */ float mat[4][4], size[3], center[3]; diff --git a/source/blender/draw/engines/gpencil/gpencil_draw_data.c b/source/blender/draw/engines/gpencil/gpencil_draw_data.c index 77baadfc83a..625af8cec6f 100644 --- a/source/blender/draw/engines/gpencil/gpencil_draw_data.c +++ b/source/blender/draw/engines/gpencil/gpencil_draw_data.c @@ -108,7 +108,7 @@ static void gpencil_object_random_color_get(const Object *ob, float r_color[3]) static void gpencil_shade_color(float color[3]) { - /* This is scene refered color, not gamma corrected and not per perceptual. + /* This is scene refereed color, not gamma corrected and not per perceptual. * So we lower the threshold a bit. (1.0 / 3.0) */ if (color[0] + color[1] + color[2] > 1.1) { add_v3_fl(color, -0.25f); diff --git a/source/blender/draw/engines/gpencil/gpencil_engine.c b/source/blender/draw/engines/gpencil/gpencil_engine.c index d47d6f8a836..37aef5a633a 100644 --- a/source/blender/draw/engines/gpencil/gpencil_engine.c +++ b/source/blender/draw/engines/gpencil/gpencil_engine.c @@ -710,7 +710,7 @@ void GPENCIL_cache_finish(void *ved) if (pd->use_mask_fb) { /* We need an extra depth to not disturb the normal drawing. - * The color_tx is needed for framebuffer cmpleteness. */ + * The color_tx is needed for frame-buffer completeness. */ GPUTexture *color_tx, *depth_tx; depth_tx = DRW_texture_pool_query_2d( size[0], size[1], GPU_DEPTH24_STENCIL8, &draw_engine_gpencil_type); diff --git a/source/blender/draw/engines/overlay/overlay_engine.c b/source/blender/draw/engines/overlay/overlay_engine.c index cfa0fa9eb1a..740ca42800e 100644 --- a/source/blender/draw/engines/overlay/overlay_engine.c +++ b/source/blender/draw/engines/overlay/overlay_engine.c @@ -382,9 +382,6 @@ static void OVERLAY_cache_finish(void *vedata) DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0); GPU_framebuffer_ensure_config( - &dfbl->default_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - GPU_framebuffer_ensure_config( &dfbl->in_front_fb, {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); } diff --git a/source/blender/draw/engines/overlay/overlay_outline.c b/source/blender/draw/engines/overlay/overlay_outline.c index e77a0a143a9..0395f6890bd 100644 --- a/source/blender/draw/engines/overlay/overlay_outline.c +++ b/source/blender/draw/engines/overlay/overlay_outline.c @@ -33,7 +33,7 @@ #include "overlay_private.h" -/* Returns the normal plane in ndc space. */ +/* Returns the normal plane in NDC space. */ static void gpencil_depth_plane(Object *ob, float r_plane[4]) { /* TODO put that into private data. */ @@ -42,11 +42,11 @@ static void gpencil_depth_plane(Object *ob, float r_plane[4]) float *camera_z_axis = viewinv[2]; float *camera_pos = viewinv[3]; - /* Find the normal most likely to represent the gpObject. */ + /* Find the normal most likely to represent the grease pencil object. */ /* TODO: This does not work quite well if you use * strokes not aligned with the object axes. Maybe we could try to * compute the minimum axis of all strokes. But this would be more - * computationaly heavy and should go into the GPData evaluation. */ + * computationally heavy and should go into the GPData evaluation. */ BoundBox *bbox = BKE_object_boundbox_get(ob); /* Convert bbox to matrix */ float mat[4][4], size[3], center[3]; diff --git a/source/blender/draw/engines/overlay/overlay_wireframe.c b/source/blender/draw/engines/overlay/overlay_wireframe.c index 722055c36f0..6b0e5e0b72e 100644 --- a/source/blender/draw/engines/overlay/overlay_wireframe.c +++ b/source/blender/draw/engines/overlay/overlay_wireframe.c @@ -68,22 +68,17 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) OVERLAY_shader_wireframe(); for (int xray = 0; xray < (is_material_shmode ? 1 : 2); xray++) { - /* Only do stencil test if stencil buffer is written by the render engine. */ - DRWState stencil_state = is_material_shmode ? 0 : DRW_STATE_STENCIL_EQUAL; DRWState state = DRW_STATE_FIRST_VERTEX_CONVENTION | DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; DRWPass *pass; - uint stencil_mask; if (xray == 0) { - DRW_PASS_CREATE(psl->wireframe_ps, state | stencil_state | pd->clipping_state); + DRW_PASS_CREATE(psl->wireframe_ps, state | pd->clipping_state); pass = psl->wireframe_ps; - stencil_mask = 0xFF; } else { DRW_PASS_CREATE(psl->wireframe_xray_ps, state | pd->clipping_state); pass = psl->wireframe_xray_ps; - stencil_mask = 0x00; } for (int use_coloring = 0; use_coloring < 2; use_coloring++) { @@ -94,17 +89,14 @@ void OVERLAY_wireframe_cache_init(OVERLAY_Data *vedata) DRW_shgroup_uniform_bool_copy(grp, "isTransform", (G.moving & G_TRANSFORM_OBJ) != 0); DRW_shgroup_uniform_bool_copy(grp, "isObjectColor", is_object_color); DRW_shgroup_uniform_bool_copy(grp, "isRandomColor", is_random_color); - DRW_shgroup_stencil_mask(grp, stencil_mask); pd->wires_all_grp[xray][use_coloring] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 1.0f); - DRW_shgroup_stencil_mask(grp, stencil_mask); } pd->wires_sculpt_grp[xray] = grp = DRW_shgroup_create(wires_sh, pass); DRW_shgroup_uniform_float_copy(grp, "wireStepParam", 10.0f); DRW_shgroup_uniform_bool_copy(grp, "useColoring", false); - DRW_shgroup_stencil_mask(grp, stencil_mask); } if (is_material_shmode) { diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl deleted file mode 100644 index a0e04f252e2..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_frag.glsl +++ /dev/null @@ -1,81 +0,0 @@ -out vec4 fragColor; - -uniform sampler2D depthBuffer; -uniform sampler2D colorBuffer; -uniform sampler2D normalBuffer; -uniform usampler2D objectId; - -uniform vec2 invertedViewportSize; -uniform mat4 WinMatrix; /* inverse WinMatrix */ - -uniform vec4 viewvecs[3]; -uniform vec4 ssao_params; -uniform vec4 ssao_settings; -uniform vec2 curvature_settings; -uniform sampler2D ssao_jitter; - -layout(std140) uniform samples_block -{ - vec4 ssao_samples[500]; -}; - -#define ssao_samples_num ssao_params.x -#define jitter_tilling ssao_params.yz -#define ssao_iteration ssao_params.w - -#define ssao_distance ssao_settings.x -#define ssao_factor_cavity ssao_settings.y -#define ssao_factor_edge ssao_settings.z -#define ssao_attenuation ssao_settings.w - -vec3 get_view_space_from_depth(in vec2 uvcoords, in float depth) -{ - if (WinMatrix[3][3] == 0.0) { - /* Perspective */ - float d = 2.0 * depth - 1.0; - - float zview = -WinMatrix[3][2] / (d + WinMatrix[2][2]); - - return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); - } - else { - /* Orthographic */ - vec3 offset = vec3(uvcoords, depth); - - return viewvecs[0].xyz + offset * viewvecs[1].xyz; - } -} - -/* forward declaration */ -void ssao_factors(in float depth, - in vec3 normal, - in vec3 position, - in vec2 screenco, - out float cavities, - out float edges); - -void main() -{ - vec2 screenco = vec2(gl_FragCoord.xy) * invertedViewportSize; - ivec2 texel = ivec2(gl_FragCoord.xy); - - float cavity = 0.0, edges = 0.0, curvature = 0.0; - -#ifdef USE_CAVITY - float depth = texelFetch(depthBuffer, texel, 0).x; - vec3 position = get_view_space_from_depth(screenco, depth); - vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); - - ssao_factors(depth, normal_viewport, position, screenco, cavity, edges); -#endif - -#ifdef USE_CURVATURE - curvature = calculate_curvature( - objectId, normalBuffer, texel, curvature_settings.x, curvature_settings.y); -#endif - - float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); - - /* Using UNORM render target so compress the range. */ - fragColor = vec4(final_cavity_factor / CAVITY_BUFFER_RANGE); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl index 376b19cdd1b..87d04144cde 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_cavity_lib.glsl @@ -1,77 +1,87 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) -/* from The Alchemy screen-space ambient obscurance algorithm +layout(std140) uniform samples_block +{ + vec4 samples_coords[512]; +}; + +uniform sampler2D cavityJitter; + +/* From The Alchemy screen-space ambient obscurance algorithm * http://graphics.cs.williams.edu/papers/AlchemyHPG11/VV11AlchemyAO.pdf */ -void ssao_factors(in float depth, - in vec3 normal, - in vec3 position, - in vec2 screenco, - out float cavities, - out float edges) +void cavity_compute(vec2 screenco, + sampler2D depthBuffer, + sampler2D normalBuffer, + 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) { + + float depth = texture(depthBuffer, screenco).x; + + /* Early out if background and infront. */ + if (depth == 1.0 || depth == 0.0) { return; } - /* take the normalized ray direction here */ - vec3 noise = texture(ssao_jitter, screenco.xy * jitter_tilling).rgb; + vec3 position = view_position_from_depth(screenco, depth, world_data.viewvecs, ProjectionMatrix); + vec3 normal = workbench_normal_decode(texture(normalBuffer, screenco)); + + vec2 jitter_co = (screenco * world_data.viewport_size.xy) * world_data.cavity_jitter_scale; + vec3 noise = texture(cavityJitter, jitter_co).rgb; /* find the offset in screen space by multiplying a point * in camera space at the depth of the point by the projection matrix. */ vec2 offset; - float homcoord = WinMatrix[2][3] * position.z + WinMatrix[3][3]; - offset.x = WinMatrix[0][0] * ssao_distance / homcoord; - offset.y = WinMatrix[1][1] * ssao_distance / homcoord; + float homcoord = ProjectionMatrix[2][3] * position.z + ProjectionMatrix[3][3]; + offset.x = ProjectionMatrix[0][0] * world_data.cavity_distance / homcoord; + offset.y = ProjectionMatrix[1][1] * world_data.cavity_distance / homcoord; /* convert from -1.0...1.0 range to 0.0..1.0 for easy use with texture coordinates */ offset *= 0.5; - int num_samples = int(ssao_samples_num); - /* Note. Putting noise usage here to put some ALU after texture fetch. */ vec2 rotX = noise.rg; vec2 rotY = vec2(-rotX.y, rotX.x); - for (int x = 0; x < num_samples; x++) { - int sample_index = x + (int(ssao_iteration) * num_samples); - if (sample_index > 500) { - continue; - } - /* ssao_samples[x].xy is sample direction (normalized). - * ssao_samples[x].z is sample distance from disk center. */ - + int sample_start = world_data.cavity_sample_start; + int sample_end = world_data.cavity_sample_end; + for (int i = sample_start; i < sample_end && i < 512; i++) { + /* sample_coord.xy is sample direction (normalized). + * sample_coord.z is sample distance from disk center. */ + vec3 sample_coord = samples_coords[i].xyz; /* Rotate with random direction to get jittered result. */ - vec2 dir_jittered = vec2(dot(ssao_samples[sample_index].xy, rotX), - dot(ssao_samples[sample_index].xy, rotY)); - dir_jittered.xy *= ssao_samples[sample_index].z + noise.b; + vec2 dir_jittered = vec2(dot(sample_coord.xy, rotX), dot(sample_coord.xy, rotY)); + dir_jittered.xy *= sample_coord.z + noise.b; - vec2 uvcoords = screenco.xy + dir_jittered * offset; - - if (uvcoords.x > 1.0 || uvcoords.x < 0.0 || uvcoords.y > 1.0 || uvcoords.y < 0.0) { + vec2 uvcoords = screenco + dir_jittered * offset; + /* Out of screen case. */ + if (any(greaterThan(abs(uvcoords - 0.5), vec2(0.5)))) { continue; } - - float depth_new = texture(depthBuffer, uvcoords).r; - + /* Sample depth. */ + float s_depth = texture(depthBuffer, uvcoords).r; /* Handle Background case */ - bool is_background = (depth_new == 1.0); - + bool is_background = (s_depth == 1.0); /* This trick provide good edge effect even if no neighbor is found. */ - vec3 pos_new = get_view_space_from_depth(uvcoords, (is_background) ? depth : depth_new); + s_depth = (is_background) ? depth : s_depth; + vec3 s_pos = view_position_from_depth( + uvcoords, s_depth, world_data.viewvecs, ProjectionMatrix); if (is_background) { - pos_new.z -= ssao_distance; + s_pos.z -= world_data.cavity_distance; } - vec3 dir = pos_new - position; + vec3 dir = s_pos - position; float len = length(dir); float f_cavities = dot(dir, normal); float f_edge = -f_cavities; float f_bias = 0.05 * len + 0.0001; - float attenuation = 1.0 / (len * (1.0 + len * len * ssao_attenuation)); + float attenuation = 1.0 / (len * (1.0 + len * len * world_data.cavity_attenuation)); /* use minor bias here to avoid self shadowing */ if (f_cavities > -f_bias) { @@ -82,11 +92,10 @@ void ssao_factors(in float depth, edges += f_edge * attenuation; } } - - cavities /= ssao_samples_num; - edges /= ssao_samples_num; + cavities *= world_data.cavity_sample_count_inv; + edges *= world_data.cavity_sample_count_inv; /* don't let cavity wash out the surface appearance */ - cavities = clamp(cavities * ssao_factor_cavity, 0.0, 1.0); - edges = edges * ssao_factor_edge; + cavities = clamp(cavities * world_data.cavity_valley_factor, 0.0, 1.0); + edges = edges * world_data.cavity_ridge_factor; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl index c0d7719180b..25eaf003e07 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_common_lib.glsl @@ -1,30 +1,16 @@ -#define NO_OBJECT_ID uint(0) + #define EPSILON 0.00001 #define M_PI 3.14159265358979323846 #define CAVITY_BUFFER_RANGE 4.0 -/* 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_mat4x4[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))); - -float bayer_dither_noise() -{ - ivec2 tx1 = ivec2(gl_FragCoord.xy) % 4; - ivec2 tx2 = ivec2(gl_FragCoord.xy) % 2; - return dither_mat4x4[tx1.x][tx1.y]; -} - #ifdef WORKBENCH_ENCODE_NORMALS # define WB_Normal vec2 /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -vec3 workbench_normal_decode(WB_Normal enc) +vec3 workbench_normal_decode(vec4 enc) { vec2 fenc = enc.xy * 4.0 - 2.0; float f = dot(fenc, fenc); @@ -37,8 +23,9 @@ vec3 workbench_normal_decode(WB_Normal enc) /* From http://aras-p.info/texts/CompactNormalStorage.html * Using Method #4: Spheremap Transform */ -WB_Normal workbench_normal_encode(vec3 n) +WB_Normal workbench_normal_encode(bool front_face, vec3 n) { + n = normalize(front_face ? n : -n); float p = sqrt(n.z * 8.0 + 8.0); n.xy = clamp(n.xy / p + 0.5, 0.0, 1.0); return n.xy; @@ -47,161 +34,64 @@ WB_Normal workbench_normal_encode(vec3 n) #else # define WB_Normal vec3 /* Well just do nothing... */ -# define workbench_normal_encode(a) (a) -# define workbench_normal_decode(a) (a) +# define workbench_normal_encode(f, a) (a) +# define workbench_normal_decode(a) (a.xyz) #endif /* WORKBENCH_ENCODE_NORMALS */ -/* Encoding into the alpha of a RGBA8 UNORM texture. */ +/* Encoding into the alpha of a RGBA16F texture. (10bit mantissa) */ #define TARGET_BITCOUNT 8u #define METALLIC_BITS 3u /* Metallic channel is less important. */ #define ROUGHNESS_BITS (TARGET_BITCOUNT - METALLIC_BITS) -#define TOTAL_BITS (METALLIC_BITS + ROUGHNESS_BITS) /* Encode 2 float into 1 with the desired precision. */ float workbench_float_pair_encode(float v1, float v2) { - // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); /* Same as above because some compiler are dumb af. and think we use mediump int. */ - const int total_mask = 0xFF; const int v1_mask = 0x1F; const int v2_mask = 0x7; int iv1 = int(v1 * float(v1_mask)); int iv2 = int(v2 * float(v2_mask)) << int(ROUGHNESS_BITS); - return float(iv1 | iv2) * (1.0 / float(total_mask)); + return float(iv1 | iv2); } void workbench_float_pair_decode(float data, out float v1, out float v2) { - // const uint total_mask = ~(0xFFFFFFFFu << TOTAL_BITS); // const uint v1_mask = ~(0xFFFFFFFFu << ROUGHNESS_BITS); // const uint v2_mask = ~(0xFFFFFFFFu << METALLIC_BITS); /* Same as above because some compiler are dumb af. and think we use mediump int. */ - const int total_mask = 0xFF; const int v1_mask = 0x1F; const int v2_mask = 0x7; - int idata = int(data * float(total_mask)); + int idata = int(data); v1 = float(idata & v1_mask) * (1.0 / float(v1_mask)); v2 = float(idata >> int(ROUGHNESS_BITS)) * (1.0 / float(v2_mask)); } -float calculate_transparent_weight(float z, float alpha) -{ -#if 0 - /* Eq 10 : Good for surfaces with varying opacity (like particles) */ - float a = min(1.0, alpha * 10.0) + 0.01; - float b = -gl_FragCoord.z * 0.95 + 1.0; - float w = a * a * a * 3e2 * b * b * b; -#else - /* Eq 7 put more emphasis on surfaces closer to the view. */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */ - // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */ - /* Same as eq 7, but optimized. */ - float a = abs(z) / 5.0; - float b = abs(z) / 200.0; - b *= b; - float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */ -#endif - return alpha * clamp(w, 1e-2, 3e2); -} - -/* Special function only to be used with calculate_transparent_weight(). */ -float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat) +vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) { if (proj_mat[3][3] == 0.0) { - float d = 2.0 * depth - 1.0; - return -proj_mat[3][2] / (d + proj_mat[2][2]); + return normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz); } else { - /* Return depth from near plane. */ - return depth * viewvecs[1].z; - } -} - -vec3 view_vector_from_screen_uv(vec2 uv, vec4 viewvecs[3], mat4 proj_mat) -{ - return (proj_mat[3][3] == 0.0) ? normalize(viewvecs[0].xyz + vec3(uv, 0.0) * viewvecs[1].xyz) : - vec3(0.0, 0.0, 1.0); -} - -vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) -{ - /* Quick creation of an orthonormal basis */ - float a = 1.0 / (1.0 + I.z); - float b = -I.x * I.y * a; - vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x); - vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y); - vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N)); - if (flipped) { - matcap_uv.x = -matcap_uv.x; + return vec3(0.0, 0.0, 1.0); } - return matcap_uv * 0.496 + 0.5; } -bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +vec3 view_position_from_depth(vec2 uvcoords, float depth, vec4 viewvecs[3], mat4 proj_mat) { - vec2 tile_pos = floor(co.xy); - - if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) - return false; - - float tile = 10.0 * tile_pos.y + tile_pos.x; - if (tile >= textureSize(map, 0).x) - return false; - - /* Fetch tile information. */ - float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; - if (tile_layer < 0.0) - return false; - - vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); - - co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); - return true; -} + if (proj_mat[3][3] == 0.0) { + /* Perspective */ + float d = 2.0 * depth - 1.0; -vec4 workbench_sample_texture(sampler2D image, - vec2 coord, - bool nearest_sampling, - bool premultiplied) -{ - vec2 tex_size = vec2(textureSize(image, 0).xy); - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; - vec4 color = texture(image, uv); + float zview = -proj_mat[3][2] / (d + proj_mat[2][2]); - /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ - if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) { - color.rgb = color.rgb / color.a; + return zview * (viewvecs[0].xyz + vec3(uvcoords, 0.0) * viewvecs[1].xyz); } + else { + /* Orthographic */ + vec3 offset = vec3(uvcoords, depth); - return color; -} - -vec4 workbench_sample_texture_array(sampler2DArray tile_array, - sampler1DArray tile_data, - vec2 coord, - bool nearest_sampling, - bool premultiplied) -{ - vec2 tex_size = vec2(textureSize(tile_array, 0).xy); - - vec3 uv = vec3(coord, 0); - if (!node_tex_tile_lookup(uv, tile_array, tile_data)) - return vec4(1.0, 0.0, 1.0, 1.0); - - /* TODO(fclem) We could do the same with sampler objects. - * But this is a quick workaround instead of messing with the GPUTexture itself. */ - uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; - vec4 color = texture(tile_array, uv); - - /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ - if (premultiplied && !(color.a == 0.0 || color.a == 1.0)) { - color.rgb = color.rgb / color.a; + return viewvecs[0].xyz + offset * viewvecs[1].xyz; } - - return color; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl new file mode 100644 index 00000000000..cdb9823096c --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_composite_frag.glsl @@ -0,0 +1,44 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) + +uniform sampler2D materialBuffer; +uniform sampler2D normalBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */ + vec3 I = view_vector_from_screen_uv(uvcoordsvar.st, world_data.viewvecs, ProjectionMatrix); + vec3 N = workbench_normal_decode(texture(normalBuffer, uvcoordsvar.st)); + vec4 mat_data = texture(materialBuffer, uvcoordsvar.st); + + vec3 base_color = mat_data.rgb; + + float roughness, metallic; + workbench_float_pair_decode(mat_data.a, roughness, metallic); + +#ifdef V3D_LIGHTING_MATCAP + /* When using matcaps, mat_data.a is the backface sign. */ + N = (mat_data.a > 0.0) ? N : -N; + + fragColor.rgb = get_matcap_lighting(base_color, N, I); +#endif + +#ifdef V3D_LIGHTING_STUDIO + fragColor.rgb = get_world_lighting(base_color, roughness, metallic, N, I); +#endif + +#ifdef V3D_LIGHTING_FLAT + fragColor.rgb = base_color; +#endif + + fragColor.rgb *= get_shadow(N); + + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl index 22dc906be83..e6bc4c7bbc6 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_curvature_lib.glsl @@ -1,6 +1,5 @@ -#ifndef CURVATURE_OFFSET -# define CURVATURE_OFFSET 1 -#endif + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) float curvature_soft_clamp(float curvature, float control) { @@ -10,33 +9,35 @@ float curvature_soft_clamp(float curvature, float control) return 0.25 / control; } -float calculate_curvature( - usampler2D objectId, sampler2D normalBuffer, ivec2 texel, float ridge, float valley) +void curvature_compute(vec2 uv, + usampler2D objectIdBuffer, + sampler2D normalBuffer, + out float curvature) { - uint object_up = texelFetchOffset(objectId, texel, 0, ivec2(0, CURVATURE_OFFSET)).r; - uint object_down = texelFetchOffset(objectId, texel, 0, ivec2(0, -CURVATURE_OFFSET)).r; - uint object_left = texelFetchOffset(objectId, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).r; - uint object_right = texelFetchOffset(objectId, texel, 0, ivec2(CURVATURE_OFFSET, 0)).r; + curvature = 0.0; + + vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale; + uint object_up = texture(objectIdBuffer, uv + offset.zy).r; + uint object_down = texture(objectIdBuffer, uv - offset.zy).r; + uint object_right = texture(objectIdBuffer, uv + offset.xz).r; + uint object_left = texture(objectIdBuffer, uv - offset.xz).r; + /* Remove object outlines. */ if ((object_up != object_down) || (object_right != object_left)) { - return 0.0; + return; } - vec2 normal_up = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, CURVATURE_OFFSET)).rg; - vec2 normal_down = texelFetchOffset(normalBuffer, texel, 0, ivec2(0, -CURVATURE_OFFSET)).rg; - vec2 normal_left = texelFetchOffset(normalBuffer, texel, 0, ivec2(-CURVATURE_OFFSET, 0)).rg; - vec2 normal_right = texelFetchOffset(normalBuffer, texel, 0, ivec2(CURVATURE_OFFSET, 0)).rg; - - normal_up = workbench_normal_decode(normal_up).rg; - normal_down = workbench_normal_decode(normal_down).rg; - normal_left = workbench_normal_decode(normal_left).rg; - normal_right = workbench_normal_decode(normal_right).rg; + float normal_up = workbench_normal_decode(texture(normalBuffer, uv + offset.zy)).g; + float normal_down = workbench_normal_decode(texture(normalBuffer, uv - offset.zy)).g; + float normal_right = workbench_normal_decode(texture(normalBuffer, uv + offset.xz)).r; + float normal_left = workbench_normal_decode(texture(normalBuffer, uv - offset.xz)).r; - float normal_diff = ((normal_up.g - normal_down.g) + (normal_right.r - normal_left.r)); + float normal_diff = (normal_up - normal_down) + (normal_right - normal_left); if (normal_diff < 0) { - return -2.0 * curvature_soft_clamp(-normal_diff, valley); + curvature = -2.0 * curvature_soft_clamp(-normal_diff, world_data.curvature_valley); + } + else { + curvature = 2.0 * curvature_soft_clamp(normal_diff, world_data.curvature_ridge); } - - return 2.0 * curvature_soft_clamp(normal_diff, ridge); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl index 0c984b094d3..5f3283e1643 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_data_lib.glsl @@ -5,12 +5,42 @@ struct LightData { }; struct WorldData { + vec4 viewvecs[3]; + vec4 viewport_size; vec4 object_outline_color; vec4 shadow_direction_vs; + float shadow_focus; + float shadow_shift; + float shadow_mul; + float shadow_add; + /* - 16 bytes alignment- */ LightData lights[4]; vec4 ambient_color; - int num_lights; - int matcap_orientation; + + int cavity_sample_start; + int cavity_sample_end; + float cavity_sample_count_inv; + float cavity_jitter_scale; + + float cavity_valley_factor; + float cavity_ridge_factor; + float cavity_attenuation; + float cavity_distance; + float curvature_ridge; float curvature_valley; + float ui_scale; + float _pad0; + + int matcap_orientation; + bool use_specular; + int _pad1; + int _pad2; +}; + +#define viewport_size_inv viewport_size.zw + +layout(std140) uniform world_block +{ + WorldData world_data; }; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl deleted file mode 100644 index 22fa2babbbf..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_background_frag.glsl +++ /dev/null @@ -1,30 +0,0 @@ - -uniform usampler2D objectId; - -uniform vec2 invertedViewportSize; - -out vec4 fragColor; - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -void main() -{ - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - -#ifndef V3D_SHADING_OBJECT_OUTLINE - - fragColor = vec4(0.0); - -#else /* !V3D_SHADING_OBJECT_OUTLINE */ - - ivec2 texel = ivec2(gl_FragCoord.xy); - uint object_id = texelFetch(objectId, texel, 0).r; - float object_outline = calculate_object_outline(objectId, texel, object_id); - - fragColor = vec4(world_data.object_outline_color.rgb, 1.0) * (1.0 - object_outline); - -#endif /* !V3D_SHADING_OBJECT_OUTLINE */ -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl deleted file mode 100644 index fd4cea4279a..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_deferred_composite_frag.glsl +++ /dev/null @@ -1,103 +0,0 @@ -out vec4 fragColor; - -uniform usampler2D objectId; -uniform sampler2D materialBuffer; -uniform sampler2D normalBuffer; -/* normalBuffer contains viewport normals */ -uniform sampler2D cavityBuffer; -uniform sampler2D matcapDiffuseImage; -uniform sampler2D matcapSpecularImage; - -uniform vec2 invertedViewportSize; -uniform vec4 viewvecs[3]; -uniform float shadowMultiplier; -uniform float lightMultiplier; -uniform float shadowShift = 0.1; -uniform float shadowFocus = 1.0; - -uniform vec3 materialSingleColor; - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - - float roughness, metallic; - vec3 base_color; - -#ifndef MATDATA_PASS_ENABLED - base_color = materialSingleColor; - metallic = 0.0; - roughness = 0.5; -#else - vec4 material_data = texelFetch(materialBuffer, texel, 0); - base_color = material_data.rgb; - workbench_float_pair_decode(material_data.a, roughness, metallic); -#endif - -/* Do we need normals */ -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 normal_viewport = workbench_normal_decode(texelFetch(normalBuffer, texel, 0).rg); -#endif - - vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); - - /* -------- SHADING --------- */ -#ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = base_color; - -#elif defined(V3D_LIGHTING_MATCAP) - /* When using matcaps, the metallic is the backface sign. */ - normal_viewport = (metallic > 0.0) ? normal_viewport : -normal_viewport; - bool flipped = world_data.matcap_orientation != 0; - vec2 matcap_uv = matcap_uv_compute(I_vs, normal_viewport, flipped); - vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb; - -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb; -# else - vec3 matcap_specular = vec3(0.0); -# endif - - vec3 shaded_color = matcap_diffuse * base_color + matcap_specular; - -#elif defined(V3D_LIGHTING_STUDIO) - -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 specular_color = mix(vec3(0.05), base_color, metallic); - vec3 diffuse_color = mix(base_color, vec3(0.0), metallic); -# else - roughness = 0.0; - vec3 specular_color = vec3(0.0); - vec3 diffuse_color = base_color; -# endif - - vec3 shaded_color = get_world_lighting( - world_data, diffuse_color, specular_color, roughness, normal_viewport, I_vs); -#endif - - /* -------- POST EFFECTS --------- */ -#ifdef WB_CAVITY - /* Using UNORM texture so decompress the range */ - shaded_color *= texelFetch(cavityBuffer, texel, 0).r * CAVITY_BUFFER_RANGE; -#endif - -#ifdef V3D_SHADING_SHADOW - float light_factor = -dot(normal_viewport, world_data.shadow_direction_vs.xyz); - float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); - shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); -#endif - -#ifdef V3D_SHADING_OBJECT_OUTLINE - uint object_id = texelFetch(objectId, texel, 0).r; - float object_outline = calculate_object_outline(objectId, texel, object_id); - shaded_color = mix(world_data.object_outline_color.rgb, shaded_color, object_outline); -#endif - - fragColor = vec4(shaded_color, 1.0); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl new file mode 100644 index 00000000000..328d50e69e0 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_cavity_frag.glsl @@ -0,0 +1,31 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_cavity_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_curvature_lib.glsl) + +uniform sampler2D depthBuffer; +uniform sampler2D normalBuffer; +uniform usampler2D objectIdBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + float cavity = 0.0, edges = 0.0, curvature = 0.0; + +#ifdef USE_CAVITY + cavity_compute(uvcoordsvar.st, depthBuffer, normalBuffer, cavity, edges); +#endif + +#ifdef USE_CURVATURE + curvature_compute(uvcoordsvar.st, objectIdBuffer, normalBuffer, curvature); +#endif + + float final_cavity_factor = clamp((1.0 - cavity) * (1.0 + edges) * (1.0 + curvature), 0.0, 4.0); + + fragColor.rgb = vec3(final_cavity_factor); + fragColor.a = 1.0; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl deleted file mode 100644 index 95ca2c0c297..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_fxaa_frag.glsl +++ /dev/null @@ -1,14 +0,0 @@ - -in vec4 uvcoordsvar; - -out vec4 FragColor; - -uniform sampler2D colorBuffer; -uniform vec2 invertedViewportSize; - -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - FragColor = FxaaPixelShader( - uvcoordsvar.st, colorBuffer, invertedViewportSize, 1.0, 0.166, 0.0833); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl new file mode 100644 index 00000000000..fb6fdb93462 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_outline_frag.glsl @@ -0,0 +1,24 @@ + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + +uniform usampler2D objectIdBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + vec3 offset = vec3(world_data.viewport_size_inv, 0.0) * world_data.ui_scale; + vec2 uv = uvcoordsvar.st; + + uint center_id = texture(objectIdBuffer, uv).r; + uvec4 adjacent_ids = uvec4(texture(objectIdBuffer, uv + offset.zy).r, + texture(objectIdBuffer, uv - offset.zy).r, + texture(objectIdBuffer, uv + offset.xz).r, + texture(objectIdBuffer, uv - offset.xz).r); + + float outline_opacity = 1.0 - dot(vec4(equal(uvec4(center_id), adjacent_ids)), vec4(0.25)); + + fragColor = world_data.object_outline_color * outline_opacity; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl new file mode 100644 index 00000000000..2dea2fc4883 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_frag.glsl @@ -0,0 +1,44 @@ + +uniform sampler2D edgesTex; +uniform sampler2D areaTex; +uniform sampler2D searchTex; +uniform sampler2D blendTex; +uniform sampler2D colorTex; +uniform float mixFactor; +uniform float taaSampleCountInv; + +in vec2 uvs; +in vec2 pixcoord; +in vec4 offset[3]; + +#if SMAA_STAGE == 0 +out vec2 fragColor; +#else +out vec4 fragColor; +#endif + +void main() +{ +#if SMAA_STAGE == 0 + /* Detect edges in color and revealage buffer. */ + fragColor = SMAALumaEdgeDetectionPS(uvs, offset, colorTex); + /* Discard if there is no edge. */ + if (dot(fragColor, float2(1.0, 1.0)) == 0.0) { + discard; + } + +#elif SMAA_STAGE == 1 + fragColor = SMAABlendingWeightCalculationPS( + uvs, pixcoord, offset, edgesTex, areaTex, searchTex, vec4(0)); + +#elif SMAA_STAGE == 2 + fragColor = vec4(0.0); + if (mixFactor > 0.0) { + fragColor += SMAANeighborhoodBlendingPS(uvs, offset[0], colorTex, blendTex) * mixFactor; + } + if (mixFactor < 1.0) { + fragColor += texture(colorTex, uvs) * (1.0 - mixFactor); + } + fragColor *= taaSampleCountInv; +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl new file mode 100644 index 00000000000..07734d19972 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_smaa_vert.glsl @@ -0,0 +1,21 @@ + +out vec2 uvs; +out vec2 pixcoord; +out vec4 offset[3]; + +void main() +{ + int v = gl_VertexID % 3; + float x = -1.0 + float((v & 1) << 2); + float y = -1.0 + float((v & 2) << 1); + gl_Position = vec4(x, y, 1.0, 1.0); + uvs = (gl_Position.xy + 1.0) * 0.5; + +#if SMAA_STAGE == 0 + SMAAEdgeDetectionVS(uvs, offset); +#elif SMAA_STAGE == 1 + SMAABlendingWeightCalculationVS(uvs, pixcoord, offset); +#elif SMAA_STAGE == 2 + SMAANeighborhoodBlendingVS(uvs, offset[0]); +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl index 5795268f794..b877c2c3f76 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_effect_taa_frag.glsl @@ -1,14 +1,11 @@ -uniform sampler2D historyBuffer; + uniform sampler2D colorBuffer; -out vec4 colorOutput; +in vec4 uvcoordsvar; -uniform float mixFactor; +out vec4 fragColor; void main() { - ivec2 texel = ivec2(gl_FragCoord.xy); - vec4 color_buffer = texelFetch(colorBuffer, texel, 0); - vec4 history_buffer = texelFetch(historyBuffer, texel, 0); - colorOutput = mix(history_buffer, color_buffer, mixFactor); + fragColor = texture(colorBuffer, uvcoordsvar.st); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl deleted file mode 100644 index 0a4d64b37ad..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_composite_frag.glsl +++ /dev/null @@ -1,36 +0,0 @@ -out vec4 fragColor; - -uniform usampler2D objectId; -uniform sampler2D transparentAccum; -uniform sampler2D transparentRevealage; -uniform vec2 invertedViewportSize; - -#ifndef ALPHA_COMPOSITE -layout(std140) uniform world_block -{ - WorldData world_data; -}; -#endif - -/* TODO: Bypass the whole shader if there is no xray pass and no outline pass. */ -void main() -{ - ivec2 texel = ivec2(gl_FragCoord.xy); - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - - /* Listing 4 */ - vec4 trans_accum = texelFetch(transparentAccum, texel, 0); - float trans_revealage = trans_accum.a; - trans_accum.a = texelFetch(transparentRevealage, texel, 0).r; - - vec3 trans_color = trans_accum.rgb / clamp(trans_accum.a, 1e-4, 5e4); - - fragColor.a = 1.0 - trans_revealage; - fragColor.rgb = trans_color * fragColor.a; - -#ifdef V3D_SHADING_OBJECT_OUTLINE - uint object_id = texelFetch(objectId, texel, 0).r; - float outline = calculate_object_outline(objectId, texel, object_id); - fragColor = mix(vec4(world_data.object_outline_color.rgb, 1.0), fragColor, outline); -#endif -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl deleted file mode 100644 index abd8c1f6579..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_depth_frag.glsl +++ /dev/null @@ -1,20 +0,0 @@ - -layout(location = 0) out uint objectId; - -uniform float ImageTransparencyCutoff = 0.1; -#ifdef V3D_SHADING_TEXTURE_COLOR -uniform sampler2D image; - -in vec2 uv_interp; -#endif - -void main() -{ -#ifdef V3D_SHADING_TEXTURE_COLOR - if (texture(image, uv_interp).a < ImageTransparencyCutoff) { - discard; - } -#endif - - objectId = uint(resource_id + 1) & 0xFFu; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl deleted file mode 100644 index 559dc07c107..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_forward_transparent_accum_frag.glsl +++ /dev/null @@ -1,118 +0,0 @@ - -uniform float ImageTransparencyCutoff = 0.1; -#ifdef TEXTURE_IMAGE_ARRAY -uniform sampler2DArray image_tile_array; -uniform sampler1DArray image_tile_data; -#else -uniform sampler2D image; -#endif -uniform bool imageNearest; -uniform bool imagePremultiplied; - -uniform float alpha = 0.5; -uniform vec2 invertedViewportSize; -uniform vec4 viewvecs[3]; - -uniform vec4 materialColorAndMetal; -uniform float materialRoughness; - -uniform float shadowMultiplier = 0.5; -uniform float lightMultiplier = 1.0; -uniform float shadowShift = 0.1; -uniform float shadowFocus = 1.0; - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 normal_viewport; -#endif /* NORMAL_VIEWPORT_PASS_ENABLED */ -#ifdef V3D_SHADING_TEXTURE_COLOR -in vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -in vec3 vertexColor; -#endif -#ifdef V3D_LIGHTING_MATCAP -uniform sampler2D matcapDiffuseImage; -uniform sampler2D matcapSpecularImage; -#endif - -layout(std140) uniform world_block -{ - WorldData world_data; -}; - -layout(location = 0) out vec4 transparentAccum; -layout(location = 1) out - float revealageAccum; /* revealage actually stored in transparentAccum.a */ - -void main() -{ - vec4 base_color; - -#if defined(V3D_SHADING_TEXTURE_COLOR) -# ifdef TEXTURE_IMAGE_ARRAY - base_color = workbench_sample_texture_array( - image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied); -# else - base_color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); -# endif - if (base_color.a < ImageTransparencyCutoff) { - discard; - } -#elif defined(V3D_SHADING_VERTEX_COLOR) - base_color.rgb = vertexColor; -#else - base_color.rgb = materialColorAndMetal.rgb; -#endif /* V3D_SHADING_TEXTURE_COLOR */ - - vec2 uv_viewport = gl_FragCoord.xy * invertedViewportSize; - vec3 I_vs = view_vector_from_screen_uv(uv_viewport, viewvecs, ProjectionMatrix); - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 nor = normalize(normal_viewport); -#endif - - /* -------- SHADING --------- */ -#ifdef V3D_LIGHTING_FLAT - vec3 shaded_color = base_color.rgb; - -#elif defined(V3D_LIGHTING_MATCAP) - bool flipped = world_data.matcap_orientation != 0; - vec2 matcap_uv = matcap_uv_compute(I_vs, nor, flipped); - vec3 matcap_diffuse = textureLod(matcapDiffuseImage, matcap_uv, 0.0).rgb; -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - vec3 matcap_specular = textureLod(matcapSpecularImage, matcap_uv, 0.0).rgb; -# else - vec3 matcap_specular = vec3(0.0); -# endif - vec3 shaded_color = matcap_diffuse * base_color.rgb + matcap_specular; - -#elif defined(V3D_LIGHTING_STUDIO) -# ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - float metallic = materialColorAndMetal.a; - vec3 specular_color = mix(vec3(0.05), base_color.rgb, metallic); - vec3 diffuse_color = mix(base_color.rgb, vec3(0.0), metallic); -# else - vec3 specular_color = vec3(0.0); - vec3 diffuse_color = base_color.rgb; -# endif - - vec3 shaded_color = get_world_lighting( - world_data, diffuse_color, specular_color, materialRoughness, nor, I_vs); -#endif - -#ifdef V3D_SHADING_SHADOW - float light_factor = -dot(nor, world_data.shadow_direction_vs.xyz); - float shadow_mix = smoothstep(shadowFocus, shadowShift, light_factor); - shaded_color *= mix(lightMultiplier, shadowMultiplier, shadow_mix); -#endif - - /* Based on : - * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of - * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 - */ - /* Listing 4 */ - float z = linear_zdepth(gl_FragCoord.z, viewvecs, ProjectionMatrix); - float weight = calculate_transparent_weight(z, alpha); - transparentAccum = vec4(shaded_color * weight, alpha); - revealageAccum = weight; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl deleted file mode 100644 index d223a7650c5..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_ghost_resolve_frag.glsl +++ /dev/null @@ -1,13 +0,0 @@ -uniform sampler2D depthBuffer; - -void main(void) -{ - float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; - - /* background, discard */ - if (depth >= 1.0) { - discard; - } - - gl_FragDepth = depth; -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl new file mode 100644 index 00000000000..6f99739f259 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_image_lib.glsl @@ -0,0 +1,83 @@ + +/* TODO(fclem) deduplicate code. */ +bool node_tex_tile_lookup(inout vec3 co, sampler2DArray ima, sampler1DArray map) +{ + vec2 tile_pos = floor(co.xy); + + if (tile_pos.x < 0 || tile_pos.y < 0 || tile_pos.x >= 10) + return false; + + float tile = 10.0 * tile_pos.y + tile_pos.x; + if (tile >= textureSize(map, 0).x) + return false; + + /* Fetch tile information. */ + float tile_layer = texelFetch(map, ivec2(tile, 0), 0).x; + if (tile_layer < 0.0) + return false; + + vec4 tile_info = texelFetch(map, ivec2(tile, 1), 0); + + co = vec3(((co.xy - tile_pos) * tile_info.zw) + tile_info.xy, tile_layer); + return true; +} + +vec4 workbench_sample_texture(sampler2D image, vec2 coord, bool nearest_sampling) +{ + vec2 tex_size = vec2(textureSize(image, 0).xy); + /* TODO(fclem) We could do the same with sampler objects. + * But this is a quick workaround instead of messing with the GPUTexture itself. */ + vec2 uv = nearest_sampling ? (floor(coord * tex_size) + 0.5) / tex_size : coord; + return texture(image, uv); +} + +vec4 workbench_sample_texture_array(sampler2DArray tile_array, + sampler1DArray tile_data, + vec2 coord, + bool nearest_sampling) +{ + vec2 tex_size = vec2(textureSize(tile_array, 0).xy); + + vec3 uv = vec3(coord, 0); + if (!node_tex_tile_lookup(uv, tile_array, tile_data)) + return vec4(1.0, 0.0, 1.0, 1.0); + + /* TODO(fclem) We could do the same with sampler objects. + * But this is a quick workaround instead of messing with the GPUTexture itself. */ + uv.xy = nearest_sampling ? (floor(uv.xy * tex_size) + 0.5) / tex_size : uv.xy; + return texture(tile_array, uv); +} + +uniform sampler2DArray imageTileArray; +uniform sampler1DArray imageTileData; +uniform sampler2D imageTexture; + +uniform float imageTransparencyCutoff = 0.1; +uniform bool imageNearest; +uniform bool imagePremult; + +vec3 workbench_image_color(vec2 uvs) +{ +#ifdef V3D_SHADING_TEXTURE_COLOR +# ifdef TEXTURE_IMAGE_ARRAY + vec4 color = workbench_sample_texture_array(imageTileArray, imageTileData, uvs, imageNearest); +# else + vec4 color = workbench_sample_texture(imageTexture, uvs, imageNearest); +# endif + + /* Unpremultiply if stored multiplied, since straight alpha is expected by shaders. */ + if (imagePremult && !(color.a == 0.0 || color.a == 1.0)) { + color.rgb /= color.a; + } + +# ifdef GPU_FRAGMENT_SHADER + if (color.a < imageTransparencyCutoff) { + discard; + } +# endif + + return color.rgb; +#else + return vec3(1.0); +#endif +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl new file mode 100644 index 00000000000..2d18cc1b014 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_matcap_lib.glsl @@ -0,0 +1,30 @@ + +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + +vec2 matcap_uv_compute(vec3 I, vec3 N, bool flipped) +{ + /* Quick creation of an orthonormal basis */ + float a = 1.0 / (1.0 + I.z); + float b = -I.x * I.y * a; + vec3 b1 = vec3(1.0 - I.x * I.x * a, b, -I.x); + vec3 b2 = vec3(b, 1.0 - I.y * I.y * a, -I.y); + vec2 matcap_uv = vec2(dot(b1, N), dot(b2, N)); + if (flipped) { + matcap_uv.x = -matcap_uv.x; + } + return matcap_uv * 0.496 + 0.5; +} + +uniform sampler2D matcapDiffuseImage; +uniform sampler2D matcapSpecularImage; + +vec3 get_matcap_lighting(vec3 base_color, vec3 N, vec3 I) +{ + bool flipped = world_data.matcap_orientation != 0; + vec2 uv = matcap_uv_compute(I, N, flipped); + + vec3 diffuse = textureLod(matcapDiffuseImage, uv, 0.0).rgb; + vec3 specular = textureLod(matcapSpecularImage, uv, 0.0).rgb; + + return diffuse * base_color + specular * float(world_data.use_specular); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl new file mode 100644 index 00000000000..1d8950e34b3 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_material_lib.glsl @@ -0,0 +1,21 @@ + +layout(std140) uniform material_block +{ + vec4 mat_data[4096]; +}; + +/* If set to -1, the resource handle is used instead. */ +uniform int materialIndex; + +void workbench_material_data_get( + int handle, out vec3 color, out float alpha, out float roughness, out float metallic) +{ + handle = (materialIndex != -1) ? materialIndex : handle; + vec4 data = mat_data[uint(handle) & 0xFFFu]; + color = data.rgb; + + uint encoded_data = floatBitsToUint(data.w); + alpha = float((encoded_data >> 16u) & 0xFFu) * (1.0 / 255.0); + roughness = float((encoded_data >> 8u) & 0xFFu) * (1.0 / 255.0); + metallic = float(encoded_data & 0xFFu) * (1.0 / 255.0); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl new file mode 100644 index 00000000000..58becb03290 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_merge_infront_frag.glsl @@ -0,0 +1,18 @@ + +uniform sampler2D depthBuffer; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +void main() +{ + float depth = texture(depthBuffer, uvcoordsvar.st).r; + /* Discard background pixels. */ + if (depth == 1.0) { + discard; + } + /* Make this fragment occlude any fragment that will try to + * render over it in the normal passes. */ + gl_FragDepth = 0.0; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl deleted file mode 100644 index a4a5d9c31a3..00000000000 --- a/source/blender/draw/engines/workbench/shaders/workbench_object_outline_lib.glsl +++ /dev/null @@ -1,12 +0,0 @@ -#define OBJECT_OUTLINE_OFFSET 1 - -float calculate_object_outline(usampler2D objectId, ivec2 texel, uint object_id) -{ - uvec4 oid_offset = uvec4( - texelFetchOffset(objectId, texel, 0, ivec2(0, OBJECT_OUTLINE_OFFSET)).r, - texelFetchOffset(objectId, texel, 0, ivec2(0, -OBJECT_OUTLINE_OFFSET)).r, - texelFetchOffset(objectId, texel, 0, ivec2(-OBJECT_OUTLINE_OFFSET, 0)).r, - texelFetchOffset(objectId, texel, 0, ivec2(OBJECT_OUTLINE_OFFSET, 0)).r); - - return dot(vec4(equal(uvec4(object_id), oid_offset)), vec4(0.25)); -} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl index 94e41b4bcd4..6d24b001d4d 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_frag.glsl @@ -1,92 +1,29 @@ -uniform vec4 materialColorAndMetal; -uniform float materialRoughness; +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) -#ifdef TEXTURE_IMAGE_ARRAY -uniform sampler2DArray image_tile_array; -uniform sampler1DArray image_tile_data; -#else -uniform sampler2D image; -#endif -uniform float ImageTransparencyCutoff = 0.1; -uniform bool imageNearest; -uniform bool imagePremultiplied; - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -in vec3 normal_viewport; -#endif - -#ifdef V3D_SHADING_TEXTURE_COLOR -in vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -in vec3 vertexColor; -#endif - -#ifdef HAIR_SHADER -flat in float hair_rand; -#endif - -#ifdef MATDATA_PASS_ENABLED layout(location = 0) out vec4 materialData; -#endif -#ifdef OBJECT_ID_PASS_ENABLED -layout(location = 1) out uint objectId; -#endif -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -layout(location = 2) out WB_Normal normalViewport; -#endif +layout(location = 1) out WB_Normal normalData; +layout(location = 2) out uint objectId; + +uniform bool useMatcap = false; void main() { -#ifdef MATDATA_PASS_ENABLED - float metallic, roughness; - vec4 color; - -# if defined(V3D_SHADING_TEXTURE_COLOR) -# ifdef TEXTURE_IMAGE_ARRAY - color = workbench_sample_texture_array( - image_tile_array, image_tile_data, uv_interp, imageNearest, imagePremultiplied); -# else - color = workbench_sample_texture(image, uv_interp, imageNearest, imagePremultiplied); -# endif - if (color.a < ImageTransparencyCutoff) { - discard; - } -# elif defined(V3D_SHADING_VERTEX_COLOR) - color.rgb = vertexColor; -# else - color.rgb = materialColorAndMetal.rgb; -# endif - -# ifdef V3D_LIGHTING_MATCAP - /* Encode front facing in metallic channel. */ - metallic = float(gl_FrontFacing); - roughness = 0.0; -# else - metallic = materialColorAndMetal.a; - roughness = materialRoughness; -# endif + normalData = workbench_normal_encode(gl_FrontFacing, normal_interp); -# ifdef HAIR_SHADER - /* Add some variation to the hairs to avoid uniform look. */ - float hair_variation = hair_rand * 0.1; - color = clamp(color - hair_variation, 0.0, 1.0); - metallic = clamp(materialColorAndMetal.a - hair_variation, 0.0, 1.0); - roughness = clamp(materialRoughness - hair_variation, 0.0, 1.0); -# endif + materialData = vec4(color_interp, packed_rough_metal); - materialData.rgb = color.rgb; - materialData.a = workbench_float_pair_encode(roughness, metallic); -#endif /* MATDATA_PASS_ENABLED */ + objectId = uint(object_id); -#ifdef OBJECT_ID_PASS_ENABLED - objectId = uint(resource_id + 1) & 0xFFu; -#endif + if (useMatcap) { + /* For matcaps, save front facing in alpha channel. */ + materialData.a = float(gl_FrontFacing); + } -#ifdef NORMAL_VIEWPORT_PASS_ENABLED - vec3 n = (gl_FrontFacing) ? normal_viewport : -normal_viewport; - n = normalize(n); - normalViewport = workbench_normal_encode(n); +#ifdef V3D_SHADING_TEXTURE_COLOR + materialData.rgb = workbench_image_color(uv_interp); #endif } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl new file mode 100644 index 00000000000..6a7bc185fe9 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_hair_vert.glsl @@ -0,0 +1,94 @@ +#pragma BLENDER_REQUIRE(common_hair_lib.glsl) +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_material_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) + +uniform samplerBuffer ac; /* active color layer */ +uniform samplerBuffer au; /* active texture layer */ + +/* From http://libnoise.sourceforge.net/noisegen/index.html */ +float integer_noise(int n) +{ + n = (n >> 13) ^ n; + int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; + return (float(nn) / 1073741824.0); +} + +vec3 workbench_hair_random_normal(vec3 tan, vec3 binor, float rand) +{ + /* To "simulate" anisotropic shading, randomize hair normal per strand. */ + vec3 nor = cross(tan, binor); + nor = normalize(mix(nor, -tan, rand * 0.1)); + float cos_theta = (rand * 2.0 - 1.0) * 0.2; + float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); + nor = nor * sin_theta + binor * cos_theta; + return nor; +} + +void workbench_hair_random_material(float rand, + inout vec3 color, + inout float roughness, + inout float metallic) +{ + /* Center noise around 0. */ + rand -= 0.5; + rand *= 0.1; + /* Add some variation to the hairs to avoid uniform look. */ + metallic = clamp(metallic + rand, 0.0, 1.0); + roughness = clamp(roughness + rand, 0.0, 1.0); + /* Modulate by color intensity to reduce very high contrast when color is dark. */ + color = clamp(color + rand * (color + 0.05), 0.0, 1.0); +} + +void main() +{ + bool is_persp = (ProjectionMatrix[3][3] == 0.0); + float time, thick_time, thickness; + vec3 world_pos, tan, binor; + hair_get_pos_tan_binor_time(is_persp, + ModelMatrixInverse, + ViewMatrixInverse[3].xyz, + ViewMatrixInverse[2].xyz, + world_pos, + tan, + binor, + time, + thickness, + thick_time); + + gl_Position = point_world_to_ndc(world_pos); + + float hair_rand = integer_noise(hair_get_strand_id()); + vec3 nor = workbench_hair_random_normal(tan, binor, hair_rand); + +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); +#endif + + uv_interp = hair_get_customdata_vec2(au); + + normal_interp = normalize(normal_world_to_view(nor)); + +#ifdef OPAQUE_MATERIAL + float metallic, roughness; +#endif + workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); + + if (materialIndex == 0) { + color_interp = hair_get_customdata_vec3(ac); + } + + /* Hairs have lots of layer and can rapidly become the most prominent surface. + * So we lower their alpha artificially. */ + alpha_interp *= 0.3; + + workbench_hair_random_material(hair_rand, color_interp, roughness, metallic); + +#ifdef OPAQUE_MATERIAL + packed_rough_metal = workbench_float_pair_encode(roughness, metallic); +#endif + + object_id = int((uint(resource_id) + 1u) & 0xFFu); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl index 0a3252f0b9b..31e298d1540 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_prepass_vert.glsl @@ -1,110 +1,40 @@ -#ifndef HAIR_SHADER +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_material_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) + in vec3 pos; in vec3 nor; -in vec2 au; /* active texture layer */ -# ifdef V3D_SHADING_VERTEX_COLOR in vec4 ac; /* active color */ -# endif -# define uv au -#else /* HAIR_SHADER */ - -# ifdef V3D_SHADING_TEXTURE_COLOR -uniform samplerBuffer au; /* active texture layer */ -# endif -# ifdef V3D_SHADING_VERTEX_COLOR -uniform samplerBuffer ac; /* active color layer */ -# endif - -flat out float hair_rand; -#endif /* HAIR_SHADER */ - -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -out vec3 normal_viewport; -#endif - -#ifdef V3D_SHADING_TEXTURE_COLOR -out vec2 uv_interp; -#endif -#ifdef V3D_SHADING_VERTEX_COLOR -out vec3 vertexColor; -#endif - -#ifdef OBJECT_ID_PASS_ENABLED -RESOURCE_ID_VARYING -#endif - -/* From http://libnoise.sourceforge.net/noisegen/index.html */ -float integer_noise(int n) -{ - n = (n >> 13) ^ n; - int nn = (n * (n * n * 60493 + 19990303) + 1376312589) & 0x7fffffff; - return (float(nn) / 1073741824.0); -} - -vec3 workbench_hair_hair_normal(vec3 tan, vec3 binor, float rand) -{ - /* To "simulate" anisotropic shading, randomize hair normal per strand. */ - vec3 nor = cross(tan, binor); - nor = normalize(mix(nor, -tan, rand * 0.1)); - float cos_theta = (rand * 2.0 - 1.0) * 0.2; - float sin_theta = sqrt(max(0.0, 1.0 - cos_theta * cos_theta)); - nor = nor * sin_theta + binor * cos_theta; - return nor; -} +in vec2 au; /* active texture layer */ void main() { -#ifdef HAIR_SHADER -# ifdef V3D_SHADING_TEXTURE_COLOR - vec2 uv = hair_get_customdata_vec2(au); -# endif - float time, thick_time, thickness; - vec3 world_pos, tan, binor; - hair_get_pos_tan_binor_time((ProjectionMatrix[3][3] == 0.0), - ModelMatrixInverse, - ViewMatrixInverse[3].xyz, - ViewMatrixInverse[2].xyz, - world_pos, - tan, - binor, - time, - thickness, - thick_time); - - hair_rand = integer_noise(hair_get_strand_id()); - vec3 nor = workbench_hair_hair_normal(tan, binor, hair_rand); -#else vec3 world_pos = point_object_to_world(pos); -#endif gl_Position = point_world_to_ndc(world_pos); -#ifdef V3D_SHADING_TEXTURE_COLOR - uv_interp = uv; +#ifdef USE_WORLD_CLIP_PLANES + world_clip_planes_calc_clip_distance(world_pos); #endif -#ifdef V3D_SHADING_VERTEX_COLOR -# ifndef HAIR_SHADER - vertexColor = ac.rgb; -# else - vertexColor = hair_get_customdata_vec4(ac).rgb; -# endif -#endif + uv_interp = au; -#ifdef NORMAL_VIEWPORT_PASS_ENABLED -# ifndef HAIR_SHADER - normal_viewport = normal_object_to_view(nor); - normal_viewport = normalize(normal_viewport); -# else - normal_viewport = normal_world_to_view(nor); -# endif -#endif + normal_interp = normalize(normal_object_to_view(nor)); -#ifdef OBJECT_ID_PASS_ENABLED - PASS_RESOURCE_ID +#ifdef OPAQUE_MATERIAL + float metallic, roughness; #endif + workbench_material_data_get(resource_handle, color_interp, alpha_interp, roughness, metallic); -#ifdef USE_WORLD_CLIP_PLANES - world_clip_planes_calc_clip_distance(world_pos); + if (materialIndex == 0) { + color_interp = ac.rgb; + } + +#ifdef OPAQUE_MATERIAL + packed_rough_metal = workbench_float_pair_encode(roughness, metallic); #endif + + object_id = int((uint(resource_id) + 1u) & 0xFFu); } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl new file mode 100644 index 00000000000..8e2f7ba4735 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_shader_interface_lib.glsl @@ -0,0 +1,21 @@ + +#ifdef GPU_VERTEX_SHADER +# define IN_OUT out +#else +# define IN_OUT in +#endif + +IN_OUT ShaderStageInterface +{ + vec3 normal_interp; + vec3 color_interp; + float alpha_interp; + vec2 uv_interp; +#ifdef TRANSPARENT_MATERIAL + flat float roughness; + flat float metallic; +#else + flat float packed_rough_metal; +#endif + flat int object_id; +}; diff --git a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl index 6b0741b6d1b..6fa76510e6e 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_shadow_debug_frag.glsl @@ -1,15 +1,19 @@ out vec4 fragColor; +layout(location = 0) out vec4 materialData; +layout(location = 1) out vec4 normalData; +layout(location = 2) out uint objectId; + void main() { - const float intensity = 0.25; + const float a = 0.25; #ifdef SHADOW_PASS - fragColor = vec4( - (gl_FrontFacing) ? vec3(intensity, -intensity, 0.0) : vec3(-intensity, intensity, 0.0), 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, -a, 0.0) : vec3(-a, a, 0.0); #else - fragColor = vec4((gl_FrontFacing) ? vec3(intensity, intensity, -intensity) : - vec3(-intensity, -intensity, intensity), - 1.0); + materialData.rgb = gl_FrontFacing ? vec3(a, a, -a) : vec3(-a, -a, a); #endif + materialData.a = 0.0; + normalData = vec4(0.0); + objectId = 0u; } diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl new file mode 100644 index 00000000000..3c2d1a9c0c7 --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_accum_frag.glsl @@ -0,0 +1,89 @@ + +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_shader_interface_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_image_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_matcap_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_world_light_lib.glsl) + +/* Revealage is actually stored in transparentAccum alpha channel. + * This is a workaround to older hardware not having separate blend equation per render target. */ +layout(location = 0) out vec4 transparentAccum; +layout(location = 1) out vec4 revealageAccum; + +/* Note: Blending will be skipped on objectId because output is a non-normalized integer buffer. */ +layout(location = 2) out uint objectId; + +/* Special function only to be used with calculate_transparent_weight(). */ +float linear_zdepth(float depth, vec4 viewvecs[3], mat4 proj_mat) +{ + if (proj_mat[3][3] == 0.0) { + float d = 2.0 * depth - 1.0; + return -proj_mat[3][2] / (d + proj_mat[2][2]); + } + else { + /* Return depth from near plane. */ + return depth * viewvecs[1].z; + } +} + +/* Based on : + * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of + * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 + */ +float calculate_transparent_weight(void) +{ + float z = linear_zdepth(gl_FragCoord.z, world_data.viewvecs, ProjectionMatrix); +#if 0 + /* Eq 10 : Good for surfaces with varying opacity (like particles) */ + float a = min(1.0, alpha * 10.0) + 0.01; + float b = -gl_FragCoord.z * 0.95 + 1.0; + float w = a * a * a * 3e2 * b * b * b; +#else + /* Eq 7 put more emphasis on surfaces closer to the view. */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 5.0, 2.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 7 */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 10.0, 3.0) + pow(abs(z) / 200.0, 6.0)); /* Eq 8 */ + // float w = 10.0 / (1e-5 + pow(abs(z) / 200.0, 4.0)); /* Eq 9 */ + /* Same as eq 7, but optimized. */ + float a = abs(z) / 5.0; + float b = abs(z) / 200.0; + b *= b; + float w = 10.0 / ((1e-5 + a * a) + b * (b * b)); /* Eq 7 */ +#endif + return clamp(w, 1e-2, 3e2); +} + +void main() +{ + /* Normal and Incident vector are in viewspace. Lighting is evaluated in viewspace. */ + vec2 uv_viewport = gl_FragCoord.xy * world_data.viewport_size_inv; + vec3 I = view_vector_from_screen_uv(uv_viewport, world_data.viewvecs, ProjectionMatrix); + vec3 N = normalize(normal_interp); + + vec3 color = color_interp; + +#ifdef V3D_SHADING_TEXTURE_COLOR + color = workbench_image_color(uv_interp); +#endif + +#ifdef V3D_LIGHTING_MATCAP + vec3 shaded_color = get_matcap_lighting(color, N, I); +#endif + +#ifdef V3D_LIGHTING_STUDIO + vec3 shaded_color = get_world_lighting(color, roughness, metallic, N, I); +#endif + +#ifdef V3D_LIGHTING_FLAT + vec3 shaded_color = color; +#endif + + shaded_color *= get_shadow(N); + + /* Listing 4 */ + float weight = calculate_transparent_weight() * alpha_interp; + transparentAccum = vec4(shaded_color * weight, alpha_interp); + revealageAccum = vec4(weight); + + objectId = uint(object_id); +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl new file mode 100644 index 00000000000..d985737a35b --- /dev/null +++ b/source/blender/draw/engines/workbench/shaders/workbench_transparent_resolve_frag.glsl @@ -0,0 +1,26 @@ + +uniform sampler2D transparentAccum; +uniform sampler2D transparentRevealage; + +in vec4 uvcoordsvar; + +out vec4 fragColor; + +/* Based on : + * McGuire and Bavoil, Weighted Blended Order-Independent Transparency, Journal of + * Computer Graphics Techniques (JCGT), vol. 2, no. 2, 122–141, 2013 + */ + +void main() +{ + /* Revealage is actually stored in transparentAccum alpha channel. + * This is a workaround to older hardware not having separate blend equation per render target. + */ + vec4 trans_accum = texture(transparentAccum, uvcoordsvar.st); + float trans_weight = texture(transparentRevealage, uvcoordsvar.st).r; + float trans_reveal = trans_accum.a; + + /* Listing 4 */ + fragColor.rgb = trans_accum.rgb / clamp(trans_weight, 1e-4, 5e4); + fragColor.a = 1.0 - trans_reveal; +} diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl index c38d8fe06bc..e957f8bbe9c 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_frag.glsl @@ -1,4 +1,9 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) +#pragma BLENDER_REQUIRE(workbench_common_lib.glsl) + uniform sampler2D depthBuffer; uniform sampler3D densityTexture; @@ -8,10 +13,9 @@ uniform sampler1D flameColorTexture; uniform sampler1D transferTexture; uniform int samplesLen = 256; -uniform float noiseOfs = 0.0f; +uniform float noiseOfs = 0.0; uniform float stepLength; /* Step length in local space. */ uniform float densityScale; /* Simple Opacity multiplicator. */ -uniform vec4 viewvecs[3]; uniform vec3 activeColor; uniform float slicePosition; @@ -23,34 +27,11 @@ in vec3 localPos; out vec4 fragColor; -#define M_PI 3.1415926535897932 /* pi */ - float phase_function_isotropic() { return 1.0 / (4.0 * M_PI); } -float get_view_z_from_depth(float depth) -{ - if (ProjectionMatrix[3][3] == 0.0) { - float d = 2.0 * depth - 1.0; - return -ProjectionMatrix[3][2] / (d + ProjectionMatrix[2][2]); - } - else { - return viewvecs[0].z + depth * viewvecs[1].z; - } -} - -vec3 get_view_space_from_depth(vec2 uvcoords, float depth) -{ - if (ProjectionMatrix[3][3] == 0.0) { - 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; - } -} - float max_v3(vec3 v) { return max(v.x, max(v.y, v.z)); @@ -134,8 +115,9 @@ void volume_properties(vec3 ls_pos, out vec3 scattering, out float extinction) float shadows = sample_volume_texture(shadowTexture, co).r; vec4 density = sample_volume_texture(densityTexture, co); /* rgb: color, a: density */ - scattering = density.rgb * (density.a * densityScale) * activeColor; + scattering = density.rgb * densityScale; extinction = max(1e-4, dot(scattering, vec3(0.33333))); + scattering *= activeColor; /* Scale shadows in log space and clamp them to avoid completely black shadows. */ scattering *= exp(clamp(log(shadows) * densityScale * 0.1, -2.5, 0.0)) * M_PI; @@ -208,8 +190,10 @@ void main() float depth = texelFetch(depthBuffer, ivec2(gl_FragCoord.xy), 0).r; float depth_end = min(depth, gl_FragCoord.z); - vec3 vs_ray_end = get_view_space_from_depth(screen_uv, depth_end); - vec3 vs_ray_ori = get_view_space_from_depth(screen_uv, 0.0); + vec3 vs_ray_end = view_position_from_depth( + screen_uv, depth_end, world_data.viewvecs, ProjectionMatrix); + vec3 vs_ray_ori = view_position_from_depth( + screen_uv, 0.0, world_data.viewvecs, ProjectionMatrix); vec3 vs_ray_dir = (is_persp) ? (vs_ray_end - vs_ray_ori) : vec3(0.0, 0.0, -1.0); vs_ray_dir /= abs(vs_ray_dir.z); diff --git a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl index 3542a1a91fc..1a32a202290 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_volume_vert.glsl @@ -1,4 +1,7 @@ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) +#pragma BLENDER_REQUIRE(gpu_shader_common_obinfos_lib.glsl) + uniform float slicePosition; uniform int sliceAxis; /* -1 is no slice, 0 is X, 1 is Y, 2 is Z. */ diff --git a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl index 690ce5d527f..81f6e651be0 100644 --- a/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl +++ b/source/blender/draw/engines/workbench/shaders/workbench_world_light_lib.glsl @@ -1,4 +1,6 @@ +#pragma BLENDER_REQUIRE(workbench_data_lib.glsl) + /* [Drobot2014a] Low Level Optimizations for GCN */ vec4 fast_rcp(vec4 v) { @@ -41,9 +43,19 @@ vec4 wrapped_lighting(vec4 NL, vec4 w) return clamp((NL + w) * denom, 0.0, 1.0); } -vec3 get_world_lighting( - WorldData world_data, vec3 diffuse_color, vec3 specular_color, float roughness, vec3 N, vec3 I) +vec3 get_world_lighting(vec3 base_color, float roughness, float metallic, vec3 N, vec3 I) { + vec3 specular_color, diffuse_color; + + if (world_data.use_specular) { + diffuse_color = mix(base_color, vec3(0.0), metallic); + specular_color = mix(vec3(0.05), base_color, metallic); + } + else { + diffuse_color = base_color; + specular_color = vec3(0.0); + } + vec3 specular_light = world_data.ambient_color.rgb; vec3 diffuse_light = world_data.ambient_color.rgb; vec4 wrap = vec4(world_data.lights[0].diffuse_color_wrap.a, @@ -51,37 +63,37 @@ vec3 get_world_lighting( world_data.lights[2].diffuse_color_wrap.a, world_data.lights[3].diffuse_color_wrap.a); -#ifdef V3D_SHADING_SPECULAR_HIGHLIGHT - /* Prepare Specular computation. Eval 4 lights at once. */ - vec3 R = -reflect(I, N); - vec4 spec_angle, spec_NL, wrap_NL; - prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); - prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); - prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); - prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); - - vec4 gloss = vec4(1.0 - roughness); - /* Reduce gloss for smooth light. (simulate bigger light) */ - gloss *= 1.0 - wrap; - vec4 shininess = exp2(10.0 * gloss + 1.0); - - vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); - - /* Simulate Env. light. */ - vec4 w = mix(wrap, vec4(1.0), roughness); - vec4 spec_env = wrapped_lighting(wrap_NL, w); - - spec_light = mix(spec_light, spec_env, wrap * wrap); - - /* Multiply result by lights specular colors. */ - specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; - specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; - specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; - specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; - - float NV = clamp(dot(N, I), 0.0, 1.0); - specular_color = brdf_approx(specular_color, roughness, NV); -#endif + if (world_data.use_specular) { + /* Prepare Specular computation. Eval 4 lights at once. */ + vec3 R = -reflect(I, N); + vec4 spec_angle, spec_NL, wrap_NL; + prep_specular(world_data.lights[0].direction.xyz, I, N, R, spec_NL.x, wrap_NL.x, spec_angle.x); + prep_specular(world_data.lights[1].direction.xyz, I, N, R, spec_NL.y, wrap_NL.y, spec_angle.y); + prep_specular(world_data.lights[2].direction.xyz, I, N, R, spec_NL.z, wrap_NL.z, spec_angle.z); + prep_specular(world_data.lights[3].direction.xyz, I, N, R, spec_NL.w, wrap_NL.w, spec_angle.w); + + vec4 gloss = vec4(1.0 - roughness); + /* Reduce gloss for smooth light. (simulate bigger light) */ + gloss *= 1.0 - wrap; + vec4 shininess = exp2(10.0 * gloss + 1.0); + + vec4 spec_light = blinn_specular(shininess, spec_angle, spec_NL); + + /* Simulate Env. light. */ + vec4 w = mix(wrap, vec4(1.0), roughness); + vec4 spec_env = wrapped_lighting(wrap_NL, w); + + spec_light = mix(spec_light, spec_env, wrap * wrap); + + /* Multiply result by lights specular colors. */ + specular_light += spec_light.x * world_data.lights[0].specular_color.rgb; + specular_light += spec_light.y * world_data.lights[1].specular_color.rgb; + specular_light += spec_light.z * world_data.lights[2].specular_color.rgb; + specular_light += spec_light.w * world_data.lights[3].specular_color.rgb; + + float NV = clamp(dot(N, I), 0.0, 1.0); + specular_color = brdf_approx(specular_color, roughness, NV); + } specular_light *= specular_color; /* Prepare diffuse computation. Eval 4 lights at once. */ @@ -107,3 +119,13 @@ vec3 get_world_lighting( return diffuse_light + specular_light; } + +uniform bool forceShadowing = false; + +float get_shadow(vec3 N) +{ + float light_factor = -dot(N, world_data.shadow_direction_vs.xyz); + float shadow_mix = smoothstep(world_data.shadow_shift, world_data.shadow_focus, light_factor); + shadow_mix *= forceShadowing ? 0.0 : world_data.shadow_mul; + return shadow_mix + world_data.shadow_add; +}
\ No newline at end of file diff --git a/source/blender/draw/engines/workbench/solid_mode.c b/source/blender/draw/engines/workbench/solid_mode.c deleted file mode 100644 index fed7e230a86..00000000000 --- a/source/blender/draw/engines/workbench/solid_mode.c +++ /dev/null @@ -1,119 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - * - * Simple engine for drawing color and/or depth. - * When we only need simple studio shaders. - */ - -#include "DRW_render.h" - -#include "GPU_shader.h" - -#include "RE_pipeline.h" - -#include "workbench_private.h" - -/* Functions */ - -static void workbench_solid_engine_init(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_deferred_engine_init(data); -} - -static void workbench_solid_cache_init(void *vedata) -{ - - WORKBENCH_Data *data = vedata; - workbench_deferred_cache_init(data); -} - -static void workbench_solid_cache_populate(void *vedata, Object *ob) -{ - WORKBENCH_Data *data = vedata; - workbench_deferred_solid_cache_populate(data, ob); -} - -static void workbench_solid_cache_finish(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_deferred_cache_finish(data); -} - -static void workbench_solid_draw_scene(void *vedata) -{ - WORKBENCH_Data *data = vedata; - const int num_samples = workbench_num_viewport_rendering_iterations(data); - - for (int sample = 0; sample < num_samples; sample++) { - workbench_deferred_draw_scene(data); - } - workbench_deferred_draw_finish(data); -} - -static void workbench_solid_engine_free(void) -{ - workbench_deferred_engine_free(); -} - -static void workbench_solid_view_update(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_taa_view_updated(data); -} - -static void workbench_solid_id_update(void *UNUSED(vedata), struct ID *id) -{ - if (GS(id->name) == ID_OB) { - WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get( - id, &draw_engine_workbench_solid); - if (oed != NULL && oed->dd.recalc != 0) { - oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0; - oed->dd.recalc = 0; - } - } -} - -static void workbench_render_to_image(void *vedata, - RenderEngine *engine, - RenderLayer *render_layer, - const rcti *rect) -{ - workbench_render(vedata, engine, render_layer, rect); -} - -static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); - -DrawEngineType draw_engine_workbench_solid = { - NULL, - NULL, - N_("Workbench"), - &workbench_data_size, - &workbench_solid_engine_init, - &workbench_solid_engine_free, - &workbench_solid_cache_init, - &workbench_solid_cache_populate, - &workbench_solid_cache_finish, - &workbench_solid_draw_scene, - &workbench_solid_view_update, - &workbench_solid_id_update, - &workbench_render_to_image, -}; diff --git a/source/blender/draw/engines/workbench/transparent_mode.c b/source/blender/draw/engines/workbench/transparent_mode.c deleted file mode 100644 index fef1ffded8d..00000000000 --- a/source/blender/draw/engines/workbench/transparent_mode.c +++ /dev/null @@ -1,97 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - * - * Simple engine for drawing color and/or depth. - * When we only need simple studio shaders. - */ - -#include "DRW_render.h" - -#include "GPU_shader.h" - -#include "workbench_private.h" - -/* Functions */ - -static void workbench_transparent_engine_init(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_forward_engine_init(data); -} - -static void workbench_transparent_cache_init(void *vedata) -{ - - WORKBENCH_Data *data = vedata; - workbench_forward_cache_init(data); -} - -static void workbench_transparent_cache_populate(void *vedata, Object *ob) -{ - WORKBENCH_Data *data = vedata; - workbench_forward_cache_populate(data, ob); -} - -static void workbench_transparent_cache_finish(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_forward_cache_finish(data); -} - -static void workbench_transparent_draw_scene(void *vedata) -{ - WORKBENCH_Data *data = vedata; - const int num_samples = workbench_num_viewport_rendering_iterations(data); - - for (int sample = 0; sample < num_samples; sample++) { - workbench_forward_draw_scene(data); - } - workbench_forward_draw_finish(data); -} - -static void workbench_transparent_engine_free(void) -{ - workbench_forward_engine_free(); -} - -static void workbench_transparent_view_update(void *vedata) -{ - WORKBENCH_Data *data = vedata; - workbench_taa_view_updated(data); -} - -static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); - -DrawEngineType draw_engine_workbench_transparent = { - NULL, - NULL, - N_("Workbench"), - &workbench_data_size, - &workbench_transparent_engine_init, - &workbench_transparent_engine_free, - &workbench_transparent_cache_init, - &workbench_transparent_cache_populate, - &workbench_transparent_cache_finish, - &workbench_transparent_draw_scene, - &workbench_transparent_view_update, - NULL, - NULL, -}; diff --git a/source/blender/draw/engines/workbench/workbench_data.c b/source/blender/draw/engines/workbench/workbench_data.c index 623a3c0cb15..0ab67d620ee 100644 --- a/source/blender/draw/engines/workbench/workbench_data.c +++ b/source/blender/draw/engines/workbench/workbench_data.c @@ -22,133 +22,231 @@ #include "workbench_private.h" +#include "BLI_memblock.h" + #include "DNA_userdef_types.h" #include "ED_view3d.h" +#include "ED_screen.h" #include "UI_resources.h" -#include "GPU_batch.h" +#include "GPU_uniformbuffer.h" /* -------------------------------------------------------------------- */ /** \name World Data * \{ */ -static void workbench_world_data_free(DrawData *dd) +GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd) { - WORKBENCH_WorldData *data = (WORKBENCH_WorldData *)dd; - DRW_UBO_FREE_SAFE(data->world_ubo); + struct GPUUniformBuffer **ubo = BLI_memblock_alloc(wpd->material_ubo); + if (*ubo == NULL) { + *ubo = GPU_uniformbuffer_create(sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL, NULL, NULL); + } + return *ubo; } -/* Ensure the availability of the world_ubo in the given WORKBENCH_PrivateData - * - * See T70167: Some platforms create threads to upload ubo's. - * - * Reuses the last previous created `world_ubo`. Due to limitations of - * DrawData it will only be reused when there is a world attached to the Scene. - * Future development: The best location would be to store it in the View3D. - * - * We don't cache the data itself as there was no indication that that lead to - * an improvement. - * - * This functions also sets the `WORKBENCH_PrivateData.is_world_ubo_owner` that must - * be respected. - */ -static void workbench_world_data_ubo_ensure(const Scene *scene, WORKBENCH_PrivateData *wpd) +static void workbench_ubo_free(void *elem) { - World *world = scene->world; - if (world) { - WORKBENCH_WorldData *engine_world_data = (WORKBENCH_WorldData *)DRW_drawdata_ensure( - &world->id, - &draw_engine_workbench_solid, - sizeof(WORKBENCH_WorldData), - NULL, - &workbench_world_data_free); - - if (engine_world_data->world_ubo == NULL) { - engine_world_data->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), - &wpd->world_data); - } - else { - DRW_uniformbuffer_update(engine_world_data->world_ubo, &wpd->world_data); - } - - /* Borrow world data ubo */ - wpd->is_world_ubo_owner = false; - wpd->world_ubo = engine_world_data->world_ubo; - } - else { - /* there is no world so we cannot cache the UBO. */ - BLI_assert(!wpd->world_ubo || wpd->is_world_ubo_owner); - if (!wpd->world_ubo) { - wpd->is_world_ubo_owner = true; - wpd->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), &wpd->world_data); - } - } + GPUUniformBuffer **ubo = elem; + DRW_UBO_FREE_SAFE(*ubo); } -static void workbench_world_data_update_shadow_direction_vs(WORKBENCH_PrivateData *wpd) +static void workbench_view_layer_data_free(void *storage) { - WORKBENCH_UBO_World *wd = &wpd->world_data; - float light_direction[3]; - float view_matrix[4][4]; - DRW_view_viewmat_get(NULL, view_matrix, false); + WORKBENCH_ViewLayerData *vldata = (WORKBENCH_ViewLayerData *)storage; + + DRW_UBO_FREE_SAFE(vldata->dof_sample_ubo); + DRW_UBO_FREE_SAFE(vldata->world_ubo); + DRW_UBO_FREE_SAFE(vldata->cavity_sample_ubo); + DRW_TEXTURE_FREE_SAFE(vldata->cavity_jitter_tx); + + BLI_memblock_destroy(vldata->material_ubo_data, NULL); + BLI_memblock_destroy(vldata->material_ubo, workbench_ubo_free); +} - workbench_private_data_get_light_direction(light_direction); +static WORKBENCH_ViewLayerData *workbench_view_layer_data_ensure_ex(struct ViewLayer *view_layer) +{ + WORKBENCH_ViewLayerData **vldata = (WORKBENCH_ViewLayerData **) + DRW_view_layer_engine_data_ensure_ex(view_layer, + (DrawEngineType *)&workbench_view_layer_data_ensure_ex, + &workbench_view_layer_data_free); + + if (*vldata == NULL) { + *vldata = MEM_callocN(sizeof(**vldata), "WORKBENCH_ViewLayerData"); + size_t matbuf_size = sizeof(WORKBENCH_UBO_Material) * MAX_MATERIAL; + (*vldata)->material_ubo_data = BLI_memblock_create_ex(matbuf_size, matbuf_size * 2); + (*vldata)->material_ubo = BLI_memblock_create_ex(sizeof(void *), sizeof(void *) * 8); + (*vldata)->world_ubo = DRW_uniformbuffer_create(sizeof(WORKBENCH_UBO_World), NULL); + } - /* Shadow direction. */ - mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, light_direction); + return *vldata; } /* \} */ -void workbench_clear_color_get(float color[4]) +static void workbench_viewvecs_update(float r_viewvecs[3][4]) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; + float invproj[4][4]; + const bool is_persp = DRW_view_is_persp_get(NULL); + DRW_view_winmat_get(NULL, invproj, true); + + /* view vectors for the corners of the view frustum. + * Can be used to recreate the world space position easily */ + copy_v4_fl4(r_viewvecs[0], -1.0f, -1.0f, -1.0f, 1.0f); + copy_v4_fl4(r_viewvecs[1], 1.0f, -1.0f, -1.0f, 1.0f); + copy_v4_fl4(r_viewvecs[2], -1.0f, 1.0f, -1.0f, 1.0f); + + /* convert the view vectors to view space */ + for (int i = 0; i < 3; i++) { + mul_m4_v4(invproj, r_viewvecs[i]); + /* normalized trick see: + * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ + mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][3]); + if (is_persp) { + mul_v3_fl(r_viewvecs[i], 1.0f / r_viewvecs[i][2]); + } + r_viewvecs[i][3] = 1.0; + } + + /* we need to store the differences */ + r_viewvecs[1][0] -= r_viewvecs[0][0]; + r_viewvecs[1][1] = r_viewvecs[2][1] - r_viewvecs[0][1]; - if (!DRW_state_is_scene_render() || !DRW_state_draw_background()) { - zero_v4(color); + /* 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]); + r_viewvecs[1][2] = vec_far[2] - r_viewvecs[0][2]; } - else if (scene->world) { - copy_v3_v3(color, &scene->world->horr); - color[3] = 1.0f; +} + +static void workbench_studiolight_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) +{ + StudioLight *studiolight = wpd->studio_light; + float view_matrix[4][4], rot_matrix[4][4]; + DRW_view_viewmat_get(NULL, view_matrix, false); + + if (USE_WORLD_ORIENTATION(wpd)) { + axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); + mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix); + swap_v3_v3(rot_matrix[2], rot_matrix[1]); + negate_v3(rot_matrix[2]); } else { - zero_v3(color); - color[3] = 1.0f; + unit_m4(rot_matrix); } -} -void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info) -{ - effect_info->jitter_index = 0; - effect_info->view_updated = true; + if (U.edit_studio_light) { + studiolight = BKE_studiolight_studio_edit_get(); + } + + /* Studio Lights. */ + for (int i = 0; i < 4; i++) { + WORKBENCH_UBO_Light *light = &wd->lights[i]; + + SolidLight *sl = (studiolight) ? &studiolight->light[i] : NULL; + if (sl && sl->flag) { + copy_v3_v3(light->light_direction, sl->vec); + mul_mat3_m4_v3(rot_matrix, light->light_direction); + /* We should predivide the power by PI but that makes the lights really dim. */ + copy_v3_v3(light->specular_color, sl->spec); + copy_v3_v3(light->diffuse_color, sl->col); + light->wrapped = sl->smooth; + } + else { + copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); + copy_v3_fl(light->specular_color, 0.0f); + copy_v3_fl(light->diffuse_color, 0.0f); + } + } + + if (studiolight) { + copy_v3_v3(wd->ambient_color, studiolight->light_ambient); + } + else { + copy_v3_fl(wd->ambient_color, 1.0f); + } + + wd->use_specular = workbench_is_specular_highlight_enabled(wpd); } void workbench_private_data_init(WORKBENCH_PrivateData *wpd) { const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; - wpd->material_hash = BLI_ghash_ptr_new(__func__); - wpd->material_transp_hash = BLI_ghash_ptr_new(__func__); + RegionView3D *rv3d = draw_ctx->rv3d; + View3D *v3d = draw_ctx->v3d; + Scene *scene = draw_ctx->scene; + WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer); + + wpd->is_playback = DRW_state_is_playback(); + wpd->is_navigating = rv3d && (rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)); + + wpd->ctx_mode = CTX_data_mode_enum_ex( + draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); + wpd->preferences = &U; + wpd->scene = scene; + wpd->sh_cfg = draw_ctx->sh_cfg; + wpd->clip_state = RV3D_CLIPPING_ENABLED(v3d, rv3d) ? DRW_STATE_CLIP_PLANES : 0; + wpd->cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; + wpd->vldata = vldata; + wpd->world_ubo = vldata->world_ubo; - View3D *v3d = draw_ctx->v3d; - RegionView3D *rv3d = draw_ctx->rv3d; + wpd->taa_sample_len = workbench_antialiasing_sample_count_get(wpd); + + wpd->volumes_do = false; + BLI_listbase_clear(&wpd->smoke_domains); if (!v3d || (v3d->shading.type == OB_RENDER && BKE_scene_uses_blender_workbench(scene))) { + /* FIXME: This reproduce old behavior when workbench was separated in 2 engines. + * But this is a workaround for a missing update tagging from operators. */ + if (scene->display.shading.type != wpd->shading.type || + XRAY_ENABLED(v3d) != XRAY_ENABLED((&scene->display))) { + wpd->view_updated = true; + } + wpd->shading = scene->display.shading; - wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display)); - wpd->use_color_render_settings = true; + if (XRAY_FLAG_ENABLED((&scene->display))) { + wpd->shading.xray_alpha = XRAY_ALPHA((&scene->display)); + } + else { + wpd->shading.xray_alpha = 1.0f; + } + + if (scene->r.alphamode == R_ALPHAPREMUL) { + copy_v4_fl(wpd->background_color, 0.0f); + } + else if (scene->world) { + World *wo = scene->world; + copy_v4_fl4(wpd->background_color, wo->horr, wo->horg, wo->horb, 1.0f); + } + else { + copy_v4_fl4(wpd->background_color, 0.0f, 0.0f, 0.0f, 1.0f); + } } else { + /* FIXME: This reproduce old behavior when workbench was separated in 2 engines. + * But this is a workaround for a missing update tagging from operators. */ + if (v3d->shading.type != wpd->shading.type || XRAY_ENABLED(v3d) != XRAY_ENABLED(wpd)) { + wpd->view_updated = true; + } + wpd->shading = v3d->shading; - wpd->shading.xray_alpha = XRAY_ALPHA(v3d); - wpd->use_color_render_settings = false; - } + if (wpd->shading.type < OB_SOLID) { + wpd->shading.xray_alpha = 0.0f; + } + else if (XRAY_ENABLED(v3d)) { + wpd->shading.xray_alpha = XRAY_ALPHA(v3d); + } + else { + wpd->shading.xray_alpha = 1.0f; + } - wpd->use_color_management = BKE_scene_check_color_management_enabled(scene); + /* No background. The overlays will draw the correct one. */ + copy_v4_fl(wpd->background_color, 0.0f); + } if (wpd->shading.light == V3D_LIGHTING_MATCAP) { wpd->studio_light = BKE_studiolight_find(wpd->shading.matcap, STUDIOLIGHT_TYPE_MATCAP); @@ -162,119 +260,56 @@ void workbench_private_data_init(WORKBENCH_PrivateData *wpd) wpd->studio_light = BKE_studiolight_find(wpd->shading.studio_light, STUDIOLIGHT_TYPE_STUDIO); } - float shadow_focus = scene->display.shadow_focus; - /* Clamp to avoid overshadowing and shading errors. */ - CLAMP(shadow_focus, 0.0001f, 0.99999f); - wpd->shadow_shift = scene->display.shadow_shift; - wpd->shadow_focus = 1.0f - shadow_focus * (1.0f - wpd->shadow_shift); - wpd->shadow_multiplier = 1.0 - wpd->shading.shadow_intensity; - - WORKBENCH_UBO_World *wd = &wpd->world_data; - wd->matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; - - studiolight_update_world(wpd, wpd->studio_light, wd); - - copy_v3_v3(wd->object_outline_color, wpd->shading.object_outline_color); - wd->object_outline_color[3] = 1.0f; - - wd->curvature_ridge = 0.5f / max_ff(square_f(wpd->shading.curvature_ridge_factor), 1e-4f); - wd->curvature_valley = 0.7f / max_ff(square_f(wpd->shading.curvature_valley_factor), 1e-4f); - - /* Will be NULL when rendering. */ - if (RV3D_CLIPPING_ENABLED(v3d, rv3d)) { - wpd->world_clip_planes = rv3d->clip; - } - else { - wpd->world_clip_planes = NULL; - } - - workbench_world_data_update_shadow_direction_vs(wpd); - workbench_world_data_ubo_ensure(scene, wpd); - - /* Cavity settings */ { - const int ssao_samples = scene->display.matcap_ssao_samples; - - float invproj[4][4]; - const bool is_persp = DRW_view_is_persp_get(NULL); - /* view vectors for the corners of the view frustum. - * Can be used to recreate the world space position easily */ - float viewvecs[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}, - }; - int i; - const float *size = DRW_viewport_size_get(); - - wpd->ssao_params[0] = ssao_samples; - wpd->ssao_params[1] = size[0] / 64.0; - wpd->ssao_params[2] = size[1] / 64.0; - wpd->ssao_params[3] = 0; - - /* distance, factor, factor, attenuation */ - copy_v4_fl4(wpd->ssao_settings, - scene->display.matcap_ssao_distance, - wpd->shading.cavity_valley_factor, - wpd->shading.cavity_ridge_factor, - scene->display.matcap_ssao_attenuation); - - DRW_view_winmat_get(NULL, wpd->winmat, false); - DRW_view_winmat_get(NULL, invproj, true); - - /* convert the view vectors to view space */ - for (i = 0; i < 3; i++) { - mul_m4_v4(invproj, viewvecs[i]); - /* normalized trick see: - * http://www.derschmale.com/2014/01/26/reconstructing-positions-from-the-depth-buffer */ - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][3]); - if (is_persp) { - mul_v3_fl(viewvecs[i], 1.0f / viewvecs[i][2]); - } - viewvecs[i][3] = 1.0; - - copy_v4_v4(wpd->viewvecs[i], viewvecs[i]); - } - - /* we need to store the differences */ - wpd->viewvecs[1][0] -= wpd->viewvecs[0][0]; - wpd->viewvecs[1][1] = wpd->viewvecs[2][1] - wpd->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]); - wpd->viewvecs[1][2] = vec_far[2] - wpd->viewvecs[0][2]; - } + /* Material UBOs. */ + wpd->material_ubo_data = vldata->material_ubo_data; + wpd->material_ubo = vldata->material_ubo; + wpd->material_chunk_count = 1; + wpd->material_chunk_curr = 0; + wpd->material_index = 1; + /* Create default material ubo. */ + wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data); + wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd); + /* Init default material used by vertex color & texture. */ + workbench_material_ubo_data( + wpd, NULL, NULL, &wpd->material_ubo_data_curr[0], V3D_SHADING_MATERIAL_COLOR); } - - wpd->volumes_do = false; - BLI_listbase_clear(&wpd->smoke_domains); } -void workbench_private_data_get_light_direction(float r_light_direction[3]) +void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; + WORKBENCH_UBO_World wd; - copy_v3_v3(r_light_direction, scene->display.light_direction); - SWAP(float, r_light_direction[2], r_light_direction[1]); - r_light_direction[2] = -r_light_direction[2]; - r_light_direction[0] = -r_light_direction[0]; + copy_v2_v2(wd.viewport_size, DRW_viewport_size_get()); + copy_v2_v2(wd.viewport_size_inv, DRW_viewport_invert_size_get()); + copy_v3_v3(wd.object_outline_color, wpd->shading.object_outline_color); + wd.object_outline_color[3] = 1.0f; + wd.ui_scale = G_draw.block.sizePixel; + wd.matcap_orientation = (wpd->shading.flag & V3D_SHADING_MATCAP_FLIP_X) != 0; + + workbench_studiolight_data_update(wpd, &wd); + workbench_shadow_data_update(wpd, &wd); + workbench_cavity_data_update(wpd, &wd); + workbench_viewvecs_update(wd.viewvecs); + + DRW_uniformbuffer_update(wpd->world_ubo, &wd); } -void workbench_private_data_free(WORKBENCH_PrivateData *wpd) +void workbench_update_material_ubos(WORKBENCH_PrivateData *UNUSED(wpd)) { - BLI_ghash_free(wpd->material_hash, NULL, MEM_freeN); - BLI_ghash_free(wpd->material_transp_hash, NULL, MEM_freeN); - - if (wpd->is_world_ubo_owner) { - DRW_UBO_FREE_SAFE(wpd->world_ubo); - } - else { - wpd->world_ubo = NULL; + const DRWContextState *draw_ctx = DRW_context_state_get(); + WORKBENCH_ViewLayerData *vldata = workbench_view_layer_data_ensure_ex(draw_ctx->view_layer); + + BLI_memblock_iter iter, iter_data; + BLI_memblock_iternew(vldata->material_ubo, &iter); + BLI_memblock_iternew(vldata->material_ubo_data, &iter_data); + WORKBENCH_UBO_Material *matchunk; + while ((matchunk = BLI_memblock_iterstep(&iter_data))) { + GPUUniformBuffer **ubo = BLI_memblock_iterstep(&iter); + BLI_assert(*ubo != NULL); + GPU_uniformbuffer_update(*ubo, matchunk); } - DRW_UBO_FREE_SAFE(wpd->dof_ubo); + BLI_memblock_clear(vldata->material_ubo, workbench_ubo_free); + BLI_memblock_clear(vldata->material_ubo_data, NULL); } diff --git a/source/blender/draw/engines/workbench/workbench_deferred.c b/source/blender/draw/engines/workbench/workbench_deferred.c deleted file mode 100644 index df9a597faf9..00000000000 --- a/source/blender/draw/engines/workbench/workbench_deferred.c +++ /dev/null @@ -1,1415 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "workbench_private.h" - -#include "BLI_alloca.h" -#include "BLI_dynstr.h" -#include "BLI_utildefines.h" -#include "BLI_rand.h" -#include "BLI_string_utils.h" - -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" - -#include "DNA_image_types.h" -#include "DNA_fluid_types.h" -#include "DNA_mesh_types.h" -#include "DNA_modifier_types.h" -#include "DNA_node_types.h" - -#include "GPU_shader.h" -#include "GPU_texture.h" -#include "GPU_extensions.h" - -#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ - -/* *********** STATIC *********** */ - -/* #define DEBUG_SHADOW_VOLUME */ - -#ifdef DEBUG_SHADOW_VOLUME -# include "draw_debug.h" -#endif - -typedef struct WORKBENCH_DEFERRED_Shaders { - struct GPUShader *prepass_sh_cache[MAX_PREPASS_SHADERS]; -} WORKBENCH_DEFERRED_Shaders; - -static struct { - WORKBENCH_DEFERRED_Shaders sh_data[GPU_SHADER_CFG_LEN]; - - struct GPUShader *composite_sh_cache[MAX_COMPOSITE_SHADERS]; - struct GPUShader *cavity_sh[MAX_CAVITY_SHADERS]; - struct GPUShader *background_sh[2]; - struct GPUShader *ghost_resolve_sh; - struct GPUShader *shadow_fail_sh; - struct GPUShader *shadow_fail_manifold_sh; - struct GPUShader *shadow_pass_sh; - struct GPUShader *shadow_pass_manifold_sh; - struct GPUShader *shadow_caps_sh; - struct GPUShader *shadow_caps_manifold_sh; - struct GPUShader *oit_resolve_sh; - - /* TODO(fclem) move everything below to wpd and custom viewlayer data. */ - struct GPUTexture *oit_accum_tx; /* ref only, not alloced */ - struct GPUTexture *oit_revealage_tx; /* ref only, not alloced */ - struct GPUTexture *object_id_tx; /* ref only, not alloced */ - struct GPUTexture *color_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *cavity_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *normal_buffer_tx; /* ref only, not alloced */ - struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ - - SceneDisplay display; /* world light direction for shadows */ - - struct GPUUniformBuffer *sampling_ubo; - struct GPUTexture *jitter_tx; - int cached_sample_num; -} e_data = {{{{NULL}}}}; - -/* Shaders */ -extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_view_lib_glsl[]; - -extern char datatoc_workbench_prepass_vert_glsl[]; -extern char datatoc_workbench_prepass_frag_glsl[]; -extern char datatoc_workbench_cavity_frag_glsl[]; -extern char datatoc_workbench_forward_composite_frag_glsl[]; -extern char datatoc_workbench_deferred_composite_frag_glsl[]; -extern char datatoc_workbench_deferred_background_frag_glsl[]; -extern char datatoc_workbench_ghost_resolve_frag_glsl[]; - -extern char datatoc_workbench_shadow_vert_glsl[]; -extern char datatoc_workbench_shadow_geom_glsl[]; -extern char datatoc_workbench_shadow_caps_geom_glsl[]; -extern char datatoc_workbench_shadow_debug_frag_glsl[]; - -extern char datatoc_workbench_cavity_lib_glsl[]; -extern char datatoc_workbench_common_lib_glsl[]; -extern char datatoc_workbench_data_lib_glsl[]; -extern char datatoc_workbench_object_outline_lib_glsl[]; -extern char datatoc_workbench_curvature_lib_glsl[]; -extern char datatoc_workbench_world_light_lib_glsl[]; - -extern char datatoc_gpu_shader_depth_only_frag_glsl[]; - -static char *workbench_build_composite_frag(WORKBENCH_PrivateData *wpd) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - - if (!FLAT_ENABLED(wpd)) { - BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); - } - if (OBJECT_OUTLINE_ENABLED(wpd)) { - BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); - } - if (CURVATURE_ENABLED(wpd)) { - BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); - } - - BLI_dynstr_append(ds, datatoc_workbench_deferred_composite_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_prepass_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_prepass_vert(bool is_hair) -{ - DynStr *ds = BLI_dynstr_new(); - if (is_hair) { - BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); - } - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_cavity_frag(bool cavity, bool curvature, bool high_dpi) -{ - DynStr *ds = BLI_dynstr_new(); - - if (cavity) { - BLI_dynstr_append(ds, "#define USE_CAVITY\n"); - } - if (curvature) { - BLI_dynstr_append(ds, "#define USE_CURVATURE\n"); - } - if (high_dpi) { - BLI_dynstr_append(ds, "#define CURVATURE_OFFSET 2\n"); - } - if (NORMAL_ENCODING_ENABLED()) { - BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); - } - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_cavity_frag_glsl); - BLI_dynstr_append(ds, datatoc_workbench_cavity_lib_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static GPUShader *workbench_cavity_shader_get(bool cavity, bool curvature) -{ - const bool high_dpi = (U.pixelsize > 1.5f); - int index = 0; - SET_FLAG_FROM_TEST(index, cavity, 1 << 0); - SET_FLAG_FROM_TEST(index, curvature, 1 << 1); - SET_FLAG_FROM_TEST(index, high_dpi, 1 << 2); - - GPUShader **sh = &e_data.cavity_sh[index]; - if (*sh == NULL) { - char *cavity_frag = workbench_build_cavity_frag(cavity, curvature, high_dpi); - *sh = DRW_shader_create_fullscreen(cavity_frag, NULL); - MEM_freeN(cavity_frag); - } - return *sh; -} - -static GPUShader *ensure_deferred_prepass_shader(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override, - eGPUShaderConfig sh_cfg) -{ - WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_prepass_shader_index( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - if (sh_data->prepass_sh_cache[index] == NULL) { - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - char *prepass_vert = workbench_build_prepass_vert(is_hair); - char *prepass_frag = workbench_build_prepass_frag(); - sh_data->prepass_sh_cache[index] = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, prepass_vert, NULL}, - .frag = (const char *[]){prepass_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, NULL}, - }); - MEM_freeN(prepass_vert); - MEM_freeN(prepass_frag); - MEM_freeN(defines); - } - return sh_data->prepass_sh_cache[index]; -} - -static GPUShader *ensure_deferred_composite_shader(WORKBENCH_PrivateData *wpd) -{ - int index = workbench_material_get_composite_shader_index(wpd); - if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *composite_frag = workbench_build_composite_frag(wpd); - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - MEM_freeN(composite_frag); - MEM_freeN(defines); - } - return e_data.composite_sh_cache[index]; -} - -static GPUShader *ensure_background_shader(WORKBENCH_PrivateData *wpd) -{ - const int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; - if (e_data.background_sh[index] == NULL) { - const char *defines = (index) ? "#define V3D_SHADING_OBJECT_OUTLINE\n" : NULL; - char *frag = BLI_string_joinN(datatoc_workbench_data_lib_glsl, - datatoc_workbench_common_lib_glsl, - datatoc_workbench_object_outline_lib_glsl, - datatoc_workbench_deferred_background_frag_glsl); - e_data.background_sh[index] = DRW_shader_create_fullscreen(frag, defines); - MEM_freeN(frag); - } - return e_data.background_sh[index]; -} - -static void select_deferred_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) -{ - wpd->prepass_sh = ensure_deferred_prepass_shader( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_hair_sh = ensure_deferred_prepass_shader( - wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_uniform_sh = ensure_deferred_prepass_shader( - wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_uniform_hair_sh = ensure_deferred_prepass_shader( - wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->prepass_textured_sh = ensure_deferred_prepass_shader( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->prepass_textured_array_sh = ensure_deferred_prepass_shader( - wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->prepass_vertex_sh = ensure_deferred_prepass_shader( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg); - wpd->composite_sh = ensure_deferred_composite_shader(wpd); - wpd->background_sh = ensure_background_shader(wpd); -} - -/* Using Hammersley distribution */ -static float *create_disk_samples(int num_samples, int num_iterations) -{ - /* vec4 to ensure memory alignment. */ - const int total_samples = num_samples * num_iterations; - float(*texels)[4] = MEM_mallocN(sizeof(float[4]) * total_samples, __func__); - const float num_samples_inv = 1.0f / num_samples; - - for (int i = 0; i < total_samples; i++) { - float it_add = (i / num_samples) * 0.499f; - float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f); - double dphi; - BLI_hammersley_1d(i, &dphi); - - float phi = (float)dphi * 2.0f * M_PI + it_add; - texels[i][0] = cosf(phi); - texels[i][1] = sinf(phi); - /* This deliberately distribute more samples - * at the center of the disk (and thus the shadow). */ - texels[i][2] = r; - } - - return (float *)texels; -} - -static struct GPUTexture *create_jitter_texture(int num_samples) -{ - float jitter[64 * 64][4]; - const float num_samples_inv = 1.0f / num_samples; - - for (int i = 0; i < 64 * 64; i++) { - float phi = blue_noise[i][0] * 2.0f * M_PI; - /* This rotate the sample per pixels */ - jitter[i][0] = cosf(phi); - jitter[i][1] = sinf(phi); - /* This offset the sample along it's direction axis (reduce banding) */ - float bn = blue_noise[i][1] - 0.5f; - CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */ - jitter[i][2] = bn * num_samples_inv; - jitter[i][3] = blue_noise[i][1]; - } - - UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral); - - return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_FILTER | DRW_TEX_WRAP, &jitter[0][0]); -} -/* Functions */ - -static void workbench_init_object_data(DrawData *dd) -{ - WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; - data->shadow_bbox_dirty = true; -} - -static void workbench_init_oit_framebuffer(WORKBENCH_FramebufferList *fbl, - DefaultTextureList *dtxl) -{ - const float *size = DRW_viewport_size_get(); - e_data.oit_accum_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); - e_data.oit_revealage_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R16F, &draw_engine_workbench_solid); - - GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.oit_accum_tx), - GPU_ATTACHMENT_TEXTURE(e_data.oit_revealage_tx), - }); -} - -void workbench_deferred_engine_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - View3D *v3d = draw_ctx->v3d; - Scene *scene = draw_ctx->scene; - Object *camera; - - if (v3d && rv3d) { - camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; - } - else { - camera = scene->camera; - } - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); - } - if (!stl->effects) { - stl->effects = MEM_callocN(sizeof(*stl->effects), __func__); - workbench_effect_info_init(stl->effects); - } - - if (!e_data.shadow_pass_sh) { - WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - memset(sh_data->prepass_sh_cache, 0, sizeof(sh_data->prepass_sh_cache)); - memset(e_data.composite_sh_cache, 0, sizeof(e_data.composite_sh_cache)); -#ifdef DEBUG_SHADOW_VOLUME - const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; -#else - const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; -#endif - /* TODO only compile on demand */ - e_data.shadow_pass_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_PASS\n" - "#define DOUBLE_MANIFOLD\n", - NULL}, - }); - e_data.shadow_pass_manifold_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_PASS\n", NULL}, - }); - e_data.shadow_fail_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n" - "#define DOUBLE_MANIFOLD\n", - NULL}, - }); - e_data.shadow_fail_manifold_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL}, - }); - e_data.shadow_caps_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n" - "#define DOUBLE_MANIFOLD\n", - NULL}, - }); - e_data.shadow_caps_manifold_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){datatoc_common_view_lib_glsl, - datatoc_workbench_shadow_vert_glsl, - NULL}, - .geom = (const char *[]){datatoc_workbench_shadow_caps_geom_glsl, NULL}, - .frag = (const char *[]){shadow_frag, NULL}, - .defs = (const char *[]){"#define SHADOW_FAIL\n", NULL}, - }); - - e_data.ghost_resolve_sh = DRW_shader_create_fullscreen( - datatoc_workbench_ghost_resolve_frag_glsl, NULL); - } - workbench_volume_engine_init(); - workbench_fxaa_engine_init(); - workbench_taa_engine_init(vedata); - - WORKBENCH_PrivateData *wpd = stl->g_data; - workbench_private_data_init(wpd); - - wpd->shading.xray_alpha = 1.0f; - - workbench_dof_engine_init(vedata, camera); - - if (OIT_ENABLED(wpd)) { - if (e_data.oit_resolve_sh == NULL) { - e_data.oit_resolve_sh = DRW_shader_create_fullscreen( - datatoc_workbench_forward_composite_frag_glsl, "#define ALPHA_COMPOSITE\n"); - } - - workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg); - workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg); - } - - { - const float *viewport_size = DRW_viewport_size_get(); - const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16 : GPU_RGBA32F; - const eGPUTextureFormat comp_tex_format = GPU_RGBA16F; - const eGPUTextureFormat col_tex_format = workbench_color_texture_format(wpd); - const eGPUTextureFormat id_tex_format = OBJECT_ID_PASS_ENABLED(wpd) ? GPU_R32UI : GPU_R8; - - e_data.object_id_tx = NULL; - e_data.color_buffer_tx = NULL; - e_data.composite_buffer_tx = NULL; - e_data.normal_buffer_tx = NULL; - e_data.cavity_buffer_tx = NULL; - - e_data.composite_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], comp_tex_format, &draw_engine_workbench_solid); - - if (workbench_is_matdata_pass_enabled(wpd) || GPU_unused_fb_slot_workaround()) { - e_data.color_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], col_tex_format, &draw_engine_workbench_solid); - } - if (OBJECT_ID_PASS_ENABLED(wpd) || GPU_unused_fb_slot_workaround()) { - e_data.object_id_tx = DRW_texture_pool_query_2d( - size[0], size[1], id_tex_format, &draw_engine_workbench_solid); - } - if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { - e_data.normal_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], nor_tex_format, &draw_engine_workbench_solid); - } - if (CAVITY_ENABLED(wpd)) { - e_data.cavity_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R16, &draw_engine_workbench_solid); - } - - GPU_framebuffer_ensure_config(&fbl->prepass_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->cavity_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.cavity_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->composite_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->color_only_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - - if (!workbench_is_matdata_pass_enabled(wpd) && !GPU_unused_fb_slot_workaround()) { - e_data.color_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], col_tex_format, &draw_engine_workbench_solid); - } - - GPU_framebuffer_ensure_config(&fbl->effect_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - }); - - if (OBJECT_ID_PASS_ENABLED(wpd)) { - GPU_framebuffer_ensure_config(&fbl->id_clear_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - }); - } - } - - { - /* AO Samples Tex */ - int num_iterations = workbench_taa_calculate_num_iterations(vedata); - - const int ssao_samples_single_iteration = scene->display.matcap_ssao_samples; - const int ssao_samples = MIN2(num_iterations * ssao_samples_single_iteration, 500); - - if (e_data.sampling_ubo && (e_data.cached_sample_num != ssao_samples)) { - DRW_UBO_FREE_SAFE(e_data.sampling_ubo); - DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); - } - - if (e_data.sampling_ubo == NULL) { - float *samples = create_disk_samples(ssao_samples_single_iteration, num_iterations); - e_data.jitter_tx = create_jitter_texture(ssao_samples); - e_data.sampling_ubo = DRW_uniformbuffer_create(sizeof(float[4]) * ssao_samples, samples); - e_data.cached_sample_num = ssao_samples; - MEM_freeN(samples); - } - } - - /* Prepass */ - { - DRWShadingGroup *grp; - DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0; - DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; - - psl->prepass_pass = DRW_pass_create("Prepass", state | cull_state | clip_state); - psl->prepass_hair_pass = DRW_pass_create("Prepass", state | clip_state); - - psl->ghost_prepass_pass = DRW_pass_create("Prepass Ghost", state | cull_state | clip_state); - psl->ghost_prepass_hair_pass = DRW_pass_create("Prepass Ghost", state | clip_state); - - psl->ghost_resolve_pass = DRW_pass_create("Resolve Ghost Depth", - DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS); - grp = DRW_shgroup_create(e_data.ghost_resolve_sh, psl->ghost_resolve_pass); - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - workbench_aa_create_pass(vedata, &e_data.color_buffer_tx); - } - - { - workbench_dof_create_pass(vedata, &e_data.composite_buffer_tx, e_data.jitter_tx); - } - - if (CAVITY_ENABLED(wpd)) { - int state = DRW_STATE_WRITE_COLOR; - GPUShader *shader = workbench_cavity_shader_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); - psl->cavity_pass = DRW_pass_create("Cavity", state); - DRWShadingGroup *grp = DRW_shgroup_create(shader, psl->cavity_pass); - DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - DRW_shgroup_uniform_block(grp, "samples_block", e_data.sampling_ubo); - - if (SSAO_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - DRW_shgroup_uniform_vec4(grp, "ssao_params", wpd->ssao_params, 1); - DRW_shgroup_uniform_vec4(grp, "ssao_settings", wpd->ssao_settings, 1); - DRW_shgroup_uniform_mat4(grp, "WinMatrix", wpd->winmat); - DRW_shgroup_uniform_texture(grp, "ssao_jitter", e_data.jitter_tx); - } - - if (CURVATURE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - DRW_shgroup_uniform_vec2(grp, "curvature_settings", &wpd->world_data.curvature_ridge, 1); - } - - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } -} - -void workbench_deferred_engine_free(void) -{ - for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { - WORKBENCH_DEFERRED_Shaders *sh_data = &e_data.sh_data[sh_data_index]; - for (int index = 0; index < MAX_PREPASS_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(sh_data->prepass_sh_cache[index]); - } - } - for (int index = 0; index < MAX_COMPOSITE_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); - } - for (int index = 0; index < MAX_CAVITY_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(e_data.cavity_sh[index]); - } - DRW_SHADER_FREE_SAFE(e_data.ghost_resolve_sh); - DRW_UBO_FREE_SAFE(e_data.sampling_ubo); - DRW_TEXTURE_FREE_SAFE(e_data.jitter_tx); - DRW_SHADER_FREE_SAFE(e_data.background_sh[0]); - DRW_SHADER_FREE_SAFE(e_data.background_sh[1]); - - DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); - - DRW_SHADER_FREE_SAFE(e_data.shadow_pass_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_pass_manifold_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_fail_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_fail_manifold_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_caps_sh); - DRW_SHADER_FREE_SAFE(e_data.shadow_caps_manifold_sh); - - workbench_volume_engine_free(); - workbench_fxaa_engine_free(); - workbench_taa_engine_free(); - workbench_dof_engine_free(); -} - -static void workbench_composite_uniforms(WORKBENCH_PrivateData *wpd, DRWShadingGroup *grp) -{ - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - if (workbench_is_matdata_pass_enabled(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "materialBuffer", &e_data.color_buffer_tx); - } - else { - DRW_shgroup_uniform_vec3(grp, "materialSingleColor", wpd->shading.single_color, 1); - } - if (OBJECT_OUTLINE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - } - if (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "normalBuffer", &e_data.normal_buffer_tx); - } - if (CAVITY_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "cavityBuffer", &e_data.cavity_buffer_tx); - } - if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - } - if (workbench_is_specular_highlight_enabled(wpd) || STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - } - if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, - STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | - STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); - DRW_shgroup_uniform_texture( - grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture); - if (workbench_is_specular_highlight_enabled(wpd)) { - DRW_shgroup_uniform_texture( - grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture); - } - } -} - -void workbench_deferred_cache_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - DRWShadingGroup *grp; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - - workbench_volume_cache_init(vedata); - select_deferred_shaders(wpd, draw_ctx->sh_cfg); - - /* Background Pass */ - { - DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_EQUAL; - if (DRW_state_is_scene_render()) { - /* Composite the scene over cleared background. */ - state |= DRW_STATE_BLEND_ALPHA_PREMUL; - } - psl->background_pass = DRW_pass_create("Background", state); - grp = DRW_shgroup_create(wpd->background_sh, psl->background_pass); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - if (OBJECT_OUTLINE_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - } - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - /* Deferred Mix Pass */ - { - workbench_private_data_get_light_direction(e_data.display.light_direction); - studiolight_update_light(wpd, e_data.display.light_direction); - - if (SHADOW_ENABLED(wpd)) { - psl->composite_pass = DRW_pass_create( - "Composite", DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_EQUAL | DRW_STATE_DEPTH_GREATER); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_stencil_mask(grp, 0x00); - DRW_shgroup_uniform_float_copy(grp, "lightMultiplier", 1.0f); - DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); - DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - - /* Stencil Shadow passes. */ -#ifdef DEBUG_SHADOW_VOLUME - DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_COLOR | - DRW_STATE_BLEND_ADD; - DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL | DRW_STATE_WRITE_COLOR | - DRW_STATE_BLEND_ADD; -#else - DRWState depth_pass_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_PASS | - DRW_STATE_STENCIL_ALWAYS; - DRWState depth_fail_state = DRW_STATE_DEPTH_LESS | DRW_STATE_WRITE_STENCIL_SHADOW_FAIL | - DRW_STATE_STENCIL_ALWAYS; -#endif - psl->shadow_depth_pass_pass = DRW_pass_create("Shadow Pass", depth_pass_state); - psl->shadow_depth_pass_mani_pass = DRW_pass_create("Shadow Pass Mani", depth_pass_state); - psl->shadow_depth_fail_pass = DRW_pass_create("Shadow Fail", depth_fail_state); - psl->shadow_depth_fail_mani_pass = DRW_pass_create("Shadow Fail Mani", depth_fail_state); - psl->shadow_depth_fail_caps_pass = DRW_pass_create("Shadow Fail Caps", depth_fail_state); - psl->shadow_depth_fail_caps_mani_pass = DRW_pass_create("Shadow Fail Caps Mani", - depth_fail_state); - -#ifndef DEBUG_SHADOW_VOLUME - grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, psl->shadow_depth_pass_mani_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, psl->shadow_depth_fail_mani_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_caps_sh, psl->shadow_depth_fail_caps_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, - psl->shadow_depth_fail_caps_mani_pass); - DRW_shgroup_stencil_mask(grp, 0xFF); - - psl->composite_shadow_pass = DRW_pass_create( - "Composite Shadow", - DRW_STATE_WRITE_COLOR | DRW_STATE_STENCIL_NEQUAL | DRW_STATE_DEPTH_GREATER); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_shadow_pass); - DRW_shgroup_stencil_mask(grp, 0x00); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_uniform_float(grp, "lightMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float(grp, "shadowMultiplier", &wpd->shadow_multiplier, 1); - DRW_shgroup_uniform_float_copy(grp, "shadowShift", scene->display.shadow_shift); - DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); -#endif - } - else { - psl->composite_pass = DRW_pass_create("Composite", - DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER); - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - workbench_composite_uniforms(wpd, grp); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } - - /** - * Order Independent Transparency. - * Similar to workbench forward. Duplicated code to avoid - * spaghetti with workbench forward. It would be great if we unify - * this in a clean way. - */ - if (OIT_ENABLED(wpd)) { - DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0; - DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; - /* Transparency Accum */ - { - /* Same as forward but here we use depth test to - * not bleed through other solid objects. */ - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS | DRW_STATE_BLEND_OIT | cull_state | - clip_state; - psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state); - } - /* Depth */ - { - int state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | clip_state; - psl->object_outline_pass = DRW_pass_create("Transparent Depth", state); - } - /* OIT Composite */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; - psl->oit_composite_pass = DRW_pass_create("OIT Composite", state); - - grp = DRW_shgroup_create(e_data.oit_resolve_sh, psl->oit_composite_pass); - DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.oit_accum_tx); - DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.oit_revealage_tx); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - } -} - -static WORKBENCH_MaterialData *get_or_create_material_data(WORKBENCH_Data *vedata, - Object *ob, - Material *mat, - Image *ima, - ImageUser *iuser, - eV3DShadingColorType color_type, - int interp) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_MaterialData *material; - WORKBENCH_MaterialData material_template; - const bool is_ghost = (ob->dtx & OB_DRAWXRAY); - - /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template, color_type); - material_template.color_type = color_type; - material_template.ima = ima; - material_template.iuser = iuser; - material_template.interp = interp; - uint hash = workbench_material_get_hash(&material_template, is_ghost); - - material = BLI_ghash_lookup(wpd->material_hash, POINTER_FROM_UINT(hash)); - if (material == NULL) { - material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); - /* select the correct prepass shader */ - GPUShader *shader = (wpd->shading.color_type == color_type) ? wpd->prepass_sh : - wpd->prepass_uniform_sh; - const bool is_tiled = (ima && ima->source == IMA_SRC_TILED); - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - shader = is_tiled ? wpd->prepass_textured_array_sh : wpd->prepass_textured_sh; - } - if (color_type == V3D_SHADING_VERTEX_COLOR) { - shader = wpd->prepass_vertex_sh; - } - material->shgrp = DRW_shgroup_create( - shader, (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_pass : psl->prepass_pass); - workbench_material_copy(material, &material_template); - DRW_shgroup_stencil_mask(material->shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); - workbench_material_shgroup_uniform(wpd, material->shgrp, material, ob, true, is_tiled, interp); - BLI_ghash_insert(wpd->material_hash, POINTER_FROM_UINT(hash), material); - } - return material; -} - -static void workbench_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type != eModifierType_ParticleSystem) { - continue; - } - ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { - continue; - } - ParticleSettings *part = psys->part; - const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - if (draw_as == PART_DRAW_PATH) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, false); - WORKBENCH_MaterialData *material = get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - - struct GPUShader *shader = (wpd->shading.color_type == color_type) ? - wpd->prepass_hair_sh : - wpd->prepass_uniform_hair_sh; - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, - psys, - md, - (ob->dtx & OB_DRAWXRAY) ? psl->ghost_prepass_hair_pass : psl->prepass_hair_pass, - shader); - DRW_shgroup_stencil_mask(shgrp, (ob->dtx & OB_DRAWXRAY) ? 0x00 : 0xFF); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob, true, false, interp); - } - } -} - -static void workbench_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - /* Force workbench to render active object textured when in texture paint mode */ - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* Single Image mode */ - if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { - Image *image = imapaint->canvas; - int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : - SHD_INTERP_CLOSEST; - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - material = get_or_create_material_data(vedata, ob, NULL, image, NULL, color_type, interp); - - DRW_shgroup_call(material->shgrp, geom, ob); - } - else { - /* IMAGEPAINT_MODE_MATERIAL */ - const int materials_len = DRW_cache_object_material_count_get(ob); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - if (geom_array != NULL && geom_array[i] != NULL) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - material = get_or_create_material_data(vedata, ob, mat, image, iuser, color_type, interp); - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - } - } - } -} - -static void workbench_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob); - material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, false); - DRW_shgroup_call(material->shgrp, geom, ob); -} - -void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - - if (!DRW_object_is_renderable(ob)) { - return; - } - - if (ob->type == OB_MESH) { - workbench_cache_populate_particles(vedata, ob); - } - - ModifierData *md; - if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Fluid)) && - (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((FluidModifierData *)md)->domain != NULL) && - (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) { - workbench_volume_cache_populate(vedata, scene, ob, md); - return; /* Do not draw solid in this case. */ - } - - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - return; - } - if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) { - return; - } - - WORKBENCH_MaterialData *material; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const bool is_active = (ob == draw_ctx->obact); - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const bool use_hide = is_active && DRW_object_use_hide_faces(ob); - const int materials_len = DRW_cache_object_material_count_get(ob); - const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - bool has_transp_mat = false; - const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob); - const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) && - me && me->mloopuv; - const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) && - me && me->mloopcol; - - if (use_texture_paint_drawing) { - workbench_cache_populate_texture_paint_mode(vedata, ob); - } - else if (use_vertex_paint_drawing) { - workbench_cache_populate_vertex_paint_mode(vedata, ob); - } - else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { - /* Draw textured */ - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - if (geom_array != NULL && geom_array[i] != NULL) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - if (color_type == V3D_SHADING_MATERIAL_COLOR && mat && mat->a < 1.0) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, 0); - has_transp_mat = true; - } - else { - material = get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - } - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - } - } - } - else if (ELEM(wpd->shading.color_type, - V3D_SHADING_SINGLE_COLOR, - V3D_SHADING_OBJECT_COLOR, - V3D_SHADING_RANDOM_COLOR, - V3D_SHADING_VERTEX_COLOR)) { - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - - if ((ob->color[3] < 1.0f) && (color_type == V3D_SHADING_OBJECT_COLOR)) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0); - has_transp_mat = true; - } - else { - /* Draw solid color */ - material = get_or_create_material_data(vedata, ob, NULL, NULL, NULL, color_type, 0); - } - - if (use_sculpt_pbvh) { - bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); - DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol); - } - else { - struct GPUBatch *geom; - if (color_type == V3D_SHADING_VERTEX_COLOR) { - geom = DRW_cache_mesh_surface_vertpaint_get(ob); - } - else { - geom = DRW_cache_object_surface_get(ob); - } - - if (geom) { - DRW_shgroup_call(material->shgrp, geom, ob); - } - } - } - else { - /* Draw material color */ - if (use_sculpt_pbvh) { - struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); - - for (int i = 0; i < materials_len; i++) { - struct Material *mat = BKE_object_material_get(ob, i + 1); - if (mat != NULL && mat->a < 1.0f) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - has_transp_mat = true; - } - else { - material = get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - } - shgrps[i] = material->shgrp; - } - DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); - } - else { - struct GPUBatch **geoms; - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); - - geoms = DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); - for (int i = 0; i < materials_len; i++) { - if (geoms != NULL && geoms[i] != NULL) { - Material *mat = BKE_object_material_get(ob, i + 1); - if (mat != NULL && mat->a < 1.0f) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - has_transp_mat = true; - } - else { - material = get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - } - DRW_shgroup_call(material->shgrp, geoms[i], ob); - } - } - } - } - - if (SHADOW_ENABLED(wpd) && !(ob->dtx & OB_DRAW_NO_SHADOW_CAST)) { - bool is_manifold; - struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold); - if (geom_shadow) { - if (use_sculpt_pbvh || use_hide) { - /* Currently unsupported in sculpt mode. We could revert to the slow - * method in this case but I'm not sure if it's a good idea given that - * sculpted meshes are heavy to begin with. */ - // DRW_shgroup_call_sculpt(wpd->shadow_shgrp, ob, ob->obmat); - } - else { - WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( - &ob->id, - &draw_engine_workbench_solid, - sizeof(WORKBENCH_ObjectData), - &workbench_init_object_data, - NULL); - - if (studiolight_object_cast_visible_shadow(wpd, ob, engine_object_data)) { - - mul_v3_mat3_m4v3( - engine_object_data->shadow_dir, ob->imat, e_data.display.light_direction); - - DRWShadingGroup *grp; - bool use_shadow_pass_technique = !studiolight_camera_in_object_shadow( - wpd, ob, engine_object_data); - - if (use_shadow_pass_technique && !has_transp_mat) { - if (is_manifold) { - grp = DRW_shgroup_create(e_data.shadow_pass_manifold_sh, - psl->shadow_depth_pass_mani_pass); - } - else { - grp = DRW_shgroup_create(e_data.shadow_pass_sh, psl->shadow_depth_pass_pass); - } - DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); - DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f); - DRW_shgroup_call_no_cull(grp, geom_shadow, ob); -#ifdef DEBUG_SHADOW_VOLUME - DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f}); -#endif - } - else { - float extrude_distance = studiolight_object_shadow_distance( - wpd, ob, engine_object_data); - - /* TODO(fclem): only use caps if they are in the view frustum. */ - const bool need_caps = true; - if (need_caps) { - if (is_manifold) { - grp = DRW_shgroup_create(e_data.shadow_caps_manifold_sh, - psl->shadow_depth_fail_caps_mani_pass); - } - else { - grp = DRW_shgroup_create(e_data.shadow_caps_sh, - psl->shadow_depth_fail_caps_pass); - } - DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); - DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); - DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob); - } - - if (is_manifold) { - grp = DRW_shgroup_create(e_data.shadow_fail_manifold_sh, - psl->shadow_depth_fail_mani_pass); - } - else { - grp = DRW_shgroup_create(e_data.shadow_fail_sh, psl->shadow_depth_fail_pass); - } - DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); - DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); - DRW_shgroup_call_no_cull(grp, geom_shadow, ob); -#ifdef DEBUG_SHADOW_VOLUME - DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); -#endif - } - } - } - } - } - } -} - -void workbench_deferred_cache_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - - if (GHOST_ENABLED(psl)) { - /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0); - - GPU_framebuffer_ensure_config( - &dfbl->default_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - GPU_framebuffer_ensure_config( - &dfbl->in_front_fb, - {GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), GPU_ATTACHMENT_TEXTURE(dtxl->color)}); - - GPU_framebuffer_ensure_config(&fbl->ghost_prepass_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), - GPU_ATTACHMENT_TEXTURE(e_data.color_buffer_tx), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - GPU_ATTACHMENT_TEXTURE(e_data.normal_buffer_tx), - }); - } -} - -void workbench_deferred_draw_scene(WORKBENCH_Data *vedata) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PrivateData *wpd = stl->g_data; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - - if (workbench_is_taa_enabled(wpd)) { - workbench_taa_draw_scene_start(vedata); - } - - const float clear_depth = 1.0f; - const float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - uint clear_stencil = 0x00; - int clear_bits = GPU_DEPTH_BIT; - SET_FLAG_FROM_TEST(clear_bits, SHADOW_ENABLED(wpd), GPU_STENCIL_BIT); - - if (OBJECT_ID_PASS_ENABLED(wpd)) { - /* From all the color buffers, only object id needs to be cleared. */ - GPU_framebuffer_bind(fbl->id_clear_fb); - GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col); - } - - GPU_framebuffer_bind(fbl->prepass_fb); - GPU_framebuffer_clear(fbl->prepass_fb, clear_bits, clear_col, clear_depth, clear_stencil); - - DRW_draw_pass(psl->prepass_pass); - DRW_draw_pass(psl->prepass_hair_pass); - - if (fbl->ghost_prepass_fb) { - GPU_framebuffer_bind(fbl->ghost_prepass_fb); - GPU_framebuffer_clear_depth(fbl->ghost_prepass_fb, 1.0f); - } - else if (dtxl->depth_in_front) { - /* TODO(fclem) This clear should be done in a global place. */ - GPU_framebuffer_bind(dfbl->in_front_fb); - GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f); - } - - if (GHOST_ENABLED(psl)) { - DRW_draw_pass(psl->ghost_prepass_pass); - DRW_draw_pass(psl->ghost_prepass_hair_pass); - - GPU_framebuffer_bind(dfbl->depth_only_fb); - DRW_draw_pass(psl->ghost_resolve_pass); - } - - if (CAVITY_ENABLED(wpd)) { - GPU_framebuffer_bind(fbl->cavity_fb); - DRW_draw_pass(psl->cavity_pass); - } - - if (DRW_state_is_scene_render()) { - float clear_color[4]; - workbench_clear_color_get(clear_color); - GPU_framebuffer_bind(fbl->composite_fb); - GPU_framebuffer_clear_color(fbl->composite_fb, clear_color); - } - - if (SHADOW_ENABLED(wpd)) { -#ifdef DEBUG_SHADOW_VOLUME - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); -#else - GPU_framebuffer_bind(dfbl->depth_only_fb); -#endif - DRW_draw_pass(psl->shadow_depth_pass_pass); - DRW_draw_pass(psl->shadow_depth_pass_mani_pass); - DRW_draw_pass(psl->shadow_depth_fail_pass); - DRW_draw_pass(psl->shadow_depth_fail_mani_pass); - DRW_draw_pass(psl->shadow_depth_fail_caps_pass); - DRW_draw_pass(psl->shadow_depth_fail_caps_mani_pass); - - if (GHOST_ENABLED(psl)) { - /* We need to set the stencil buffer to 0 where Ghost objects are - * else they will get shadow and even badly shadowed. */ - DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - DRW_pass_state_set(psl->ghost_prepass_pass, state); - DRW_pass_state_set(psl->ghost_prepass_hair_pass, state); - - DRW_draw_pass(psl->ghost_prepass_pass); - DRW_draw_pass(psl->ghost_prepass_hair_pass); - } -#ifndef DEBUG_SHADOW_VOLUME - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); - DRW_draw_pass(psl->composite_shadow_pass); -#endif - } - else { - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->composite_pass); - } - - /* In order to not draw on top of ghost objects, we clear the stencil - * to 0xFF and the ghost object to 0x00 and only draw overlays on top if - * stencil is not 0. */ - /* TODO(fclem) Remove this hack. */ - GPU_framebuffer_bind(dfbl->depth_only_fb); - GPU_framebuffer_clear_stencil(dfbl->depth_only_fb, 0xFF); - - /* TODO(fclem): only enable when needed (when there is overlays). */ - if (GHOST_ENABLED(psl)) { - DRWState state = DRW_STATE_DEPTH_EQUAL | DRW_STATE_WRITE_STENCIL | DRW_STATE_STENCIL_ALWAYS; - DRW_pass_state_set(psl->ghost_prepass_pass, state); - DRW_pass_state_set(psl->ghost_prepass_hair_pass, state); - - DRW_draw_pass(psl->ghost_prepass_pass); - DRW_draw_pass(psl->ghost_prepass_hair_pass); - } - - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->background_pass); - - if (OIT_ENABLED(wpd) && !DRW_pass_is_empty(psl->transparent_accum_pass)) { - /* meh, late init to not request buffers we won't use. */ - workbench_init_oit_framebuffer(fbl, dtxl); - - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPU_framebuffer_bind(fbl->transparent_accum_fb); - GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); - DRW_draw_pass(psl->transparent_accum_pass); - - GPU_framebuffer_bind(fbl->composite_fb); - DRW_draw_pass(psl->oit_composite_pass); - } - - if (wpd->volumes_do) { - GPU_framebuffer_bind(fbl->color_only_fb); - DRW_draw_pass(psl->volume_pass); - } - - workbench_dof_draw_pass(vedata); - workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx); -} - -void workbench_deferred_draw_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - /* XXX TODO(fclem) do not discard UBOS after drawing! Store them per viewport. */ - workbench_private_data_free(wpd); - workbench_volume_smoke_textures_free(wpd); -} diff --git a/source/blender/draw/engines/workbench/workbench_effect_aa.c b/source/blender/draw/engines/workbench/workbench_effect_aa.c deleted file mode 100644 index c03fe5cd5c8..00000000000 --- a/source/blender/draw/engines/workbench/workbench_effect_aa.c +++ /dev/null @@ -1,101 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "ED_screen.h" - -#include "draw_color_management.h" - -#include "workbench_private.h" - -void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - if (draw_ctx->evil_C != NULL) { - struct wmWindowManager *wm = CTX_wm_manager(draw_ctx->evil_C); - wpd->is_playback = ED_screen_animation_playing(wm) != NULL; - } - else { - wpd->is_playback = false; - } - - if (workbench_is_taa_enabled(wpd)) { - psl->effect_aa_pass = workbench_taa_create_pass(vedata, tx); - } - else if (workbench_is_fxaa_enabled(wpd)) { - psl->effect_aa_pass = workbench_fxaa_create_pass(tx); - effect_info->jitter_index = 0; - } - else { - psl->effect_aa_pass = NULL; - effect_info->jitter_index = 0; - } -} - -static void workspace_aa_draw_transform(GPUTexture *tx, WORKBENCH_PrivateData *UNUSED(wpd)) -{ - DRW_transform_none(tx); -} - -void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - if (workbench_is_fxaa_enabled(wpd)) { - GPU_framebuffer_bind(fbl->effect_fb); - workspace_aa_draw_transform(tx, wpd); - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_draw_pass(psl->effect_aa_pass); - } - else if (workbench_is_taa_enabled(wpd)) { - /* - * when drawing the first TAA frame, we transform directly to the - * color_only_fb as the TAA shader is just performing a direct copy. - * the workbench_taa_draw_screen_end will fill the history buffer - * for the other iterations. - */ - if (effect_info->jitter_index == 1) { - GPU_framebuffer_bind(dfbl->color_only_fb); - workspace_aa_draw_transform(tx, wpd); - } - else { - GPU_framebuffer_bind(fbl->effect_fb); - workspace_aa_draw_transform(tx, wpd); - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_draw_pass(psl->effect_aa_pass); - } - workbench_taa_draw_scene_end(vedata); - } - else { - GPU_framebuffer_bind(dfbl->color_only_fb); - workspace_aa_draw_transform(tx, wpd); - } -} diff --git a/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c new file mode 100644 index 00000000000..3cd21dfeace --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_antialiasing.c @@ -0,0 +1,421 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Anti-aliasing: + * + * We use SMAA (Smart Morphological Anti-Aliasing) as a fast antialiasing solution. + * + * If the viewport stays static, the engine ask for multiple redraw and will progressively + * converge to a much more accurate image without aliasing. + * We call this one TAA (Temporal Anti-Aliasing). + * + * This is done using an accumulation buffer and a final pass that will output the final color + * to the scene buffer. We softly blend between SMAA and TAA to avoid really harsh transitions. + */ + +#include "ED_screen.h" + +#include "BLI_jitter_2d.h" + +#include "smaa_textures.h" + +#include "workbench_private.h" + +static struct { + bool init; + float jitter_5[5][2]; + float jitter_8[8][2]; + float jitter_11[11][2]; + float jitter_16[16][2]; + float jitter_32[32][2]; +} e_data = {false}; + +static void workbench_taa_jitter_init_order(float (*table)[2], int num) +{ + BLI_jitter_init(table, num); + + /* find closest element to center */ + int closest_index = 0; + float closest_squared_distance = 1.0f; + + for (int index = 0; index < num; index++) { + const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]); + if (squared_dist < closest_squared_distance) { + closest_squared_distance = squared_dist; + closest_index = index; + } + } + + /* move jitter table so that closest sample is in center */ + for (int index = 0; index < num; index++) { + sub_v2_v2(table[index], table[closest_index]); + mul_v2_fl(table[index], 2.0f); + } + + /* swap center sample to the start of the table */ + if (closest_index != 0) { + swap_v2_v2(table[0], table[closest_index]); + } + + /* sort list based on furtest distance with previous */ + for (int i = 0; i < num - 2; i++) { + float f_squared_dist = 0.0; + int f_index = i; + for (int j = i + 1; j < num; j++) { + const float squared_dist = square_f(table[i][0] - table[j][0]) + + square_f(table[i][1] - table[j][1]); + if (squared_dist > f_squared_dist) { + f_squared_dist = squared_dist; + f_index = j; + } + } + swap_v2_v2(table[i + 1], table[f_index]); + } +} + +static void workbench_taa_jitter_init(void) +{ + if (e_data.init == false) { + e_data.init = true; + workbench_taa_jitter_init_order(e_data.jitter_5, 5); + workbench_taa_jitter_init_order(e_data.jitter_8, 8); + workbench_taa_jitter_init_order(e_data.jitter_11, 11); + workbench_taa_jitter_init_order(e_data.jitter_16, 16); + workbench_taa_jitter_init_order(e_data.jitter_32, 32); + } +} + +int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + + if (wpd->is_navigating || wpd->is_playback) { + /* Only draw using SMAA or no AA when navigating. */ + return min_ii(wpd->preferences->viewport_aa, 1); + } + else if (DRW_state_is_image_render()) { + if (draw_ctx->v3d) { + return scene->display.viewport_aa; + } + else { + return scene->display.render_aa; + } + } + else { + return wpd->preferences->viewport_aa; + } +} + +void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata) +{ + WORKBENCH_StorageList *stl = vedata->stl; + if (stl && stl->wpd) { + stl->wpd->view_updated = true; + } +} + +void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata) +{ + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_TextureList *txl = vedata->txl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + DrawEngineType *owner = (DrawEngineType *)&workbench_antialiasing_engine_init; + + wpd->view = NULL; + + /* reset complete drawing when navigating. */ + if (wpd->taa_sample != 0) { + if (wpd->is_navigating) { + wpd->taa_sample = 0; + } + } + + if (wpd->view_updated) { + wpd->taa_sample = 0; + wpd->view_updated = false; + } + + { + float persmat[4][4]; + DRW_view_persmat_get(NULL, persmat, false); + if (!equals_m4m4(persmat, wpd->last_mat)) { + copy_m4_m4(wpd->last_mat, persmat); + wpd->taa_sample = 0; + } + } + + if (wpd->taa_sample_len > 0) { + workbench_taa_jitter_init(); + + DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, GPU_RGBA16F, DRW_TEX_FILTER); + DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); + + wpd->smaa_edge_tx = DRW_texture_pool_query_fullscreen(GPU_RG8, owner); + wpd->smaa_weight_tx = DRW_texture_pool_query_fullscreen(GPU_RGBA8, owner); + + GPU_framebuffer_ensure_config(&fbl->antialiasing_fb, + { + GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx), + GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->smaa_edge_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(wpd->smaa_edge_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->smaa_weight_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(wpd->smaa_weight_tx), + }); + + /* TODO could be shared for all viewports. */ + if (txl->smaa_search_tx == NULL) { + txl->smaa_search_tx = GPU_texture_create_nD(SEARCHTEX_WIDTH, + SEARCHTEX_HEIGHT, + 0, + 2, + searchTexBytes, + GPU_R8, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + + txl->smaa_area_tx = GPU_texture_create_nD(AREATEX_WIDTH, + AREATEX_HEIGHT, + 0, + 2, + areaTexBytes, + GPU_RG8, + GPU_DATA_UNSIGNED_BYTE, + 0, + false, + NULL); + + GPU_texture_bind(txl->smaa_search_tx, 0); + GPU_texture_filter_mode(txl->smaa_search_tx, true); + GPU_texture_unbind(txl->smaa_search_tx); + + GPU_texture_bind(txl->smaa_area_tx, 0); + GPU_texture_filter_mode(txl->smaa_area_tx, true); + GPU_texture_unbind(txl->smaa_area_tx); + } + } + else { + /* Cleanup */ + DRW_TEXTURE_FREE_SAFE(txl->history_buffer_tx); + DRW_TEXTURE_FREE_SAFE(txl->depth_buffer_tx); + DRW_TEXTURE_FREE_SAFE(txl->smaa_search_tx); + DRW_TEXTURE_FREE_SAFE(txl->smaa_area_tx); + } +} + +void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata) +{ + WORKBENCH_TextureList *txl = vedata->txl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_PassList *psl = vedata->psl; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DRWShadingGroup *grp = NULL; + + if (wpd->taa_sample_len == 0) { + return; + } + + { + DRW_PASS_CREATE(psl->aa_accum_ps, DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL); + + GPUShader *shader = workbench_shader_antialiasing_accumulation_get(); + grp = DRW_shgroup_create(shader, psl->aa_accum_ps); + DRW_shgroup_uniform_texture(grp, "colorBuffer", dtxl->color); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + + const float *size = DRW_viewport_size_get(); + const float *sizeinv = DRW_viewport_invert_size_get(); + float metrics[4] = {sizeinv[0], sizeinv[1], size[0], size[1]}; + + { + /* Stage 1: Edge detection. */ + DRW_PASS_CREATE(psl->aa_edge_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = workbench_shader_antialiasing_get(0); + grp = DRW_shgroup_create(sh, psl->aa_edge_ps); + DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + /* Stage 2: Blend Weight/Coord. */ + DRW_PASS_CREATE(psl->aa_weight_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = workbench_shader_antialiasing_get(1); + grp = DRW_shgroup_create(sh, psl->aa_weight_ps); + DRW_shgroup_uniform_texture(grp, "edgesTex", wpd->smaa_edge_tx); + DRW_shgroup_uniform_texture(grp, "areaTex", txl->smaa_area_tx); + DRW_shgroup_uniform_texture(grp, "searchTex", txl->smaa_search_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + + DRW_shgroup_clear_framebuffer(grp, GPU_COLOR_BIT, 0, 0, 0, 0, 0.0f, 0x0); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + { + /* Stage 3: Resolve. */ + DRW_PASS_CREATE(psl->aa_resolve_ps, DRW_STATE_WRITE_COLOR); + + GPUShader *sh = workbench_shader_antialiasing_get(2); + grp = DRW_shgroup_create(sh, psl->aa_resolve_ps); + DRW_shgroup_uniform_texture(grp, "blendTex", wpd->smaa_weight_tx); + DRW_shgroup_uniform_texture(grp, "colorTex", txl->history_buffer_tx); + DRW_shgroup_uniform_vec4_copy(grp, "viewportMetrics", metrics); + DRW_shgroup_uniform_float(grp, "mixFactor", &wpd->smaa_mix_factor, 1); + DRW_shgroup_uniform_float(grp, "taaSampleCountInv", &wpd->taa_sample_inv, 1); + + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} + +/* Return true if render is not cached. */ +bool workbench_antialiasing_setup(WORKBENCH_Data *vedata) +{ + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + + if (wpd->taa_sample_len == 0) { + /* AA disabled. */ + return true; + } + + if (wpd->taa_sample >= wpd->taa_sample_len) { + /* TAA accumulation has finish. Just copy the result back */ + return false; + } + else { + const float *viewport_size = DRW_viewport_size_get(); + const DRWView *default_view = DRW_view_default_get(); + float *transform_offset; + + switch (wpd->taa_sample_len) { + default: + case 5: + transform_offset = e_data.jitter_5[min_ii(wpd->taa_sample, 5)]; + break; + case 8: + transform_offset = e_data.jitter_8[min_ii(wpd->taa_sample, 8)]; + break; + case 11: + transform_offset = e_data.jitter_11[min_ii(wpd->taa_sample, 11)]; + break; + case 16: + transform_offset = e_data.jitter_16[min_ii(wpd->taa_sample, 16)]; + break; + case 32: + transform_offset = e_data.jitter_32[min_ii(wpd->taa_sample, 32)]; + break; + } + + /* construct new matrices from transform delta */ + float winmat[4][4], viewmat[4][4], persmat[4][4]; + DRW_view_winmat_get(default_view, winmat, false); + DRW_view_viewmat_get(default_view, viewmat, false); + DRW_view_persmat_get(default_view, persmat, false); + + window_translate_m4(winmat, + persmat, + transform_offset[0] / viewport_size[0], + transform_offset[1] / viewport_size[1]); + + if (wpd->view) { + /* When rendering just update the view. This avoids recomputing the culling. */ + DRW_view_update_sub(wpd->view, viewmat, winmat); + } + else { + /* TAA is not making a big change to the matrices. + * Reuse the main view culling by creating a sub-view. */ + wpd->view = DRW_view_create_sub(default_view, viewmat, winmat); + } + DRW_view_set_active(wpd->view); + return true; + } +} + +void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata) +{ + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PassList *psl = vedata->psl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + if (wpd->taa_sample_len == 0) { + /* AA disabled. */ + /* Just set sample to 1 to avoid rendering indefinitely. */ + wpd->taa_sample = 1; + return; + } + + /** + * We always do SMAA on top of TAA accumulation, unless the number of samples of TAA is already + * high. This ensure a smoother transition. + * If TAA accumulation is finished, we only blit the result. + */ + + if (wpd->taa_sample == 0) { + /* In playback mode, we are sure the next redraw will not use the same viewmatrix. + * In this case no need to save the depth buffer. */ + eGPUFrameBufferBits bits = GPU_COLOR_BIT | (!wpd->is_playback ? GPU_DEPTH_BIT : 0); + GPU_framebuffer_blit(dfbl->default_fb, 0, fbl->antialiasing_fb, 0, bits); + } + else { + /* Accumulate result to the TAA buffer. */ + GPU_framebuffer_bind(fbl->antialiasing_fb); + DRW_draw_pass(psl->aa_accum_ps); + /* Copy back the saved depth buffer for correct overlays. */ + GPU_framebuffer_blit(fbl->antialiasing_fb, 0, dfbl->default_fb, 0, GPU_DEPTH_BIT); + } + + if (!DRW_state_is_image_render() || wpd->taa_sample + 1 == wpd->taa_sample_len) { + /* After a certain point SMAA is no longer necessary. */ + wpd->smaa_mix_factor = 1.0f - clamp_f(wpd->taa_sample / 4.0f, 0.0f, 1.0f); + wpd->taa_sample_inv = 1.0f / (wpd->taa_sample + 1); + + if (wpd->smaa_mix_factor > 0.0f) { + GPU_framebuffer_bind(fbl->smaa_edge_fb); + DRW_draw_pass(psl->aa_edge_ps); + + GPU_framebuffer_bind(fbl->smaa_weight_fb); + DRW_draw_pass(psl->aa_weight_ps); + } + + GPU_framebuffer_bind(dfbl->default_fb); + DRW_draw_pass(psl->aa_resolve_ps); + } + + wpd->taa_sample++; + + if (!DRW_state_is_image_render() && wpd->taa_sample < wpd->taa_sample_len) { + DRW_viewport_request_redraw(); + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_cavity.c b/source/blender/draw/engines/workbench/workbench_effect_cavity.c new file mode 100644 index 00000000000..cdf8a93fc57 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_cavity.c @@ -0,0 +1,182 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Cavity Effect: + * + * We use Screen Space Ambient Occlusion (SSAO) to enhance geometric details of the surfaces. + * We also use a Curvature effect computed only using the surface normals. + * + * This is done after the opaque pass. It only affects the opaque surfaces. + */ + +#include "DRW_render.h" + +#include "BLI_rand.h" + +#include "../eevee/eevee_lut.h" /* TODO find somewhere to share blue noise Table */ + +#include "workbench_engine.h" +#include "workbench_private.h" + +#define JITTER_TEX_SIZE 64 +#define CAVITY_MAX_SAMPLES 512 + +/* Using Hammersley distribution */ +static float *create_disk_samples(int num_samples, int num_iterations) +{ + const int total_samples = num_samples * num_iterations; + const float num_samples_inv = 1.0f / num_samples; + /* vec4 to ensure memory alignment. */ + float(*texels)[4] = MEM_callocN(sizeof(float[4]) * CAVITY_MAX_SAMPLES, __func__); + + for (int i = 0; i < total_samples; i++) { + float it_add = (i / num_samples) * 0.499f; + float r = fmodf((i + 0.5f + it_add) * num_samples_inv, 1.0f); + double dphi; + BLI_hammersley_1d(i, &dphi); + + float phi = (float)dphi * 2.0f * M_PI + it_add; + texels[i][0] = cosf(phi); + texels[i][1] = sinf(phi); + /* This deliberately distribute more samples + * at the center of the disk (and thus the shadow). */ + texels[i][2] = r; + } + + return (float *)texels; +} + +static struct GPUTexture *create_jitter_texture(int num_samples) +{ + float jitter[64 * 64][4]; + const float num_samples_inv = 1.0f / num_samples; + + for (int i = 0; i < 64 * 64; i++) { + float phi = blue_noise[i][0] * 2.0f * M_PI; + /* This rotate the sample per pixels */ + jitter[i][0] = cosf(phi); + jitter[i][1] = sinf(phi); + /* This offset the sample along it's direction axis (reduce banding) */ + float bn = blue_noise[i][1] - 0.5f; + CLAMP(bn, -0.499f, 0.499f); /* fix fireflies */ + jitter[i][2] = bn * num_samples_inv; + jitter[i][3] = blue_noise[i][1]; + } + + UNUSED_VARS(bsdf_split_sum_ggx, btdf_split_sum_ggx, ltc_mag_ggx, ltc_mat_ggx, ltc_disk_integral); + + return DRW_texture_create_2d(64, 64, GPU_RGBA16F, DRW_TEX_WRAP, &jitter[0][0]); +} + +BLI_INLINE int workbench_cavity_total_sample_count(const WORKBENCH_PrivateData *wpd, + const Scene *scene) +{ + return min_ii(max_ii(1, wpd->taa_sample_len) * scene->display.matcap_ssao_samples, + CAVITY_MAX_SAMPLES); +} + +void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) +{ + View3DShading *shading = &wpd->shading; + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + if (CAVITY_ENABLED(wpd)) { + int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples; + int cavity_sample_count_total = workbench_cavity_total_sample_count(wpd, scene); + int max_iter_count = cavity_sample_count_total / cavity_sample_count_single_iteration; + + int sample = wpd->taa_sample % max_iter_count; + wd->cavity_sample_start = cavity_sample_count_single_iteration * sample; + wd->cavity_sample_end = cavity_sample_count_single_iteration * (sample + 1); + + wd->cavity_sample_count_inv = 1.0f / (wd->cavity_sample_end - wd->cavity_sample_start); + wd->cavity_jitter_scale = 1.0f / 64.0f; + + wd->cavity_valley_factor = shading->cavity_valley_factor; + wd->cavity_ridge_factor = shading->cavity_ridge_factor; + wd->cavity_attenuation = scene->display.matcap_ssao_attenuation; + wd->cavity_distance = scene->display.matcap_ssao_distance; + + wd->curvature_ridge = 0.5f / max_ff(square_f(shading->curvature_ridge_factor), 1e-4f); + wd->curvature_valley = 0.7f / max_ff(square_f(shading->curvature_valley_factor), 1e-4f); + } +} + +void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + Scene *scene = draw_ctx->scene; + + int cavity_sample_count_single_iteration = scene->display.matcap_ssao_samples; + int cavity_sample_count = workbench_cavity_total_sample_count(wpd, scene); + + if (wpd->vldata->cavity_sample_count != cavity_sample_count) { + DRW_UBO_FREE_SAFE(wpd->vldata->cavity_sample_ubo); + DRW_TEXTURE_FREE_SAFE(wpd->vldata->cavity_jitter_tx); + } + + if (wpd->vldata->cavity_sample_ubo == NULL) { + float *samples = create_disk_samples(cavity_sample_count_single_iteration, + max_ii(1, wpd->taa_sample_len)); + wpd->vldata->cavity_jitter_tx = create_jitter_texture(cavity_sample_count); + /* NOTE: Uniform buffer needs to always be filled to be valid. */ + wpd->vldata->cavity_sample_ubo = DRW_uniformbuffer_create( + sizeof(float[4]) * CAVITY_MAX_SAMPLES, samples); + wpd->vldata->cavity_sample_count = cavity_sample_count; + MEM_freeN(samples); + } +} + +void workbench_cavity_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + + if (CAVITY_ENABLED(wpd)) { + workbench_cavity_samples_ubo_ensure(wpd); + + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_MUL; + DRW_PASS_CREATE(psl->cavity_ps, state); + + sh = workbench_shader_cavity_get(SSAO_ENABLED(wpd), CURVATURE_ENABLED(wpd)); + + grp = DRW_shgroup_create(sh, psl->cavity_ps); + DRW_shgroup_uniform_texture(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_block(grp, "samples_block", wpd->vldata->cavity_sample_ubo); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + + if (SSAO_ENABLED(wpd)) { + DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth); + DRW_shgroup_uniform_texture(grp, "cavityJitter", wpd->vldata->cavity_jitter_tx); + } + if (CURVATURE_ENABLED(wpd)) { + DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx); + } + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + else { + psl->cavity_ps = NULL; + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_dof.c b/source/blender/draw/engines/workbench/workbench_effect_dof.c index ae3e2218463..9716ccd4b44 100644 --- a/source/blender/draw/engines/workbench/workbench_effect_dof.c +++ b/source/blender/draw/engines/workbench/workbench_effect_dof.c @@ -18,6 +18,17 @@ /** \file * \ingroup draw_engine + * + * Depth of Field Effect: + * + * We use a gather approach by sampling a lowres version of the color buffer. + * The process can be summarized like this: + * - down-sample the color buffer using a COC (Circle of Confusion) aware down-sample algorithm. + * - do a gather pass using the COC computed in the previous pass. + * - do a median filter to reduce noise amount. + * - composite on top of main color buffer. + * + * This is done after all passes and affects every surfaces. */ #include "workbench_private.h" @@ -27,24 +38,6 @@ #include "DNA_camera_types.h" -/* *********** STATIC *********** */ -static struct { - struct GPUShader *effect_dof_prepare_sh; - struct GPUShader *effect_dof_downsample_sh; - struct GPUShader *effect_dof_flatten_v_sh; - struct GPUShader *effect_dof_flatten_h_sh; - struct GPUShader *effect_dof_dilate_v_sh; - struct GPUShader *effect_dof_dilate_h_sh; - struct GPUShader *effect_dof_blur1_sh; - struct GPUShader *effect_dof_blur2_sh; - struct GPUShader *effect_dof_resolve_sh; -} e_data = {NULL}; - -/* Shaders */ -extern char datatoc_workbench_effect_dof_frag_glsl[]; - -/* *********** Functions *********** */ - /** * Transform [-1..1] square to unit circle. */ @@ -130,52 +123,40 @@ static void workbench_dof_setup_samples(struct GPUUniformBuffer **ubo, DRW_uniformbuffer_update(*ubo, *data); } -void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) +void workbench_dof_engine_init(WORKBENCH_Data *vedata) { WORKBENCH_TextureList *txl = vedata->txl; WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_PrivateData *wpd = stl->wpd; WORKBENCH_FramebufferList *fbl = vedata->fbl; + const DRWContextState *draw_ctx = DRW_context_state_get(); + RegionView3D *rv3d = draw_ctx->rv3d; + View3D *v3d = draw_ctx->v3d; + Scene *scene = draw_ctx->scene; + Object *camera; + + if (v3d && rv3d) { + camera = (rv3d->persp == RV3D_CAMOB) ? v3d->camera : NULL; + } + else { + camera = scene->camera; + } + Camera *cam = camera != NULL ? camera->data : NULL; if ((wpd->shading.flag & V3D_SHADING_DEPTH_OF_FIELD) == 0 || (cam == NULL) || ((cam->dof.flag & CAM_DOF_ENABLED) == 0)) { wpd->dof_enabled = false; - return; - } - - if (e_data.effect_dof_prepare_sh == NULL) { - e_data.effect_dof_prepare_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define PREPARE\n"); - - e_data.effect_dof_downsample_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define DOWNSAMPLE\n"); - - e_data.effect_dof_flatten_v_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_VERTICAL\n"); - - e_data.effect_dof_flatten_h_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define FLATTEN_HORIZONTAL\n"); - - e_data.effect_dof_dilate_v_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_VERTICAL\n"); - - e_data.effect_dof_dilate_h_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define DILATE_HORIZONTAL\n"); - e_data.effect_dof_blur1_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define BLUR1\n"); - - e_data.effect_dof_blur2_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define BLUR2\n"); - - e_data.effect_dof_resolve_sh = DRW_shader_create_fullscreen( - datatoc_workbench_effect_dof_frag_glsl, "#define RESOLVE\n"); + /* Cleanup. */ + DRW_TEXTURE_FREE_SAFE(txl->dof_source_tx); + DRW_TEXTURE_FREE_SAFE(txl->coc_halfres_tx); + return; } const float *full_size = DRW_viewport_size_get(); int size[2] = {max_ii(1, (int)full_size[0] / 2), max_ii(1, (int)full_size[1] / 2)}; -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimisation */ /* NOTE: We Ceil here in order to not miss any edge texel if using a NPO2 texture. */ int shrink_h_size[2] = {ceilf(size[0] / 8.0f), size[1]}; int shrink_w_size[2] = {shrink_h_size[0], ceilf(size[1] / 8.0f)}; @@ -186,14 +167,14 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) DRW_texture_ensure_2d( &txl->coc_halfres_tx, size[0], size[1], GPU_RG8, DRW_TEX_FILTER | DRW_TEX_MIPMAP); wpd->dof_blur_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_solid); -#if 0 + size[0], size[1], GPU_RGBA16F, &draw_engine_workbench); +#if 0 /* TODO(fclem) finish COC min_max optimisation */ wpd->coc_temp_tx = DRW_texture_pool_query_2d( - shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench_solid); + shrink_h_size[0], shrink_h_size[1], GPU_RG8, &draw_engine_workbench); wpd->coc_tiles_tx[0] = DRW_texture_pool_query_2d( - shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid); + shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench); wpd->coc_tiles_tx[1] = DRW_texture_pool_query_2d( - shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench_solid); + shrink_w_size[0], shrink_w_size[1], GPU_RG8, &draw_engine_workbench); #endif GPU_framebuffer_ensure_config(&fbl->dof_downsample_fb, @@ -202,7 +183,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) GPU_ATTACHMENT_TEXTURE(txl->dof_source_tx), GPU_ATTACHMENT_TEXTURE(txl->coc_halfres_tx), }); -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimisation */ GPU_framebuffer_ensure_config(&fbl->dof_coc_tile_h_fb, { GPU_ATTACHMENT_NONE, @@ -231,11 +212,7 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) }); { - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - /* Parameters */ - /* TODO UI Options */ float fstop = cam->dof.aperture_fstop; float sensor = BKE_camera_sensor_size(cam->sensor_fit, cam->sensor_x, cam->sensor_y); float focus_dist = BKE_camera_object_dof_distance(camera); @@ -263,128 +240,125 @@ void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera) float rotation = cam->dof.aperture_rotation; float ratio = 1.0f / cam->dof.aperture_ratio; - if (wpd->dof_ubo == NULL || blades != wpd->dof_blades || rotation != wpd->dof_rotation || - ratio != wpd->dof_ratio) { + if (wpd->vldata->dof_sample_ubo == NULL || blades != wpd->dof_blades || + rotation != wpd->dof_rotation || ratio != wpd->dof_ratio) { wpd->dof_blades = blades; wpd->dof_rotation = rotation; wpd->dof_ratio = ratio; - workbench_dof_setup_samples(&wpd->dof_ubo, &stl->dof_ubo_data, blades, rotation, ratio); + workbench_dof_setup_samples( + &wpd->vldata->dof_sample_ubo, &stl->dof_ubo_data, blades, rotation, ratio); } } wpd->dof_enabled = true; } -void workbench_dof_create_pass(WORKBENCH_Data *vedata, - GPUTexture **dof_input, - GPUTexture *noise_tex) +void workbench_dof_cache_init(WORKBENCH_Data *vedata) { WORKBENCH_PassList *psl = vedata->psl; WORKBENCH_TextureList *txl = vedata->txl; WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - struct GPUBatch *quad = DRW_cache_fullscreen_quad_get(); + WORKBENCH_PrivateData *wpd = stl->wpd; if (!wpd->dof_enabled) { return; } - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + GPUShader *prepare_sh, *downsample_sh, *blur1_sh, *blur2_sh, *resolve_sh; + workbench_shader_depth_of_field_get( + &prepare_sh, &downsample_sh, &blur1_sh, &blur2_sh, &resolve_sh); - psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); - psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); - psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR); - psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR); - psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR); - psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR); - psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR); - psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR); - psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", - DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_prepare_sh, psl->dof_down_ps); - DRW_shgroup_uniform_texture_ref(grp, "sceneColorTex", dof_input); + psl->dof_down_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(prepare_sh, psl->dof_down_ps); + DRW_shgroup_uniform_texture(grp, "sceneColorTex", dtxl->color); DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1); DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_downsample_sh, psl->dof_down2_ps); + psl->dof_down2_ps = DRW_pass_create("DoF DownSample", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(downsample_sh, psl->dof_down2_ps); DRW_shgroup_uniform_texture(grp, "sceneColorTex", txl->dof_source_tx); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimization */ { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_h_sh, - psl->dof_flatten_h_ps); + psl->dof_flatten_h_ps = DRW_pass_create("DoF Flatten Coc H", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(flatten_h_sh, psl->dof_flatten_h_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_flatten_v_sh, - psl->dof_flatten_v_ps); + psl->dof_flatten_v_ps = DRW_pass_create("DoF Flatten Coc V", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(flatten_v_sh, psl->dof_flatten_v_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_temp_tx); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_v_sh, psl->dof_dilate_v_ps); + psl->dof_dilate_h_ps = DRW_pass_create("DoF Dilate Coc H", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(dilate_v_sh, psl->dof_dilate_v_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[0]); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_dilate_h_sh, psl->dof_dilate_h_ps); + psl->dof_dilate_v_ps = DRW_pass_create("DoF Dilate Coc V", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(dilate_h_sh, psl->dof_dilate_h_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", wpd->coc_tiles_tx[1]); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } #endif { - float offset = stl->effects->jitter_index / - (float)workbench_taa_calculate_num_iterations(vedata); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur1_sh, psl->dof_blur1_ps); - DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->dof_ubo); - DRW_shgroup_uniform_texture(grp, "noiseTex", noise_tex); + psl->dof_blur1_ps = DRW_pass_create("DoF Blur 1", DRW_STATE_WRITE_COLOR); + + /* We reuse the same noise texture. Ensure it is up to date. */ + workbench_cavity_samples_ubo_ensure(wpd); + + float offset = wpd->taa_sample / wpd->taa_sample_len; + DRWShadingGroup *grp = DRW_shgroup_create(blur1_sh, psl->dof_blur1_ps); + DRW_shgroup_uniform_block(grp, "dofSamplesBlock", wpd->vldata->dof_sample_ubo); + DRW_shgroup_uniform_texture(grp, "noiseTex", wpd->vldata->cavity_jitter_tx); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_float_copy(grp, "noiseOffset", offset); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_blur2_sh, psl->dof_blur2_ps); + psl->dof_blur2_ps = DRW_pass_create("DoF Blur 2", DRW_STATE_WRITE_COLOR); + + DRWShadingGroup *grp = DRW_shgroup_create(blur2_sh, psl->dof_blur2_ps); DRW_shgroup_uniform_texture(grp, "inputCocTex", txl->coc_halfres_tx); DRW_shgroup_uniform_texture(grp, "blurTex", wpd->dof_blur_tx); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } { - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_dof_resolve_sh, psl->dof_resolve_ps); + psl->dof_resolve_ps = DRW_pass_create("DoF Resolve", + DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_CUSTOM); + + DRWShadingGroup *grp = DRW_shgroup_create(resolve_sh, psl->dof_resolve_ps); DRW_shgroup_uniform_texture(grp, "halfResColorTex", txl->dof_source_tx); DRW_shgroup_uniform_texture(grp, "sceneDepthTex", dtxl->depth); DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); DRW_shgroup_uniform_vec3(grp, "dofParams", &wpd->dof_aperturesize, 1); DRW_shgroup_uniform_vec2(grp, "nearFar", wpd->dof_near_far, 1); - DRW_shgroup_call(grp, quad, NULL); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); } } -void workbench_dof_engine_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.effect_dof_prepare_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_downsample_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_v_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_flatten_h_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_v_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_dilate_h_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur1_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_blur2_sh); - DRW_SHADER_FREE_SAFE(e_data.effect_dof_resolve_sh); -} - static void workbench_dof_downsample_level(void *userData, int UNUSED(level)) { WORKBENCH_PassList *psl = (WORKBENCH_PassList *)userData; @@ -396,7 +370,8 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata) WORKBENCH_FramebufferList *fbl = vedata->fbl; WORKBENCH_StorageList *stl = vedata->stl; WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; + WORKBENCH_PrivateData *wpd = stl->wpd; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); if (!wpd->dof_enabled) { return; @@ -410,7 +385,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata) GPU_framebuffer_recursive_downsample( fbl->dof_downsample_fb, 2, workbench_dof_downsample_level, psl); -#if 0 +#if 0 /* TODO(fclem) finish COC min_max optimization */ GPU_framebuffer_bind(fbl->dof_coc_tile_h_fb); DRW_draw_pass(psl->dof_flatten_h_ps); @@ -430,7 +405,7 @@ void workbench_dof_draw_pass(WORKBENCH_Data *vedata) GPU_framebuffer_bind(fbl->dof_blur2_fb); DRW_draw_pass(psl->dof_blur2_ps); - GPU_framebuffer_bind(fbl->color_only_fb); + GPU_framebuffer_bind(dfbl->color_only_fb); DRW_draw_pass(psl->dof_resolve_ps); DRW_stats_group_end(); diff --git a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c b/source/blender/draw/engines/workbench/workbench_effect_fxaa.c deleted file mode 100644 index 6e3bf1658ab..00000000000 --- a/source/blender/draw/engines/workbench/workbench_effect_fxaa.c +++ /dev/null @@ -1,59 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ -#include "workbench_private.h" - -/* *********** STATIC *********** */ -static struct { - struct GPUShader *effect_fxaa_sh; -} e_data = {NULL}; - -/* Shaders */ -extern char datatoc_common_fxaa_lib_glsl[]; -extern char datatoc_common_fullscreen_vert_glsl[]; -extern char datatoc_workbench_effect_fxaa_frag_glsl[]; - -/* *********** Functions *********** */ -void workbench_fxaa_engine_init(void) -{ - if (e_data.effect_fxaa_sh == NULL) { - e_data.effect_fxaa_sh = DRW_shader_create_with_lib(datatoc_common_fullscreen_vert_glsl, - NULL, - datatoc_workbench_effect_fxaa_frag_glsl, - datatoc_common_fxaa_lib_glsl, - NULL); - } -} - -DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx) -{ - DRWPass *pass = DRW_pass_create("Effect FXAA", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_fxaa_sh, pass); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - return pass; -} - -void workbench_fxaa_engine_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.effect_fxaa_sh); -} diff --git a/source/blender/draw/engines/workbench/workbench_effect_outline.c b/source/blender/draw/engines/workbench/workbench_effect_outline.c new file mode 100644 index 00000000000..d1bc6b6c435 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_effect_outline.c @@ -0,0 +1,55 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Outline Effect: + * + * Simple effect that just samples an object id buffer to detect objects outlines. + */ + +#include "DRW_render.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_outline_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + + if (OBJECT_OUTLINE_ENABLED(wpd)) { + int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL; + DRW_PASS_CREATE(psl->outline_ps, state); + + sh = workbench_shader_outline_get(); + + grp = DRW_shgroup_create(sh, psl->outline_ps); + DRW_shgroup_uniform_texture(grp, "objectIdBuffer", wpd->object_id_tx); + DRW_shgroup_uniform_texture(grp, "depthBuffer", dtxl->depth); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + else { + psl->outline_ps = NULL; + } +} diff --git a/source/blender/draw/engines/workbench/workbench_effect_taa.c b/source/blender/draw/engines/workbench/workbench_effect_taa.c deleted file mode 100644 index e2864f8c832..00000000000 --- a/source/blender/draw/engines/workbench/workbench_effect_taa.c +++ /dev/null @@ -1,305 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "workbench_private.h" -#include "BLI_jitter_2d.h" - -static struct { - struct GPUShader *effect_taa_sh; - float jitter_5[5][2]; - float jitter_8[8][2]; - float jitter_11[11][2]; - float jitter_16[16][2]; - float jitter_32[32][2]; -} e_data = {NULL}; - -extern char datatoc_workbench_effect_taa_frag_glsl[]; - -static void workbench_taa_jitter_init_order(float (*table)[2], int num) -{ - BLI_jitter_init(table, num); - - /* find closest element to center */ - int closest_index = 0; - float closest_squared_distance = 1.0f; - - for (int index = 0; index < num; index++) { - const float squared_dist = square_f(table[index][0]) + square_f(table[index][1]); - if (squared_dist < closest_squared_distance) { - closest_squared_distance = squared_dist; - closest_index = index; - } - } - - /* move jitter table so that closest sample is in center */ - for (int index = 0; index < num; index++) { - sub_v2_v2(table[index], table[closest_index]); - mul_v2_fl(table[index], 2.0f); - } - - /* swap center sample to the start of the table */ - if (closest_index != 0) { - swap_v2_v2(table[0], table[closest_index]); - } - - /* sort list based on furtest distance with previous */ - for (int i = 0; i < num - 2; i++) { - float f_squared_dist = 0.0; - int f_index = i; - for (int j = i + 1; j < num; j++) { - const float squared_dist = square_f(table[i][0] - table[j][0]) + - square_f(table[i][1] - table[j][1]); - if (squared_dist > f_squared_dist) { - f_squared_dist = squared_dist; - f_index = j; - } - } - swap_v2_v2(table[i + 1], table[f_index]); - } -} - -static void workbench_taa_jitter_init(void) -{ - workbench_taa_jitter_init_order(e_data.jitter_5, 5); - workbench_taa_jitter_init_order(e_data.jitter_8, 8); - workbench_taa_jitter_init_order(e_data.jitter_11, 11); - workbench_taa_jitter_init_order(e_data.jitter_16, 16); - workbench_taa_jitter_init_order(e_data.jitter_32, 32); -} - -int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const Scene *scene = DRW_context_state_get()->scene; - int result; - if (workbench_is_taa_enabled(wpd)) { - if (DRW_state_is_image_render()) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->v3d) { - result = scene->display.viewport_aa; - } - else { - result = scene->display.render_aa; - } - } - else { - result = wpd->preferences->viewport_aa; - } - } - else { - /* when no TAA is disabled return 1 to render a single sample - * see `workbench_render.c` */ - result = 1; - } - return result; -} - -int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *UNUSED(vedata)) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; - int result = DRW_state_is_image_render() ? scene->display.viewport_aa : 1; - result = MAX2(result, 1); - return result; -} - -void workbench_taa_engine_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_EffectInfo *effect_info = vedata->stl->effects; - const DRWContextState *draw_ctx = DRW_context_state_get(); - RegionView3D *rv3d = draw_ctx->rv3d; - - if (e_data.effect_taa_sh == NULL) { - e_data.effect_taa_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_taa_frag_glsl, - NULL); - workbench_taa_jitter_init(); - } - - effect_info->view = NULL; - - /* reset complete drawing when navigating. */ - if (effect_info->jitter_index != 0) { - if (rv3d && rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING)) { - effect_info->jitter_index = 0; - } - } - - if (effect_info->view_updated) { - effect_info->jitter_index = 0; - effect_info->view_updated = false; - } - - { - float persmat[4][4]; - DRW_view_persmat_get(NULL, persmat, false); - if (!equals_m4m4(persmat, effect_info->last_mat)) { - copy_m4_m4(effect_info->last_mat, persmat); - effect_info->jitter_index = 0; - } - } -} - -void workbench_taa_engine_free(void) -{ - DRW_SHADER_FREE_SAFE(e_data.effect_taa_sh); -} - -DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_TextureList *txl = vedata->txl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - const WORKBENCH_PrivateData *wpd = stl->g_data; - - { - const eGPUTextureFormat hist_buffer_format = workbench_color_texture_format(wpd); - DRW_texture_ensure_fullscreen_2d(&txl->history_buffer_tx, hist_buffer_format, 0); - DRW_texture_ensure_fullscreen_2d(&txl->depth_buffer_tx, GPU_DEPTH24_STENCIL8, 0); - } - - { - GPU_framebuffer_ensure_config(&fbl->effect_taa_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(txl->history_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->depth_buffer_fb, - { - GPU_ATTACHMENT_TEXTURE(txl->depth_buffer_tx), - }); - } - - DRWPass *pass = DRW_pass_create("Effect TAA", DRW_STATE_WRITE_COLOR); - DRWShadingGroup *grp = DRW_shgroup_create(e_data.effect_taa_sh, pass); - DRW_shgroup_uniform_texture_ref(grp, "colorBuffer", color_buffer_tx); - DRW_shgroup_uniform_texture_ref(grp, "historyBuffer", &txl->history_buffer_tx); - DRW_shgroup_uniform_float(grp, "mixFactor", &effect_info->taa_mix_factor, 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - - return pass; -} - -void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_EffectInfo *effect_info = stl->effects; - WORKBENCH_PrivateData *wpd = stl->g_data; - - const float *viewport_size = DRW_viewport_size_get(); - const DRWView *default_view = DRW_view_default_get(); - int num_samples = 8; - float(*samples)[2]; - - num_samples = workbench_taa_calculate_num_iterations(vedata); - switch (num_samples) { - default: - case 5: - samples = e_data.jitter_5; - break; - case 8: - samples = e_data.jitter_8; - break; - case 11: - samples = e_data.jitter_11; - break; - case 16: - samples = e_data.jitter_16; - break; - case 32: - samples = e_data.jitter_32; - break; - } - - const int jitter_index = effect_info->jitter_index; - const float *transform_offset = samples[jitter_index]; - effect_info->taa_mix_factor = 1.0f / (jitter_index + 1); - effect_info->jitter_index = (jitter_index + 1) % num_samples; - /* Copy jitter index to Cavity iteration */ - wpd->ssao_params[3] = effect_info->jitter_index; - - /* construct new matrices from transform delta */ - float winmat[4][4], viewmat[4][4], persmat[4][4]; - DRW_view_winmat_get(default_view, winmat, false); - DRW_view_viewmat_get(default_view, viewmat, false); - DRW_view_persmat_get(default_view, persmat, false); - - window_translate_m4(winmat, - persmat, - transform_offset[0] / viewport_size[0], - transform_offset[1] / viewport_size[1]); - - if (effect_info->view) { - /* When rendering just update the view. This avoids recomputing the culling. */ - DRW_view_update_sub(effect_info->view, viewmat, winmat); - } - else { - /* TAA is not making a big change to the matrices. - * Reuse the main view culling by creating a subview. */ - effect_info->view = DRW_view_create_sub(default_view, viewmat, winmat); - } - DRW_view_set_active(effect_info->view); -} - -void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata) -{ - /* - * If first frame then the offset is 0.0 and its depth is the depth buffer to use - * for the rest of the draw engines. We store it in a persistent buffer. - * - * If it is not the first frame we copy the persistent buffer back to the - * default depth buffer - */ - const WORKBENCH_StorageList *stl = vedata->stl; - const WORKBENCH_FramebufferList *fbl = vedata->fbl; - const DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - WORKBENCH_EffectInfo *effect_info = stl->effects; - - if (effect_info->jitter_index == 1) { - GPU_framebuffer_blit(dfbl->depth_only_fb, 0, fbl->depth_buffer_fb, 0, GPU_DEPTH_BIT); - } - else { - GPU_framebuffer_blit(fbl->depth_buffer_fb, 0, dfbl->depth_only_fb, 0, GPU_DEPTH_BIT); - } - - GPU_framebuffer_blit(dfbl->color_only_fb, 0, fbl->effect_taa_fb, 0, GPU_COLOR_BIT); - - if (!DRW_state_is_image_render()) { - DRW_view_set_active(NULL); - } - - if (effect_info->jitter_index != 0 && !DRW_state_is_image_render()) { - DRW_viewport_request_redraw(); - } -} - -void workbench_taa_view_updated(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - if (stl) { - WORKBENCH_EffectInfo *effect_info = stl->effects; - if (effect_info) { - effect_info->view_updated = true; - } - } -} diff --git a/source/blender/draw/engines/workbench/workbench_engine.c b/source/blender/draw/engines/workbench/workbench_engine.c index 62a192bbb25..b91ca7cf070 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.c +++ b/source/blender/draw/engines/workbench/workbench_engine.c @@ -19,18 +19,557 @@ /** \file * \ingroup draw_engine * - * Simple engine for drawing color and/or depth. - * When we only need simple flat shaders. + * Workbench Engine: + * + * Optimized engine to draw the working viewport with solid and transparent geometry. */ #include "DRW_render.h" +#include "BLI_alloca.h" + +#include "BKE_modifier.h" +#include "BKE_object.h" +#include "BKE_paint.h" +#include "BKE_particle.h" + +#include "DNA_image_types.h" +#include "DNA_fluid_types.h" +#include "DNA_mesh_types.h" +#include "DNA_modifier_types.h" +#include "DNA_node_types.h" + #include "workbench_engine.h" #include "workbench_private.h" #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" -/* Note: currently unused, we may want to register so we can see this when debugging the view. */ +void workbench_engine_init(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_TextureList *txl = vedata->txl; + + workbench_shader_library_ensure(); + + if (!stl->wpd) { + stl->wpd = MEM_callocN(sizeof(*stl->wpd), __func__); + stl->wpd->view_updated = true; + } + + WORKBENCH_PrivateData *wpd = stl->wpd; + workbench_private_data_init(wpd); + workbench_update_world_ubo(wpd); + + if (txl->dummy_image_tx == NULL) { + float fpixel[4] = {1.0f, 0.0f, 1.0f, 1.0f}; + txl->dummy_image_tx = DRW_texture_create_2d(1, 1, GPU_RGBA8, 0, fpixel); + } + wpd->dummy_image_tx = txl->dummy_image_tx; + + if (OBJECT_ID_PASS_ENABLED(wpd)) { + wpd->object_id_tx = DRW_texture_pool_query_fullscreen(GPU_R16UI, &draw_engine_workbench); + } + else { + /* Dont free because it's a pool texture. */ + wpd->object_id_tx = NULL; + } + + workbench_opaque_engine_init(vedata); + workbench_transparent_engine_init(vedata); + workbench_dof_engine_init(vedata); + workbench_antialiasing_engine_init(vedata); + workbench_volume_engine_init(vedata); +} + +void workbench_cache_init(void *ved) +{ + WORKBENCH_Data *vedata = ved; + + workbench_opaque_cache_init(vedata); + workbench_transparent_cache_init(vedata); + workbench_shadow_cache_init(vedata); + workbench_cavity_cache_init(vedata); + workbench_outline_cache_init(vedata); + workbench_dof_cache_init(vedata); + workbench_antialiasing_cache_init(vedata); + workbench_volume_cache_init(vedata); +} + +/* TODO(fclem) DRW_cache_object_surface_material_get needs a refactor to allow passing NULL + * instead of gpumat_array. Avoiding all this boilerplate code. */ +static struct GPUBatch **workbench_object_surface_material_get(Object *ob) +{ + const int materials_len = DRW_cache_object_material_count_get(ob); + struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); + memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); + + return DRW_cache_object_surface_material_get(ob, gpumat_array, materials_len); +} + +static void workbench_cache_sculpt_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + eV3DShadingColorType color_type) +{ + const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR); + const bool use_single_drawcall = !ELEM(color_type, V3D_SHADING_MATERIAL_COLOR); + BLI_assert(wpd->shading.color_type != V3D_SHADING_TEXTURE_COLOR); + + if (use_single_drawcall) { + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, NULL); + DRW_shgroup_call_sculpt(grp, ob, false, false, use_vcol); + } + else { + const int materials_len = DRW_cache_object_material_count_get(ob); + struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); + for (int i = 0; i < materials_len; i++) { + shgrps[i] = workbench_material_setup(wpd, ob, i + 1, color_type, NULL); + } + DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); + } +} + +static void workbench_cache_texpaint_populate(WORKBENCH_PrivateData *wpd, Object *ob) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; + const bool use_single_drawcall = imapaint->mode == IMAGEPAINT_MODE_IMAGE; + + if (use_single_drawcall) { + struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); + if (geom) { + Image *ima = imapaint->canvas; + int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, 0, ima, NULL, interp); + DRW_shgroup_call(grp, geom, ob); + } + } + else { + struct GPUBatch **geoms = DRW_cache_mesh_surface_texpaint_get(ob); + if (geoms) { + const int materials_len = DRW_cache_object_material_count_get(ob); + for (int i = 0; i < materials_len; i++) { + DRWShadingGroup *grp = workbench_image_setup(wpd, ob, i + 1, NULL, NULL, 0); + DRW_shgroup_call(grp, geoms[i], ob); + } + } + } +} + +static void workbench_cache_common_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + eV3DShadingColorType color_type, + bool *r_transp) +{ + const bool use_tex = ELEM(color_type, V3D_SHADING_TEXTURE_COLOR); + const bool use_vcol = ELEM(color_type, V3D_SHADING_VERTEX_COLOR); + const bool use_single_drawcall = !ELEM( + color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR); + + if (use_single_drawcall) { + struct GPUBatch *geom = (use_vcol) ? DRW_cache_mesh_surface_vertpaint_get(ob) : + DRW_cache_object_surface_get(ob); + if (geom) { + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, 0, color_type, r_transp); + DRW_shgroup_call(grp, geom, ob); + } + } + else { + struct GPUBatch **geoms = (use_tex) ? DRW_cache_mesh_surface_texpaint_get(ob) : + workbench_object_surface_material_get(ob); + if (geoms) { + const int materials_len = DRW_cache_object_material_count_get(ob); + for (int i = 0; i < materials_len; i++) { + DRWShadingGroup *grp = workbench_material_setup(wpd, ob, i + 1, color_type, r_transp); + DRW_shgroup_call(grp, geoms[i], ob); + } + } + } +} + +static void workbench_cache_hair_populate(WORKBENCH_PrivateData *wpd, + Object *ob, + ModifierData *md, + eV3DShadingColorType color_type, + bool use_texpaint_mode) +{ + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; + ParticleSettings *part = psys->part; + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + + const ImagePaintSettings *imapaint = use_texpaint_mode ? &scene->toolsettings->imapaint : NULL; + Image *ima = (imapaint && imapaint->mode == IMAGEPAINT_MODE_IMAGE) ? imapaint->canvas : NULL; + int interp = (imapaint && imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : + SHD_INTERP_CLOSEST; + DRWShadingGroup *grp = (use_texpaint_mode) ? + workbench_image_hair_setup(wpd, ob, part->omat, ima, NULL, interp) : + workbench_material_hair_setup(wpd, ob, part->omat, color_type); + + DRW_shgroup_hair_create_sub(ob, psys, md, grp); +} + +/* Decide what colortype to draw the object with. + * In some cases it can be overwritten by workbench_material_setup(). */ +static eV3DShadingColorType workbench_color_type_get(WORKBENCH_PrivateData *wpd, + Object *ob, + bool *r_sculpt_pbvh, + bool *r_texpaint_mode, + bool *r_draw_shadow) +{ + eV3DShadingColorType color_type = wpd->shading.color_type; + const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; + + const DRWContextState *draw_ctx = DRW_context_state_get(); + const bool is_active = (ob == draw_ctx->obact); + const bool is_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && + !DRW_state_is_image_render(); + const bool is_render = DRW_state_is_image_render() && (draw_ctx->v3d == NULL); + const bool is_texpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_TEXTURE); + const bool is_vertpaint_mode = is_active && (wpd->ctx_mode == CTX_MODE_PAINT_VERTEX); + + if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (ob->dt < OB_TEXTURE)) { + color_type = V3D_SHADING_MATERIAL_COLOR; + } + /* Disable color mode if data layer is unavailable. */ + if ((color_type == V3D_SHADING_TEXTURE_COLOR) && (me == NULL || me->mloopuv == NULL)) { + color_type = V3D_SHADING_MATERIAL_COLOR; + } + if ((color_type == V3D_SHADING_VERTEX_COLOR) && (me == NULL || me->mloopcol == NULL)) { + color_type = V3D_SHADING_OBJECT_COLOR; + } + + *r_sculpt_pbvh = is_sculpt_pbvh; + *r_texpaint_mode = false; + + if (!is_sculpt_pbvh && !is_render) { + /* Force texture or vertex mode if object is in paint mode. */ + if (is_texpaint_mode && me && me->mloopuv) { + color_type = V3D_SHADING_TEXTURE_COLOR; + *r_texpaint_mode = true; + } + else if (is_vertpaint_mode && me && me->mloopcol) { + color_type = V3D_SHADING_VERTEX_COLOR; + } + } + + if (r_draw_shadow) { + *r_draw_shadow = (ob->dtx & OB_DRAW_NO_SHADOW_CAST) == 0 && SHADOW_ENABLED(wpd); + /* Currently unsupported in sculpt mode. We could revert to the slow + * method in this case but I'm not sure if it's a good idea given that + * sculpted meshes are heavy to begin with. */ + if (is_sculpt_pbvh) { + *r_draw_shadow = false; + } + + if (is_active && DRW_object_use_hide_faces(ob)) { + *r_draw_shadow = false; + } + } + + return color_type; +} + +void workbench_cache_populate(void *ved, Object *ob) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_PrivateData *wpd = stl->wpd; + + if (!DRW_object_is_renderable(ob)) { + return; + } + + if (ob->type == OB_MESH && ob->modifiers.first != NULL) { + bool use_sculpt_pbvh, use_texpaint_mode; + int color_type = workbench_color_type_get(wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, NULL); + + LISTBASE_FOREACH (ModifierData *, md, &ob->modifiers) { + if (md->type != eModifierType_ParticleSystem) { + continue; + } + ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; + if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { + continue; + } + ParticleSettings *part = psys->part; + const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; + + if (draw_as == PART_DRAW_PATH) { + workbench_cache_hair_populate(wpd, ob, md, color_type, use_texpaint_mode); + } + } + } + + if (!(ob->base_flag & BASE_FROM_DUPLI)) { + ModifierData *md = modifiers_findByType(ob, eModifierType_Fluid); + if (md && modifier_isEnabled(wpd->scene, md, eModifierMode_Realtime)) { + FluidModifierData *fmd = (FluidModifierData *)md; + if (fmd->domain && fmd->domain->type == FLUID_DOMAIN_TYPE_GAS) { + workbench_volume_cache_populate(vedata, wpd->scene, ob, md); + return; /* Do not draw solid in this case. */ + } + } + } + + if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { + return; + } + + if ((ob->dt < OB_SOLID) && !DRW_state_is_scene_render()) { + return; + } + + if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { + bool use_sculpt_pbvh, use_texpaint_mode, draw_shadow, has_transp_mat = false; + eV3DShadingColorType color_type = workbench_color_type_get( + wpd, ob, &use_sculpt_pbvh, &use_texpaint_mode, &draw_shadow); + + if (use_sculpt_pbvh) { + workbench_cache_sculpt_populate(wpd, ob, color_type); + } + else if (use_texpaint_mode) { + workbench_cache_texpaint_populate(wpd, ob); + } + else { + workbench_cache_common_populate(wpd, ob, color_type, &has_transp_mat); + } + + if (draw_shadow) { + workbench_shadow_cache_populate(vedata, ob, has_transp_mat); + } + } +} + +void workbench_cache_finish(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_StorageList *stl = vedata->stl; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PrivateData *wpd = stl->wpd; + + /* TODO(fclem) Only do this when really needed. */ + { + /* HACK we allocate the infront depth here to avoid the overhead when if is not needed. */ + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + + DRW_texture_ensure_fullscreen_2d(&dtxl->depth_in_front, GPU_DEPTH24_STENCIL8, 0); + + GPU_framebuffer_ensure_config(&dfbl->in_front_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(dtxl->color), + }); + + GPU_framebuffer_ensure_config(&fbl->opaque_infront_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx), + }); + + GPU_framebuffer_ensure_config(&fbl->transp_accum_infront_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth_in_front), + GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx), + }); + } + + if (wpd->object_id_tx) { + GPU_framebuffer_ensure_config(&fbl->id_clear_fb, + { + GPU_ATTACHMENT_NONE, + GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx), + }); + } + else { + GPU_FRAMEBUFFER_FREE_SAFE(fbl->id_clear_fb); + } + + workbench_update_material_ubos(wpd); + + /* TODO don't free reuse next redraw. */ + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { + if (wpd->prepass[i][j][k].material_hash) { + BLI_ghash_free(wpd->prepass[i][j][k].material_hash, NULL, NULL); + wpd->prepass[i][j][k].material_hash = NULL; + } + } + } + } +} + +/* Used by viewport rendering & final rendering. + * Do one render loop iteration (i.e: One TAA sample). */ +void workbench_draw_sample(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_FramebufferList *fbl = vedata->fbl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_PassList *psl = vedata->psl; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + float clear_col[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + float clear_col_with_alpha[4] = {0.0f, 0.0f, 0.0f, 1.0f}; + + const bool do_render = workbench_antialiasing_setup(vedata); + const bool xray_is_visible = wpd->shading.xray_alpha > 0.0f; + const bool do_transparent_infront_pass = !DRW_pass_is_empty(psl->transp_accum_infront_ps); + const bool do_transparent_pass = !DRW_pass_is_empty(psl->transp_accum_ps); + const bool do_opaque_infront_pass = !DRW_pass_is_empty(psl->opaque_infront_ps); + const bool do_opaque_pass = !DRW_pass_is_empty(psl->opaque_ps) || do_opaque_infront_pass; + + if (dfbl->in_front_fb) { + GPU_framebuffer_bind(dfbl->in_front_fb); + GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f); + } + + if (do_render) { + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_clear_color_depth_stencil(dfbl->default_fb, wpd->background_color, 1.0f, 0x00); + + if (fbl->id_clear_fb) { + GPU_framebuffer_bind(fbl->id_clear_fb); + GPU_framebuffer_clear_color(fbl->id_clear_fb, clear_col); + } + + if (do_opaque_pass) { + GPU_framebuffer_bind(fbl->opaque_fb); + DRW_draw_pass(psl->opaque_ps); + + if (psl->shadow_ps[0]) { + DRW_draw_pass(psl->shadow_ps[0]); + DRW_draw_pass(psl->shadow_ps[1]); + } + + if (do_opaque_infront_pass) { + GPU_framebuffer_bind(fbl->opaque_infront_fb); + DRW_draw_pass(psl->opaque_infront_ps); + + GPU_framebuffer_bind(fbl->opaque_fb); + DRW_draw_pass(psl->merge_infront_ps); + } + + GPU_framebuffer_bind(dfbl->default_fb); + DRW_draw_pass(psl->composite_ps); + + if (psl->cavity_ps) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->cavity_ps); + } + } + + workbench_volume_draw_pass(vedata); + + if (xray_is_visible) { + if (do_transparent_pass) { + GPU_framebuffer_bind(fbl->transp_accum_fb); + GPU_framebuffer_clear_color(fbl->transp_accum_fb, clear_col_with_alpha); + + DRW_draw_pass(psl->transp_accum_ps); + + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->transp_resolve_ps); + } + + if (do_transparent_infront_pass) { + GPU_framebuffer_bind(fbl->transp_accum_infront_fb); + GPU_framebuffer_clear_color(fbl->transp_accum_infront_fb, clear_col_with_alpha); + + DRW_draw_pass(psl->transp_accum_infront_ps); + + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->transp_resolve_ps); + } + } + + workbench_transparent_draw_depth_pass(vedata); + + if (psl->outline_ps) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->outline_ps); + } + + workbench_dof_draw_pass(vedata); + } + + workbench_antialiasing_draw_pass(vedata); +} + +/* Viewport rendering. */ +static void workbench_draw_scene(void *ved) +{ + WORKBENCH_Data *vedata = ved; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + + if (DRW_state_is_opengl_render()) { + while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) { + workbench_update_world_ubo(wpd); + + workbench_draw_sample(vedata); + } + } + else { + workbench_draw_sample(vedata); + } + + workbench_draw_finish(vedata); +} + +void workbench_draw_finish(void *ved) +{ + WORKBENCH_Data *vedata = ved; + workbench_volume_draw_finish(vedata); +} + +static void workbench_engine_free(void) +{ + workbench_shader_free(); +} + +static void workbench_view_update(void *vedata) +{ + WORKBENCH_Data *data = vedata; + workbench_antialiasing_view_updated(data); +} + +static void workbench_id_update(void *UNUSED(vedata), struct ID *id) +{ + if (GS(id->name) == ID_OB) { + WORKBENCH_ObjectData *oed = (WORKBENCH_ObjectData *)DRW_drawdata_get(id, + &draw_engine_workbench); + if (oed != NULL && oed->dd.recalc != 0) { + oed->shadow_bbox_dirty = (oed->dd.recalc & ID_RECALC_ALL) != 0; + oed->dd.recalc = 0; + } + } +} + +static const DrawEngineDataSize workbench_data_size = DRW_VIEWPORT_DATA_SIZE(WORKBENCH_Data); + +DrawEngineType draw_engine_workbench = { + NULL, + NULL, + N_("Workbench"), + &workbench_data_size, + &workbench_engine_init, + &workbench_engine_free, + &workbench_cache_init, + &workbench_cache_populate, + &workbench_cache_finish, + &workbench_draw_scene, + &workbench_view_update, + &workbench_id_update, + &workbench_render, +}; + RenderEngineType DRW_engine_viewport_workbench_type = { NULL, NULL, @@ -44,7 +583,7 @@ RenderEngineType DRW_engine_viewport_workbench_type = { NULL, NULL, &workbench_render_update_passes, - &draw_engine_workbench_solid, + &draw_engine_workbench, {NULL, NULL, NULL}, }; diff --git a/source/blender/draw/engines/workbench/workbench_engine.h b/source/blender/draw/engines/workbench/workbench_engine.h index 78f70abdaab..eee53fcde07 100644 --- a/source/blender/draw/engines/workbench/workbench_engine.h +++ b/source/blender/draw/engines/workbench/workbench_engine.h @@ -23,8 +23,6 @@ #ifndef __WORKBENCH_ENGINE_H__ #define __WORKBENCH_ENGINE_H__ -extern DrawEngineType draw_engine_workbench_solid; -extern DrawEngineType draw_engine_workbench_transparent; extern RenderEngineType DRW_engine_viewport_workbench_type; #endif /* __WORKBENCH_ENGINE_H__ */ diff --git a/source/blender/draw/engines/workbench/workbench_forward.c b/source/blender/draw/engines/workbench/workbench_forward.c deleted file mode 100644 index 7e09016cf61..00000000000 --- a/source/blender/draw/engines/workbench/workbench_forward.c +++ /dev/null @@ -1,817 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ - -#include "workbench_private.h" - -#include "BLI_alloca.h" -#include "BLI_dynstr.h" -#include "BLI_string_utils.h" -#include "BLI_utildefines.h" - -#include "BKE_modifier.h" -#include "BKE_object.h" -#include "BKE_paint.h" -#include "BKE_particle.h" - -#include "DNA_image_types.h" -#include "DNA_fluid_types.h" -#include "DNA_mesh_types.h" -#include "DNA_modifier_types.h" -#include "DNA_node_types.h" - -#include "ED_view3d.h" - -#include "GPU_shader.h" -#include "GPU_texture.h" - -/* *********** STATIC *********** */ - -typedef struct WORKBENCH_FORWARD_Shaders { - struct GPUShader *transparent_accum_sh_cache[MAX_ACCUM_SHADERS]; - struct GPUShader *object_outline_sh; - struct GPUShader *object_outline_texture_sh; - struct GPUShader *object_outline_hair_sh; -} WORKBENCH_FORWARD_Shaders; - -static struct { - WORKBENCH_FORWARD_Shaders sh_data[GPU_SHADER_CFG_LEN]; - - struct GPUShader *composite_sh_cache[2]; - - struct GPUTexture *object_id_tx; /* ref only, not alloced */ - struct GPUTexture *transparent_accum_tx; /* ref only, not alloced */ - struct GPUTexture *transparent_revealage_tx; /* ref only, not alloced */ - struct GPUTexture *composite_buffer_tx; /* ref only, not alloced */ -} e_data = {{{{NULL}}}}; - -/* Shaders */ -extern char datatoc_common_hair_lib_glsl[]; -extern char datatoc_common_view_lib_glsl[]; - -extern char datatoc_workbench_forward_composite_frag_glsl[]; -extern char datatoc_workbench_forward_depth_frag_glsl[]; -extern char datatoc_workbench_forward_transparent_accum_frag_glsl[]; -extern char datatoc_workbench_data_lib_glsl[]; -extern char datatoc_workbench_object_outline_lib_glsl[]; -extern char datatoc_workbench_curvature_lib_glsl[]; -extern char datatoc_workbench_prepass_vert_glsl[]; -extern char datatoc_workbench_common_lib_glsl[]; -extern char datatoc_workbench_world_light_lib_glsl[]; - -/* static functions */ -static char *workbench_build_forward_vert(bool is_hair) -{ - DynStr *ds = BLI_dynstr_new(); - if (is_hair) { - BLI_dynstr_append(ds, datatoc_common_hair_lib_glsl); - } - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_prepass_vert_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_forward_outline_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_forward_depth_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_forward_transparent_accum_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_common_view_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_world_light_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_forward_transparent_accum_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -static char *workbench_build_forward_composite_frag(void) -{ - DynStr *ds = BLI_dynstr_new(); - - BLI_dynstr_append(ds, datatoc_workbench_data_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_common_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_object_outline_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_curvature_lib_glsl); - BLI_dynstr_append(ds, datatoc_workbench_forward_composite_frag_glsl); - - char *str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data( - WORKBENCH_Data *vedata, - Object *ob, - Material *mat, - Image *ima, - ImageUser *iuser, - eV3DShadingColorType color_type, - int interp) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - WORKBENCH_MaterialData *material; - WORKBENCH_MaterialData material_template; - DRWShadingGroup *grp; - - /* Solid */ - workbench_material_update_data(wpd, ob, mat, &material_template, color_type); - material_template.color_type = color_type; - material_template.ima = ima; - material_template.iuser = iuser; - material_template.interp = interp; - uint hash = workbench_material_get_hash(&material_template, false); - - material = BLI_ghash_lookup(wpd->material_transp_hash, POINTER_FROM_UINT(hash)); - if (material == NULL) { - material = MEM_mallocN(sizeof(WORKBENCH_MaterialData), __func__); - - /* transparent accum */ - /* select the correct transparent accum shader */ - GPUShader *shader = (wpd->shading.color_type == color_type) ? - wpd->transparent_accum_sh : - wpd->transparent_accum_uniform_sh; - const bool is_tiled = (ima && ima->source == IMA_SRC_TILED); - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - shader = is_tiled ? wpd->transparent_accum_textured_array_sh : - wpd->transparent_accum_textured_sh; - } - - grp = DRW_shgroup_create(shader, psl->transparent_accum_pass); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_float_copy(grp, "alpha", material_template.alpha); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - workbench_material_copy(material, &material_template); - if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, - STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | - STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); - DRW_shgroup_uniform_texture( - grp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture); - if (workbench_is_specular_highlight_enabled(wpd)) { - DRW_shgroup_uniform_texture( - grp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture); - } - } - if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - } - if (SHADOW_ENABLED(wpd)) { - DRW_shgroup_uniform_float_copy(grp, "shadowMultiplier", wpd->shadow_multiplier); - DRW_shgroup_uniform_float_copy(grp, "shadowShift", wpd->shadow_shift); - DRW_shgroup_uniform_float_copy(grp, "shadowFocus", wpd->shadow_focus); - } - - workbench_material_shgroup_uniform(wpd, grp, material, ob, false, is_tiled, interp); - material->shgrp = grp; - - /* Depth */ - if (color_type == V3D_SHADING_TEXTURE_COLOR) { - material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_texture_sh, - psl->object_outline_pass); - GPUTexture *tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(material->shgrp_object_outline, "image", tex); - } - else { - material->shgrp_object_outline = DRW_shgroup_create(sh_data->object_outline_sh, - psl->object_outline_pass); - } - if (draw_ctx->sh_cfg == GPU_SHADER_CFG_CLIPPED) { - DRW_shgroup_state_enable(material->shgrp_object_outline, DRW_STATE_CLIP_PLANES); - } - BLI_ghash_insert(wpd->material_transp_hash, POINTER_FROM_UINT(hash), material); - } - return material; -} - -static GPUShader *ensure_forward_accum_shaders(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override, - eGPUShaderConfig sh_cfg) -{ - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - int index = workbench_material_get_accum_shader_index( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - if (sh_data->transparent_accum_sh_cache[index] == NULL) { - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines( - wpd, is_uniform_color, is_hair, is_tiled, color_override); - char *transparent_accum_vert = workbench_build_forward_vert(is_hair); - char *transparent_accum_frag = workbench_build_forward_transparent_accum_frag(); - sh_data->transparent_accum_sh_cache[index] = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, transparent_accum_vert, NULL}, - .frag = (const char *[]){transparent_accum_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, NULL}, - }); - MEM_freeN(transparent_accum_vert); - MEM_freeN(transparent_accum_frag); - MEM_freeN(defines); - } - return sh_data->transparent_accum_sh_cache[index]; -} - -static GPUShader *ensure_forward_composite_shaders(WORKBENCH_PrivateData *wpd) -{ - int index = OBJECT_OUTLINE_ENABLED(wpd) ? 1 : 0; - if (e_data.composite_sh_cache[index] == NULL) { - char *defines = workbench_material_build_defines( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *composite_frag = workbench_build_forward_composite_frag(); - e_data.composite_sh_cache[index] = DRW_shader_create_fullscreen(composite_frag, defines); - MEM_freeN(composite_frag); - MEM_freeN(defines); - } - return e_data.composite_sh_cache[index]; -} - -void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) -{ - wpd->composite_sh = ensure_forward_composite_shaders(wpd); - wpd->transparent_accum_sh = ensure_forward_accum_shaders( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_hair_sh = ensure_forward_accum_shaders( - wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_uniform_sh = ensure_forward_accum_shaders( - wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_uniform_hair_sh = ensure_forward_accum_shaders( - wpd, true, true, false, WORKBENCH_COLOR_OVERRIDE_OFF, sh_cfg); - wpd->transparent_accum_textured_sh = ensure_forward_accum_shaders( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->transparent_accum_textured_array_sh = ensure_forward_accum_shaders( - wpd, false, false, true, WORKBENCH_COLOR_OVERRIDE_TEXTURE, sh_cfg); - wpd->transparent_accum_vertex_sh = ensure_forward_accum_shaders( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_VERTEX, sh_cfg); -} - -void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg) -{ - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_cfg]; - - if (sh_data->object_outline_sh == NULL) { - const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[sh_cfg]; - char *defines = workbench_material_build_defines( - wpd, false, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *defines_texture = workbench_material_build_defines( - wpd, true, false, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *defines_hair = workbench_material_build_defines( - wpd, false, true, false, WORKBENCH_COLOR_OVERRIDE_OFF); - char *forward_vert = workbench_build_forward_vert(false); - char *forward_frag = workbench_build_forward_outline_frag(); - char *forward_hair_vert = workbench_build_forward_vert(true); - - const char *define_id_pass = "#define OBJECT_ID_PASS_ENABLED\n"; - - sh_data->object_outline_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL}, - .frag = (const char *[]){forward_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines, define_id_pass, NULL}, - }); - sh_data->object_outline_texture_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, forward_vert, NULL}, - .frag = (const char *[]){forward_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines_texture, define_id_pass, NULL}, - }); - sh_data->object_outline_hair_sh = GPU_shader_create_from_arrays({ - .vert = (const char *[]){sh_cfg_data->lib, forward_hair_vert, NULL}, - .frag = (const char *[]){forward_frag, NULL}, - .defs = (const char *[]){sh_cfg_data->def, defines_hair, define_id_pass, NULL}, - }); - - MEM_freeN(forward_hair_vert); - MEM_freeN(forward_vert); - MEM_freeN(forward_frag); - MEM_freeN(defines); - MEM_freeN(defines_texture); - MEM_freeN(defines_hair); - } -} - -/* public functions */ -void workbench_forward_engine_init(WORKBENCH_Data *vedata) -{ - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); - const DRWContextState *draw_ctx = DRW_context_state_get(); - DRWShadingGroup *grp; - - if (!stl->g_data) { - /* Alloc transient pointers */ - stl->g_data = MEM_callocN(sizeof(*stl->g_data), __func__); - } - if (!stl->effects) { - stl->effects = MEM_callocN(sizeof(*stl->effects), __func__); - workbench_effect_info_init(stl->effects); - } - WORKBENCH_PrivateData *wpd = stl->g_data; - workbench_private_data_init(wpd); - - workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg); - - workbench_volume_engine_init(); - workbench_fxaa_engine_init(); - workbench_taa_engine_init(vedata); - - workbench_forward_outline_shaders_ensure(wpd, draw_ctx->sh_cfg); - workbench_forward_choose_shaders(wpd, draw_ctx->sh_cfg); - - const float *viewport_size = DRW_viewport_size_get(); - const int size[2] = {(int)viewport_size[0], (int)viewport_size[1]}; - const eGPUTextureFormat comp_tex_format = GPU_RGBA16F; - - e_data.object_id_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R32UI, &draw_engine_workbench_transparent); - e_data.transparent_accum_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_RGBA16F, &draw_engine_workbench_transparent); - e_data.transparent_revealage_tx = DRW_texture_pool_query_2d( - size[0], size[1], GPU_R16F, &draw_engine_workbench_transparent); - e_data.composite_buffer_tx = DRW_texture_pool_query_2d( - size[0], size[1], comp_tex_format, &draw_engine_workbench_transparent); - - GPU_framebuffer_ensure_config(&fbl->object_outline_fb, - { - GPU_ATTACHMENT_TEXTURE(dtxl->depth), - GPU_ATTACHMENT_TEXTURE(e_data.object_id_tx), - }); - GPU_framebuffer_ensure_config(&fbl->transparent_accum_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx), - GPU_ATTACHMENT_TEXTURE(e_data.transparent_revealage_tx), - }); - GPU_framebuffer_ensure_config(&fbl->composite_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.composite_buffer_tx), - }); - GPU_framebuffer_ensure_config(&fbl->effect_fb, - { - GPU_ATTACHMENT_NONE, - GPU_ATTACHMENT_TEXTURE(e_data.transparent_accum_tx), - }); - - workbench_volume_cache_init(vedata); - - DRWState clip_state = WORLD_CLIPPING_ENABLED(wpd) ? DRW_STATE_CLIP_PLANES : 0; - DRWState cull_state = CULL_BACKFACE_ENABLED(wpd) ? DRW_STATE_CULL_BACK : 0; - - /* Transparency Accum */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_OIT | cull_state | clip_state; - psl->transparent_accum_pass = DRW_pass_create("Transparent Accum", state); - } - /* Depth */ - { - int state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS | cull_state | - clip_state; - psl->object_outline_pass = DRW_pass_create("Object Outline Pass", state); - } - /* Composite */ - { - int state = DRW_STATE_WRITE_COLOR; - if (DRW_state_is_scene_render()) { - /* Composite the scene over cleared background. */ - state |= DRW_STATE_BLEND_ALPHA_PREMUL; - } - psl->composite_pass = DRW_pass_create("Composite", state); - - grp = DRW_shgroup_create(wpd->composite_sh, psl->composite_pass); - if (OBJECT_ID_PASS_ENABLED(wpd)) { - DRW_shgroup_uniform_texture_ref(grp, "objectId", &e_data.object_id_tx); - } - DRW_shgroup_uniform_texture_ref(grp, "transparentAccum", &e_data.transparent_accum_tx); - DRW_shgroup_uniform_texture_ref(grp, "transparentRevealage", &e_data.transparent_revealage_tx); - DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); - DRW_shgroup_uniform_vec2(grp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - DRW_shgroup_call(grp, DRW_cache_fullscreen_quad_get(), NULL); - } - - { - workbench_aa_create_pass(vedata, &e_data.transparent_accum_tx); - } - - if (wpd->shading.type == OB_WIRE) { - wpd->shading.xray_alpha = 0.0f; - wpd->shading.xray_alpha_wire = 0.0f; - } -} - -void workbench_forward_engine_free() -{ - for (int sh_data_index = 0; sh_data_index < ARRAY_SIZE(e_data.sh_data); sh_data_index++) { - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[sh_data_index]; - for (int index = 0; index < MAX_ACCUM_SHADERS; index++) { - DRW_SHADER_FREE_SAFE(sh_data->transparent_accum_sh_cache[index]); - } - DRW_SHADER_FREE_SAFE(sh_data->object_outline_sh); - DRW_SHADER_FREE_SAFE(sh_data->object_outline_texture_sh); - DRW_SHADER_FREE_SAFE(sh_data->object_outline_hair_sh); - } - - for (int index = 0; index < 2; index++) { - DRW_SHADER_FREE_SAFE(e_data.composite_sh_cache[index]); - } - - workbench_volume_engine_free(); - workbench_fxaa_engine_free(); - workbench_taa_engine_free(); - workbench_dof_engine_free(); -} - -void workbench_forward_cache_init(WORKBENCH_Data *UNUSED(vedata)) -{ -} - -static void workbench_forward_cache_populate_particles(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - for (ModifierData *md = ob->modifiers.first; md; md = md->next) { - if (md->type != eModifierType_ParticleSystem) { - continue; - } - ParticleSystem *psys = ((ParticleSystemModifierData *)md)->psys; - if (!DRW_object_is_visible_psys_in_active_context(ob, psys)) { - continue; - } - ParticleSettings *part = psys->part; - const int draw_as = (part->draw_as == PART_DRAW_REND) ? part->ren_as : part->draw_as; - - if (draw_as == PART_DRAW_PATH) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, part->omat, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, false); - WORKBENCH_MaterialData *material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - - struct GPUShader *shader = (wpd->shading.color_type == color_type) ? - wpd->transparent_accum_hair_sh : - wpd->transparent_accum_uniform_hair_sh; - DRWShadingGroup *shgrp = DRW_shgroup_hair_create( - ob, psys, md, psl->transparent_accum_pass, shader); - DRW_shgroup_uniform_block(shgrp, "world_block", wpd->world_ubo); - workbench_material_shgroup_uniform(wpd, shgrp, material, ob, false, false, interp); - DRW_shgroup_uniform_vec4(shgrp, "viewvecs[0]", (float *)wpd->viewvecs, 3); - /* Hairs have lots of layer and can rapidly become the most prominent surface. - * So lower their alpha artificially. */ - float hair_alpha = XRAY_ALPHA(wpd) * 0.33f; - DRW_shgroup_uniform_float_copy(shgrp, "alpha", hair_alpha); - if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { - BKE_studiolight_ensure_flag(wpd->studio_light, - STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | - STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); - DRW_shgroup_uniform_texture( - shgrp, "matcapDiffuseImage", wpd->studio_light->matcap_diffuse.gputexture); - if (workbench_is_specular_highlight_enabled(wpd)) { - DRW_shgroup_uniform_texture( - shgrp, "matcapSpecularImage", wpd->studio_light->matcap_specular.gputexture); - } - } - if (workbench_is_specular_highlight_enabled(wpd) || MATCAP_ENABLED(wpd)) { - DRW_shgroup_uniform_vec2(shgrp, "invertedViewportSize", DRW_viewport_invert_size_get(), 1); - } - - WORKBENCH_FORWARD_Shaders *sh_data = &e_data.sh_data[draw_ctx->sh_cfg]; - shgrp = DRW_shgroup_hair_create( - ob, psys, md, vedata->psl->object_outline_pass, sh_data->object_outline_hair_sh); - } - } -} -static void workbench_forward_cache_populate_texture_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - Scene *scene = draw_ctx->scene; - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - /* Force workbench to render active object textured when in texture paint mode */ - const ImagePaintSettings *imapaint = &scene->toolsettings->imapaint; - - /* Single Image mode */ - if (imapaint->mode == IMAGEPAINT_MODE_IMAGE) { - Image *image = imapaint->canvas; - int interp = (imapaint->interp == IMAGEPAINT_INTERP_LINEAR) ? SHD_INTERP_LINEAR : - SHD_INTERP_CLOSEST; - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_texpaint_single_get(ob); - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, image, NULL, color_type, interp); - - DRW_shgroup_call(material->shgrp, geom, ob); - DRW_shgroup_call(material->shgrp_object_outline, geom, ob); - } - else { - /* IMAGEPAINT_MODE_MATERIAL */ - const int materials_len = DRW_cache_object_material_count_get(ob); - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - if (geom_array != NULL && geom_array[i] != NULL) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); - } - } - } -} -static void workbench_forward_cache_populate_vertex_paint_mode(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - WORKBENCH_MaterialData *material; - - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - struct GPUBatch *geom = DRW_cache_mesh_surface_vertpaint_get(ob); - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, false); - DRW_shgroup_call(material->shgrp, geom, ob); - DRW_shgroup_call(material->shgrp_object_outline, geom, ob); -} - -void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - const DRWContextState *draw_ctx = DRW_context_state_get(); - Scene *scene = draw_ctx->scene; - const bool is_wire = (ob->dt == OB_WIRE); - - if (!DRW_object_is_renderable(ob)) { - return; - } - - if (ob->type == OB_MESH) { - workbench_forward_cache_populate_particles(vedata, ob); - } - - ModifierData *md; - if (((ob->base_flag & BASE_FROM_DUPLI) == 0) && - (md = modifiers_findByType(ob, eModifierType_Fluid)) && - (modifier_isEnabled(scene, md, eModifierMode_Realtime)) && - (((FluidModifierData *)md)->domain != NULL) && - (((FluidModifierData *)md)->domain->type == FLUID_DOMAIN_TYPE_GAS)) { - workbench_volume_cache_populate(vedata, scene, ob, md); - return; /* Do not draw solid in this case. */ - } - - if (!(DRW_object_visibility_in_active_context(ob) & OB_VISIBLE_SELF)) { - return; - } - if (ob->dt < OB_WIRE) { - return; - } - - WORKBENCH_MaterialData *material = NULL; - if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL)) { - const bool use_sculpt_pbvh = BKE_sculptsession_use_pbvh_draw(ob, draw_ctx->v3d) && - !DRW_state_is_image_render(); - const int materials_len = DRW_cache_object_material_count_get(ob); - const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - const WORKBENCH_ColorOverride color_override = workbench_object_color_override_get(ob); - const bool use_texture_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_TEXTURE) && - me && me->mloopuv; - const bool use_vertex_paint_drawing = !(DRW_state_is_image_render() && - draw_ctx->v3d == NULL) && - (color_override == WORKBENCH_COLOR_OVERRIDE_VERTEX) && - me && me->mloopcol; - - if (use_texture_paint_drawing) { - workbench_forward_cache_populate_texture_paint_mode(vedata, ob); - } - else if (use_vertex_paint_drawing) { - workbench_forward_cache_populate_vertex_paint_mode(vedata, ob); - } - else if (!use_sculpt_pbvh && TEXTURE_DRAWING_ENABLED(wpd) && me && me->mloopuv) { - struct GPUBatch **geom_array = DRW_cache_mesh_surface_texpaint_get(ob); - for (int i = 0; i < materials_len; i++) { - Material *mat; - Image *image; - ImageUser *iuser; - int interp; - workbench_material_get_image_and_mat(ob, i + 1, &image, &iuser, &interp, &mat); - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, image, ob, use_sculpt_pbvh); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, image, iuser, color_type, interp); - DRW_shgroup_call(material->shgrp_object_outline, geom_array[i], ob); - DRW_shgroup_call(material->shgrp, geom_array[i], ob); - } - } - else if (ELEM(wpd->shading.color_type, - V3D_SHADING_SINGLE_COLOR, - V3D_SHADING_OBJECT_COLOR, - V3D_SHADING_RANDOM_COLOR, - V3D_SHADING_VERTEX_COLOR)) { - /* No material split needed */ - eV3DShadingColorType color_type = workbench_material_determine_color_type( - wpd, NULL, ob, use_sculpt_pbvh); - - if (use_sculpt_pbvh) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0); - bool use_vcol = (color_type == V3D_SHADING_VERTEX_COLOR); - /* TODO(fclem) make this call optional */ - DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); - if (!is_wire) { - DRW_shgroup_call_sculpt(material->shgrp, ob, false, false, use_vcol); - } - } - else { - struct GPUBatch *geom = (color_type == V3D_SHADING_VERTEX_COLOR) ? - DRW_cache_mesh_surface_vertpaint_get(ob) : - DRW_cache_object_surface_get(ob); - if (geom) { - material = workbench_forward_get_or_create_material_data( - vedata, ob, NULL, NULL, NULL, color_type, 0); - /* TODO(fclem) make this call optional */ - DRW_shgroup_call(material->shgrp_object_outline, geom, ob); - if (!is_wire) { - DRW_shgroup_call(material->shgrp, geom, ob); - } - } - } - } - else { - /* Draw material color */ - if (use_sculpt_pbvh) { - struct DRWShadingGroup **shgrps = BLI_array_alloca(shgrps, materials_len); - - for (int i = 0; i < materials_len; i++) { - struct Material *mat = BKE_object_material_get(ob, i + 1); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - shgrps[i] = material->shgrp; - } - /* TODO(fclem) make this call optional */ - DRW_shgroup_call_sculpt(material->shgrp_object_outline, ob, false, false, false); - if (!is_wire) { - DRW_shgroup_call_sculpt_with_materials(shgrps, ob, false); - } - } - else { - struct GPUMaterial **gpumat_array = BLI_array_alloca(gpumat_array, materials_len); - memset(gpumat_array, 0, sizeof(*gpumat_array) * materials_len); - - struct GPUBatch **mat_geom = DRW_cache_object_surface_material_get( - ob, gpumat_array, materials_len); - if (mat_geom) { - for (int i = 0; i < materials_len; i++) { - if (mat_geom[i] == NULL) { - continue; - } - - Material *mat = BKE_object_material_get(ob, i + 1); - material = workbench_forward_get_or_create_material_data( - vedata, ob, mat, NULL, NULL, V3D_SHADING_MATERIAL_COLOR, 0); - /* TODO(fclem) make this call optional */ - DRW_shgroup_call(material->shgrp_object_outline, mat_geom[i], ob); - if (!is_wire) { - DRW_shgroup_call(material->shgrp, mat_geom[i], ob); - } - } - } - } - } - } -} - -void workbench_forward_cache_finish(WORKBENCH_Data *UNUSED(vedata)) -{ -} - -void workbench_forward_draw_scene(WORKBENCH_Data *vedata) -{ - WORKBENCH_PassList *psl = vedata->psl; - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_FramebufferList *fbl = vedata->fbl; - WORKBENCH_PrivateData *wpd = stl->g_data; - DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); - - if (dfbl->in_front_fb) { - /* TODO(fclem) This clear should be done in a global place. */ - GPU_framebuffer_bind(dfbl->in_front_fb); - GPU_framebuffer_clear_depth(dfbl->in_front_fb, 1.0f); - } - - if (workbench_is_taa_enabled(wpd)) { - workbench_taa_draw_scene_start(vedata); - } - - /* Write Depth + Object ID */ - const float clear_outline[4] = {0.0f}; - GPU_framebuffer_bind(fbl->object_outline_fb); - GPU_framebuffer_clear_color(fbl->object_outline_fb, clear_outline); - DRW_draw_pass(psl->object_outline_pass); - - if (XRAY_ALPHA(wpd) > 0.0) { - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPU_framebuffer_bind(fbl->transparent_accum_fb); - GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); - DRW_draw_pass(psl->transparent_accum_pass); - } - else { - /* TODO(fclem): this is unnecessary and takes up perf. - * Better change the composite frag shader to not use the tx. */ - const float clear_color[4] = {0.0f, 0.0f, 0.0f, 1.0f}; - GPU_framebuffer_bind(fbl->transparent_accum_fb); - GPU_framebuffer_clear_color(fbl->transparent_accum_fb, clear_color); - } - - /* Composite */ - GPU_framebuffer_bind(fbl->composite_fb); - - if (DRW_state_is_scene_render()) { - float clear_color[4]; - workbench_clear_color_get(clear_color); - GPU_framebuffer_clear_color(fbl->composite_fb, clear_color); - } - - DRW_draw_pass(psl->composite_pass); - DRW_draw_pass(psl->volume_pass); - - /* Only when clipping is enabled. */ - if (psl->background_pass) { - DRW_draw_pass(psl->background_pass); - } - - /* Color correct and Anti aliasing */ - workbench_aa_draw_pass(vedata, e_data.composite_buffer_tx); -} - -void workbench_forward_draw_finish(WORKBENCH_Data *vedata) -{ - WORKBENCH_StorageList *stl = vedata->stl; - WORKBENCH_PrivateData *wpd = stl->g_data; - - workbench_private_data_free(wpd); - workbench_volume_smoke_textures_free(wpd); -} diff --git a/source/blender/draw/engines/workbench/workbench_materials.c b/source/blender/draw/engines/workbench/workbench_materials.c index 5f1e3461d9f..246f5f88045 100644 --- a/source/blender/draw/engines/workbench/workbench_materials.c +++ b/source/blender/draw/engines/workbench/workbench_materials.c @@ -22,6 +22,8 @@ #include "workbench_private.h" +#include "BLI_memblock.h" + #include "BKE_image.h" #include "BKE_node.h" @@ -31,310 +33,78 @@ #include "DNA_node_types.h" #include "DNA_mesh_types.h" +#include "GPU_uniformbuffer.h" + #include "ED_uvedit.h" #define HSV_SATURATION 0.5 #define HSV_VALUE 0.8 -void workbench_material_update_data(WORKBENCH_PrivateData *wpd, - Object *ob, - Material *mat, - WORKBENCH_MaterialData *data, - int color_type) +void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, + Object *ob, + Material *mat, + WORKBENCH_UBO_Material *data, + eV3DShadingColorType color_type) { - data->metallic = 0.0f; - data->roughness = 0.632455532f; /* sqrtf(0.4f); */ - data->alpha = wpd->shading.xray_alpha; + float metallic = 0.0f; + float roughness = 0.632455532f; /* sqrtf(0.4f); */ + float alpha = wpd->shading.xray_alpha; - if (color_type == V3D_SHADING_SINGLE_COLOR) { - copy_v3_v3(data->base_color, wpd->shading.single_color); - } - else if (color_type == V3D_SHADING_ERROR_COLOR) { - copy_v3_fl3(data->base_color, 0.8, 0.0, 0.8); - } - else if (color_type == V3D_SHADING_RANDOM_COLOR) { - uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); - if (ob->id.lib) { - hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); - } - - float hue = BLI_hash_int_01(hash); - float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; - hsv_to_rgb_v(hsv, data->base_color); - } - else if (ELEM(color_type, V3D_SHADING_OBJECT_COLOR, V3D_SHADING_VERTEX_COLOR)) { - data->alpha *= ob->color[3]; - copy_v3_v3(data->base_color, ob->color); - } - else { - /* V3D_SHADING_MATERIAL_COLOR or V3D_SHADING_TEXTURE_COLOR */ - if (mat) { - data->alpha *= mat->a; - copy_v3_v3(data->base_color, &mat->r); - if (workbench_is_specular_highlight_enabled(wpd)) { - data->metallic = mat->metallic; - data->roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */ - } - } - else { - copy_v3_fl(data->base_color, 0.8f); - } - } -} - -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override) -{ - char *str = NULL; - bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; - bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && - !is_uniform_color; - - switch (color_override) { - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - use_textures = true; - use_vertex_colors = false; - is_hair = false; - break; - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - use_textures = false; - use_vertex_colors = true; - is_hair = false; - is_tiled = false; + switch (color_type) { + case V3D_SHADING_SINGLE_COLOR: + copy_v3_v3(data->base_color, wpd->shading.single_color); break; - case WORKBENCH_COLOR_OVERRIDE_OFF: - break; - } - - DynStr *ds = BLI_dynstr_new(); - - if (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) { - BLI_dynstr_append(ds, "#define V3D_SHADING_OBJECT_OUTLINE\n"); - } - if (wpd->shading.flag & V3D_SHADING_SHADOW) { - BLI_dynstr_append(ds, "#define V3D_SHADING_SHADOW\n"); - } - if (SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define WB_CAVITY\n"); - } - if (workbench_is_specular_highlight_enabled(wpd)) { - BLI_dynstr_append(ds, "#define V3D_SHADING_SPECULAR_HIGHLIGHT\n"); - } - if (STUDIOLIGHT_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n"); - } - if (FLAT_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n"); - } - if (MATCAP_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n"); - } - if (OBJECT_ID_PASS_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define OBJECT_ID_PASS_ENABLED\n"); - } - if (workbench_is_matdata_pass_enabled(wpd)) { - BLI_dynstr_append(ds, "#define MATDATA_PASS_ENABLED\n"); - } - if (NORMAL_VIEWPORT_PASS_ENABLED(wpd)) { - BLI_dynstr_append(ds, "#define NORMAL_VIEWPORT_PASS_ENABLED\n"); - } - if (use_vertex_colors) { - BLI_dynstr_append(ds, "#define V3D_SHADING_VERTEX_COLOR\n"); - } - if (use_textures) { - BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n"); - } - if (NORMAL_ENCODING_ENABLED()) { - BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); - } - if (is_hair) { - BLI_dynstr_append(ds, "#define HAIR_SHADER\n"); - } - if (use_textures && is_tiled) { - BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n"); - } - - str = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - return str; -} - -uint workbench_material_get_hash(WORKBENCH_MaterialData *mat, bool is_ghost) -{ - union { - struct { - /* WHATCH: Keep in sync with View3DShading.color_type max value. */ - uchar color_type; - uchar diff_r; - uchar diff_g; - uchar diff_b; - - uchar alpha; - uchar ghost; - uchar metal; - uchar roughness; - - void *ima; - }; - /* HACK to ensure input is 4 uint long. */ - uint a[4]; - } input = {.color_type = (uchar)(mat->color_type), - .diff_r = (uchar)(mat->base_color[0] * 0xFF), - .diff_g = (uchar)(mat->base_color[1] * 0xFF), - .diff_b = (uchar)(mat->base_color[2] * 0xFF), - - .alpha = (uint)(mat->alpha * 0xFF), - .ghost = (uchar)is_ghost, - .metal = (uchar)(mat->metallic * 0xFF), - .roughness = (uchar)(mat->roughness * 0xFF), - - .ima = mat->ima}; - - BLI_assert(sizeof(input) == sizeof(uint) * 4); - - return BLI_ghashutil_uinthash_v4((uint *)&input); -} - -int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd) -{ - /* NOTE: change MAX_COMPOSITE_SHADERS accordingly when modifying this function. */ - int index = 0; - /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ - index = wpd->shading.light; - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_SHADOW, 1 << 2); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_CAVITY, 1 << 3); - SET_FLAG_FROM_TEST(index, wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE, 1 << 4); - SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 5); - SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6); - BLI_assert(index < MAX_COMPOSITE_SHADERS); - return index; -} - -int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override) -{ - bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; - bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && - !is_uniform_color; - - switch (color_override) { - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - use_textures = true; - use_vertex_colors = false; - break; - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - use_textures = false; - use_vertex_colors = true; - is_tiled = false; - break; - case WORKBENCH_COLOR_OVERRIDE_OFF: - break; - } - - /* NOTE: change MAX_PREPASS_SHADERS accordingly when modifying this function. */ - int index = 0; - SET_FLAG_FROM_TEST(index, is_hair, 1 << 0); - SET_FLAG_FROM_TEST(index, workbench_is_matdata_pass_enabled(wpd), 1 << 1); - SET_FLAG_FROM_TEST(index, OBJECT_ID_PASS_ENABLED(wpd), 1 << 2); - SET_FLAG_FROM_TEST(index, NORMAL_VIEWPORT_PASS_ENABLED(wpd), 1 << 3); - SET_FLAG_FROM_TEST(index, MATCAP_ENABLED(wpd), 1 << 4); - SET_FLAG_FROM_TEST(index, use_textures, 1 << 5); - SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 6); - SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7); - BLI_assert(index < MAX_PREPASS_SHADERS); - return index; -} - -int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override) -{ - bool use_textures = (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) && !is_uniform_color; - bool use_vertex_colors = (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) && - !is_uniform_color; - - switch (color_override) { - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - use_textures = true; - use_vertex_colors = false; - is_hair = false; + case V3D_SHADING_RANDOM_COLOR: { + uint hash = BLI_ghashutil_strhash_p_murmur(ob->id.name); + if (ob->id.lib) { + hash = (hash * 13) ^ BLI_ghashutil_strhash_p_murmur(ob->id.lib->name); + } + float hue = BLI_hash_int_01(hash); + float hsv[3] = {hue, HSV_SATURATION, HSV_VALUE}; + hsv_to_rgb_v(hsv, data->base_color); break; - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - use_textures = false; - use_vertex_colors = true; - is_hair = false; - is_tiled = false; + } + case V3D_SHADING_OBJECT_COLOR: + case V3D_SHADING_VERTEX_COLOR: + alpha *= ob->color[3]; + copy_v3_v3(data->base_color, ob->color); break; - case WORKBENCH_COLOR_OVERRIDE_OFF: + case V3D_SHADING_MATERIAL_COLOR: + case V3D_SHADING_TEXTURE_COLOR: + default: + if (mat) { + alpha *= mat->a; + copy_v3_v3(data->base_color, &mat->r); + metallic = mat->metallic; + roughness = sqrtf(mat->roughness); /* Remap to disney roughness. */ + } + else { + copy_v3_fl(data->base_color, 0.8f); + } break; } - /* NOTE: change MAX_ACCUM_SHADERS accordingly when modifying this function. */ - int index = 0; - /* 2 bits FLAT/STUDIO/MATCAP + Specular highlight */ - index = wpd->shading.light; - SET_FLAG_FROM_TEST(index, use_textures, 1 << 2); - SET_FLAG_FROM_TEST(index, use_vertex_colors, 1 << 3); - SET_FLAG_FROM_TEST(index, is_hair, 1 << 4); - /* 1 bits SHADOWS (only facing factor) */ - SET_FLAG_FROM_TEST(index, SHADOW_ENABLED(wpd), 1 << 5); - SET_FLAG_FROM_TEST(index, workbench_is_specular_highlight_enabled(wpd), 1 << 6); - SET_FLAG_FROM_TEST(index, is_tiled && use_textures, 1 << 7); - BLI_assert(index < MAX_ACCUM_SHADERS); - return index; + uint32_t packed_metallic = unit_float_to_uchar_clamp(metallic); + uint32_t packed_roughness = unit_float_to_uchar_clamp(roughness); + uint32_t packed_alpha = unit_float_to_uchar_clamp(alpha); + data->packed_data = (packed_alpha << 16u) | (packed_roughness << 8u) | packed_metallic; } -eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, - Image *ima, - Object *ob, - bool use_sculpt_pbvh) +/* Return correct material or empty default material if slot is empty. */ +BLI_INLINE Material *workbench_object_material_get(Object *ob, int mat_nr) { - eV3DShadingColorType color_type = wpd->shading.color_type; - const Mesh *me = (ob->type == OB_MESH) ? ob->data : NULL; - - if ((color_type == V3D_SHADING_TEXTURE_COLOR) && - (ima == NULL || use_sculpt_pbvh || (ob->dt < OB_TEXTURE))) { - color_type = V3D_SHADING_MATERIAL_COLOR; + Material *ma = BKE_object_material_get(ob, mat_nr); + if (ma == NULL) { + ma = BKE_material_default_empty(); } - if (color_type == V3D_SHADING_VERTEX_COLOR && (me == NULL || me->mloopcol == NULL)) { - color_type = V3D_SHADING_OBJECT_COLOR; - } - - switch (workbench_object_color_override_get(ob)) { - /* Force V3D_SHADING_TEXTURE_COLOR for active object when in texture painting - * no matter the shading color that the user has chosen, when there is no - * texture we will render the object with the error color */ - case WORKBENCH_COLOR_OVERRIDE_TEXTURE: - color_type = ima ? V3D_SHADING_TEXTURE_COLOR : V3D_SHADING_ERROR_COLOR; - break; - - /* Force V3D_SHADING_VERTEX_COLOR for active object when in vertex painting - * no matter the shading color that the user has chosen, when there is no - * vertex color we will render the object with the error color */ - case WORKBENCH_COLOR_OVERRIDE_VERTEX: - color_type = V3D_SHADING_VERTEX_COLOR; - break; - - case WORKBENCH_COLOR_OVERRIDE_OFF: - break; - } - - return color_type; + return ma; } -void workbench_material_get_image_and_mat( - Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat) +BLI_INLINE void workbench_material_get_image( + Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp) { bNode *node; - *r_mat = BKE_object_material_get(ob, mat_nr); + ED_object_get_active_image(ob, mat_nr, r_image, r_iuser, &node, NULL); if (node && *r_image) { switch (node->type) { @@ -358,53 +128,170 @@ void workbench_material_get_image_and_mat( } } -void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, - DRWShadingGroup *grp, - WORKBENCH_MaterialData *material, - Object *ob, - const bool deferred, - const bool is_tiled, - const int interp) +/* Return true if the current material ubo has changed and needs to be rebind. */ +BLI_INLINE bool workbench_material_chunk_select(WORKBENCH_PrivateData *wpd, + uint32_t id, + uint32_t *r_mat_id) { - if (deferred && !workbench_is_matdata_pass_enabled(wpd)) { - return; + bool resource_changed = false; + /* Divide in chunks of MAX_MATERIAL. */ + uint32_t chunk = id >> 12u; + *r_mat_id = id & 0xFFFu; + /* We need to add a new chunk. */ + while (chunk >= wpd->material_chunk_count) { + wpd->material_chunk_count++; + wpd->material_ubo_data_curr = BLI_memblock_alloc(wpd->material_ubo_data); + wpd->material_ubo_curr = workbench_material_ubo_alloc(wpd); + wpd->material_chunk_curr = chunk; + resource_changed = true; + } + /* We need to go back to a previous chunk. */ + if (wpd->material_chunk_curr != chunk) { + wpd->material_ubo_data_curr = BLI_memblock_elem_get(wpd->material_ubo_data, 0, chunk); + wpd->material_ubo_curr = BLI_memblock_elem_get(wpd->material_ubo, 0, chunk); + wpd->material_chunk_curr = chunk; + resource_changed = true; } + return resource_changed; +} - const bool use_highlight = workbench_is_specular_highlight_enabled(wpd); - const bool use_texture = (V3D_SHADING_TEXTURE_COLOR == workbench_material_determine_color_type( - wpd, material->ima, ob, false)); - if (use_texture) { - if (is_tiled) { - GPUTexture *array_tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_2D_ARRAY); - GPUTexture *data_tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_1D_ARRAY); - DRW_shgroup_uniform_texture(grp, "image_tile_array", array_tex); - DRW_shgroup_uniform_texture(grp, "image_tile_data", data_tex); - } - else { - GPUTexture *tex = GPU_texture_from_blender( - material->ima, material->iuser, NULL, GL_TEXTURE_2D); - DRW_shgroup_uniform_texture(grp, "image", tex); +DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + eV3DShadingColorType color_type, + bool hair, + bool *r_transp) +{ + Image *ima = NULL; + ImageUser *iuser = NULL; + int interp; + const bool infront = (ob->dtx & OB_DRAWXRAY) != 0; + + if (color_type == V3D_SHADING_TEXTURE_COLOR) { + workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp); + if (ima == NULL) { + /* Fallback to material color. */ + color_type = V3D_SHADING_MATERIAL_COLOR; } - DRW_shgroup_uniform_bool_copy( - grp, "imagePremultiplied", (material->ima->alpha_mode == IMA_ALPHA_PREMUL)); - DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); } - DRW_shgroup_uniform_vec4(grp, "materialColorAndMetal", material->base_color, 1); + switch (color_type) { + case V3D_SHADING_TEXTURE_COLOR: { + return workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, hair); + } + case V3D_SHADING_MATERIAL_COLOR: { + /* For now, we use the same ubo for material and object coloring but with different indices. + * This means they are mutually exclusive. */ + BLI_assert( + ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR)); + + Material *ma = workbench_object_material_get(ob, mat_nr); + + const bool transp = wpd->shading.xray_alpha < 1.0f || ma->a < 1.0f; + WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair]; + + if (r_transp && transp) { + *r_transp = true; + } - if (use_highlight) { - DRW_shgroup_uniform_float(grp, "materialRoughness", &material->roughness, 1); + DRWShadingGroup **grp_mat = NULL; + /* A hashmap stores material shgroups to pack all similar drawcalls together. */ + if (BLI_ghash_ensure_p(prepass->material_hash, ma, (void ***)&grp_mat)) { + return *grp_mat; + } + + uint32_t mat_id, id = wpd->material_index++; + + workbench_material_chunk_select(wpd, id, &mat_id); + workbench_material_ubo_data(wpd, ob, ma, &wpd->material_ubo_data_curr[mat_id], color_type); + + DRWShadingGroup *grp = prepass->common_shgrp; + *grp_mat = grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", mat_id); + return grp; + } + case V3D_SHADING_VERTEX_COLOR: { + const bool transp = wpd->shading.xray_alpha < 1.0f; + DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].vcol_shgrp; + return grp; + } + default: { + /* For now, we use the same ubo for material and object coloring but with different indices. + * This means they are mutually exclusive. */ + BLI_assert( + !ELEM(wpd->shading.color_type, V3D_SHADING_MATERIAL_COLOR, V3D_SHADING_TEXTURE_COLOR)); + + uint32_t mat_id, id = DRW_object_resource_id_get(ob); + + bool resource_changed = workbench_material_chunk_select(wpd, id, &mat_id); + workbench_material_ubo_data(wpd, ob, NULL, &wpd->material_ubo_data_curr[mat_id], color_type); + + const bool transp = wpd->shading.xray_alpha < 1.0f || ob->color[3] < 1.0f; + DRWShadingGroup *grp = wpd->prepass[transp][infront][hair].common_shgrp; + if (resource_changed) { + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + } + if (r_transp && transp) { + *r_transp = true; + } + return grp; + } } } -void workbench_material_copy(WORKBENCH_MaterialData *dest_material, - const WORKBENCH_MaterialData *source_material) +/* If ima is null, search appropriate image node but will fallback to purple texture otherwise. */ +DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + Image *ima, + ImageUser *iuser, + int interp, + bool hair) { - copy_v3_v3(dest_material->base_color, source_material->base_color); - dest_material->metallic = source_material->metallic; - dest_material->roughness = source_material->roughness; - dest_material->ima = source_material->ima; - dest_material->iuser = source_material->iuser; + GPUTexture *tex = NULL, *tex_tile_data = NULL; + + if (ima == NULL) { + workbench_material_get_image(ob, mat_nr, &ima, &iuser, &interp); + } + + if (ima) { + if (ima->source == IMA_SRC_TILED) { + tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D_ARRAY); + tex_tile_data = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_1D_ARRAY); + } + else { + tex = GPU_texture_from_blender(ima, iuser, NULL, GL_TEXTURE_2D); + } + } + + if (tex == NULL) { + printf("Image not foudn\n"); + tex = wpd->dummy_image_tx; + } + + const bool infront = (ob->dtx & OB_DRAWXRAY) != 0; + const bool transp = wpd->shading.xray_alpha < 1.0f; + WORKBENCH_Prepass *prepass = &wpd->prepass[transp][infront][hair]; + + DRWShadingGroup **grp_tex = NULL; + /* A hashmap stores image shgroups to pack all similar drawcalls together. */ + if (BLI_ghash_ensure_p(prepass->material_hash, tex, (void ***)&grp_tex)) { + return *grp_tex; + } + + DRWShadingGroup *grp = (tex_tile_data) ? prepass->image_tiled_shgrp : prepass->image_shgrp; + + *grp_tex = grp = DRW_shgroup_create_sub(grp); + if (tex_tile_data) { + DRW_shgroup_uniform_texture_persistent(grp, "imageTileArray", tex); + DRW_shgroup_uniform_texture_persistent(grp, "imageTileData", tex_tile_data); + } + else { + DRW_shgroup_uniform_texture_persistent(grp, "imageTexture", tex); + } + DRW_shgroup_uniform_bool_copy(grp, "imagePremult", (ima && ima->alpha_mode == IMA_ALPHA_PREMUL)); + DRW_shgroup_uniform_bool_copy(grp, "imageNearest", (interp == SHD_INTERP_CLOSEST)); + return grp; } diff --git a/source/blender/draw/engines/workbench/workbench_opaque.c b/source/blender/draw/engines/workbench/workbench_opaque.c new file mode 100644 index 00000000000..08511ca092c --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_opaque.c @@ -0,0 +1,165 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Opaque Pipeline: + * + * Use deferred shading to render opaque surfaces. + * This decouple the shading cost from scene complexity. + * + * The rendering is broken down in two passes: + * - the pre-pass where we render all the surfaces and output material data. + * - the composite pass where we compute the final aspect of the pixels. + */ + +#include "DRW_render.h" + +#include "GPU_extensions.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_opaque_engine_init(WORKBENCH_Data *data) +{ + WORKBENCH_FramebufferList *fbl = data->fbl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DrawEngineType *owner = (DrawEngineType *)&workbench_opaque_engine_init; + + /* Reused the same textures format for transparent pipeline to share the textures. */ + const eGPUTextureFormat col_tex_format = GPU_RGBA16F; + const eGPUTextureFormat nor_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA16F; + + wpd->material_buffer_tx = DRW_texture_pool_query_fullscreen(col_tex_format, owner); + wpd->normal_buffer_tx = DRW_texture_pool_query_fullscreen(nor_tex_format, owner); + + GPU_framebuffer_ensure_config(&fbl->opaque_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(wpd->material_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->normal_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->object_id_tx), + }); +} + +void workbench_opaque_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + struct GPUShader *sh; + DRWShadingGroup *grp; + + const bool use_matcap = (wpd->shading.light == V3D_LIGHTING_MATCAP); + + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + + int opaque = 0; + for (int infront = 0; infront < 2; infront++) { + DRWPass *pass; + if (infront) { + DRW_PASS_CREATE(psl->opaque_infront_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->opaque_infront_ps; + } + else { + DRW_PASS_CREATE(psl->opaque_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->opaque_ps; + } + + for (int hair = 0; hair < 2; hair++) { + wpd->prepass[opaque][infront][hair].material_hash = BLI_ghash_ptr_new(__func__); + + sh = workbench_shader_opaque_get(wpd, hair); + + wpd->prepass[opaque][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1); + + wpd->prepass[opaque][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ + + sh = workbench_shader_opaque_image_get(wpd, hair, false); + + wpd->prepass[opaque][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); + + sh = workbench_shader_opaque_image_get(wpd, hair, true); + + wpd->prepass[opaque][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + DRW_shgroup_uniform_bool_copy(grp, "useMatcap", use_matcap); + } + } + } + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_GREATER | DRW_STATE_STENCIL_EQUAL; + + DRW_PASS_CREATE(psl->composite_ps, state); + + sh = workbench_shader_composite_get(wpd); + + grp = DRW_shgroup_create(sh, psl->composite_ps); + DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_texture_persistent(grp, "materialBuffer", wpd->material_buffer_tx); + DRW_shgroup_uniform_texture_persistent(grp, "normalBuffer", wpd->normal_buffer_tx); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); + DRW_shgroup_stencil_mask(grp, 0x00); + + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, + STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | + STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); + struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture; + struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; + const bool use_spec = workbench_is_specular_highlight_enabled(wpd); + spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; + DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + } + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + + if (SHADOW_ENABLED(wpd)) { + grp = DRW_shgroup_create_sub(grp); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", true); + DRW_shgroup_state_disable(grp, DRW_STATE_STENCIL_EQUAL); + DRW_shgroup_state_enable(grp, DRW_STATE_STENCIL_NEQUAL); + DRW_shgroup_stencil_mask(grp, 0x00); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } + } + { + DRWState state = DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_ALWAYS | DRW_STATE_WRITE_STENCIL | + DRW_STATE_STENCIL_ALWAYS; + + DRW_PASS_CREATE(psl->merge_infront_ps, state); + + sh = workbench_shader_merge_infront_get(wpd); + + grp = DRW_shgroup_create(sh, psl->merge_infront_ps); + DRW_shgroup_uniform_texture_ref(grp, "depthBuffer", &dtxl->depth_in_front); + DRW_shgroup_stencil_mask(grp, 0x00); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} diff --git a/source/blender/draw/engines/workbench/workbench_private.h b/source/blender/draw/engines/workbench/workbench_private.h index bb93864966e..a68b66e0f85 100644 --- a/source/blender/draw/engines/workbench/workbench_private.h +++ b/source/blender/draw/engines/workbench/workbench_private.h @@ -34,16 +34,14 @@ #include "workbench_engine.h" +extern struct DrawEngineType draw_engine_workbench; + #define WORKBENCH_ENGINE "BLENDER_WORKBENCH" -#define MAX_COMPOSITE_SHADERS (1 << 7) -#define MAX_PREPASS_SHADERS (1 << 8) -#define MAX_ACCUM_SHADERS (1 << 8) -#define MAX_CAVITY_SHADERS (1 << 3) - -#define TEXTURE_DRAWING_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_TEXTURE_COLOR) -#define VERTEX_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_VERTEX_COLOR) -#define MATERIAL_COLORS_ENABLED(wpd) (wpd->shading.color_type == V3D_SHADING_MATERIAL_COLOR) -#define FLAT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_FLAT) + +#define MAX_MATERIAL (1 << 12) + +#define DEBUG_SHADOW_VOLUME 0 + #define STUDIOLIGHT_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_STUDIO) #define MATCAP_ENABLED(wpd) (wpd->shading.light == V3D_LIGHTING_MATCAP) #define USE_WORLD_ORIENTATION(wpd) ((wpd->shading.flag & V3D_SHADING_WORLD_ORIENTATION) != 0) @@ -63,45 +61,24 @@ (wpd->shading.cavity_type == V3D_SHADING_CAVITY_BOTH))) #define CAVITY_ENABLED(wpd) (CURVATURE_ENABLED(wpd) || SSAO_ENABLED(wpd)) #define SHADOW_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_SHADOW) -#define GHOST_ENABLED(psl) \ - (!DRW_pass_is_empty(psl->ghost_prepass_pass) || !DRW_pass_is_empty(psl->ghost_prepass_hair_pass)) #define CULL_BACKFACE_ENABLED(wpd) ((wpd->shading.flag & V3D_SHADING_BACKFACE_CULLING) != 0) -#define OIT_ENABLED(wpd) \ - (ELEM(wpd->shading.color_type, \ - V3D_SHADING_MATERIAL_COLOR, \ - V3D_SHADING_OBJECT_COLOR, \ - V3D_SHADING_TEXTURE_COLOR, \ - V3D_SHADING_VERTEX_COLOR)) - -#define IS_NAVIGATING(wpd) \ - ((DRW_context_state_get()->rv3d) && \ - (DRW_context_state_get()->rv3d->rflag & (RV3D_NAVIGATING | RV3D_PAINTING))) #define OBJECT_OUTLINE_ENABLED(wpd) (wpd->shading.flag & V3D_SHADING_OBJECT_OUTLINE) #define OBJECT_ID_PASS_ENABLED(wpd) (OBJECT_OUTLINE_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) -#define NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) \ - (MATCAP_ENABLED(wpd) || STUDIOLIGHT_ENABLED(wpd) || SHADOW_ENABLED(wpd)) -#define NORMAL_VIEWPORT_PASS_ENABLED(wpd) \ - (NORMAL_VIEWPORT_COMP_PASS_ENABLED(wpd) || SSAO_ENABLED(wpd) || CURVATURE_ENABLED(wpd)) #define NORMAL_ENCODING_ENABLED() (true) -#define WORLD_CLIPPING_ENABLED(wpd) (wpd->world_clip_planes != NULL) struct RenderEngine; struct RenderLayer; struct rcti; typedef struct WORKBENCH_FramebufferList { - /* Deferred render buffers */ - struct GPUFrameBuffer *prepass_fb; - struct GPUFrameBuffer *ghost_prepass_fb; - struct GPUFrameBuffer *cavity_fb; - struct GPUFrameBuffer *composite_fb; - struct GPUFrameBuffer *id_clear_fb; + struct GPUFrameBuffer *opaque_fb; + struct GPUFrameBuffer *opaque_infront_fb; - struct GPUFrameBuffer *effect_fb; - struct GPUFrameBuffer *effect_taa_fb; - struct GPUFrameBuffer *depth_buffer_fb; - struct GPUFrameBuffer *color_only_fb; + struct GPUFrameBuffer *transp_accum_fb; + struct GPUFrameBuffer *transp_accum_infront_fb; + + struct GPUFrameBuffer *id_clear_fb; struct GPUFrameBuffer *dof_downsample_fb; struct GPUFrameBuffer *dof_coc_tile_h_fb; @@ -110,10 +87,9 @@ typedef struct WORKBENCH_FramebufferList { struct GPUFrameBuffer *dof_blur1_fb; struct GPUFrameBuffer *dof_blur2_fb; - /* Forward render buffers */ - struct GPUFrameBuffer *object_outline_fb; - struct GPUFrameBuffer *transparent_accum_fb; - struct GPUFrameBuffer *transparent_revealage_fb; + struct GPUFrameBuffer *antialiasing_fb; + struct GPUFrameBuffer *smaa_edge_fb; + struct GPUFrameBuffer *smaa_weight_fb; } WORKBENCH_FramebufferList; typedef struct WORKBENCH_TextureList { @@ -121,34 +97,35 @@ typedef struct WORKBENCH_TextureList { struct GPUTexture *coc_halfres_tx; struct GPUTexture *history_buffer_tx; struct GPUTexture *depth_buffer_tx; + struct GPUTexture *smaa_search_tx; + struct GPUTexture *smaa_area_tx; + struct GPUTexture *dummy_image_tx; + struct GPUTexture *dummy_volume_tx; + struct GPUTexture *dummy_coba_tx; } WORKBENCH_TextureList; typedef struct WORKBENCH_StorageList { - struct WORKBENCH_PrivateData *g_data; - struct WORKBENCH_EffectInfo *effects; + struct WORKBENCH_PrivateData *wpd; float *dof_ubo_data; } WORKBENCH_StorageList; typedef struct WORKBENCH_PassList { - /* deferred rendering */ - struct DRWPass *prepass_pass; - struct DRWPass *prepass_hair_pass; - struct DRWPass *ghost_prepass_pass; - struct DRWPass *ghost_prepass_hair_pass; - struct DRWPass *cavity_pass; - struct DRWPass *shadow_depth_pass_pass; - struct DRWPass *shadow_depth_pass_mani_pass; - struct DRWPass *shadow_depth_fail_pass; - struct DRWPass *shadow_depth_fail_mani_pass; - struct DRWPass *shadow_depth_fail_caps_pass; - struct DRWPass *shadow_depth_fail_caps_mani_pass; - struct DRWPass *composite_pass; - struct DRWPass *composite_shadow_pass; - struct DRWPass *oit_composite_pass; - struct DRWPass *background_pass; - struct DRWPass *background_pass_clip; - struct DRWPass *ghost_resolve_pass; - struct DRWPass *effect_aa_pass; + struct DRWPass *opaque_ps; + struct DRWPass *opaque_infront_ps; + + struct DRWPass *transp_resolve_ps; + struct DRWPass *transp_accum_ps; + struct DRWPass *transp_accum_infront_ps; + + struct DRWPass *shadow_ps[2]; + + struct DRWPass *merge_infront_ps; + + struct DRWPass *cavity_ps; + struct DRWPass *outline_ps; + + struct DRWPass *composite_ps; + struct DRWPass *dof_down_ps; struct DRWPass *dof_down2_ps; struct DRWPass *dof_flatten_v_ps; @@ -158,12 +135,13 @@ typedef struct WORKBENCH_PassList { struct DRWPass *dof_blur1_ps; struct DRWPass *dof_blur2_ps; struct DRWPass *dof_resolve_ps; - struct DRWPass *volume_pass; - /* forward rendering */ - struct DRWPass *transparent_accum_pass; - struct DRWPass *object_outline_pass; - struct DRWPass *depth_pass; + struct DRWPass *volume_ps; + + struct DRWPass *aa_accum_ps; + struct DRWPass *aa_edge_ps; + struct DRWPass *aa_weight_ps; + struct DRWPass *aa_resolve_ps; } WORKBENCH_PassList; typedef struct WORKBENCH_Data { @@ -180,84 +158,164 @@ typedef struct WORKBENCH_UBO_Light { float diffuse_color[3], wrapped; } WORKBENCH_UBO_Light; +typedef struct WORKBENCH_UBO_Material { + float base_color[3]; + /* Packed data into a int. Decoded in the shader. */ + uint32_t packed_data; +} WORKBENCH_UBO_Material; + typedef struct WORKBENCH_UBO_World { + float viewvecs[3][4]; + float viewport_size[2], viewport_size_inv[2]; float object_outline_color[4]; float shadow_direction_vs[4]; + float shadow_focus, shadow_shift, shadow_mul, shadow_add; WORKBENCH_UBO_Light lights[4]; float ambient_color[4]; - int num_lights; - int matcap_orientation; + + int cavity_sample_start; + int cavity_sample_end; + float cavity_sample_count_inv; + float cavity_jitter_scale; + + float cavity_valley_factor; + float cavity_ridge_factor; + float cavity_attenuation; + float cavity_distance; + float curvature_ridge; float curvature_valley; + float ui_scale; + float _pad0; + + int matcap_orientation; + int use_specular; /* Bools are 32bit ints in GLSL. */ + int _pad1; + int _pad2; } WORKBENCH_UBO_World; + BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_World, 16) +BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Light, 16) +BLI_STATIC_ASSERT_ALIGN(WORKBENCH_UBO_Material, 16) -typedef struct WORKBENCH_PrivateData { +typedef struct WORKBENCH_Prepass { + /** Hash storing shading group for each Material or GPUTexture to reduce state changes. */ struct GHash *material_hash; - struct GHash *material_transp_hash; - struct GPUShader *prepass_sh; - struct GPUShader *prepass_hair_sh; - struct GPUShader *prepass_uniform_sh; - struct GPUShader *prepass_uniform_hair_sh; - struct GPUShader *prepass_textured_sh; - struct GPUShader *prepass_textured_array_sh; - struct GPUShader *prepass_vertex_sh; - struct GPUShader *composite_sh; - struct GPUShader *background_sh; - struct GPUShader *transparent_accum_sh; - struct GPUShader *transparent_accum_hair_sh; - struct GPUShader *transparent_accum_uniform_sh; - struct GPUShader *transparent_accum_uniform_hair_sh; - struct GPUShader *transparent_accum_textured_sh; - struct GPUShader *transparent_accum_textured_array_sh; - struct GPUShader *transparent_accum_vertex_sh; + /** First common (non-vcol and non-image colored) shading group to created subgroups. */ + struct DRWShadingGroup *common_shgrp; + /** First Vertex Color shading group to created subgroups. */ + struct DRWShadingGroup *vcol_shgrp; + /** First Image shading group to created subgroups. */ + struct DRWShadingGroup *image_shgrp; + /** First UDIM (tiled image) shading group to created subgroups. */ + struct DRWShadingGroup *image_tiled_shgrp; +} WORKBENCH_Prepass; + +typedef struct WORKBENCH_PrivateData { + /** ViewLayerData for faster access. */ + struct WORKBENCH_ViewLayerData *vldata; + /** Copy of draw_ctx->sh_cfg for faster access. */ + eGPUShaderConfig sh_cfg; + /** Global clip and cull states. */ + DRWState clip_state, cull_state; + /** Copy of scene->display.shading or v3d->shading for viewport. */ View3DShading shading; + /** Chosen studiolight or matcap. */ StudioLight *studio_light; + /** Copy of ctx_draw->scene for faster access. */ + struct Scene *scene; + /** Shorthand version of U global for user preferences. */ const UserDef *preferences; - /* Does this instance owns the `world_ubo` field. - * Normally the field is borrowed from `WORKBENCH_WorldData`. In case that - * there is no World attached to the scene the UBO cannot be cached and should - * be freed after using. */ - bool is_world_ubo_owner; + /** Copy of context mode for faster access. */ + eContextObjectMode ctx_mode; + /** Shorthand for wpd->vldata->world_ubo. */ struct GPUUniformBuffer *world_ubo; - struct DRWShadingGroup *shadow_shgrp; - struct DRWShadingGroup *depth_shgrp; - WORKBENCH_UBO_World world_data; - float shadow_multiplier; - float shadow_shift; - float shadow_focus; - float cached_shadow_direction[3]; + /** Background color to clear the color buffer with. */ + float background_color[4]; + + /* Shadow */ + /** Previous shadow direction to test if shadow has changed. */ + float shadow_cached_direction[3]; + /** Current shadow direction in world space. */ + float shadow_direction_ws[3]; + /** Shadow precomputed matrices. */ float shadow_mat[4][4]; float shadow_inv[4][4]; - /* Far plane of the view frustum. */ + /** Far plane of the view frustum. Used for shadow volume extrusion. */ float shadow_far_plane[4]; - /* Near plane corners in shadow space. */ - float shadow_near_corners[4][3]; - /* min and max of shadow_near_corners. allow fast test */ + /** Min and max of shadow_near_corners. Speed up culling test. */ float shadow_near_min[3]; float shadow_near_max[3]; - /* This is a parallelogram, so only 2 normal and distance to the edges. */ + /** This is a parallelogram, so only 2 normal and distance to the edges. */ float shadow_near_sides[2][4]; + /* Shadow shading groups. First array elem is for non-manifold geom and second for manifold. */ + struct DRWShadingGroup *shadow_pass_grp[2]; + struct DRWShadingGroup *shadow_fail_grp[2]; + struct DRWShadingGroup *shadow_fail_caps_grp[2]; + /** If the shadow has changed direction and ob bboxes needs to be updated. */ bool shadow_changed; - bool is_playback; - float (*world_clip_planes)[4]; + /* Temporal Antialiasing */ + /** Total number of samples to after which TAA stops accumulating samples. */ + int taa_sample_len; + /** Current TAA sample index in [0..taa_sample_len[ range. */ + int taa_sample; + /** Inverse of taa_sample to divide the accumulation buffer. */ + float taa_sample_inv; + /** If the view has been updated and TAA needs to be reset. */ + bool view_updated; + /** View */ + struct DRWView *view; + /** Last projection matrix to see if view is still valid. */ + float last_mat[4][4]; + + /* Smart Morphological Anti-Aliasing */ + /** Temp buffers to store edges and weights. */ + struct GPUTexture *smaa_edge_tx; + struct GPUTexture *smaa_weight_tx; + /** Weight of the smaa pass. */ + float smaa_mix_factor; + + /** Opaque pipeline buffers. */ + struct GPUTexture *material_buffer_tx; + struct GPUTexture *composite_buffer_tx; + struct GPUTexture *normal_buffer_tx; + /** Transparent pipeline buffers. */ + struct GPUTexture *accum_buffer_tx; + struct GPUTexture *reveal_buffer_tx; + /** Object IDs buffer for curvature & outline. */ + struct GPUTexture *object_id_tx; + + /** Prepass infos for each draw types [transparent][infront][hair]. */ + WORKBENCH_Prepass prepass[2][2][2]; + + /* Materials */ + /** Copy of vldata->material_ubo for faster access. */ + struct BLI_memblock *material_ubo; + /** Copy of vldata->material_ubo_data for faster access. */ + struct BLI_memblock *material_ubo_data; + /** Current material chunk being filled by workbench_material_setup_ex(). */ + WORKBENCH_UBO_Material *material_ubo_data_curr; + struct GPUUniformBuffer *material_ubo_curr; + /** Copy of txl->dummy_image_tx for faster access. */ + struct GPUTexture *dummy_image_tx; + /** Total number of used material chunk. */ + int material_chunk_count; + /** Index of current material chunk. */ + int material_chunk_curr; + /** Index of current material inside the material chunk. Only for material coloring mode. */ + int material_index; /* Volumes */ - bool volumes_do; + /** List of smoke domain textures to free after drawing. */ ListBase smoke_domains; - /* Ssao */ - float winmat[4][4]; - float viewvecs[3][4]; - float ssao_params[4]; - float ssao_settings[4]; - - /* Dof */ + /* Depth of Field */ + /** Depth of field temp buffers. */ struct GPUTexture *dof_blur_tx; struct GPUTexture *coc_temp_tx; struct GPUTexture *coc_tiles_tx[2]; - struct GPUUniformBuffer *dof_ubo; + /** Depth of field parameters. */ float dof_aperturesize; float dof_distance; float dof_invsensorsize; @@ -265,37 +323,15 @@ typedef struct WORKBENCH_PrivateData { float dof_blades; float dof_rotation; float dof_ratio; - bool dof_enabled; - /* Color Management */ - bool use_color_management; - bool use_color_render_settings; + /** True if any volume needs to be rendered. */ + bool volumes_do; + /** Convenience boolean. */ + bool dof_enabled; + bool is_playback; + bool is_navigating; } WORKBENCH_PrivateData; /* Transient data */ -typedef struct WORKBENCH_EffectInfo { - /** View */ - struct DRWView *view; - /** Last projection matrix to see if view is still valid. */ - float last_mat[4][4]; - int jitter_index; - float taa_mix_factor; - bool view_updated; -} WORKBENCH_EffectInfo; - -typedef struct WORKBENCH_MaterialData { - float base_color[3], metallic; - float roughness, alpha; - eV3DShadingColorType color_type; - int interp; - Image *ima; - ImageUser *iuser; - - /* Linked shgroup for drawing */ - DRWShadingGroup *shgrp; - /* forward rendering */ - DRWShadingGroup *shgrp_object_outline; -} WORKBENCH_MaterialData; - typedef struct WORKBENCH_ObjectData { DrawData dd; @@ -307,20 +343,21 @@ typedef struct WORKBENCH_ObjectData { bool shadow_bbox_dirty; } WORKBENCH_ObjectData; -typedef struct WORKBENCH_WorldData { - DrawData dd; - /* The cached `GPUUniformBuffer`, that is reused between draw calls. */ +typedef struct WORKBENCH_ViewLayerData { + /** Depth of field sample location array.*/ + struct GPUUniformBuffer *dof_sample_ubo; + /** All constant data used for a render loop.*/ struct GPUUniformBuffer *world_ubo; -} WORKBENCH_WorldData; - -/* Enumeration containing override options for base color rendering. - * This is used to during painting to force the base color to show what you are - * painting using the selected lighting model. */ -typedef enum WORKBENCH_ColorOverride { - WORKBENCH_COLOR_OVERRIDE_OFF = 0, - WORKBENCH_COLOR_OVERRIDE_TEXTURE = CTX_MODE_PAINT_TEXTURE, - WORKBENCH_COLOR_OVERRIDE_VERTEX = CTX_MODE_PAINT_VERTEX, -} WORKBENCH_ColorOverride; + /** Cavity sample location array.*/ + struct GPUUniformBuffer *cavity_sample_ubo; + /** Blue noise texture used to randomize the sampling of some effects.*/ + struct GPUTexture *cavity_jitter_tx; + /** Materials ubos allocated in a memblock for easy bookeeping. */ + struct BLI_memblock *material_ubo; + struct BLI_memblock *material_ubo_data; + /** Number of samples for which cavity_sample_ubo is valid. */ + int cavity_sample_count; +} WORKBENCH_ViewLayerData; /* inline helper functions */ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *wpd) @@ -333,234 +370,129 @@ BLI_INLINE bool workbench_is_specular_highlight_enabled(WORKBENCH_PrivateData *w return false; } -BLI_INLINE bool workbench_is_taa_enabled(WORKBENCH_PrivateData *wpd) -{ - if (DRW_state_is_image_render()) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->v3d) { - return draw_ctx->scene->display.viewport_aa > SCE_DISPLAY_AA_FXAA; - } - else { - return draw_ctx->scene->display.render_aa > SCE_DISPLAY_AA_FXAA; - } - } - else { - return !(IS_NAVIGATING(wpd) || wpd->is_playback) && - wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA; - } -} - -BLI_INLINE bool workbench_is_fxaa_enabled(WORKBENCH_PrivateData *wpd) -{ - if (DRW_state_is_image_render()) { - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (draw_ctx->v3d) { - return draw_ctx->scene->display.viewport_aa == SCE_DISPLAY_AA_FXAA; - } - else { - return draw_ctx->scene->display.render_aa == SCE_DISPLAY_AA_FXAA; - } - } - else { - if (wpd->preferences->viewport_aa == SCE_DISPLAY_AA_FXAA) { - return true; - } - - /* when navigating or animation playback use FXAA if scene uses TAA. */ - return (IS_NAVIGATING(wpd) || wpd->is_playback) && - wpd->preferences->viewport_aa > SCE_DISPLAY_AA_FXAA; - } -} - -/** Is texture paint mode enabled (globally) */ -BLI_INLINE bool workbench_is_in_texture_paint_mode(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - return draw_ctx->object_mode == OB_MODE_TEXTURE_PAINT; -} - -/** Is vertex paint mode enabled (globally) */ -BLI_INLINE bool workbench_is_in_vertex_paint_mode(void) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - return draw_ctx->object_mode == OB_MODE_VERTEX_PAINT; -} - -/* Must the `View3DShading.color_type` be overriden for the given object. */ -BLI_INLINE WORKBENCH_ColorOverride workbench_object_color_override_get(Object *ob) -{ - const DRWContextState *draw_ctx = DRW_context_state_get(); - if (ob->type == OB_MESH && (draw_ctx->obact == ob)) { - const enum eContextObjectMode mode = CTX_data_mode_enum_ex( - draw_ctx->object_edit, draw_ctx->obact, draw_ctx->object_mode); - if (mode == CTX_MODE_PAINT_TEXTURE) { - return WORKBENCH_COLOR_OVERRIDE_TEXTURE; - } - else if (mode == CTX_MODE_PAINT_VERTEX) { - return WORKBENCH_COLOR_OVERRIDE_VERTEX; - } - } - - return WORKBENCH_COLOR_OVERRIDE_OFF; -} - -BLI_INLINE bool workbench_is_matdata_pass_enabled(WORKBENCH_PrivateData *wpd) -{ - return (wpd->shading.color_type != V3D_SHADING_SINGLE_COLOR || MATCAP_ENABLED(wpd)) || - workbench_is_in_texture_paint_mode() || workbench_is_in_vertex_paint_mode(); -} - -/** - * Get the default texture format to be used by the color and history buffers. - * - * Use GPU_RGBA16F for final renderings and for drawing textures. This - * allows displaying HDRI textures. Vertex Colors uses GPU_RGBA16 to resolve - * color banding issues (T66100). All other modes use GPU_RGBA8 to reduce - * bandwidth and gpu memory. - */ -BLI_INLINE eGPUTextureFormat workbench_color_texture_format(const WORKBENCH_PrivateData *wpd) -{ - eGPUTextureFormat result; - if (DRW_state_is_image_render() || workbench_is_in_texture_paint_mode() || - TEXTURE_DRAWING_ENABLED(wpd)) { - result = GPU_RGBA16F; - } - else { - result = GPU_RGBA16; - } - return result; -} - -/* workbench_deferred.c */ -void workbench_deferred_engine_init(WORKBENCH_Data *vedata); -void workbench_deferred_engine_free(void); -void workbench_deferred_draw_scene(WORKBENCH_Data *vedata); -void workbench_deferred_draw_finish(WORKBENCH_Data *vedata); -void workbench_deferred_cache_init(WORKBENCH_Data *vedata); -void workbench_deferred_solid_cache_populate(WORKBENCH_Data *vedata, Object *ob); -void workbench_deferred_cache_finish(WORKBENCH_Data *vedata); - -/* workbench_forward.c */ -void workbench_forward_engine_init(WORKBENCH_Data *vedata); -void workbench_forward_engine_free(void); -void workbench_forward_draw_scene(WORKBENCH_Data *vedata); -void workbench_forward_draw_finish(WORKBENCH_Data *vedata); -void workbench_forward_cache_init(WORKBENCH_Data *vedata); -void workbench_forward_cache_populate(WORKBENCH_Data *vedata, Object *ob); -void workbench_forward_cache_finish(WORKBENCH_Data *vedata); - -/* For OIT in deferred */ -void workbench_forward_outline_shaders_ensure(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg); -void workbench_forward_choose_shaders(WORKBENCH_PrivateData *wpd, eGPUShaderConfig sh_cfg); -WORKBENCH_MaterialData *workbench_forward_get_or_create_material_data( - WORKBENCH_Data *vedata, - Object *ob, - Material *mat, - Image *ima, - ImageUser *iuser, - eV3DShadingColorType color_type, - int interp); - -/* workbench_effect_aa.c */ -void workbench_aa_create_pass(WORKBENCH_Data *vedata, GPUTexture **tx); -void workbench_aa_draw_pass(WORKBENCH_Data *vedata, GPUTexture *tx); - -/* workbench_effect_fxaa.c */ -void workbench_fxaa_engine_init(void); -void workbench_fxaa_engine_free(void); -DRWPass *workbench_fxaa_create_pass(GPUTexture **color_buffer_tx); - -/* workbench_effect_taa.c */ -void workbench_taa_engine_init(WORKBENCH_Data *vedata); -void workbench_taa_engine_free(void); -DRWPass *workbench_taa_create_pass(WORKBENCH_Data *vedata, GPUTexture **color_buffer_tx); -void workbench_taa_draw_scene_start(WORKBENCH_Data *vedata); -void workbench_taa_draw_scene_end(WORKBENCH_Data *vedata); -void workbench_taa_view_updated(WORKBENCH_Data *vedata); -int workbench_taa_calculate_num_iterations(WORKBENCH_Data *vedata); -int workbench_num_viewport_rendering_iterations(WORKBENCH_Data *vedata); - +/* workbench_opaque.c */ +void workbench_opaque_engine_init(WORKBENCH_Data *data); +void workbench_opaque_cache_init(WORKBENCH_Data *data); + +/* workbench_transparent.c */ +void workbench_transparent_engine_init(WORKBENCH_Data *data); +void workbench_transparent_cache_init(WORKBENCH_Data *data); +void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data); + +/* workbench_shadow.c */ +void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd); +void workbench_shadow_cache_init(WORKBENCH_Data *data); +void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat); + +/* workbench_shader.c */ +GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair); +GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled); +GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd); +GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *wpd); + +GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair); +GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd, + bool hair, + bool tiled); +GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd); + +GPUShader *workbench_shader_shadow_pass_get(bool manifold); +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap); + +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature); +GPUShader *workbench_shader_outline_get(void); + +GPUShader *workbench_shader_antialiasing_accumulation_get(void); +GPUShader *workbench_shader_antialiasing_get(int stage); + +GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic); + +void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, + GPUShader **downsample_sh, + GPUShader **blur1_sh, + GPUShader **blur2_sh, + GPUShader **resolve_sh); + +void workbench_shader_library_ensure(void); +void workbench_shader_free(void); + +/* workbench_effect_antialiasing.c */ +int workbench_antialiasing_sample_count_get(WORKBENCH_PrivateData *wpd); +void workbench_antialiasing_engine_init(WORKBENCH_Data *vedata); +void workbench_antialiasing_cache_init(WORKBENCH_Data *vedata); +void workbench_antialiasing_view_updated(WORKBENCH_Data *vedata); +bool workbench_antialiasing_setup(WORKBENCH_Data *vedata); +void workbench_antialiasing_draw_pass(WORKBENCH_Data *vedata); + +/* workbench_effect_cavity.c */ +void workbench_cavity_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd); +void workbench_cavity_samples_ubo_ensure(WORKBENCH_PrivateData *wpd); +void workbench_cavity_cache_init(WORKBENCH_Data *data); + +/* workbench_effect_outline.c */ +void workbench_outline_cache_init(WORKBENCH_Data *data); /* workbench_effect_dof.c */ -void workbench_dof_engine_init(WORKBENCH_Data *vedata, Object *camera); -void workbench_dof_engine_free(void); -void workbench_dof_create_pass(WORKBENCH_Data *vedata, - GPUTexture **dof_input, - GPUTexture *noise_tex); +void workbench_dof_engine_init(WORKBENCH_Data *vedata); +void workbench_dof_cache_init(WORKBENCH_Data *vedata); void workbench_dof_draw_pass(WORKBENCH_Data *vedata); /* workbench_materials.c */ -eV3DShadingColorType workbench_material_determine_color_type(WORKBENCH_PrivateData *wpd, - Image *ima, - Object *ob, - bool use_sculpt_pbvh); -void workbench_material_get_image_and_mat( - Object *ob, int mat_nr, Image **r_image, ImageUser **r_iuser, int *r_interp, Material **r_mat); -char *workbench_material_build_defines(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override); -void workbench_material_update_data(WORKBENCH_PrivateData *wpd, - Object *ob, - Material *mat, - WORKBENCH_MaterialData *data, - int color_type); -uint workbench_material_get_hash(WORKBENCH_MaterialData *material_template, bool is_ghost); -int workbench_material_get_composite_shader_index(WORKBENCH_PrivateData *wpd); -int workbench_material_get_prepass_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override); -int workbench_material_get_accum_shader_index(WORKBENCH_PrivateData *wpd, - bool is_uniform_color, - bool is_hair, - bool is_tiled, - const WORKBENCH_ColorOverride color_override); -void workbench_material_shgroup_uniform(WORKBENCH_PrivateData *wpd, - DRWShadingGroup *grp, - WORKBENCH_MaterialData *material, - Object *ob, - const bool deferred, - const bool is_tiled, - const int interp); -void workbench_material_copy(WORKBENCH_MaterialData *dest_material, - const WORKBENCH_MaterialData *source_material); - -/* workbench_studiolight.c */ -void studiolight_update_world(WORKBENCH_PrivateData *wpd, - StudioLight *sl, - WORKBENCH_UBO_World *wd); -void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]); -bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed); -float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed); -bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed); +void workbench_material_ubo_data(WORKBENCH_PrivateData *wpd, + Object *ob, + Material *mat, + WORKBENCH_UBO_Material *data, + eV3DShadingColorType color_type); + +DRWShadingGroup *workbench_material_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + eV3DShadingColorType color_type, + bool hair, + bool *r_transp); +DRWShadingGroup *workbench_image_setup_ex(WORKBENCH_PrivateData *wpd, + Object *ob, + int mat_nr, + Image *ima, + ImageUser *iuser, + int interp, + bool hair); + +#define workbench_material_setup(wpd, ob, mat_nr, color_type, r_transp) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, false, r_transp) +#define workbench_image_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, false) + +#define workbench_material_hair_setup(wpd, ob, mat_nr, color_type) \ + workbench_material_setup_ex(wpd, ob, mat_nr, color_type, true, 0) +#define workbench_image_hair_setup(wpd, ob, mat_nr, ima, iuser, interp) \ + workbench_image_setup_ex(wpd, ob, mat_nr, ima, iuser, interp, true) /* workbench_data.c */ -void workbench_effect_info_init(WORKBENCH_EffectInfo *effect_info); void workbench_private_data_init(WORKBENCH_PrivateData *wpd); -void workbench_private_data_free(WORKBENCH_PrivateData *wpd); -void workbench_private_data_get_light_direction(float r_light_direction[3]); -void workbench_clear_color_get(float color[4]); +void workbench_update_world_ubo(WORKBENCH_PrivateData *wpd); +void workbench_update_material_ubos(WORKBENCH_PrivateData *wpd); +struct GPUUniformBuffer *workbench_material_ubo_alloc(WORKBENCH_PrivateData *wpd); /* workbench_volume.c */ -void workbench_volume_engine_init(void); -void workbench_volume_engine_free(void); +void workbench_volume_engine_init(WORKBENCH_Data *vedata); void workbench_volume_cache_init(WORKBENCH_Data *vedata); void workbench_volume_cache_populate(WORKBENCH_Data *vedata, - Scene *scene, - Object *ob, + struct Scene *UNUSED(scene), + struct Object *ob, struct ModifierData *md); -void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd); +void workbench_volume_draw_pass(WORKBENCH_Data *vedata); +void workbench_volume_draw_finish(WORKBENCH_Data *vedata); + +/* workbench_engine.c */ +void workbench_engine_init(void *ved); +void workbench_cache_init(void *ved); +void workbench_cache_populate(void *ved, Object *ob); +void workbench_cache_finish(void *ved); +void workbench_draw_sample(void *ved); +void workbench_draw_finish(void *ved); /* workbench_render.c */ -void workbench_render(WORKBENCH_Data *vedata, +void workbench_render(void *ved, struct RenderEngine *engine, struct RenderLayer *render_layer, const struct rcti *rect); diff --git a/source/blender/draw/engines/workbench/workbench_render.c b/source/blender/draw/engines/workbench/workbench_render.c index 6e005e7ccaf..5a315e80a47 100644 --- a/source/blender/draw/engines/workbench/workbench_render.c +++ b/source/blender/draw/engines/workbench/workbench_render.c @@ -41,20 +41,12 @@ #include "workbench_private.h" -static void workbench_render_deferred_cache(void *vedata, - struct Object *ob, - struct RenderEngine *UNUSED(engine), - struct Depsgraph *UNUSED(depsgraph)) +static void workbench_render_cache(void *vedata, + struct Object *ob, + struct RenderEngine *UNUSED(engine), + struct Depsgraph *UNUSED(depsgraph)) { - workbench_deferred_solid_cache_populate(vedata, ob); -} - -static void workbench_render_forward_cache(void *vedata, - struct Object *ob, - struct RenderEngine *UNUSED(engine), - struct Depsgraph *UNUSED(depsgraph)) -{ - workbench_forward_cache_populate(vedata, ob); + workbench_cache_populate(vedata, ob); } static void workbench_render_matrices_init(RenderEngine *engine, Depsgraph *depsgraph) @@ -171,18 +163,11 @@ static void workbench_render_result_z(struct RenderLayer *rl, } } -static void workbench_render_framebuffers_finish(void) -{ -} - -void workbench_render(WORKBENCH_Data *data, - RenderEngine *engine, - RenderLayer *render_layer, - const rcti *rect) +void workbench_render(void *ved, RenderEngine *engine, RenderLayer *render_layer, const rcti *rect) { + WORKBENCH_Data *data = ved; DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); const DRWContextState *draw_ctx = DRW_context_state_get(); - const Scene *scene = draw_ctx->scene; Depsgraph *depsgraph = draw_ctx->depsgraph; workbench_render_matrices_init(engine, depsgraph); @@ -191,60 +176,32 @@ void workbench_render(WORKBENCH_Data *data, return; } - const bool deferred = !XRAY_FLAG_ENABLED(&scene->display); + workbench_engine_init(data); - if (deferred) { - /* Init engine. */ - workbench_deferred_engine_init(data); + workbench_cache_init(data); + DRW_render_object_iter(data, engine, depsgraph, workbench_render_cache); + workbench_cache_finish(data); - /* Init objects. */ - workbench_deferred_cache_init(data); - DRW_render_object_iter(data, engine, depsgraph, workbench_render_deferred_cache); - workbench_deferred_cache_finish(data); - DRW_render_instance_buffer_finish(); + DRW_render_instance_buffer_finish(); - /* Also we weed to have a correct fbo bound for DRW_hair_update */ - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_hair_update(); - - /* Draw. */ - int num_samples = workbench_taa_calculate_num_iterations(data); - for (int sample = 0; sample < num_samples; sample++) { - if (RE_engine_test_break(engine)) { - break; - } - workbench_deferred_draw_scene(data); - } + /* Also we weed to have a correct fbo bound for DRW_hair_update */ + GPU_framebuffer_bind(dfbl->default_fb); + DRW_hair_update(); - workbench_deferred_draw_finish(data); - } - else { - /* Init engine. */ - workbench_forward_engine_init(data); - - /* Init objects. */ - workbench_forward_cache_init(data); - DRW_render_object_iter(data, engine, depsgraph, workbench_render_forward_cache); - workbench_forward_cache_finish(data); - DRW_render_instance_buffer_finish(); - - /* Also we weed to have a correct fbo bound for DRW_hair_update */ - GPU_framebuffer_bind(dfbl->color_only_fb); - DRW_hair_update(); - - /* Draw. */ - int num_samples = workbench_taa_calculate_num_iterations(data); - for (int sample = 0; sample < num_samples; sample++) { - if (RE_engine_test_break(engine)) { - break; - } + GPU_framebuffer_bind(dfbl->default_fb); + GPU_framebuffer_clear_depth(dfbl->default_fb, 1.0f); - workbench_forward_draw_scene(data); + WORKBENCH_PrivateData *wpd = data->stl->wpd; + while (wpd->taa_sample < max_ii(1, wpd->taa_sample_len)) { + if (RE_engine_test_break(engine)) { + break; } - - workbench_forward_draw_finish(data); + workbench_update_world_ubo(wpd); + workbench_draw_sample(data); } + workbench_draw_finish(data); + /* Write render output. */ const char *viewname = RE_GetActiveRenderView(engine->re); RenderPass *rp = RE_pass_find_by_name(render_layer, RE_PASSNAME_COMBINED, viewname); @@ -260,8 +217,6 @@ void workbench_render(WORKBENCH_Data *data, rp->rect); workbench_render_result_z(render_layer, viewname, rect); - - workbench_render_framebuffers_finish(); } void workbench_render_update_passes(RenderEngine *engine, Scene *scene, ViewLayer *view_layer) diff --git a/source/blender/draw/engines/workbench/workbench_shader.c b/source/blender/draw/engines/workbench/workbench_shader.c new file mode 100644 index 00000000000..14a980fe628 --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_shader.c @@ -0,0 +1,533 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + */ + +#include "DRW_render.h" + +#include "BLI_dynstr.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +extern char datatoc_common_hair_lib_glsl[]; +extern char datatoc_common_view_lib_glsl[]; +extern char datatoc_common_smaa_lib_glsl[]; + +extern char datatoc_workbench_prepass_vert_glsl[]; +extern char datatoc_workbench_prepass_hair_vert_glsl[]; +extern char datatoc_workbench_prepass_frag_glsl[]; + +extern char datatoc_workbench_effect_cavity_frag_glsl[]; +extern char datatoc_workbench_effect_outline_frag_glsl[]; +extern char datatoc_workbench_effect_dof_frag_glsl[]; +extern char datatoc_workbench_effect_taa_frag_glsl[]; +extern char datatoc_workbench_effect_smaa_frag_glsl[]; +extern char datatoc_workbench_effect_smaa_vert_glsl[]; + +extern char datatoc_workbench_composite_frag_glsl[]; + +extern char datatoc_workbench_transparent_accum_frag_glsl[]; +extern char datatoc_workbench_transparent_resolve_frag_glsl[]; + +extern char datatoc_workbench_merge_infront_frag_glsl[]; + +extern char datatoc_workbench_shadow_vert_glsl[]; +extern char datatoc_workbench_shadow_geom_glsl[]; +extern char datatoc_workbench_shadow_caps_geom_glsl[]; +extern char datatoc_workbench_shadow_debug_frag_glsl[]; + +extern char datatoc_workbench_volume_vert_glsl[]; +extern char datatoc_workbench_volume_frag_glsl[]; + +extern char datatoc_workbench_cavity_lib_glsl[]; +extern char datatoc_workbench_common_lib_glsl[]; +extern char datatoc_workbench_curvature_lib_glsl[]; +extern char datatoc_workbench_data_lib_glsl[]; +extern char datatoc_workbench_image_lib_glsl[]; +extern char datatoc_workbench_matcap_lib_glsl[]; +extern char datatoc_workbench_material_lib_glsl[]; +extern char datatoc_workbench_shader_interface_lib_glsl[]; +extern char datatoc_workbench_world_light_lib_glsl[]; + +extern char datatoc_gpu_shader_depth_only_frag_glsl[]; +extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; + +/* Maximum number of variations. */ +#define MAX_LIGHTING 3 +#define MAX_COLOR 3 +#define MAX_GEOM 2 + +enum { + VOLUME_SH_SLICE = 0, + VOLUME_SH_COBA, + VOLUME_SH_CUBIC, +}; + +#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1)) + +static struct { + struct GPUShader *opaque_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_COLOR]; + struct GPUShader *transp_prepass_sh_cache[GPU_SHADER_CFG_LEN][MAX_GEOM][MAX_LIGHTING][MAX_COLOR]; + + struct GPUShader *opaque_composite_sh[MAX_LIGHTING]; + struct GPUShader *oit_resolve_sh; + struct GPUShader *outline_sh; + struct GPUShader *merge_infront_sh; + + struct GPUShader *shadow_depth_pass_sh[2]; + struct GPUShader *shadow_depth_fail_sh[2][2]; + + struct GPUShader *cavity_sh[2][2]; + + struct GPUShader *dof_prepare_sh; + struct GPUShader *dof_downsample_sh; + struct GPUShader *dof_blur1_sh; + struct GPUShader *dof_blur2_sh; + struct GPUShader *dof_resolve_sh; + + struct GPUShader *aa_accum_sh; + struct GPUShader *smaa_sh[3]; + + struct GPUShader *volume_sh[2][2][2]; + + struct DRWShaderLibrary *lib; +} e_data = {{{{NULL}}}}; + +void workbench_shader_library_ensure(void) +{ + if (e_data.lib == NULL) { + e_data.lib = DRW_shader_library_create(); + /* NOTE: Theses needs to be ordered by dependencies. */ + DRW_SHADER_LIB_ADD(e_data.lib, common_hair_lib); + DRW_SHADER_LIB_ADD(e_data.lib, common_view_lib); + DRW_SHADER_LIB_ADD(e_data.lib, gpu_shader_common_obinfos_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_shader_interface_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_common_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_image_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_material_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_data_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_matcap_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_cavity_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_curvature_lib); + DRW_SHADER_LIB_ADD(e_data.lib, workbench_world_light_lib); + } +} + +static char *workbench_build_defines( + WORKBENCH_PrivateData *wpd, bool textured, bool tiled, bool cavity, bool curvature) +{ + char *str = NULL; + + DynStr *ds = BLI_dynstr_new(); + + if (wpd && wpd->shading.light == V3D_LIGHTING_STUDIO) { + BLI_dynstr_append(ds, "#define V3D_LIGHTING_STUDIO\n"); + } + else if (wpd && wpd->shading.light == V3D_LIGHTING_MATCAP) { + BLI_dynstr_append(ds, "#define V3D_LIGHTING_MATCAP\n"); + } + else { + BLI_dynstr_append(ds, "#define V3D_LIGHTING_FLAT\n"); + } + + if (NORMAL_ENCODING_ENABLED()) { + BLI_dynstr_append(ds, "#define WORKBENCH_ENCODE_NORMALS\n"); + } + + if (textured) { + BLI_dynstr_append(ds, "#define V3D_SHADING_TEXTURE_COLOR\n"); + } + if (tiled) { + BLI_dynstr_append(ds, "#define TEXTURE_IMAGE_ARRAY\n"); + } + if (cavity) { + BLI_dynstr_append(ds, "#define USE_CAVITY\n"); + } + if (curvature) { + BLI_dynstr_append(ds, "#define USE_CURVATURE\n"); + } + + str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + return str; +} + +static int workbench_color_index(WORKBENCH_PrivateData *UNUSED(wpd), bool textured, bool tiled) +{ + BLI_assert(2 < MAX_COLOR); + return (textured) ? (tiled ? 2 : 1) : 0; +} + +static GPUShader *workbench_shader_get_ex( + WORKBENCH_PrivateData *wpd, bool transp, bool hair, bool textured, bool tiled) +{ + int color = workbench_color_index(wpd, textured, tiled); + int light = wpd->shading.light; + BLI_assert(light < MAX_LIGHTING); + struct GPUShader **shader = + (transp) ? &e_data.transp_prepass_sh_cache[wpd->sh_cfg][hair][light][color] : + &e_data.opaque_prepass_sh_cache[wpd->sh_cfg][hair][color]; + + if (*shader == NULL) { + char *defines = workbench_build_defines(wpd, textured, tiled, false, false); + + char *frag_file = transp ? datatoc_workbench_transparent_accum_frag_glsl : + datatoc_workbench_prepass_frag_glsl; + char *frag_src = DRW_shader_library_create_shader_string(e_data.lib, frag_file); + + char *vert_file = hair ? datatoc_workbench_prepass_hair_vert_glsl : + datatoc_workbench_prepass_vert_glsl; + char *vert_src = DRW_shader_library_create_shader_string(e_data.lib, vert_file); + + const GPUShaderConfigData *sh_cfg_data = &GPU_shader_cfg_data[wpd->sh_cfg]; + + *shader = GPU_shader_create_from_arrays({ + .vert = (const char *[]){sh_cfg_data->lib, vert_src, NULL}, + .frag = (const char *[]){frag_src, NULL}, + .defs = (const char *[]){sh_cfg_data->def, + defines, + transp ? "#define TRANSPARENT_MATERIAL\n" : + "#define OPAQUE_MATERIAL\n", + NULL}, + }); + + MEM_freeN(defines); + MEM_freeN(frag_src); + MEM_freeN(vert_src); + } + return *shader; +} + +GPUShader *workbench_shader_opaque_get(WORKBENCH_PrivateData *wpd, bool hair) +{ + return workbench_shader_get_ex(wpd, false, hair, false, false); +} + +GPUShader *workbench_shader_opaque_image_get(WORKBENCH_PrivateData *wpd, bool hair, bool tiled) +{ + return workbench_shader_get_ex(wpd, false, hair, true, tiled); +} + +GPUShader *workbench_shader_transparent_get(WORKBENCH_PrivateData *wpd, bool hair) +{ + return workbench_shader_get_ex(wpd, true, hair, false, false); +} + +GPUShader *workbench_shader_transparent_image_get(WORKBENCH_PrivateData *wpd, + bool hair, + bool tiled) +{ + return workbench_shader_get_ex(wpd, true, hair, true, tiled); +} + +GPUShader *workbench_shader_composite_get(WORKBENCH_PrivateData *wpd) +{ + int light = wpd->shading.light; + struct GPUShader **shader = &e_data.opaque_composite_sh[light]; + BLI_assert(light < MAX_LIGHTING); + + if (*shader == NULL) { + char *defines = workbench_build_defines(wpd, false, false, false, false); + char *frag = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_composite_frag_glsl); + + *shader = DRW_shader_create_fullscreen(frag, defines); + + MEM_freeN(defines); + MEM_freeN(frag); + } + return *shader; +} + +GPUShader *workbench_shader_merge_infront_get(WORKBENCH_PrivateData *UNUSED(wpd)) +{ + if (e_data.merge_infront_sh == NULL) { + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_merge_infront_frag_glsl); + + e_data.merge_infront_sh = DRW_shader_create_fullscreen(frag, NULL); + + MEM_freeN(frag); + } + return e_data.merge_infront_sh; +} + +GPUShader *workbench_shader_transparent_resolve_get(WORKBENCH_PrivateData *wpd) +{ + if (e_data.oit_resolve_sh == NULL) { + char *defines = workbench_build_defines(wpd, false, false, false, false); + + e_data.oit_resolve_sh = DRW_shader_create_fullscreen( + datatoc_workbench_transparent_resolve_frag_glsl, defines); + + MEM_freeN(defines); + } + return e_data.oit_resolve_sh; +} + +static GPUShader *workbench_shader_shadow_pass_get_ex(bool depth_pass, bool manifold, bool cap) +{ + struct GPUShader **shader = (depth_pass) ? &e_data.shadow_depth_pass_sh[manifold] : + &e_data.shadow_depth_fail_sh[manifold][cap]; + + if (*shader == NULL) { +#if DEBUG_SHADOW_VOLUME + const char *shadow_frag = datatoc_workbench_shadow_debug_frag_glsl; +#else + const char *shadow_frag = datatoc_gpu_shader_depth_only_frag_glsl; +#endif + + *shader = GPU_shader_create_from_arrays({ + .vert = (const char *[]){datatoc_common_view_lib_glsl, + datatoc_workbench_shadow_vert_glsl, + NULL}, + .geom = (const char *[]){(cap) ? datatoc_workbench_shadow_caps_geom_glsl : + datatoc_workbench_shadow_geom_glsl, + NULL}, + .frag = (const char *[]){shadow_frag, NULL}, + .defs = (const char *[]){(depth_pass) ? "#define SHADOW_PASS\n" : "#define SHADOW_FAIL\n", + (manifold) ? "" : "#define DOUBLE_MANIFOLD\n", + NULL}, + }); + } + return *shader; +} + +GPUShader *workbench_shader_shadow_pass_get(bool manifold) +{ + return workbench_shader_shadow_pass_get_ex(true, manifold, false); +} + +GPUShader *workbench_shader_shadow_fail_get(bool manifold, bool cap) +{ + return workbench_shader_shadow_pass_get_ex(false, manifold, cap); +} + +GPUShader *workbench_shader_cavity_get(bool cavity, bool curvature) +{ + BLI_assert(cavity || curvature); + struct GPUShader **shader = &e_data.cavity_sh[cavity][curvature]; + + if (*shader == NULL) { + char *defines = workbench_build_defines(NULL, false, false, cavity, curvature); + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_effect_cavity_frag_glsl); + + *shader = DRW_shader_create_fullscreen(frag, defines); + + MEM_freeN(defines); + MEM_freeN(frag); + } + return *shader; +} + +GPUShader *workbench_shader_outline_get(void) +{ + if (e_data.outline_sh == NULL) { + char *frag = DRW_shader_library_create_shader_string( + e_data.lib, datatoc_workbench_effect_outline_frag_glsl); + + e_data.outline_sh = DRW_shader_create_fullscreen(frag, NULL); + + MEM_freeN(frag); + } + return e_data.outline_sh; +} + +void workbench_shader_depth_of_field_get(GPUShader **prepare_sh, + GPUShader **downsample_sh, + GPUShader **blur1_sh, + GPUShader **blur2_sh, + GPUShader **resolve_sh) +{ + if (e_data.dof_prepare_sh == NULL) { + e_data.dof_prepare_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define PREPARE\n"); + + e_data.dof_downsample_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define DOWNSAMPLE\n"); +#if 0 /* TODO(fclem) finish COC min_max optimization */ + e_data.dof_flatten_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define FLATTEN_VERTICAL\n"); + + e_data.dof_flatten_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define FLATTEN_HORIZONTAL\n"); + + e_data.dof_dilate_v_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define DILATE_VERTICAL\n"); + + e_data.dof_dilate_h_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define DILATE_HORIZONTAL\n"); +#endif + e_data.dof_blur1_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define BLUR1\n"); + + e_data.dof_blur2_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define BLUR2\n"); + + e_data.dof_resolve_sh = DRW_shader_create_fullscreen(datatoc_workbench_effect_dof_frag_glsl, + "#define RESOLVE\n"); + } + + *prepare_sh = e_data.dof_prepare_sh; + *downsample_sh = e_data.dof_downsample_sh; + *blur1_sh = e_data.dof_blur1_sh; + *blur2_sh = e_data.dof_blur2_sh; + *resolve_sh = e_data.dof_resolve_sh; +} + +GPUShader *workbench_shader_antialiasing_accumulation_get(void) +{ + if (e_data.aa_accum_sh == NULL) { + char *frag = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_effect_taa_frag_glsl); + + e_data.aa_accum_sh = DRW_shader_create_fullscreen(frag, NULL); + + MEM_freeN(frag); + } + return e_data.aa_accum_sh; +} + +GPUShader *workbench_shader_antialiasing_get(int stage) +{ + BLI_assert(stage < 3); + if (!e_data.smaa_sh[stage]) { + char stage_define[32]; + BLI_snprintf(stage_define, sizeof(stage_define), "#define SMAA_STAGE %d\n", stage); + + e_data.smaa_sh[stage] = GPU_shader_create_from_arrays({ + .vert = + (const char *[]){ + "#define SMAA_INCLUDE_VS 1\n", + "#define SMAA_INCLUDE_PS 0\n", + "uniform vec4 viewportMetrics;\n", + datatoc_common_smaa_lib_glsl, + datatoc_workbench_effect_smaa_vert_glsl, + NULL, + }, + .frag = + (const char *[]){ + "#define SMAA_INCLUDE_VS 0\n", + "#define SMAA_INCLUDE_PS 1\n", + "uniform vec4 viewportMetrics;\n", + datatoc_common_smaa_lib_glsl, + datatoc_workbench_effect_smaa_frag_glsl, + NULL, + }, + .defs = + (const char *[]){ + "#define SMAA_GLSL_3\n", + "#define SMAA_RT_METRICS viewportMetrics\n", + "#define SMAA_PRESET_HIGH\n", + "#define SMAA_LUMA_WEIGHT float4(1.0, 1.0, 1.0, 1.0)\n", + "#define SMAA_NO_DISCARD\n", + stage_define, + NULL, + }, + }); + } + return e_data.smaa_sh[stage]; +} + +GPUShader *workbench_shader_volume_get(bool slice, bool coba, bool cubic) +{ + GPUShader **shader = &e_data.volume_sh[slice][coba][cubic]; + + if (*shader == NULL) { + DynStr *ds = BLI_dynstr_new(); + + if (slice) { + BLI_dynstr_append(ds, "#define VOLUME_SLICE\n"); + } + if (coba) { + BLI_dynstr_append(ds, "#define USE_COBA\n"); + } + if (cubic) { + BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); + } + + char *defines = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + char *vert = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_volume_vert_glsl); + char *frag = DRW_shader_library_create_shader_string(e_data.lib, + datatoc_workbench_volume_frag_glsl); + + *shader = DRW_shader_create(vert, NULL, frag, defines); + + MEM_freeN(vert); + MEM_freeN(frag); + MEM_freeN(defines); + } + return *shader; +} + +void workbench_shader_free(void) +{ + for (int j = 0; j < sizeof(e_data.opaque_prepass_sh_cache) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.opaque_prepass_sh_cache[0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.transp_prepass_sh_cache) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.transp_prepass_sh_cache[0][0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.opaque_composite_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.opaque_composite_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.shadow_depth_pass_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_pass_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.shadow_depth_fail_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.shadow_depth_fail_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.cavity_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.cavity_sh[0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.smaa_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.smaa_sh[0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + for (int j = 0; j < sizeof(e_data.volume_sh) / sizeof(void *); j++) { + struct GPUShader **sh_array = &e_data.volume_sh[0][0][0]; + DRW_SHADER_FREE_SAFE(sh_array[j]); + } + + DRW_SHADER_FREE_SAFE(e_data.oit_resolve_sh); + DRW_SHADER_FREE_SAFE(e_data.outline_sh); + DRW_SHADER_FREE_SAFE(e_data.merge_infront_sh); + + DRW_SHADER_FREE_SAFE(e_data.dof_prepare_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_downsample_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_blur1_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_blur2_sh); + DRW_SHADER_FREE_SAFE(e_data.dof_resolve_sh); + + DRW_SHADER_FREE_SAFE(e_data.aa_accum_sh); + + DRW_SHADER_LIB_FREE_SAFE(e_data.lib); +} diff --git a/source/blender/draw/engines/workbench/workbench_shadow.c b/source/blender/draw/engines/workbench/workbench_shadow.c new file mode 100644 index 00000000000..efd0ad9134e --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_shadow.c @@ -0,0 +1,367 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Shadow: + * + * Use stencil shadow buffer to cast a sharp shadow over opaque surfaces. + * + * After the main pre-pass we render shadow volumes using custom depth & stencil states to + * set the stencil of shadowed area to anything but 0. + * + * Then the shading pass will shade the areas with stencil not equal 0 differently. + */ + +#include "DRW_render.h" + +#include "BKE_object.h" + +#include "BLI_math.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +static void compute_parallel_lines_nor_and_dist(const float v1[2], + const float v2[2], + const float v3[2], + float r_line[4]) +{ + sub_v2_v2v2(r_line, v2, v1); + /* Find orthogonal vector. */ + SWAP(float, r_line[0], r_line[1]); + r_line[0] = -r_line[0]; + /* Edge distances. */ + r_line[2] = dot_v2v2(r_line, v1); + r_line[3] = dot_v2v2(r_line, v3); + /* Make sure r_line[2] is the minimum. */ + if (r_line[2] > r_line[3]) { + SWAP(float, r_line[2], r_line[3]); + } +} + +static void workbench_shadow_update(WORKBENCH_PrivateData *wpd) +{ + wpd->shadow_changed = !compare_v3v3( + wpd->shadow_cached_direction, wpd->shadow_direction_ws, 1e-5f); + + if (wpd->shadow_changed) { + float up[3] = {0.0f, 0.0f, 1.0f}; + unit_m4(wpd->shadow_mat); + + /* TODO fix singularity. */ + copy_v3_v3(wpd->shadow_mat[2], wpd->shadow_direction_ws); + cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up); + normalize_v3(wpd->shadow_mat[0]); + cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]); + + invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat); + + copy_v3_v3(wpd->shadow_cached_direction, wpd->shadow_direction_ws); + } + + float planes[6][4]; + DRW_culling_frustum_planes_get(NULL, planes); + /* we only need the far plane. */ + copy_v4_v4(wpd->shadow_far_plane, planes[2]); + + BoundBox frustum_corners; + DRW_culling_frustum_corners_get(NULL, &frustum_corners); + + float shadow_near_corners[4][3]; + mul_v3_mat3_m4v3(shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]); + mul_v3_mat3_m4v3(shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]); + mul_v3_mat3_m4v3(shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]); + mul_v3_mat3_m4v3(shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]); + + INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max); + for (int i = 0; i < 4; i++) { + minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, shadow_near_corners[i]); + } + + compute_parallel_lines_nor_and_dist(shadow_near_corners[0], + shadow_near_corners[1], + shadow_near_corners[2], + wpd->shadow_near_sides[0]); + compute_parallel_lines_nor_and_dist(shadow_near_corners[1], + shadow_near_corners[2], + shadow_near_corners[0], + wpd->shadow_near_sides[1]); +} + +void workbench_shadow_data_update(WORKBENCH_PrivateData *wpd, WORKBENCH_UBO_World *wd) +{ + const DRWContextState *draw_ctx = DRW_context_state_get(); + const Scene *scene = draw_ctx->scene; + + float view_matrix[4][4]; + DRW_view_viewmat_get(NULL, view_matrix, false); + + /* Turn the light in a way where it's more user friendly to control. */ + copy_v3_v3(wpd->shadow_direction_ws, scene->display.light_direction); + SWAP(float, wpd->shadow_direction_ws[2], wpd->shadow_direction_ws[1]); + wpd->shadow_direction_ws[2] = -wpd->shadow_direction_ws[2]; + wpd->shadow_direction_ws[0] = -wpd->shadow_direction_ws[0]; + + /* Shadow direction. */ + mul_v3_mat3_m4v3(wd->shadow_direction_vs, view_matrix, wpd->shadow_direction_ws); + + /* Clamp to avoid overshadowing and shading errors. */ + float focus = clamp_f(scene->display.shadow_focus, 0.0001f, 0.99999f); + wd->shadow_shift = scene->display.shadow_shift; + wd->shadow_focus = 1.0f - focus * (1.0f - wd->shadow_shift); + + if (SHADOW_ENABLED(wpd)) { + wd->shadow_mul = wpd->shading.shadow_intensity; + wd->shadow_add = 1.0f - wd->shadow_mul; + } + else { + wd->shadow_mul = 0.0f; + wd->shadow_add = 1.0f; + } +} + +void workbench_shadow_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + if (SHADOW_ENABLED(wpd)) { + workbench_shadow_update(wpd); + +#if DEBUG_SHADOW_VOLUME + DRWState depth_pass_state = DRW_STATE_DEPTH_LESS; + DRWState depth_fail_state = DRW_STATE_DEPTH_GREATER_EQUAL; + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ADD_FULL; +#else + DRWState depth_pass_state = DRW_STATE_WRITE_STENCIL_SHADOW_PASS; + DRWState depth_fail_state = DRW_STATE_WRITE_STENCIL_SHADOW_FAIL; + DRWState state = DRW_STATE_DEPTH_LESS | DRW_STATE_STENCIL_ALWAYS; +#endif + + /* TODO(fclem) Merge into one pass with subpasses. */ + DRW_PASS_CREATE(psl->shadow_ps[0], state | depth_pass_state); + DRW_PASS_CREATE(psl->shadow_ps[1], state | depth_fail_state); + + /* Stencil Shadow passes. */ + for (int manifold = 0; manifold < 2; manifold++) { + sh = workbench_shader_shadow_pass_get(manifold); + wpd->shadow_pass_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[0]); + DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */ + + sh = workbench_shader_shadow_fail_get(manifold, false); + wpd->shadow_fail_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]); + DRW_shgroup_stencil_mask(grp, 0xFF); /* Needed once to set the stencil state for the pass. */ + + sh = workbench_shader_shadow_fail_get(manifold, true); + wpd->shadow_fail_caps_grp[manifold] = grp = DRW_shgroup_create(sh, psl->shadow_ps[1]); + } + } + else { + psl->shadow_ps[0] = NULL; + psl->shadow_ps[1] = NULL; + } +} + +static BoundBox *workbench_shadow_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + if (oed->shadow_bbox_dirty || wpd->shadow_changed) { + float tmp_mat[4][4]; + mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat); + + /* Get AABB in shadow space. */ + INIT_MINMAX(oed->shadow_min, oed->shadow_max); + + /* From object space to shadow space */ + BoundBox *bbox = BKE_object_boundbox_get(ob); + for (int i = 0; i < 8; i++) { + float corner[3]; + mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]); + minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner); + } + oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2]; + /* Extend towards infinity. */ + oed->shadow_max[2] += 1e4f; + + /* Get extended AABB in world space. */ + BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max); + for (int i = 0; i < 8; i++) { + mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]); + } + oed->shadow_bbox_dirty = false; + } + + return &oed->shadow_bbox; +} + +static bool workbench_shadow_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed); + const DRWView *default_view = DRW_view_default_get(); + return DRW_culling_box_test(default_view, shadow_bbox); +} + +static float workbench_shadow_object_shadow_distance(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + BoundBox *shadow_bbox = workbench_shadow_object_shadow_bbox_get(wpd, ob, oed); + + int corners[4] = {0, 3, 4, 7}; + float dist = 1e4f, dist_isect; + for (int i = 0; i < 4; i++) { + if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]], + wpd->shadow_cached_direction, + wpd->shadow_far_plane, + &dist_isect, + true)) { + if (dist_isect < dist) { + dist = dist_isect; + } + } + else { + /* All rays are parallels. If one fails, the other will too. */ + break; + } + } + return max_ii(dist - oed->shadow_depth, 0); +} + +static bool workbench_shadow_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, + Object *ob, + WORKBENCH_ObjectData *oed) +{ + /* Just to be sure the min, max are updated. */ + workbench_shadow_object_shadow_bbox_get(wpd, ob, oed); + /* Test if near plane is in front of the shadow. */ + if (oed->shadow_min[2] > wpd->shadow_near_max[2]) { + return false; + } + + /* Separation Axis Theorem test */ + + /* Test bbox sides first (faster) */ + if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) || + (oed->shadow_max[0] < wpd->shadow_near_min[0]) || + (oed->shadow_min[1] > wpd->shadow_near_max[1]) || + (oed->shadow_max[1] < wpd->shadow_near_min[1])) { + return false; + } + /* Test projected near rectangle sides */ + const float pts[4][2] = { + {oed->shadow_min[0], oed->shadow_min[1]}, + {oed->shadow_min[0], oed->shadow_max[1]}, + {oed->shadow_max[0], oed->shadow_min[1]}, + {oed->shadow_max[0], oed->shadow_max[1]}, + }; + + for (int i = 0; i < 2; i++) { + float min_dst = FLT_MAX, max_dst = -FLT_MAX; + for (int j = 0; j < 4; j++) { + float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]); + /* Do min max */ + if (min_dst > dst) { + min_dst = dst; + } + if (max_dst < dst) { + max_dst = dst; + } + } + + if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) { + return false; + } + } + /* No separation axis found. Both shape intersect. */ + return true; +} + +static void workbench_init_object_data(DrawData *dd) +{ + WORKBENCH_ObjectData *data = (WORKBENCH_ObjectData *)dd; + data->shadow_bbox_dirty = true; +} + +void workbench_shadow_cache_populate(WORKBENCH_Data *data, Object *ob, const bool has_transp_mat) +{ + WORKBENCH_PrivateData *wpd = data->stl->wpd; + + bool is_manifold; + struct GPUBatch *geom_shadow = DRW_cache_object_edge_detection_get(ob, &is_manifold); + if (geom_shadow == NULL) { + return; + } + + WORKBENCH_ObjectData *engine_object_data = (WORKBENCH_ObjectData *)DRW_drawdata_ensure( + &ob->id, + &draw_engine_workbench, + sizeof(WORKBENCH_ObjectData), + &workbench_init_object_data, + NULL); + + if (workbench_shadow_object_cast_visible_shadow(wpd, ob, engine_object_data)) { + mul_v3_mat3_m4v3(engine_object_data->shadow_dir, ob->imat, wpd->shadow_direction_ws); + + DRWShadingGroup *grp; + bool use_shadow_pass_technique = !workbench_shadow_camera_in_object_shadow( + wpd, ob, engine_object_data); + + /* Shadow pass technique needs object to be have all its surface opaque. */ + if (has_transp_mat) { + use_shadow_pass_technique = false; + } + + if (use_shadow_pass_technique) { + grp = DRW_shgroup_create_sub(wpd->shadow_pass_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", 1e5f); + DRW_shgroup_call_no_cull(grp, geom_shadow, ob); +#if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){1.0f, 0.0f, 0.0f, 1.0f}); +#endif + } + else { + float extrude_distance = workbench_shadow_object_shadow_distance( + wpd, ob, engine_object_data); + + /* TODO(fclem): only use caps if they are in the view frustum. */ + const bool need_caps = true; + if (need_caps) { + grp = DRW_shgroup_create_sub(wpd->shadow_fail_caps_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); + DRW_shgroup_call_no_cull(grp, DRW_cache_object_surface_get(ob), ob); + } + + grp = DRW_shgroup_create_sub(wpd->shadow_fail_grp[is_manifold]); + DRW_shgroup_uniform_vec3(grp, "lightDirection", engine_object_data->shadow_dir, 1); + DRW_shgroup_uniform_float_copy(grp, "lightDistance", extrude_distance); + DRW_shgroup_call_no_cull(grp, geom_shadow, ob); +#if DEBUG_SHADOW_VOLUME + DRW_debug_bbox(&engine_object_data->shadow_bbox, (float[4]){0.0f, 1.0f, 0.0f, 1.0f}); +#endif + } + } +} diff --git a/source/blender/draw/engines/workbench/workbench_studiolight.c b/source/blender/draw/engines/workbench/workbench_studiolight.c deleted file mode 100644 index 1fb0b394cb1..00000000000 --- a/source/blender/draw/engines/workbench/workbench_studiolight.c +++ /dev/null @@ -1,257 +0,0 @@ -/* - * 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. - * - * Copyright 2016, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ -#include "BKE_studiolight.h" - -#include "workbench_private.h" - -#include "BKE_object.h" - -#include "BLI_math.h" - -void studiolight_update_world(WORKBENCH_PrivateData *wpd, - StudioLight *studiolight, - WORKBENCH_UBO_World *wd) -{ - float view_matrix[4][4], rot_matrix[4][4]; - DRW_view_viewmat_get(NULL, view_matrix, false); - - if (USE_WORLD_ORIENTATION(wpd)) { - axis_angle_to_mat4_single(rot_matrix, 'Z', -wpd->shading.studiolight_rot_z); - mul_m4_m4m4(rot_matrix, view_matrix, rot_matrix); - swap_v3_v3(rot_matrix[2], rot_matrix[1]); - negate_v3(rot_matrix[2]); - } - else { - unit_m4(rot_matrix); - } - - if (U.edit_studio_light) { - studiolight = BKE_studiolight_studio_edit_get(); - } - - /* Studio Lights. */ - for (int i = 0; i < 4; i++) { - WORKBENCH_UBO_Light *light = &wd->lights[i]; - - SolidLight *sl = &studiolight->light[i]; - if (sl->flag) { - copy_v3_v3(light->light_direction, sl->vec); - mul_mat3_m4_v3(rot_matrix, light->light_direction); - /* We should predivide the power by PI but that makes the lights really dim. */ - copy_v3_v3(light->specular_color, sl->spec); - copy_v3_v3(light->diffuse_color, sl->col); - light->wrapped = sl->smooth; - } - else { - copy_v3_fl3(light->light_direction, 1.0f, 0.0f, 0.0f); - copy_v3_fl(light->specular_color, 0.0f); - copy_v3_fl(light->diffuse_color, 0.0f); - } - } - - copy_v3_v3(wd->ambient_color, studiolight->light_ambient); -} - -static void compute_parallel_lines_nor_and_dist(const float v1[2], - const float v2[2], - const float v3[2], - float r_line[4]) -{ - sub_v2_v2v2(r_line, v2, v1); - /* Find orthogonal vector. */ - SWAP(float, r_line[0], r_line[1]); - r_line[0] = -r_line[0]; - /* Edge distances. */ - r_line[2] = dot_v2v2(r_line, v1); - r_line[3] = dot_v2v2(r_line, v3); - /* Make sure r_line[2] is the minimum. */ - if (r_line[2] > r_line[3]) { - SWAP(float, r_line[2], r_line[3]); - } -} - -void studiolight_update_light(WORKBENCH_PrivateData *wpd, const float light_direction[3]) -{ - wpd->shadow_changed = !compare_v3v3(wpd->cached_shadow_direction, light_direction, 1e-5f); - - if (wpd->shadow_changed) { - float up[3] = {0.0f, 0.0f, 1.0f}; - unit_m4(wpd->shadow_mat); - - /* TODO fix singularity. */ - copy_v3_v3(wpd->shadow_mat[2], light_direction); - cross_v3_v3v3(wpd->shadow_mat[0], wpd->shadow_mat[2], up); - normalize_v3(wpd->shadow_mat[0]); - cross_v3_v3v3(wpd->shadow_mat[1], wpd->shadow_mat[2], wpd->shadow_mat[0]); - - invert_m4_m4(wpd->shadow_inv, wpd->shadow_mat); - - copy_v3_v3(wpd->cached_shadow_direction, light_direction); - } - - float planes[6][4]; - DRW_culling_frustum_planes_get(NULL, planes); - /* we only need the far plane. */ - copy_v4_v4(wpd->shadow_far_plane, planes[2]); - - BoundBox frustum_corners; - DRW_culling_frustum_corners_get(NULL, &frustum_corners); - - mul_v3_mat3_m4v3(wpd->shadow_near_corners[0], wpd->shadow_inv, frustum_corners.vec[0]); - mul_v3_mat3_m4v3(wpd->shadow_near_corners[1], wpd->shadow_inv, frustum_corners.vec[3]); - mul_v3_mat3_m4v3(wpd->shadow_near_corners[2], wpd->shadow_inv, frustum_corners.vec[7]); - mul_v3_mat3_m4v3(wpd->shadow_near_corners[3], wpd->shadow_inv, frustum_corners.vec[4]); - - INIT_MINMAX(wpd->shadow_near_min, wpd->shadow_near_max); - for (int i = 0; i < 4; i++) { - minmax_v3v3_v3(wpd->shadow_near_min, wpd->shadow_near_max, wpd->shadow_near_corners[i]); - } - - compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[0], - wpd->shadow_near_corners[1], - wpd->shadow_near_corners[2], - wpd->shadow_near_sides[0]); - compute_parallel_lines_nor_and_dist(wpd->shadow_near_corners[1], - wpd->shadow_near_corners[2], - wpd->shadow_near_corners[0], - wpd->shadow_near_sides[1]); -} - -static BoundBox *studiolight_object_shadow_bbox_get(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - if ((oed->shadow_bbox_dirty) || (wpd->shadow_changed)) { - float tmp_mat[4][4]; - mul_m4_m4m4(tmp_mat, wpd->shadow_inv, ob->obmat); - - /* Get AABB in shadow space. */ - INIT_MINMAX(oed->shadow_min, oed->shadow_max); - - /* From object space to shadow space */ - BoundBox *bbox = BKE_object_boundbox_get(ob); - for (int i = 0; i < 8; i++) { - float corner[3]; - mul_v3_m4v3(corner, tmp_mat, bbox->vec[i]); - minmax_v3v3_v3(oed->shadow_min, oed->shadow_max, corner); - } - oed->shadow_depth = oed->shadow_max[2] - oed->shadow_min[2]; - /* Extend towards infinity. */ - oed->shadow_max[2] += 1e4f; - - /* Get extended AABB in world space. */ - BKE_boundbox_init_from_minmax(&oed->shadow_bbox, oed->shadow_min, oed->shadow_max); - for (int i = 0; i < 8; i++) { - mul_m4_v3(wpd->shadow_mat, oed->shadow_bbox.vec[i]); - } - oed->shadow_bbox_dirty = false; - } - - return &oed->shadow_bbox; -} - -bool studiolight_object_cast_visible_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed); - const DRWView *default_view = DRW_view_default_get(); - return DRW_culling_box_test(default_view, shadow_bbox); -} - -float studiolight_object_shadow_distance(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - BoundBox *shadow_bbox = studiolight_object_shadow_bbox_get(wpd, ob, oed); - - int corners[4] = {0, 3, 4, 7}; - float dist = 1e4f, dist_isect; - for (int i = 0; i < 4; i++) { - if (isect_ray_plane_v3(shadow_bbox->vec[corners[i]], - wpd->cached_shadow_direction, - wpd->shadow_far_plane, - &dist_isect, - true)) { - if (dist_isect < dist) { - dist = dist_isect; - } - } - else { - /* All rays are parallels. If one fails, the other will too. */ - break; - } - } - return max_ii(dist - oed->shadow_depth, 0); -} - -bool studiolight_camera_in_object_shadow(WORKBENCH_PrivateData *wpd, - Object *ob, - WORKBENCH_ObjectData *oed) -{ - /* Just to be sure the min, max are updated. */ - studiolight_object_shadow_bbox_get(wpd, ob, oed); - - /* Test if near plane is in front of the shadow. */ - if (oed->shadow_min[2] > wpd->shadow_near_max[2]) { - return false; - } - - /* Separation Axis Theorem test */ - - /* Test bbox sides first (faster) */ - if ((oed->shadow_min[0] > wpd->shadow_near_max[0]) || - (oed->shadow_max[0] < wpd->shadow_near_min[0]) || - (oed->shadow_min[1] > wpd->shadow_near_max[1]) || - (oed->shadow_max[1] < wpd->shadow_near_min[1])) { - return false; - } - - /* Test projected near rectangle sides */ - const float pts[4][2] = { - {oed->shadow_min[0], oed->shadow_min[1]}, - {oed->shadow_min[0], oed->shadow_max[1]}, - {oed->shadow_max[0], oed->shadow_min[1]}, - {oed->shadow_max[0], oed->shadow_max[1]}, - }; - - for (int i = 0; i < 2; i++) { - float min_dst = FLT_MAX, max_dst = -FLT_MAX; - for (int j = 0; j < 4; j++) { - float dst = dot_v2v2(wpd->shadow_near_sides[i], pts[j]); - /* Do min max */ - if (min_dst > dst) { - min_dst = dst; - } - if (max_dst < dst) { - max_dst = dst; - } - } - - if ((wpd->shadow_near_sides[i][2] > max_dst) || (wpd->shadow_near_sides[i][3] < min_dst)) { - return false; - } - } - - /* No separation axis found. Both shape intersect. */ - return true; -} diff --git a/source/blender/draw/engines/workbench/workbench_transparent.c b/source/blender/draw/engines/workbench/workbench_transparent.c new file mode 100644 index 00000000000..39aa721a41c --- /dev/null +++ b/source/blender/draw/engines/workbench/workbench_transparent.c @@ -0,0 +1,180 @@ +/* + * 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. + * + * Copyright 2020, Blender Foundation. + */ + +/** \file + * \ingroup draw_engine + * + * Transparent Pipeline: + * + * Use Weight Blended Order Independent Transparency to render transparent surfaces. + * + * The rendering is broken down in two passes: + * - the accumulation pass where we render all the surfaces and accumulate all the weights. + * - the resolve pass where we divide the accumulated information by the weights. + * + * An additional re-render of the transparent surfaces is sometime done in order to have their + * correct depth and object ids correctly written. + */ + +#include "DRW_render.h" + +#include "ED_view3d.h" + +#include "GPU_extensions.h" + +#include "workbench_engine.h" +#include "workbench_private.h" + +void workbench_transparent_engine_init(WORKBENCH_Data *data) +{ + WORKBENCH_FramebufferList *fbl = data->fbl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); + DrawEngineType *owner = (DrawEngineType *)&workbench_transparent_engine_init; + + /* Reuse same format as opaque pipeline to reuse the textures. */ + /* Note: Floating point texture is required for the reveal_tex as it is used for + * the alpha accumulation component (see accumulation shader for more explanation). */ + const eGPUTextureFormat accum_tex_format = GPU_RGBA16F; + const eGPUTextureFormat reveal_tex_format = NORMAL_ENCODING_ENABLED() ? GPU_RG16F : GPU_RGBA32F; + + wpd->accum_buffer_tx = DRW_texture_pool_query_fullscreen(accum_tex_format, owner); + wpd->reveal_buffer_tx = DRW_texture_pool_query_fullscreen(reveal_tex_format, owner); + + GPU_framebuffer_ensure_config(&fbl->transp_accum_fb, + { + GPU_ATTACHMENT_TEXTURE(dtxl->depth), + GPU_ATTACHMENT_TEXTURE(wpd->accum_buffer_tx), + GPU_ATTACHMENT_TEXTURE(wpd->reveal_buffer_tx), + }); +} + +static void workbench_transparent_lighting_uniforms(WORKBENCH_PrivateData *wpd, + DRWShadingGroup *grp) +{ + DRW_shgroup_uniform_block_persistent(grp, "world_block", wpd->world_ubo); + DRW_shgroup_uniform_bool_copy(grp, "forceShadowing", false); + + if (STUDIOLIGHT_TYPE_MATCAP_ENABLED(wpd)) { + BKE_studiolight_ensure_flag(wpd->studio_light, + STUDIOLIGHT_MATCAP_DIFFUSE_GPUTEXTURE | + STUDIOLIGHT_MATCAP_SPECULAR_GPUTEXTURE); + struct GPUTexture *diff_tx = wpd->studio_light->matcap_diffuse.gputexture; + struct GPUTexture *spec_tx = wpd->studio_light->matcap_specular.gputexture; + const bool use_spec = workbench_is_specular_highlight_enabled(wpd); + spec_tx = (use_spec && spec_tx) ? spec_tx : diff_tx; + DRW_shgroup_uniform_texture_persistent(grp, "matcapDiffuseImage", diff_tx); + DRW_shgroup_uniform_texture_persistent(grp, "matcapSpecularImage", spec_tx); + } +} + +void workbench_transparent_cache_init(WORKBENCH_Data *data) +{ + WORKBENCH_PassList *psl = data->psl; + WORKBENCH_PrivateData *wpd = data->stl->wpd; + struct GPUShader *sh; + DRWShadingGroup *grp; + + { + int transp = 1; + for (int infront = 0; infront < 2; infront++) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_DEPTH_LESS_EQUAL | DRW_STATE_BLEND_OIT; + + DRWPass *pass; + if (infront) { + DRW_PASS_CREATE(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->transp_accum_infront_ps; + } + else { + DRW_PASS_CREATE(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state); + pass = psl->transp_accum_ps; + } + + for (int hair = 0; hair < 2; hair++) { + wpd->prepass[transp][infront][hair].material_hash = BLI_ghash_ptr_new(__func__); + + sh = workbench_shader_transparent_get(wpd, hair); + + wpd->prepass[transp][infront][hair].common_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", -1); + workbench_transparent_lighting_uniforms(wpd, grp); + + wpd->prepass[transp][infront][hair].vcol_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. (uses vcol) */ + + sh = workbench_shader_transparent_image_get(wpd, hair, false); + + wpd->prepass[transp][infront][hair].image_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + workbench_transparent_lighting_uniforms(wpd, grp); + + sh = workbench_shader_transparent_image_get(wpd, hair, true); + + wpd->prepass[transp][infront][hair].image_tiled_shgrp = grp = DRW_shgroup_create(sh, pass); + DRW_shgroup_uniform_block_persistent(grp, "material_block", wpd->material_ubo_curr); + DRW_shgroup_uniform_int_copy(grp, "materialIndex", 0); /* Default material. */ + workbench_transparent_lighting_uniforms(wpd, grp); + } + } + } + { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA; + + DRW_PASS_CREATE(psl->transp_resolve_ps, state); + + sh = workbench_shader_transparent_resolve_get(wpd); + + grp = DRW_shgroup_create(sh, psl->transp_resolve_ps); + DRW_shgroup_uniform_texture(grp, "transparentAccum", wpd->accum_buffer_tx); + DRW_shgroup_uniform_texture(grp, "transparentRevealage", wpd->reveal_buffer_tx); + DRW_shgroup_call_procedural_triangles(grp, NULL, 1); + } +} + +/* Redraw the transparent passes but with depth test + * to output correct outline IDs and depth. */ +void workbench_transparent_draw_depth_pass(WORKBENCH_Data *data) +{ + WORKBENCH_PrivateData *wpd = data->stl->wpd; + WORKBENCH_FramebufferList *fbl = data->fbl; + WORKBENCH_PassList *psl = data->psl; + + const bool do_xray_depth_pass = XRAY_ALPHA(wpd) > 0.0f; + const bool do_transparent_depth_pass = psl->outline_ps || wpd->dof_enabled || do_xray_depth_pass; + + if (do_transparent_depth_pass) { + DRWState state = DRW_STATE_WRITE_COLOR | DRW_STATE_WRITE_DEPTH | DRW_STATE_DEPTH_LESS_EQUAL; + + if (!DRW_pass_is_empty(psl->transp_accum_ps)) { + GPU_framebuffer_bind(fbl->opaque_fb); + /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + DRW_pass_state_set(psl->transp_accum_ps, state | wpd->cull_state | wpd->clip_state); + DRW_draw_pass(psl->transp_accum_ps); + } + + if (!DRW_pass_is_empty(psl->transp_accum_infront_ps)) { + GPU_framebuffer_bind(fbl->opaque_infront_fb); + /* TODO(fclem) Disable writting to first two buffers. Unecessary waste of bandwidth. */ + DRW_pass_state_set(psl->transp_accum_infront_ps, state | wpd->cull_state | wpd->clip_state); + DRW_draw_pass(psl->transp_accum_infront_ps); + } + } +} diff --git a/source/blender/draw/engines/workbench/workbench_volume.c b/source/blender/draw/engines/workbench/workbench_volume.c index 2f7296fb40f..a3072b834bd 100644 --- a/source/blender/draw/engines/workbench/workbench_volume.c +++ b/source/blender/draw/engines/workbench/workbench_volume.c @@ -35,87 +35,23 @@ #include "GPU_draw.h" -enum { - VOLUME_SH_SLICE = 0, - VOLUME_SH_COBA, - VOLUME_SH_CUBIC, -}; - -#define VOLUME_SH_MAX (1 << (VOLUME_SH_CUBIC + 1)) - -static struct { - struct GPUShader *volume_sh[VOLUME_SH_MAX]; - struct GPUShader *volume_coba_sh; - struct GPUTexture *dummy_tex; - struct GPUTexture *dummy_coba_tex; -} e_data = {{NULL}}; - -extern char datatoc_workbench_volume_vert_glsl[]; -extern char datatoc_workbench_volume_frag_glsl[]; -extern char datatoc_common_view_lib_glsl[]; -extern char datatoc_gpu_shader_common_obinfos_lib_glsl[]; - -static GPUShader *volume_shader_get(bool slice, bool coba, bool cubic) +void workbench_volume_engine_init(WORKBENCH_Data *vedata) { - int id = 0; - id += (slice) ? (1 << VOLUME_SH_SLICE) : 0; - id += (coba) ? (1 << VOLUME_SH_COBA) : 0; - id += (cubic) ? (1 << VOLUME_SH_CUBIC) : 0; - - if (!e_data.volume_sh[id]) { - DynStr *ds = BLI_dynstr_new(); - - if (slice) { - BLI_dynstr_append(ds, "#define VOLUME_SLICE\n"); - } - if (coba) { - BLI_dynstr_append(ds, "#define USE_COBA\n"); - } - if (cubic) { - BLI_dynstr_append(ds, "#define USE_TRICUBIC\n"); - } - - char *defines = BLI_dynstr_get_cstring(ds); - BLI_dynstr_free(ds); - - char *libs = BLI_string_joinN(datatoc_common_view_lib_glsl, - datatoc_gpu_shader_common_obinfos_lib_glsl); - - e_data.volume_sh[id] = DRW_shader_create_with_lib(datatoc_workbench_volume_vert_glsl, - NULL, - datatoc_workbench_volume_frag_glsl, - libs, - defines); - - MEM_freeN(libs); - MEM_freeN(defines); - } - - return e_data.volume_sh[id]; -} + WORKBENCH_TextureList *txl = vedata->txl; -void workbench_volume_engine_init(void) -{ - if (!e_data.dummy_tex) { + if (txl->dummy_volume_tx == NULL) { float pixel[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - e_data.dummy_tex = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL); - e_data.dummy_coba_tex = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL); + txl->dummy_volume_tx = GPU_texture_create_3d(1, 1, 1, GPU_RGBA8, pixel, NULL); + txl->dummy_coba_tx = GPU_texture_create_1d(1, GPU_RGBA8, pixel, NULL); } } -void workbench_volume_engine_free(void) -{ - for (int i = 0; i < VOLUME_SH_MAX; i++) { - DRW_SHADER_FREE_SAFE(e_data.volume_sh[i]); - } - DRW_TEXTURE_FREE_SAFE(e_data.dummy_tex); - DRW_TEXTURE_FREE_SAFE(e_data.dummy_coba_tex); -} - void workbench_volume_cache_init(WORKBENCH_Data *vedata) { - vedata->psl->volume_pass = DRW_pass_create( + vedata->psl->volume_ps = DRW_pass_create( "Volumes", DRW_STATE_WRITE_COLOR | DRW_STATE_BLEND_ALPHA_PREMUL | DRW_STATE_CULL_FRONT); + + vedata->stl->wpd->volumes_do = false; } void workbench_volume_cache_populate(WORKBENCH_Data *vedata, @@ -125,8 +61,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, { FluidModifierData *mmd = (FluidModifierData *)md; FluidDomainSettings *mds = mmd->domain; - WORKBENCH_PrivateData *wpd = vedata->stl->g_data; - WORKBENCH_EffectInfo *effect_info = vedata->stl->effects; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + WORKBENCH_TextureList *txl = vedata->txl; DefaultTextureList *dtxl = DRW_viewport_texture_list_get(); DRWShadingGroup *grp = NULL; @@ -146,14 +82,16 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, GPU_create_smoke(mmd, 1); } - if ((!mds->use_coba && mds->tex == NULL) || (mds->use_coba && mds->tex_field == NULL)) { + if ((!mds->use_coba && (mds->tex_density == NULL && mds->tex_color == NULL)) || + (mds->use_coba && mds->tex_field == NULL)) { return; } const bool use_slice = (mds->slice_method == FLUID_DOMAIN_SLICE_AXIS_ALIGNED && mds->axis_slice_method == AXIS_SLICE_SINGLE); const bool cubic_interp = (mds->interp_method == VOLUME_INTERP_CUBIC); - GPUShader *sh = volume_shader_get(use_slice, mds->use_coba, cubic_interp); + + GPUShader *sh = workbench_shader_volume_get(use_slice, mds->use_coba, cubic_interp); if (use_slice) { float invviewmat[4][4]; @@ -167,7 +105,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, /* 0.05f to achieve somewhat the same opacity as the full view. */ float step_length = max_ff(1e-16f, dim[axis] * 0.05f); - grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); + grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); DRW_shgroup_uniform_float_copy(grp, "slicePosition", mds->slice_depth); DRW_shgroup_uniform_int_copy(grp, "sliceAxis", axis); DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); @@ -175,7 +113,7 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, } else { double noise_ofs; - BLI_halton_1d(3, 0.0, effect_info->jitter_index, &noise_ofs); + BLI_halton_1d(3, 0.0, wpd->taa_sample, &noise_ofs); float dim[3], step_length, max_slice; float slice_ct[3] = {mds->res[0], mds->res[1], mds->res[2]}; mul_v3_fl(slice_ct, max_ff(0.001f, mds->slice_per_voxel)); @@ -185,8 +123,8 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, mul_v3_v3(dim, slice_ct); step_length = len_v3(dim); - grp = DRW_shgroup_create(sh, vedata->psl->volume_pass); - DRW_shgroup_uniform_vec4(grp, "viewvecs[0]", (float *)wpd->viewvecs, 3); + grp = DRW_shgroup_create(sh, vedata->psl->volume_ps); + DRW_shgroup_uniform_block(grp, "world_block", wpd->world_ubo); DRW_shgroup_uniform_int_copy(grp, "samplesLen", max_slice); DRW_shgroup_uniform_float_copy(grp, "stepLength", step_length); DRW_shgroup_uniform_float_copy(grp, "noiseOfs", noise_ofs); @@ -201,12 +139,13 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, static float white[3] = {1.0f, 1.0f, 1.0f}; bool use_constant_color = ((mds->active_fields & FLUID_DOMAIN_ACTIVE_COLORS) == 0 && (mds->active_fields & FLUID_DOMAIN_ACTIVE_COLOR_SET) != 0); - DRW_shgroup_uniform_texture(grp, "densityTexture", mds->tex); + DRW_shgroup_uniform_texture( + grp, "densityTexture", (mds->tex_color) ? mds->tex_color : mds->tex_density); DRW_shgroup_uniform_texture(grp, "shadowTexture", mds->tex_shadow); DRW_shgroup_uniform_texture( - grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : e_data.dummy_tex); + grp, "flameTexture", (mds->tex_flame) ? mds->tex_flame : txl->dummy_volume_tx); DRW_shgroup_uniform_texture( - grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : e_data.dummy_coba_tex); + grp, "flameColorTexture", (mds->tex_flame) ? mds->tex_flame_coba : txl->dummy_coba_tx); DRW_shgroup_uniform_vec3( grp, "activeColor", (use_constant_color) ? mds->active_color : white, 1); } @@ -223,8 +162,22 @@ void workbench_volume_cache_populate(WORKBENCH_Data *vedata, BLI_addtail(&wpd->smoke_domains, BLI_genericNodeN(mmd)); } -void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd) +void workbench_volume_draw_pass(WORKBENCH_Data *vedata) { + WORKBENCH_PassList *psl = vedata->psl; + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + DefaultFramebufferList *dfbl = DRW_viewport_framebuffer_list_get(); + + if (wpd->volumes_do) { + GPU_framebuffer_bind(dfbl->color_only_fb); + DRW_draw_pass(psl->volume_ps); + } +} + +void workbench_volume_draw_finish(WORKBENCH_Data *vedata) +{ + WORKBENCH_PrivateData *wpd = vedata->stl->wpd; + /* Free Smoke Textures after rendering */ /* XXX This is a waste of processing and GPU bandwidth if nothing * is updated. But the problem is since Textures are stored in the @@ -236,4 +189,4 @@ void workbench_volume_smoke_textures_free(WORKBENCH_PrivateData *wpd) GPU_free_smoke(mmd); } BLI_freelistN(&wpd->smoke_domains); -} +}
\ No newline at end of file diff --git a/source/blender/draw/intern/DRW_render.h b/source/blender/draw/intern/DRW_render.h index cc257b80daf..8ed7bb25336 100644 --- a/source/blender/draw/intern/DRW_render.h +++ b/source/blender/draw/intern/DRW_render.h @@ -81,6 +81,7 @@ typedef struct DRWPass DRWPass; typedef struct DRWShadingGroup DRWShadingGroup; typedef struct DRWUniform DRWUniform; typedef struct DRWView DRWView; +typedef struct DRWShaderLibrary DRWShaderLibrary; /* TODO Put it somewhere else? */ typedef struct BoundSphere { @@ -148,6 +149,8 @@ struct GPUTexture *DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, DrawEngineType *engine_type); +struct GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format, + DrawEngineType *engine_type); struct GPUTexture *DRW_texture_create_1d(int w, eGPUTextureFormat format, @@ -163,6 +166,8 @@ struct GPUTexture *DRW_texture_create_cube(int w, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels); +struct GPUTexture *DRW_texture_create_cube_array( + int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels); void DRW_texture_ensure_fullscreen_2d(struct GPUTexture **tex, eGPUTextureFormat format, @@ -211,16 +216,17 @@ struct GPUShader *DRW_shader_create_fullscreen(const char *frag, const char *def struct GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig slot); struct GPUMaterial *DRW_shader_find_from_world(struct World *wo, const void *engine_type, - int options, + const int options, bool deferred); struct GPUMaterial *DRW_shader_find_from_material(struct Material *ma, const void *engine_type, - int options, + const int options, bool deferred); struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, struct World *wo, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -229,7 +235,8 @@ struct GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, struct GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, struct Material *ma, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -244,51 +251,72 @@ void DRW_shader_free(struct GPUShader *shader); } \ } while (0) -/* Batches */ +DRWShaderLibrary *DRW_shader_library_create(void); + +/* Warning: Each library must be added after all its dependencies. */ +void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name); +#define DRW_SHADER_LIB_ADD(lib, lib_name) \ + DRW_shader_library_add_file(lib, datatoc_##lib_name##_glsl, STRINGIFY(lib_name) ".glsl") + +char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code); + +void DRW_shader_library_free(DRWShaderLibrary *lib); +#define DRW_SHADER_LIB_FREE_SAFE(lib) \ + do { \ + if (lib != NULL) { \ + DRW_shader_library_free(lib); \ + lib = NULL; \ + } \ + } while (0) +/* Batches */ +/* DRWState is a bitmask that stores the current render state and the desired render state. Based + * on the differences the minimum state changes can be invoked to setup the desired render state. + * + * The Write Stencil, Stencil test, Depth test and Blend state options are mutual exclusive + * therefore they aren't ordered as a bit mask.*/ typedef enum { /** Write mask */ DRW_STATE_WRITE_DEPTH = (1 << 0), DRW_STATE_WRITE_COLOR = (1 << 1), + /* Write Stencil. These options are mutual exclusive and packed into 2 bits */ DRW_STATE_WRITE_STENCIL = (1 << 2), - DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (1 << 3), - DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (1 << 4), - - /** Depth test */ - DRW_STATE_DEPTH_ALWAYS = (1 << 5), - DRW_STATE_DEPTH_LESS = (1 << 6), - DRW_STATE_DEPTH_LESS_EQUAL = (1 << 7), - DRW_STATE_DEPTH_EQUAL = (1 << 8), - DRW_STATE_DEPTH_GREATER = (1 << 9), - DRW_STATE_DEPTH_GREATER_EQUAL = (1 << 10), + DRW_STATE_WRITE_STENCIL_SHADOW_PASS = (2 << 2), + DRW_STATE_WRITE_STENCIL_SHADOW_FAIL = (3 << 2), + /** Depth test. These options are mutual exclusive and packed into 3 bits */ + DRW_STATE_DEPTH_ALWAYS = (1 << 4), + DRW_STATE_DEPTH_LESS = (2 << 4), + DRW_STATE_DEPTH_LESS_EQUAL = (3 << 4), + DRW_STATE_DEPTH_EQUAL = (4 << 4), + DRW_STATE_DEPTH_GREATER = (5 << 4), + DRW_STATE_DEPTH_GREATER_EQUAL = (6 << 4), /** Culling test */ - DRW_STATE_CULL_BACK = (1 << 11), - DRW_STATE_CULL_FRONT = (1 << 12), - /** Stencil test */ - DRW_STATE_STENCIL_ALWAYS = (1 << 13), - DRW_STATE_STENCIL_EQUAL = (1 << 14), - DRW_STATE_STENCIL_NEQUAL = (1 << 15), - - /** Blend state */ - DRW_STATE_BLEND_ADD = (1 << 16), + DRW_STATE_CULL_BACK = (1 << 7), + DRW_STATE_CULL_FRONT = (1 << 8), + /** Stencil test . These options are mutal exclusive and packed into 2 bits*/ + DRW_STATE_STENCIL_ALWAYS = (1 << 9), + DRW_STATE_STENCIL_EQUAL = (2 << 9), + DRW_STATE_STENCIL_NEQUAL = (3 << 9), + + /** Blend state. These options are mutual exclusive and packed into 4 bits */ + DRW_STATE_BLEND_ADD = (1 << 11), /** Same as additive but let alpha accumulate without premult. */ - DRW_STATE_BLEND_ADD_FULL = (1 << 17), + DRW_STATE_BLEND_ADD_FULL = (2 << 11), /** Standard alpha blending. */ - DRW_STATE_BLEND_ALPHA = (1 << 18), + DRW_STATE_BLEND_ALPHA = (3 << 11), /** Use that if color is already premult by alpha. */ - DRW_STATE_BLEND_ALPHA_PREMUL = (1 << 19), - DRW_STATE_BLEND_BACKGROUND = (1 << 20), - DRW_STATE_BLEND_OIT = (1 << 21), - DRW_STATE_BLEND_MUL = (1 << 22), - DRW_STATE_BLEND_SUB = (1 << 23), + DRW_STATE_BLEND_ALPHA_PREMUL = (4 << 11), + DRW_STATE_BLEND_BACKGROUND = (5 << 11), + DRW_STATE_BLEND_OIT = (6 << 11), + DRW_STATE_BLEND_MUL = (7 << 11), + DRW_STATE_BLEND_SUB = (8 << 11), /** Use dual source blending. WARNING: Only one color buffer allowed. */ - DRW_STATE_BLEND_CUSTOM = (1 << 24), + DRW_STATE_BLEND_CUSTOM = (9 << 11), + DRW_STATE_LOGIC_INVERT = (10 << 11), - DRW_STATE_IN_FRONT_SELECT = (1 << 25), - DRW_STATE_LOGIC_INVERT = (1 << 26), - DRW_STATE_SHADOW_OFFSET = (1 << 27), - DRW_STATE_CLIP_PLANES = (1 << 28), - // DRW_STATE_WIRE_SMOOTH = (1 << 29), /* UNUSED */ + DRW_STATE_IN_FRONT_SELECT = (1 << 27), + DRW_STATE_SHADOW_OFFSET = (1 << 28), + DRW_STATE_CLIP_PLANES = (1 << 29), DRW_STATE_FIRST_VERTEX_CONVENTION = (1 << 30), /** DO NOT USE. Assumed always enabled. Only used internally. */ DRW_STATE_PROGRAM_POINT_SIZE = (1u << 31), @@ -401,18 +429,21 @@ void DRW_buffer_add_entry_array(DRWCallBuffer *buffer, const void *attr[], uint DRW_buffer_add_entry_array(buffer, array, (sizeof(array) / sizeof(*array))); \ } while (0) +/* Can only be called during iter phase. */ +uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)); + void DRW_shgroup_state_enable(DRWShadingGroup *shgroup, DRWState state); void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state); /* Reminders: * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) * stencil_value being the value stored in the stencil buffer. - * - (writemask & reference) is what gets written if the test condition is fullfiled. + * - (write-mask & reference) is what gets written if the test condition is fulfilled. **/ void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, uint write_mask, uint reference, - uint comp_mask); + uint compare_mask); /* TODO remove this function. Obsolete version. mask is actually reference value. */ void DRW_shgroup_stencil_mask(DRWShadingGroup *shgroup, uint mask); diff --git a/source/blender/draw/intern/draw_common.h b/source/blender/draw/intern/draw_common.h index 24d3b7fa7b6..5818d84a7af 100644 --- a/source/blender/draw/intern/draw_common.h +++ b/source/blender/draw/intern/draw_common.h @@ -177,6 +177,11 @@ struct DRWShadingGroup *DRW_shgroup_hair_create(struct Object *object, struct DRWPass *hair_pass, struct GPUShader *shader); +struct DRWShadingGroup *DRW_shgroup_hair_create_sub(struct Object *object, + struct ParticleSystem *psys, + struct ModifierData *md, + struct DRWShadingGroup *shgrp); + struct DRWShadingGroup *DRW_shgroup_material_hair_create(struct Object *object, struct ParticleSystem *psys, struct ModifierData *md, diff --git a/source/blender/draw/intern/draw_hair.c b/source/blender/draw/intern/draw_hair.c index 08256b931ba..c88071dc6d6 100644 --- a/source/blender/draw/intern/draw_hair.c +++ b/source/blender/draw/intern/draw_hair.c @@ -36,6 +36,7 @@ #include "GPU_batch.h" #include "GPU_shader.h" +#include "GPU_vertex_buffer.h" #include "draw_hair_private.h" @@ -62,6 +63,8 @@ static int g_tf_target_width; static int g_tf_target_height; #endif +static GPUVertBuf *g_dummy_vbo = NULL; +static GPUTexture *g_dummy_texture = NULL; static GPUShader *g_refine_shaders[PART_REFINE_MAX_SHADER] = {NULL}; static DRWPass *g_tf_pass; /* XXX can be a problem with multiple DRWManager in the future */ @@ -102,12 +105,29 @@ void DRW_hair_init(void) #else g_tf_pass = DRW_pass_create("Update Hair Pass", DRW_STATE_WRITE_COLOR); #endif + + if (g_dummy_vbo == NULL) { + /* initialize vertex format */ + GPUVertFormat format = {0}; + uint dummy_id = GPU_vertformat_attr_add(&format, "dummy", GPU_COMP_F32, 4, GPU_FETCH_FLOAT); + + g_dummy_vbo = GPU_vertbuf_create_with_format(&format); + + float vert[4] = {0.0f, 0.0f, 0.0f, 0.0f}; + GPU_vertbuf_data_alloc(g_dummy_vbo, 1); + GPU_vertbuf_attr_fill(g_dummy_vbo, dummy_id, vert); + /* Create vbo immediately to bind to texture buffer. */ + GPU_vertbuf_use(g_dummy_vbo); + + g_dummy_texture = GPU_texture_create_from_vertbuf(g_dummy_vbo); + } } static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, + DRWShadingGroup *shgrp_parent, struct GPUMaterial *gpu_mat, GPUShader *gpu_shader) { @@ -127,7 +147,10 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, object, psys, md, &hair_cache, subdiv, thickness_res); DRWShadingGroup *shgrp; - if (gpu_mat) { + if (shgrp_parent) { + shgrp = DRW_shgroup_create_sub(shgrp_parent); + } + else if (gpu_mat) { shgrp = DRW_shgroup_material_create(gpu_mat, hair_pass); } else if (gpu_shader) { @@ -151,6 +174,17 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, } } + /* Fix issue with certain driver not drawing anything if there is no texture bound to + * "ac", "au", "u" or "c". */ + if (hair_cache->num_uv_layers == 0) { + DRW_shgroup_uniform_texture(shgrp, "u", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "au", g_dummy_texture); + } + if (hair_cache->num_col_layers == 0) { + DRW_shgroup_uniform_texture(shgrp, "c", g_dummy_texture); + DRW_shgroup_uniform_texture(shgrp, "ac", g_dummy_texture); + } + if ((dupli_parent != NULL) && (dupli_object != NULL)) { if (dupli_object->type & OB_DUPLICOLLECTION) { copy_m4_m4(dupli_mat, dupli_parent->obmat); @@ -220,7 +254,15 @@ static DRWShadingGroup *drw_shgroup_create_hair_procedural_ex(Object *object, DRWShadingGroup *DRW_shgroup_hair_create( Object *object, ParticleSystem *psys, ModifierData *md, DRWPass *hair_pass, GPUShader *shader) { - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, shader); + return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, NULL, shader); +} + +DRWShadingGroup *DRW_shgroup_hair_create_sub(Object *object, + ParticleSystem *psys, + ModifierData *md, + DRWShadingGroup *shgrp) +{ + return drw_shgroup_create_hair_procedural_ex(object, psys, md, NULL, shgrp, NULL, NULL); } DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object, @@ -229,7 +271,7 @@ DRWShadingGroup *DRW_shgroup_material_hair_create(Object *object, DRWPass *hair_pass, struct GPUMaterial *material) { - return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, material, NULL); + return drw_shgroup_create_hair_procedural_ex(object, psys, md, hair_pass, NULL, material, NULL); } void DRW_hair_update(void) @@ -313,4 +355,7 @@ void DRW_hair_free(void) for (int i = 0; i < PART_REFINE_MAX_SHADER; i++) { DRW_SHADER_FREE_SAFE(g_refine_shaders[i]); } + + GPU_VERTBUF_DISCARD_SAFE(g_dummy_vbo); + DRW_TEXTURE_FREE_SAFE(g_dummy_texture); } diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index b9711b4f88f..6d81d82a6cf 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1118,45 +1118,23 @@ 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 */ -static void drw_engines_enable_from_engine(RenderEngineType *engine_type, - eDrawType drawtype, - bool use_xray) +static void drw_engines_enable_from_engine(RenderEngineType *engine_type, eDrawType drawtype) { switch (drawtype) { case OB_WIRE: - use_drw_engine(&draw_engine_workbench_transparent); - break; - case OB_SOLID: - if (use_xray) { - use_drw_engine(&draw_engine_workbench_transparent); - } - else { - use_drw_engine(&draw_engine_workbench_solid); - } + use_drw_engine(DRW_engine_viewport_workbench_type.draw_engine); break; - case OB_MATERIAL: case OB_RENDER: default: - /* TODO layers */ if (engine_type->draw_engine != NULL) { use_drw_engine(engine_type->draw_engine); } - - if ((engine_type->flag & RE_INTERNAL) == 0) { - drw_engines_enable_external(); + else if ((engine_type->flag & RE_INTERNAL) == 0) { + use_drw_engine(DRW_engine_viewport_external_type.draw_engine); } break; } @@ -1182,7 +1160,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer), const eDrawType drawtype = v3d->shading.type; const bool use_xray = XRAY_ENABLED(v3d); - drw_engines_enable_from_engine(engine_type, drawtype, use_xray); + drw_engines_enable_from_engine(engine_type, drawtype); if (gpencil_engine_needed && ((drawtype >= OB_SOLID) || !use_xray)) { use_drw_engine(&draw_engine_gpencil_type); } @@ -1608,6 +1586,9 @@ void DRW_draw_render_loop_offscreen(struct Depsgraph *depsgraph, GPU_blend(true); } + GPU_matrix_identity_set(); + GPU_matrix_identity_projection_set(); + GPU_viewport_unbind_from_offscreen(render_viewport, ofs, do_color_management); if (draw_background) { @@ -2646,9 +2627,6 @@ void DRW_engines_register(void) RE_engines_register(&DRW_engine_viewport_eevee_type); RE_engines_register(&DRW_engine_viewport_workbench_type); - DRW_engine_register(&draw_engine_workbench_solid); - DRW_engine_register(&draw_engine_workbench_transparent); - DRW_engine_register(&draw_engine_gpencil_type); DRW_engine_register(&draw_engine_overlay_type); diff --git a/source/blender/draw/intern/draw_manager_data.c b/source/blender/draw/intern/draw_manager_data.c index 83142da051a..be0dd7751ed 100644 --- a/source/blender/draw/intern/draw_manager_data.c +++ b/source/blender/draw/intern/draw_manager_data.c @@ -562,6 +562,16 @@ static DRWResourceHandle drw_resource_handle_new(float (*obmat)[4], Object *ob) return handle; } +uint32_t DRW_object_resource_id_get(Object *UNUSED(ob)) +{ + DRWResourceHandle handle = DST.ob_handle; + if (handle == 0) { + /* Handle not yet allocated. Return next handle. */ + handle = DST.resource_handle; + } + return handle; +} + static DRWResourceHandle drw_resource_handle(DRWShadingGroup *shgroup, float (*obmat)[4], Object *ob) @@ -693,14 +703,14 @@ static void drw_command_set_select_id(DRWShadingGroup *shgroup, GPUVertBuf *buf, static void drw_command_set_stencil_mask(DRWShadingGroup *shgroup, uint write_mask, uint reference, - uint comp_mask) + uint compare_mask) { BLI_assert(write_mask <= 0xFF); BLI_assert(reference <= 0xFF); - BLI_assert(comp_mask <= 0xFF); + BLI_assert(compare_mask <= 0xFF); DRWCommandSetStencil *cmd = drw_command_create(shgroup, DRW_CMD_STENCIL); cmd->write_mask = write_mask; - cmd->comp_mask = comp_mask; + cmd->comp_mask = compare_mask; cmd->ref = reference; } @@ -1341,9 +1351,9 @@ void DRW_shgroup_state_disable(DRWShadingGroup *shgroup, DRWState state) void DRW_shgroup_stencil_set(DRWShadingGroup *shgroup, uint write_mask, uint reference, - uint comp_mask) + uint compare_mask) { - drw_command_set_stencil_mask(shgroup, write_mask, reference, comp_mask); + drw_command_set_stencil_mask(shgroup, write_mask, reference, compare_mask); } /* TODO remove this function. */ diff --git a/source/blender/draw/intern/draw_manager_exec.c b/source/blender/draw/intern/draw_manager_exec.c index 85525ea7b55..3d1b43537b7 100644 --- a/source/blender/draw/intern/draw_manager_exec.c +++ b/source/blender/draw/intern/draw_manager_exec.c @@ -114,19 +114,20 @@ void drw_state_set(DRWState state) /* Stencil Write */ if (test) { glStencilMask(0xFF); - if (test & DRW_STATE_WRITE_STENCIL) { - glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); - } - else if (test & DRW_STATE_WRITE_STENCIL_SHADOW_PASS) { - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP); - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP); - } - else if (test & DRW_STATE_WRITE_STENCIL_SHADOW_FAIL) { - glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP); - glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP); - } - else { - BLI_assert(0); + switch (test) { + case DRW_STATE_WRITE_STENCIL: + glStencilOp(GL_KEEP, GL_KEEP, GL_REPLACE); + break; + case DRW_STATE_WRITE_STENCIL_SHADOW_PASS: + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_KEEP, GL_INCR_WRAP); + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_KEEP, GL_DECR_WRAP); + break; + case DRW_STATE_WRITE_STENCIL_SHADOW_FAIL: + glStencilOpSeparate(GL_BACK, GL_KEEP, GL_DECR_WRAP, GL_KEEP); + glStencilOpSeparate(GL_FRONT, GL_KEEP, GL_INCR_WRAP, GL_KEEP); + break; + default: + BLI_assert(0); } } else { @@ -191,26 +192,27 @@ void drw_state_set(DRWState state) if (test) { glEnable(GL_DEPTH_TEST); - if (state & DRW_STATE_DEPTH_LESS) { - glDepthFunc(GL_LESS); - } - else if (state & DRW_STATE_DEPTH_LESS_EQUAL) { - 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_GREATER_EQUAL) { - glDepthFunc(GL_GEQUAL); - } - else if (state & DRW_STATE_DEPTH_ALWAYS) { - glDepthFunc(GL_ALWAYS); - } - else { - BLI_assert(0); + switch (test) { + case DRW_STATE_DEPTH_LESS: + glDepthFunc(GL_LESS); + break; + case DRW_STATE_DEPTH_LESS_EQUAL: + glDepthFunc(GL_LEQUAL); + break; + case DRW_STATE_DEPTH_EQUAL: + glDepthFunc(GL_EQUAL); + break; + case DRW_STATE_DEPTH_GREATER: + glDepthFunc(GL_GREATER); + break; + case DRW_STATE_DEPTH_GREATER_EQUAL: + glDepthFunc(GL_GEQUAL); + break; + case DRW_STATE_DEPTH_ALWAYS: + glDepthFunc(GL_ALWAYS); + break; + default: + BLI_assert(0); } } else { @@ -244,62 +246,63 @@ void drw_state_set(DRWState state) if (test) { glEnable(GL_BLEND); - if ((state & DRW_STATE_BLEND_ALPHA) != 0) { - glBlendFuncSeparate(GL_SRC_ALPHA, - GL_ONE_MINUS_SRC_ALPHA, /* RGB */ - GL_ONE, - GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_BACKGROUND) != 0) { - /* Special blend to add color under and multiply dst by alpha. */ - glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, - GL_SRC_ALPHA, /* RGB */ - GL_ZERO, - GL_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_ALPHA_PREMUL) != 0) { - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } - else if ((state & DRW_STATE_BLEND_MUL) != 0) { - glBlendFunc(GL_DST_COLOR, GL_ZERO); - } - else if ((state & DRW_STATE_BLEND_OIT) != 0) { - glBlendFuncSeparate(GL_ONE, - GL_ONE, /* RGB */ - GL_ZERO, - GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ - } - else if ((state & DRW_STATE_BLEND_ADD) != 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_BLEND_ADD_FULL) != 0) { - /* Let alpha accumulate. */ - glBlendFunc(GL_ONE, GL_ONE); - } - else if ((state & DRW_STATE_BLEND_SUB) != 0) { - glBlendFunc(GL_ONE, GL_ONE); - } - else if ((state & DRW_STATE_BLEND_CUSTOM) != 0) { - /* Custom blend parameters using dual source blending. - * Can only be used with one Draw Buffer. */ - glBlendFunc(GL_ONE, GL_SRC1_COLOR); - } - else if ((state & DRW_STATE_LOGIC_INVERT) != 0) { - /* Replace logic op by blend func to support floating point framebuffer. */ - glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, - GL_ZERO, /* RGB */ - GL_ZERO, - GL_ONE); /* Alpha */ - } - else { - BLI_assert(0); + switch (test) { + case DRW_STATE_BLEND_ALPHA: + glBlendFuncSeparate(GL_SRC_ALPHA, + GL_ONE_MINUS_SRC_ALPHA, /* RGB */ + GL_ONE, + GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ + break; + case DRW_STATE_BLEND_BACKGROUND: + /* Special blend to add color under and multiply dst by alpha. */ + glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, + GL_SRC_ALPHA, /* RGB */ + GL_ZERO, + GL_SRC_ALPHA); /* Alpha */ + break; + case DRW_STATE_BLEND_ALPHA_PREMUL: + glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + break; + case DRW_STATE_BLEND_MUL: + glBlendFunc(GL_DST_COLOR, GL_ZERO); + break; + case DRW_STATE_BLEND_OIT: + glBlendFuncSeparate(GL_ONE, + GL_ONE, /* RGB */ + GL_ZERO, + GL_ONE_MINUS_SRC_ALPHA); /* Alpha */ + break; + case DRW_STATE_BLEND_ADD: + /* Do not let alpha accumulate but premult the source RGB by it. */ + glBlendFuncSeparate(GL_SRC_ALPHA, + GL_ONE, /* RGB */ + GL_ZERO, + GL_ONE); /* Alpha */ + break; + case DRW_STATE_BLEND_ADD_FULL: + /* Let alpha accumulate. */ + glBlendFunc(GL_ONE, GL_ONE); + break; + case DRW_STATE_BLEND_SUB: + glBlendFunc(GL_ONE, GL_ONE); + break; + case DRW_STATE_BLEND_CUSTOM: + /* Custom blend parameters using dual source blending. + * Can only be used with one Draw Buffer. */ + glBlendFunc(GL_ONE, GL_SRC1_COLOR); + break; + case DRW_STATE_LOGIC_INVERT: + /* Replace logic op by blend func to support floating point framebuffer. */ + glBlendFuncSeparate(GL_ONE_MINUS_DST_COLOR, + GL_ZERO, /* RGB */ + GL_ZERO, + GL_ONE); /* Alpha */ + break; + default: + BLI_assert(0); } - if ((state & DRW_STATE_BLEND_SUB) != 0) { + if (test == DRW_STATE_BLEND_SUB) { glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); } else { @@ -402,17 +405,17 @@ static void drw_stencil_state_set(uint write_mask, uint reference, uint compare_ /* Reminders: * - (compare_mask & reference) is what is tested against (compare_mask & stencil_value) * stencil_value being the value stored in the stencil buffer. - * - (writemask & reference) is what gets written if the test condition is fullfiled. + * - (write-mask & reference) is what gets written if the test condition is fulfilled. **/ glStencilMask(write_mask); - - if ((DST.state & DRW_STATE_STENCIL_ALWAYS) != 0) { + DRWState stencil_test = DST.state & DRW_STATE_STENCIL_TEST_ENABLED; + if (stencil_test == DRW_STATE_STENCIL_ALWAYS) { glStencilFunc(GL_ALWAYS, reference, compare_mask); } - else if ((DST.state & DRW_STATE_STENCIL_EQUAL) != 0) { + else if (stencil_test == DRW_STATE_STENCIL_EQUAL) { glStencilFunc(GL_EQUAL, reference, compare_mask); } - else if ((DST.state & DRW_STATE_STENCIL_NEQUAL) != 0) { + else if (stencil_test == DRW_STATE_STENCIL_NEQUAL) { glStencilFunc(GL_NOTEQUAL, reference, compare_mask); } } diff --git a/source/blender/draw/intern/draw_manager_shader.c b/source/blender/draw/intern/draw_manager_shader.c index 9c34cdbac3b..7b08f44921f 100644 --- a/source/blender/draw/intern/draw_manager_shader.c +++ b/source/blender/draw/intern/draw_manager_shader.c @@ -24,6 +24,7 @@ #include "DNA_world_types.h" #include "DNA_material_types.h" +#include "BLI_dynstr.h" #include "BLI_listbase.h" #include "BLI_string_utils.h" #include "BLI_threads.h" @@ -282,6 +283,8 @@ void DRW_deferred_shader_remove(GPUMaterial *mat) /* -------------------------------------------------------------------- */ +/** \{ */ + GPUShader *DRW_shader_create(const char *vert, const char *geom, const char *frag, @@ -356,7 +359,7 @@ GPUShader *DRW_shader_create_3d_depth_only(eGPUShaderConfig sh_cfg) GPUMaterial *DRW_shader_find_from_world(World *wo, const void *engine_type, - int options, + const int options, bool deferred) { GPUMaterial *mat = GPU_material_from_nodetree_find(&wo->gpumaterial, engine_type, options); @@ -372,7 +375,7 @@ GPUMaterial *DRW_shader_find_from_world(World *wo, GPUMaterial *DRW_shader_find_from_material(Material *ma, const void *engine_type, - int options, + const int options, bool deferred) { GPUMaterial *mat = GPU_material_from_nodetree_find(&ma->gpumaterial, engine_type, options); @@ -389,7 +392,8 @@ GPUMaterial *DRW_shader_find_from_material(Material *ma, GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, World *wo, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -409,6 +413,7 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, &wo->gpumaterial, engine_type, options, + is_volume_shader, vert, geom, frag_lib, @@ -426,7 +431,8 @@ GPUMaterial *DRW_shader_create_from_world(struct Scene *scene, GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, Material *ma, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert, const char *geom, const char *frag_lib, @@ -446,6 +452,7 @@ GPUMaterial *DRW_shader_create_from_material(struct Scene *scene, &ma->gpumaterial, engine_type, options, + is_volume_shader, vert, geom, frag_lib, @@ -464,3 +471,129 @@ void DRW_shader_free(GPUShader *shader) { GPU_shader_free(shader); } + +/** \} */ + +/* -------------------------------------------------------------------- */ + +/** \name Shader Library + * + * Simple include system for glsl files. + * + * Usage: Create a DRWShaderLibrary and add the library in the right order. + * You can have nested dependencies but each new library needs to have all its dependencies already + * added to the DRWShaderLibrary. + * Finally you can use DRW_shader_library_create_shader_string to get a shader string that also + * contains the needed libraries for this shader. + * \{ */ + +/* 32 because we use a 32bit bitmap. */ +#define MAX_LIB 32 +#define MAX_LIB_NAME 64 +#define MAX_LIB_DEPS 8 + +struct DRWShaderLibrary { + char *libs[MAX_LIB]; + char libs_name[MAX_LIB][MAX_LIB_NAME]; + uint32_t libs_deps[MAX_LIB]; +}; + +DRWShaderLibrary *DRW_shader_library_create(void) +{ + return MEM_callocN(sizeof(DRWShaderLibrary), "DRWShaderLibrary"); +} + +void DRW_shader_library_free(DRWShaderLibrary *lib) +{ + MEM_SAFE_FREE(lib); +} + +static int drw_shader_library_search(DRWShaderLibrary *lib, const char *name) +{ + for (int i = 0; i < MAX_LIB; i++) { + if (lib->libs[i]) { + if (!strncmp(lib->libs_name[i], name, strlen(lib->libs_name[i]))) { + return i; + } + } + else { + break; + } + } + return -1; +} + +/* Return bitmap of dependencies. */ +static uint32_t drw_shader_dependencies_get(DRWShaderLibrary *lib, char *lib_code) +{ + /* Search dependencies. */ + uint32_t deps = 0; + char *haystack = lib_code; + while ((haystack = strstr(haystack, "BLENDER_REQUIRE("))) { + haystack += 16; + int dep = drw_shader_library_search(lib, haystack); + if (dep == -1) { + printf( + "Error: Dependency not found.\n" + "This might be due to bad lib ordering.\n"); + BLI_assert(0); + } + else { + deps |= 1u << (uint32_t)dep; + } + } + return deps; +} + +void DRW_shader_library_add_file(DRWShaderLibrary *lib, char *lib_code, const char *lib_name) +{ + int index = -1; + for (int i = 0; i < MAX_LIB; i++) { + if (lib->libs[i] == NULL) { + index = i; + break; + } + } + + if (index > -1) { + lib->libs[index] = lib_code; + BLI_strncpy(lib->libs_name[index], lib_name, MAX_LIB_NAME); + } + else { + printf("Error: Too many libraries. Cannot add %s.\n", lib_name); + BLI_assert(0); + } + + lib->libs_deps[index] = drw_shader_dependencies_get(lib, lib_code); +} + +/* Return an allocN'ed string containing the shader code with its dependencies prepended. + * Caller must free the string with MEM_freeN after use. */ +char *DRW_shader_library_create_shader_string(DRWShaderLibrary *lib, char *shader_code) +{ + uint32_t deps = drw_shader_dependencies_get(lib, shader_code); + + DynStr *ds = BLI_dynstr_new(); + /* Add all dependencies recursively. */ + for (int i = MAX_LIB - 1; i > -1; i--) { + if (lib->libs[i] && (deps & (1u << (uint32_t)i))) { + deps |= lib->libs_deps[i]; + } + } + /* Concatenate all needed libs into one string. */ + for (int i = 0; i < MAX_LIB; i++) { + if (deps & 1u) { + BLI_dynstr_append(ds, lib->libs[i]); + } + deps = deps >> 1; + } + + BLI_dynstr_append(ds, shader_code); + + char *str = BLI_dynstr_get_cstring(ds); + BLI_dynstr_free(ds); + + return str; +} + +/** \} */ diff --git a/source/blender/draw/intern/draw_manager_texture.c b/source/blender/draw/intern/draw_manager_texture.c index 373810b2f7f..3f11fe9d11e 100644 --- a/source/blender/draw/intern/draw_manager_texture.c +++ b/source/blender/draw/intern/draw_manager_texture.c @@ -123,6 +123,15 @@ GPUTexture *DRW_texture_create_cube(int w, return tex; } +GPUTexture *DRW_texture_create_cube_array( + int w, int d, eGPUTextureFormat format, DRWTextureFlag flags, const float *fpixels) +{ + GPUTexture *tex = GPU_texture_create_cube_array(w, d, format, fpixels, NULL); + drw_texture_set_parameters(tex, flags); + + return tex; +} + GPUTexture *DRW_texture_pool_query_2d(int w, int h, eGPUTextureFormat format, @@ -134,6 +143,13 @@ GPUTexture *DRW_texture_pool_query_2d(int w, return tex; } +GPUTexture *DRW_texture_pool_query_fullscreen(eGPUTextureFormat format, + DrawEngineType *engine_type) +{ + const float *size = DRW_viewport_size_get(); + return DRW_texture_pool_query_2d((int)size[0], (int)size[1], format, engine_type); +} + void DRW_texture_ensure_fullscreen_2d(GPUTexture **tex, eGPUTextureFormat format, DRWTextureFlag flags) diff --git a/source/blender/editors/animation/anim_filter.c b/source/blender/editors/animation/anim_filter.c index dcf0377ffc0..4b0a4bcf46b 100644 --- a/source/blender/editors/animation/anim_filter.c +++ b/source/blender/editors/animation/anim_filter.c @@ -1790,81 +1790,63 @@ static size_t animdata_filter_gpencil(bAnimContext *ac, bDopeSheet *ads = ac->ads; size_t items = 0; - if (ads->filterflag & ADS_FILTER_GP_3DONLY) { - Scene *scene = (Scene *)ads->source; - ViewLayer *view_layer = (ViewLayer *)ac->view_layer; - Base *base; - - /* Active scene's GPencil block first - No parent item needed... */ - if (scene->gpd) { - items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode); - } - - /* Objects in the scene */ - for (base = view_layer->object_bases.first; base; base = base->next) { - /* Only consider this object if it has got some GP data (saving on all the other tests) */ - if (base->object && (base->object->type == OB_GPENCIL)) { - Object *ob = base->object; - - /* firstly, check if object can be included, by the following factors: - * - if only visible, must check for layer and also viewport visibility - * --> while tools may demand only visible, user setting takes priority - * as user option controls whether sets of channels get included while - * tool-flag takes into account collapsed/open channels too - * - if only selected, must check if object is selected - * - there must be animation data to edit (this is done recursively as we - * try to add the channels) - */ - if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && - !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { - /* Layer visibility - we check both object and base, - * since these may not be in sync yet. */ - if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { - continue; - } - - /* outliner restrict-flag */ - if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { - continue; - } + Scene *scene = (Scene *)ads->source; + ViewLayer *view_layer = (ViewLayer *)ac->view_layer; + Base *base; + + /* Active scene's GPencil block first - No parent item needed... */ + if (scene->gpd) { + items += animdata_filter_gpencil_data(anim_data, ads, scene->gpd, filter_mode); + } + + /* Objects in the scene */ + for (base = view_layer->object_bases.first; base; base = base->next) { + /* Only consider this object if it has got some GP data (saving on all the other tests) */ + if (base->object && (base->object->type == OB_GPENCIL)) { + Object *ob = base->object; + + /* firstly, check if object can be included, by the following factors: + * - if only visible, must check for layer and also viewport visibility + * --> while tools may demand only visible, user setting takes priority + * as user option controls whether sets of channels get included while + * tool-flag takes into account collapsed/open channels too + * - if only selected, must check if object is selected + * - there must be animation data to edit (this is done recursively as we + * try to add the channels) + */ + if ((filter_mode & ANIMFILTER_DATA_VISIBLE) && !(ads->filterflag & ADS_FILTER_INCL_HIDDEN)) { + /* Layer visibility - we check both object and base, + * since these may not be in sync yet. */ + if ((base->flag & BASE_VISIBLE_DEPSGRAPH) == 0) { + continue; } - /* check selection and object type filters only for Object mode */ - if (ob->mode == OB_MODE_OBJECT) { - if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) { - /* only selected should be shown */ - continue; - } - } - /* check if object belongs to the filtering group if option to filter - * objects by the grouped status is on - * - used to ease the process of doing multiple-character choreographies - */ - if (ads->filter_grp != NULL) { - if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) { - continue; - } + /* outliner restrict-flag */ + if (ob->restrictflag & OB_RESTRICT_VIEWPORT) { + continue; } - - /* finally, include this object's grease pencil data-block. */ - /* XXX: Should we store these under expanders per item? */ - items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); } - } - } - else { - bGPdata *gpd; - /* Grab all Grease Pencil data-blocks directly from main, - * but only those that seem to be useful somewhere */ - for (gpd = ac->bmain->gpencils.first; gpd; gpd = gpd->id.next) { - /* only show if gpd is used by something... */ - if (ID_REAL_USERS(gpd) < 1) { - continue; + /* check selection and object type filters only for Object mode */ + if (ob->mode == OB_MODE_OBJECT) { + if ((ads->filterflag & ADS_FILTER_ONLYSEL) && !((base->flag & BASE_SELECTED))) { + /* only selected should be shown */ + continue; + } + } + /* check if object belongs to the filtering group if option to filter + * objects by the grouped status is on + * - used to ease the process of doing multiple-character choreographies + */ + if (ads->filter_grp != NULL) { + if (BKE_collection_has_object_recursive(ads->filter_grp, ob) == 0) { + continue; + } } - /* add GP frames from this data-block. */ - items += animdata_filter_gpencil_data(anim_data, ads, gpd, filter_mode); + /* finally, include this object's grease pencil data-block. */ + /* XXX: Should we store these under expanders per item? */ + items += animdata_filter_gpencil_data(anim_data, ads, ob->data, filter_mode); } } diff --git a/source/blender/editors/animation/anim_ipo_utils.c b/source/blender/editors/animation/anim_ipo_utils.c index 5b729c856c0..f631d08f3e4 100644 --- a/source/blender/editors/animation/anim_ipo_utils.c +++ b/source/blender/editors/animation/anim_ipo_utils.c @@ -177,8 +177,7 @@ int getname_anim_fcurve(char *name, ID *id, FCurve *fcu) icon = RNA_struct_ui_icon(ptr.type); /* valid path - remove the invalid tag since we now know how to use it saving - * users manual effort to reenable using "Revive Disabled FCurves" [#29629] - */ + * users manual effort to re-enable using "Revive Disabled FCurves" T29629. */ fcu->flag &= ~FCURVE_DISABLED; } else { diff --git a/source/blender/editors/armature/armature_select.c b/source/blender/editors/armature/armature_select.c index 0f288c0d8b8..47eb09cdf3d 100644 --- a/source/blender/editors/armature/armature_select.c +++ b/source/blender/editors/armature/armature_select.c @@ -1461,6 +1461,13 @@ static void select_similar_data_pchan(bContext *C, const size_t bytes_size, cons EditBone *ebone_act = CTX_data_active_bone(C); const bPoseChannel *pchan_active = BKE_pose_channel_find_name(obedit->pose, ebone_act->name); + + /* This will mostly happen for corner cases where the user tried to access this + * before having any valid pose data for the armature. */ + if (pchan_active == NULL) { + return; + } + const char *data_active = (const char *)POINTER_OFFSET(pchan_active, offset); for (EditBone *ebone = arm->edbo->first; ebone; ebone = ebone->next) { if (EBONE_SELECTABLE(arm, ebone)) { diff --git a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c index d8cd4d20579..f7d22223b55 100644 --- a/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c +++ b/source/blender/editors/gizmo_library/gizmo_types/move3d_gizmo.c @@ -119,21 +119,25 @@ static void move_geom_draw(const wmGizmo *gz, immUniformColor4fv(color); + /* Use the final scale as a radius if it's not already applied to the final matrix. */ + const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f; + if (draw_style == ED_GIZMO_MOVE_STYLE_RING_2D) { if (filled) { - imm_draw_circle_fill_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); + imm_draw_circle_fill_2d(pos, 0, 0, radius, DIAL_RESOLUTION); } else { - imm_draw_circle_wire_2d(pos, 0, 0, 1.0f, DIAL_RESOLUTION); + imm_draw_circle_wire_2d(pos, 0, 0, radius, DIAL_RESOLUTION); } } else if (draw_style == ED_GIZMO_MOVE_STYLE_CROSS_2D) { + const float radius_diag = M_SQRT1_2 * radius; immBegin(GPU_PRIM_LINES, 4); - immVertex2f(pos, 1.0f, 1.0f); - immVertex2f(pos, -1.0f, -1.0f); + immVertex2f(pos, radius_diag, radius_diag); + immVertex2f(pos, -radius_diag, -radius_diag); - immVertex2f(pos, -1.0f, 1.0f); - immVertex2f(pos, 1.0f, -1.0f); + immVertex2f(pos, -radius_diag, radius_diag); + immVertex2f(pos, radius_diag, -radius_diag); immEnd(); } else { @@ -260,6 +264,9 @@ static int gizmo_move_modal(bContext *C, return OPERATOR_RUNNING_MODAL; } sub_v2_v2v2(prop_delta, mval_proj_curr, mval_proj_init); + if ((gz->flag & WM_GIZMO_DRAW_NO_SCALE) == 0) { + mul_v2_fl(prop_delta, gz->scale_final); + } prop_delta[2] = 0.0f; } @@ -394,8 +401,10 @@ static int gizmo_move_test_select(bContext *C, wmGizmo *gz, const int mval[2]) return -1; } - /* The 'gz->scale_final' is already applied when projecting. */ - if (len_squared_v2(point_local) < 1.0f) { + /* The 'gz->scale_final' is already applied to the projection + * when #WM_GIZMO_DRAW_NO_SCALE isn't set. */ + const float radius = (gz->flag & WM_GIZMO_DRAW_NO_SCALE) ? gz->scale_final : 1.0f; + if (len_squared_v2(point_local) < radius) { return 0; } diff --git a/source/blender/editors/gpencil/gpencil_paint.c b/source/blender/editors/gpencil/gpencil_paint.c index 56351fbfb9a..46788eba370 100644 --- a/source/blender/editors/gpencil/gpencil_paint.c +++ b/source/blender/editors/gpencil/gpencil_paint.c @@ -3280,8 +3280,10 @@ static void gpencil_add_guide_points(const tGPsdata *p, } } -/* Add fake points for missing mouse movements when the artist draw very fast creating an arc - * with the vertice in the midle of the segment and using the angle of the previous segment. */ +/** + * Add fake points for missing mouse movements when the artist draw very fast creating an arc + * with the vertex in the middle of the segment and using the angle of the previous segment. + */ static void gpencil_add_fake_points(const wmEvent *event, tGPsdata *p) { Brush *brush = p->brush; diff --git a/source/blender/editors/gpencil/gpencil_sculpt_paint.c b/source/blender/editors/gpencil/gpencil_sculpt_paint.c index adc009efd16..5db331280f8 100644 --- a/source/blender/editors/gpencil/gpencil_sculpt_paint.c +++ b/source/blender/editors/gpencil/gpencil_sculpt_paint.c @@ -231,8 +231,8 @@ static GP_Sculpt_Settings *gpsculpt_get_settings(Scene *scene) static bool gp_brush_invert_check(tGP_BrushEditData *gso) { /* The basic setting is the brush's setting (from the panel) */ - bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0); - + bool invert = ((gso->brush->gpencil_settings->sculpt_flag & GP_SCULPT_FLAG_INVERT) != 0) || + (gso->brush->gpencil_settings->sculpt_flag & BRUSH_DIR_IN); /* During runtime, the user can hold down the Ctrl key to invert the basic behavior */ if (gso->flag & GP_SCULPT_FLAG_INVERT) { invert ^= true; @@ -1744,7 +1744,8 @@ static bool gpsculpt_brush_apply_standard(bContext *C, tGP_BrushEditData *gso) if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { /* compute multiframe falloff factor */ if (gso->use_multiframe_falloff) { - /* Faloff depends on distance to active frame (relative to the overall frame range) */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } diff --git a/source/blender/editors/gpencil/gpencil_vertex_paint.c b/source/blender/editors/gpencil/gpencil_vertex_paint.c index 5b5a306aa25..c730d1b493e 100644 --- a/source/blender/editors/gpencil/gpencil_vertex_paint.c +++ b/source/blender/editors/gpencil/gpencil_vertex_paint.c @@ -1099,10 +1099,9 @@ static bool gp_vertexpaint_brush_apply_to_layers(bContext *C, tGP_BrushVertexpai LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { - /* compute multiframe falloff factor */ + /* Compute multi-frame falloff factor. */ if (gso->use_multiframe_falloff) { - /* Faloff depends on distance to active frame (relative to the overall frame range) - */ + /* Falloff depends on distance to active frame (relative to the overall frame range) */ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } diff --git a/source/blender/editors/gpencil/gpencil_weight_paint.c b/source/blender/editors/gpencil/gpencil_weight_paint.c index 6b337afa559..c519129cdf7 100644 --- a/source/blender/editors/gpencil/gpencil_weight_paint.c +++ b/source/blender/editors/gpencil/gpencil_weight_paint.c @@ -110,7 +110,7 @@ typedef struct tGP_BrushWeightpaintData { /* Start of new paint */ bool first; - /* Is multiframe editing enabled, and are we using falloff for that? */ + /* Is multi-frame editing enabled, and are we using falloff for that? */ bool is_multiframe; bool use_multiframe_falloff; @@ -127,10 +127,10 @@ typedef struct tGP_BrushWeightpaintData { /* - Effect 2D vector */ float dvec[2]; - /* - multiframe falloff factor */ + /* - multi-frame falloff factor. */ float mf_falloff; - /* brush geometry (bounding box) */ + /* brush geometry (bounding box). */ rcti brush_rect; /* Temp data to save selected points */ @@ -206,7 +206,7 @@ static float brush_influence_calc(tGP_BrushWeightpaintData *gso, const int radiu float brush_fallof = BKE_brush_curve_strength(brush, distance, (float)radius); influence *= brush_fallof; - /* apply multiframe falloff */ + /* apply multi-frame falloff */ influence *= gso->mf_falloff; /* return influence */ @@ -585,7 +585,7 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai /* Active Frame or MultiFrame? */ if (gso->is_multiframe) { - /* init multiframe falloff options */ + /* init multi-frame falloff options */ int f_init = 0; int f_end = 0; @@ -596,10 +596,10 @@ static bool gp_weightpaint_brush_apply_to_layers(bContext *C, tGP_BrushWeightpai LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) { /* Always do active frame; Otherwise, only include selected frames */ if ((gpf == gpl->actframe) || (gpf->flag & GP_FRAME_SELECT)) { - /* compute multiframe falloff factor */ + /* Compute multi-frame falloff factor. */ if (gso->use_multiframe_falloff) { - /* Faloff depends on distance to active frame (relative to the overall frame range) - */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ gso->mf_falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } @@ -656,7 +656,7 @@ static void gp_weightpaint_brush_apply(bContext *C, wmOperator *op, PointerRNA * gso->brush_rect.xmax = mouse[0] + radius; gso->brush_rect.ymax = mouse[1] + radius; - /* Calc 2D direction vector and relative angle. */ + /* Calculate 2D direction vector and relative angle. */ brush_calc_dvec_2d(gso); changed = gp_weightpaint_brush_apply_to_layers(C, gso); diff --git a/source/blender/editors/include/UI_interface.h b/source/blender/editors/include/UI_interface.h index 277f330ad50..dba95c5106e 100644 --- a/source/blender/editors/include/UI_interface.h +++ b/source/blender/editors/include/UI_interface.h @@ -2382,6 +2382,9 @@ struct ID *UI_context_active_but_get_tab_ID(struct bContext *C); uiBut *UI_region_active_but_get(struct ARegion *region); uiBut *UI_region_but_find_rect_over(const struct ARegion *region, const struct rcti *isect); +uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region, + const int xy[2], + bool only_clip); /* uiFontStyle.align */ typedef enum eFontStyle_Align { diff --git a/source/blender/editors/interface/interface_handlers.c b/source/blender/editors/interface/interface_handlers.c index 6da9bacd865..833631f871d 100644 --- a/source/blender/editors/interface/interface_handlers.c +++ b/source/blender/editors/interface/interface_handlers.c @@ -8268,6 +8268,13 @@ uiBut *UI_region_but_find_rect_over(const ARegion *region, const rcti *rect_px) return ui_but_find_rect_over(region, rect_px); } +uiBlock *UI_region_block_find_mouse_over(const struct ARegion *region, + const int xy[2], + bool only_clip) +{ + return ui_block_find_mouse_over_ex(region, xy[0], xy[1], only_clip); +} + /** * Version of #UI_context_active_but_get that also returns RNA property info. * Helper function for insert keyframe, reset to default, etc operators. diff --git a/source/blender/editors/interface/interface_intern.h b/source/blender/editors/interface/interface_intern.h index 24977848ae4..a2e239884a3 100644 --- a/source/blender/editors/interface/interface_intern.h +++ b/source/blender/editors/interface/interface_intern.h @@ -951,6 +951,14 @@ bool ui_block_is_popover(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; bool ui_block_is_pie_menu(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; bool ui_block_is_popup_any(const uiBlock *block) ATTR_WARN_UNUSED_RESULT; +uiBlock *ui_block_find_mouse_over_ex(const struct ARegion *region, + const int x, + const int y, + bool only_clip); +uiBlock *ui_block_find_mouse_over(const struct ARegion *region, + const struct wmEvent *event, + bool only_clip); + uiBut *ui_region_find_first_but_test_flag(struct ARegion *region, int flag_include, int flag_exclude); diff --git a/source/blender/editors/interface/interface_query.c b/source/blender/editors/interface/interface_query.c index 03434b12ddb..52488027662 100644 --- a/source/blender/editors/interface/interface_query.c +++ b/source/blender/editors/interface/interface_query.c @@ -505,6 +505,40 @@ bool UI_block_can_add_separator(const uiBlock *block) /** \} */ /* -------------------------------------------------------------------- */ +/** \name Block (#uiBlock) Spatial + * \{ */ + +uiBlock *ui_block_find_mouse_over_ex(const ARegion *region, + const int x, + const int y, + bool only_clip) +{ + if (!ui_region_contains_point_px(region, x, y)) { + return NULL; + } + for (uiBlock *block = region->uiblocks.first; block; block = block->next) { + if (only_clip) { + if ((block->flag & UI_BLOCK_CLIP_EVENTS) == 0) { + continue; + } + } + float mx = x, my = y; + ui_window_to_block_fl(region, block, &mx, &my); + if (BLI_rctf_isect_pt(&block->rect, mx, my)) { + return block; + } + } + return NULL; +} + +uiBlock *ui_block_find_mouse_over(const ARegion *region, const wmEvent *event, bool only_clip) +{ + return ui_block_find_mouse_over_ex(region, event->x, event->y, only_clip); +} + +/** \} */ + +/* -------------------------------------------------------------------- */ /** \name Region (#ARegion) State * \{ */ diff --git a/source/blender/editors/mesh/editmesh_mask_extract.c b/source/blender/editors/mesh/editmesh_mask_extract.c index d688e2cb658..1c4bc33240a 100644 --- a/source/blender/editors/mesh/editmesh_mask_extract.c +++ b/source/blender/editors/mesh/editmesh_mask_extract.c @@ -349,7 +349,7 @@ static int paint_mask_slice_exec(bContext *C, wmOperator *op) if (ob->mode == OB_MODE_SCULPT) { ED_sculpt_undo_geometry_begin(ob, "mask slice"); /* TODO: The ideal functionality would be to preserve the current face sets and add a new one - * for the new triangles, but this datalayer needs to be rebuild in order to make sculpt mode + * for the new triangles, but this data-layer needs to be rebuild in order to make sculpt mode * not crash when modifying the geometry. */ CustomData_free_layers(&mesh->pdata, CD_SCULPT_FACE_SETS, mesh->totpoly); } diff --git a/source/blender/editors/mesh/meshtools.c b/source/blender/editors/mesh/meshtools.c index dc825871bb7..8f31fa0a1fa 100644 --- a/source/blender/editors/mesh/meshtools.c +++ b/source/blender/editors/mesh/meshtools.c @@ -943,7 +943,7 @@ BMVert *editbmesh_get_x_mirror_vert(Object *ob, } /** - * Wrapper for objectmode/editmode. + * Wrapper for object-mode/edit-mode. * * call #BM_mesh_elem_table_ensure first for editmesh. */ diff --git a/source/blender/editors/render/render_shading.c b/source/blender/editors/render/render_shading.c index 94e210b7243..95d044554f1 100644 --- a/source/blender/editors/render/render_shading.c +++ b/source/blender/editors/render/render_shading.c @@ -890,14 +890,14 @@ enum { static void light_cache_bake_tag_cache(Scene *scene, wmOperator *op) { - if (scene->eevee.light_cache != NULL) { + if (scene->eevee.light_cache_data != NULL) { int subset = RNA_enum_get(op->ptr, "subset"); switch (subset) { case LIGHTCACHE_SUBSET_ALL: - scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE; + scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_GRID | LIGHTCACHE_UPDATE_CUBE; break; case LIGHTCACHE_SUBSET_CUBE: - scene->eevee.light_cache->flag |= LIGHTCACHE_UPDATE_CUBE; + scene->eevee.light_cache_data->flag |= LIGHTCACHE_UPDATE_CUBE; break; case LIGHTCACHE_SUBSET_DIRTY: /* Leave tag untouched. */ @@ -1046,7 +1046,7 @@ static bool light_cache_free_poll(bContext *C) { Scene *scene = CTX_data_scene(C); - return scene->eevee.light_cache; + return scene->eevee.light_cache_data; } static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) @@ -1057,12 +1057,12 @@ static int light_cache_free_exec(bContext *C, wmOperator *UNUSED(op)) wmWindowManager *wm = CTX_wm_manager(C); WM_jobs_kill_type(wm, scene, WM_JOB_TYPE_LIGHT_BAKE); - if (!scene->eevee.light_cache) { + if (!scene->eevee.light_cache_data) { return OPERATOR_CANCELLED; } - EEVEE_lightcache_free(scene->eevee.light_cache); - scene->eevee.light_cache = NULL; + EEVEE_lightcache_free(scene->eevee.light_cache_data); + scene->eevee.light_cache_data = NULL; EEVEE_lightcache_info_update(&scene->eevee); diff --git a/source/blender/editors/scene/scene_edit.c b/source/blender/editors/scene/scene_edit.c index ad940a8e87d..114cb54636a 100644 --- a/source/blender/editors/scene/scene_edit.c +++ b/source/blender/editors/scene/scene_edit.c @@ -182,6 +182,8 @@ bool ED_scene_view_layer_delete(Main *bmain, Scene *scene, ViewLayer *layer, Rep } } + BKE_scene_free_view_layer_depsgraph(scene, layer); + BKE_view_layer_free(layer); DEG_id_tag_update(&scene->id, 0); diff --git a/source/blender/editors/sculpt_paint/paint_ops.c b/source/blender/editors/sculpt_paint/paint_ops.c index 6fe1ba0b817..fed3c2f03a4 100644 --- a/source/blender/editors/sculpt_paint/paint_ops.c +++ b/source/blender/editors/sculpt_paint/paint_ops.c @@ -377,17 +377,6 @@ static void PALETTE_OT_extract_from_image(wmOperatorType *ot) } /* Sort Palette color by Hue and Saturation. */ -static bool palette_sort_poll(bContext *C) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Palette *palette = paint->palette; - if (palette) { - return true; - } - - return false; -} - static int palette_sort_exec(bContext *C, wmOperator *op) { const int type = RNA_enum_get(op->ptr, "type"); @@ -477,7 +466,7 @@ static void PALETTE_OT_sort(wmOperatorType *ot) /* api callbacks */ ot->exec = palette_sort_exec; - ot->poll = palette_sort_poll; + ot->poll = palette_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -522,7 +511,7 @@ static void PALETTE_OT_color_move(wmOperatorType *ot) /* api callbacks */ ot->exec = palette_color_move_exec; - ot->poll = palette_sort_poll; + ot->poll = palette_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; @@ -531,17 +520,6 @@ static void PALETTE_OT_color_move(wmOperatorType *ot) } /* Join Palette swatches. */ -static bool palette_join_poll(bContext *C) -{ - Paint *paint = BKE_paint_get_active_from_context(C); - Palette *palette = paint->palette; - if (palette) { - return true; - } - - return false; -} - static int palette_join_exec(bContext *C, wmOperator *op) { Main *bmain = CTX_data_main(C); @@ -599,7 +577,7 @@ static void PALETTE_OT_join(wmOperatorType *ot) /* api callbacks */ ot->exec = palette_join_exec; - ot->poll = palette_join_poll; + ot->poll = palette_poll; /* flags */ ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; diff --git a/source/blender/editors/sculpt_paint/sculpt.c b/source/blender/editors/sculpt_paint/sculpt.c index b25cdbe39c1..5a830a90092 100644 --- a/source/blender/editors/sculpt_paint/sculpt.c +++ b/source/blender/editors/sculpt_paint/sculpt.c @@ -7030,7 +7030,9 @@ static void sculpt_update_cache_variants(bContext *C, Sculpt *sd, Object *ob, Po if (cache->first_time || !((brush->flag & BRUSH_ANCHORED) || (brush->sculpt_tool == SCULPT_TOOL_SNAKE_HOOK) || - (brush->sculpt_tool == SCULPT_TOOL_ROTATE))) { + (brush->sculpt_tool == SCULPT_TOOL_ROTATE) || + (brush->sculpt_tool == SCULPT_TOOL_CLOTH && + brush->cloth_deform_type == BRUSH_CLOTH_DEFORM_GRAB))) { RNA_float_get_array(ptr, "location", cache->true_location); } diff --git a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c index 038d0e5a08c..f2671b66f7f 100644 --- a/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c +++ b/source/blender/editors/sculpt_paint/sculpt_multiplane_scrape.c @@ -58,7 +58,6 @@ #include <math.h> #include <stdlib.h> - typedef struct MultiplaneScrapeSampleData { float area_cos[2][3]; float area_nos[2][3]; @@ -223,7 +222,6 @@ static void do_multiplane_scrape_brush_task_cb_ex(void *__restrict userdata, BKE_pbvh_vertex_iter_end; } - /* Public functions. */ /* Main Brush Function. */ @@ -400,9 +398,9 @@ void SCULPT_do_multiplane_scrape_brush(Sculpt *sd, Object *ob, PBVHNode **nodes, } void SCULPT_multiplane_scrape_preview_draw(const uint gpuattr, - SculptSession *ss, - const float outline_col[3], - const float outline_alpha) + SculptSession *ss, + const float outline_col[3], + const float outline_alpha) { float local_mat_inv[4][4]; invert_m4_m4(local_mat_inv, ss->cache->stroke_local_mat); diff --git a/source/blender/editors/space_console/console_draw.c b/source/blender/editors/space_console/console_draw.c index 7e32c3d2b5f..ee1496c96bb 100644 --- a/source/blender/editors/space_console/console_draw.c +++ b/source/blender/editors/space_console/console_draw.c @@ -38,14 +38,14 @@ #include "../space_info/textview.h" -static int console_line_data(struct TextViewContext *tvc, - uchar fg[4], - uchar UNUSED(bg[4]), - int *UNUSED(icon), - uchar UNUSED(icon_fg[4]), - uchar UNUSED(icon_bg[4])) +static enum eTextViewContext_LineFlag console_line_data(TextViewContext *tvc, + uchar fg[4], + uchar UNUSED(bg[4]), + int *UNUSED(icon), + uchar UNUSED(icon_fg[4]), + uchar UNUSED(icon_bg[4])) { - ConsoleLine *cl_iter = (ConsoleLine *)tvc->iter; + const ConsoleLine *cl_iter = tvc->iter; int fg_id = TH_TEXT; switch (cl_iter->type) { @@ -67,7 +67,7 @@ static int console_line_data(struct TextViewContext *tvc, return TVC_LINE_FG; } -void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_dummy) +void console_scrollback_prompt_begin(SpaceConsole *sc, ConsoleLine *cl_dummy) { /* fake the edit line being in the scroll buffer */ ConsoleLine *cl = sc->history.last; @@ -81,7 +81,7 @@ void console_scrollback_prompt_begin(struct SpaceConsole *sc, ConsoleLine *cl_du memcpy(cl_dummy->line + prompt_len, cl->line, cl->len + 1); BLI_addtail(&sc->scrollback, cl_dummy); } -void console_scrollback_prompt_end(struct SpaceConsole *sc, ConsoleLine *cl_dummy) +void console_scrollback_prompt_end(SpaceConsole *sc, ConsoleLine *cl_dummy) { MEM_freeN(cl_dummy->line); BLI_remlink(&sc->scrollback, cl_dummy); @@ -112,14 +112,13 @@ static int console_textview_step(TextViewContext *tvc) return ((tvc->iter = (void *)((Link *)tvc->iter)->prev) != NULL); } -static int console_textview_line_get(struct TextViewContext *tvc, const char **line, int *len) +static void console_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len) { - ConsoleLine *cl = (ConsoleLine *)tvc->iter; - *line = cl->line; - *len = cl->len; + const ConsoleLine *cl = tvc->iter; + *r_line = cl->line; + *r_len = cl->len; // printf("'%s' %d\n", *line, cl->len); BLI_assert(cl->line[cl->len] == '\0' && (cl->len == 0 || cl->line[cl->len - 1] != '\0')); - return 1; } static void console_cursor_wrap_offset( @@ -144,7 +143,7 @@ static void console_cursor_wrap_offset( return; } -static void console_textview_draw_cursor(struct TextViewContext *tvc, +static void console_textview_draw_cursor(TextViewContext *tvc, int cwidth, int columns, int descender) @@ -201,7 +200,7 @@ static void console_textview_draw_rect_calc(const ARegion *region, r_draw_rect_outer->ymax = region->winy; } -static int console_textview_main__internal(struct SpaceConsole *sc, +static int console_textview_main__internal(SpaceConsole *sc, const ARegion *region, const bool do_draw, const int mval[2], @@ -243,19 +242,19 @@ static int console_textview_main__internal(struct SpaceConsole *sc, return ret; } -void console_textview_main(struct SpaceConsole *sc, const ARegion *region) +void console_textview_main(SpaceConsole *sc, const ARegion *region) { const int mval[2] = {INT_MAX, INT_MAX}; console_textview_main__internal(sc, region, true, mval, NULL, NULL); } -int console_textview_height(struct SpaceConsole *sc, const ARegion *region) +int console_textview_height(SpaceConsole *sc, const ARegion *region) { const int mval[2] = {INT_MAX, INT_MAX}; return console_textview_main__internal(sc, region, false, mval, NULL, NULL); } -int console_char_pick(struct SpaceConsole *sc, const ARegion *region, const int mval[2]) +int console_char_pick(SpaceConsole *sc, const ARegion *region, const int mval[2]) { int r_mval_pick_offset = 0; void *mval_pick_item = NULL; diff --git a/source/blender/editors/space_info/info_draw.c b/source/blender/editors/space_info/info_draw.c index 4d5f59cdb7c..0a5ca81484c 100644 --- a/source/blender/editors/space_info/info_draw.c +++ b/source/blender/editors/space_info/info_draw.c @@ -39,14 +39,14 @@ #include "textview.h" #include "GPU_framebuffer.h" -static int report_line_data(struct TextViewContext *tvc, - uchar fg[4], - uchar bg[4], - int *icon, - uchar icon_fg[4], - uchar icon_bg[4]) +static enum eTextViewContext_LineFlag report_line_data(TextViewContext *tvc, + uchar fg[4], + uchar bg[4], + int *r_icon, + uchar r_icon_fg[4], + uchar r_icon_bg[4]) { - Report *report = (Report *)tvc->iter; + const Report *report = tvc->iter; /* Same text color no matter what type of report. */ UI_GetThemeColor4ubv((report->flag & SELECT) ? TH_INFO_SELECTED_TEXT : TH_TEXT, fg); @@ -64,35 +64,35 @@ static int report_line_data(struct TextViewContext *tvc, if (report->type & RPT_ERROR_ALL) { icon_fg_id = TH_INFO_ERROR_TEXT; icon_bg_id = TH_INFO_ERROR; - *icon = ICON_CANCEL; + *r_icon = ICON_CANCEL; } else if (report->type & RPT_WARNING_ALL) { icon_fg_id = TH_INFO_WARNING_TEXT; icon_bg_id = TH_INFO_WARNING; - *icon = ICON_ERROR; + *r_icon = ICON_ERROR; } else if (report->type & RPT_INFO_ALL) { icon_fg_id = TH_INFO_INFO_TEXT; icon_bg_id = TH_INFO_INFO; - *icon = ICON_INFO; + *r_icon = ICON_INFO; } else if (report->type & RPT_DEBUG_ALL) { icon_fg_id = TH_INFO_DEBUG_TEXT; icon_bg_id = TH_INFO_DEBUG; - *icon = ICON_SYSTEM; + *r_icon = ICON_SYSTEM; } else if (report->type & RPT_PROPERTY) { icon_fg_id = TH_INFO_PROPERTY_TEXT; icon_bg_id = TH_INFO_PROPERTY; - *icon = ICON_OPTIONS; + *r_icon = ICON_OPTIONS; } else if (report->type & RPT_OPERATOR) { icon_fg_id = TH_INFO_OPERATOR_TEXT; icon_bg_id = TH_INFO_OPERATOR; - *icon = ICON_CHECKMARK; + *r_icon = ICON_CHECKMARK; } else { - *icon = ICON_NONE; + *r_icon = ICON_NONE; } if (report->flag & SELECT) { @@ -100,9 +100,9 @@ static int report_line_data(struct TextViewContext *tvc, icon_bg_id = TH_INFO_SELECTED_TEXT; } - if (*icon != ICON_NONE) { - UI_GetThemeColor4ubv(icon_fg_id, icon_fg); - UI_GetThemeColor4ubv(icon_bg_id, icon_bg); + if (*r_icon != ICON_NONE) { + UI_GetThemeColor4ubv(icon_fg_id, r_icon_fg); + UI_GetThemeColor4ubv(icon_bg_id, r_icon_bg); return TVC_LINE_FG | TVC_LINE_BG | TVC_LINE_ICON | TVC_LINE_ICON_FG | TVC_LINE_ICON_BG; } else { @@ -113,7 +113,7 @@ static int report_line_data(struct TextViewContext *tvc, /* reports! */ static void report_textview_init__internal(TextViewContext *tvc) { - Report *report = (Report *)tvc->iter; + const Report *report = tvc->iter; const char *str = report->message; const char *next_str = strchr(str + tvc->iter_char, '\n'); @@ -127,9 +127,9 @@ static void report_textview_init__internal(TextViewContext *tvc) static int report_textview_skip__internal(TextViewContext *tvc) { - SpaceInfo *sinfo = (SpaceInfo *)tvc->arg1; + const SpaceInfo *sinfo = tvc->arg1; const int report_mask = info_report_mask(sinfo); - while (tvc->iter && (((Report *)tvc->iter)->type & report_mask) == 0) { + while (tvc->iter && (((const Report *)tvc->iter)->type & report_mask) == 0) { tvc->iter = (void *)((Link *)tvc->iter)->prev; } return (tvc->iter != NULL); @@ -137,7 +137,7 @@ static int report_textview_skip__internal(TextViewContext *tvc) static int report_textview_begin(TextViewContext *tvc) { - ReportList *reports = (ReportList *)tvc->arg2; + const ReportList *reports = tvc->arg2; tvc->lheight = 14 * UI_DPI_FAC; tvc->sel_start = 0; @@ -170,7 +170,7 @@ static void report_textview_end(TextViewContext *UNUSED(tvc)) static int report_textview_step(TextViewContext *tvc) { /* simple case, but no newline support */ - Report *report = (Report *)tvc->iter; + const Report *report = tvc->iter; if (report->len <= tvc->iter_char_next) { tvc->iter = (void *)((Link *)tvc->iter)->prev; @@ -195,12 +195,11 @@ static int report_textview_step(TextViewContext *tvc) } } -static int report_textview_line_get(struct TextViewContext *tvc, const char **line, int *len) +static void report_textview_line_get(TextViewContext *tvc, const char **r_line, int *r_len) { - Report *report = (Report *)tvc->iter; - *line = report->message + tvc->iter_char; - *len = tvc->iter_char_next - tvc->iter_char; - return 1; + const Report *report = tvc->iter; + *r_line = report->message + tvc->iter_char; + *r_len = tvc->iter_char_next - tvc->iter_char; } static void info_textview_draw_rect_calc(const ARegion *region, @@ -220,9 +219,9 @@ static void info_textview_draw_rect_calc(const ARegion *region, r_draw_rect_outer->ymax = region->winy; } -static int info_textview_main__internal(struct SpaceInfo *sinfo, +static int info_textview_main__internal(const SpaceInfo *sinfo, const ARegion *region, - ReportList *reports, + const ReportList *reports, const bool do_draw, const int mval[2], void **r_mval_pick_item, @@ -259,9 +258,9 @@ static int info_textview_main__internal(struct SpaceInfo *sinfo, return ret; } -void *info_text_pick(struct SpaceInfo *sinfo, +void *info_text_pick(const SpaceInfo *sinfo, const ARegion *region, - ReportList *reports, + const ReportList *reports, int mval_y) { void *mval_pick_item = NULL; @@ -271,13 +270,13 @@ void *info_text_pick(struct SpaceInfo *sinfo, return (void *)mval_pick_item; } -int info_textview_height(struct SpaceInfo *sinfo, const ARegion *region, ReportList *reports) +int info_textview_height(const SpaceInfo *sinfo, const ARegion *region, const ReportList *reports) { int mval[2] = {INT_MAX, INT_MAX}; return info_textview_main__internal(sinfo, region, reports, false, mval, NULL, NULL); } -void info_textview_main(struct SpaceInfo *sinfo, const ARegion *region, ReportList *reports) +void info_textview_main(const SpaceInfo *sinfo, const ARegion *region, const ReportList *reports) { int mval[2] = {INT_MAX, INT_MAX}; info_textview_main__internal(sinfo, region, reports, true, mval, NULL, NULL); diff --git a/source/blender/editors/space_info/info_intern.h b/source/blender/editors/space_info/info_intern.h index 443a1659690..79bfb1fa047 100644 --- a/source/blender/editors/space_info/info_intern.h +++ b/source/blender/editors/space_info/info_intern.h @@ -45,19 +45,19 @@ void FILE_OT_find_missing_files(struct wmOperatorType *ot); void INFO_OT_reports_display_update(struct wmOperatorType *ot); /* info_draw.c */ -void *info_text_pick(struct SpaceInfo *sinfo, +void *info_text_pick(const struct SpaceInfo *sinfo, const struct ARegion *region, - ReportList *reports, + const struct ReportList *reports, int mouse_y); -int info_textview_height(struct SpaceInfo *sinfo, +int info_textview_height(const struct SpaceInfo *sinfo, const struct ARegion *region, - struct ReportList *reports); -void info_textview_main(struct SpaceInfo *sinfo, + const struct ReportList *reports); +void info_textview_main(const struct SpaceInfo *sinfo, const struct ARegion *region, - struct ReportList *reports); + const struct ReportList *reports); /* info_report.c */ -int info_report_mask(struct SpaceInfo *sinfo); +int info_report_mask(const struct SpaceInfo *sinfo); void INFO_OT_select_pick(struct wmOperatorType *ot); /* report selection */ void INFO_OT_select_all(struct wmOperatorType *ot); void INFO_OT_select_box(struct wmOperatorType *ot); diff --git a/source/blender/editors/space_info/info_report.c b/source/blender/editors/space_info/info_report.c index 1b01ac95866..303e2bbaec9 100644 --- a/source/blender/editors/space_info/info_report.c +++ b/source/blender/editors/space_info/info_report.c @@ -72,7 +72,7 @@ static void reports_select_all(ReportList *reports, int report_mask, int action) } } -int info_report_mask(SpaceInfo *UNUSED(sinfo)) +int info_report_mask(const SpaceInfo *UNUSED(sinfo)) { #if 0 int report_mask = 0; diff --git a/source/blender/editors/space_info/textview.h b/source/blender/editors/space_info/textview.h index a33ed91570d..54b7c477791 100644 --- a/source/blender/editors/space_info/textview.h +++ b/source/blender/editors/space_info/textview.h @@ -21,6 +21,14 @@ #ifndef __TEXTVIEW_H__ #define __TEXTVIEW_H__ +enum eTextViewContext_LineFlag { + TVC_LINE_FG = (1 << 0), + TVC_LINE_BG = (1 << 1), + TVC_LINE_ICON = (1 << 2), + TVC_LINE_ICON_FG = (1 << 3), + TVC_LINE_ICON_BG = (1 << 4) +}; + typedef struct TextViewContext { /** Font size scaled by the interface size. */ int lheight; @@ -40,22 +48,22 @@ typedef struct TextViewContext { /* callbacks */ int (*begin)(struct TextViewContext *tvc); void (*end)(struct TextViewContext *tvc); - void *arg1; - void *arg2; + const void *arg1; + const void *arg2; /* iterator */ int (*step)(struct TextViewContext *tvc); - int (*line_get)(struct TextViewContext *tvc, const char **, int *); - int (*line_data)(struct TextViewContext *tvc, - unsigned char fg[4], - unsigned char bg[4], - int *icon, - unsigned char icon_fg[4], - unsigned char icon_bg[4]); + void (*line_get)(struct TextViewContext *tvc, const char **r_line, int *r_len); + enum eTextViewContext_LineFlag (*line_data)(struct TextViewContext *tvc, + uchar fg[4], + uchar bg[4], + int *r_icon, + uchar r_icon_fg[4], + uchar r_icon_bg[4]); void (*draw_cursor)(struct TextViewContext *tvc, int cwidth, int columns, int descender); /* constant theme colors */ void (*const_colors)(struct TextViewContext *tvc, unsigned char bg_sel[4]); - void *iter; + const void *iter; int iter_index; /** Char index, used for multi-line report display. */ int iter_char; @@ -72,12 +80,4 @@ int textview_draw(struct TextViewContext *tvc, void **r_mval_pick_item, int *r_mval_pick_offset); -enum { - TVC_LINE_FG = (1 << 0), - TVC_LINE_BG = (1 << 1), - TVC_LINE_ICON = (1 << 2), - TVC_LINE_ICON_FG = (1 << 3), - TVC_LINE_ICON_BG = (1 << 4) -}; - #endif /* __TEXTVIEW_H__ */ diff --git a/source/blender/editors/space_node/space_node.c b/source/blender/editors/space_node/space_node.c index d3c7374e782..951c26b69e0 100644 --- a/source/blender/editors/space_node/space_node.c +++ b/source/blender/editors/space_node/space_node.c @@ -981,6 +981,7 @@ void ED_spacetype_node(void) art->listener = node_region_listener; art->cursor = node_cursor; art->event_cursor = true; + art->clip_gizmo_events_by_ui = true; BLI_addhead(&st->regiontypes, art); diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c index 8c884783913..8ec7d5a166b 100644 --- a/source/blender/editors/space_view3d/space_view3d.c +++ b/source/blender/editors/space_view3d/space_view3d.c @@ -1422,7 +1422,7 @@ static void space_view3d_listener(wmWindow *UNUSED(win), static void space_view3d_refresh(const bContext *C, ScrArea *UNUSED(sa)) { Scene *scene = CTX_data_scene(C); - LightCache *lcache = scene->eevee.light_cache; + LightCache *lcache = scene->eevee.light_cache_data; if (lcache && (lcache->flag & LIGHTCACHE_UPDATE_AUTO) != 0) { lcache->flag &= ~LIGHTCACHE_UPDATE_AUTO; diff --git a/source/blender/editors/space_view3d/view3d_select.c b/source/blender/editors/space_view3d/view3d_select.c index bd92193206f..bfbc9b6825b 100644 --- a/source/blender/editors/space_view3d/view3d_select.c +++ b/source/blender/editors/space_view3d/view3d_select.c @@ -1987,7 +1987,7 @@ static bool ed_object_select_pick(bContext *C, is_obedit = (vc.obedit != NULL); if (object) { - /* signal for view3d_opengl_select to skip editmode objects */ + /* Signal for #view3d_opengl_select to skip edit-mode objects. */ vc.obedit = NULL; } @@ -2003,7 +2003,7 @@ static bool ed_object_select_pick(bContext *C, /* This block uses the control key to make the object selected * by its center point rather than its contents */ - /* in editmode do not activate */ + /* In edit-mode do not activate. */ if (obcenter) { /* note; shift+alt goes to group-flush-selecting */ @@ -2337,11 +2337,11 @@ static int view3d_select_exec(bContext *C, wmOperator *op) bool toggle = RNA_boolean_get(op->ptr, "toggle"); bool center = RNA_boolean_get(op->ptr, "center"); bool enumerate = RNA_boolean_get(op->ptr, "enumerate"); - /* only force object select for editmode to support vertex parenting, - * or paint-select to allow pose bone select with vert/face select */ + /* Only force object select for edit-mode to support vertex parenting, + * or paint-select to allow pose bone select with vert/face select. */ bool object = (RNA_boolean_get(op->ptr, "object") && (obedit || BKE_paint_select_elem_test(obact) || - /* so its possible to select bones in weightpaint mode (LMB select) */ + /* so its possible to select bones in weight-paint mode (LMB select) */ (obact && (obact->mode & OB_MODE_WEIGHT_PAINT) && BKE_object_pose_armature_get(obact)))); @@ -2358,8 +2358,8 @@ static int view3d_select_exec(bContext *C, wmOperator *op) obact = NULL; /* ack, this is incorrect but to do this correctly we would need an - * alternative editmode/objectmode keymap, this copies the functionality - * from 2.4x where Ctrl+Select in editmode does object select only */ + * alternative edit-mode/object-mode keymap, this copies the functionality + * from 2.4x where Ctrl+Select in edit-mode does object select only. */ center = false; } @@ -2493,12 +2493,12 @@ void VIEW3D_OT_select(wmOperatorType *ot) "center", 0, "Center", - "Use the object center when selecting, in editmode used to extend object selection"); + "Use the object center when selecting, in edit-mode used to extend object selection"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_boolean( ot->srna, "enumerate", 0, "Enumerate", "List objects under the mouse (object mode only)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); - prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (editmode only)"); + prop = RNA_def_boolean(ot->srna, "object", 0, "Object", "Use object selection (edit-mode only)"); RNA_def_property_flag(prop, PROP_SKIP_SAVE); prop = RNA_def_int_vector(ot->srna, @@ -3286,7 +3286,7 @@ static int view3d_box_select_exec(bContext *C, wmOperator *op) } FOREACH_OBJECT_IN_MODE_END; } - else { /* no editmode, unified for bones and objects */ + else { /* No edit-mode, unified for bones and objects. */ if (vc.obact && vc.obact->mode & OB_MODE_SCULPT) { /* XXX, this is not selection, could be it's own operator. */ changed_multi = ED_sculpt_mask_box_select( diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c index 17e69ff38b8..efd7879c8b2 100644 --- a/source/blender/editors/transform/transform_convert_gpencil.c +++ b/source/blender/editors/transform/transform_convert_gpencil.c @@ -228,10 +228,11 @@ void createTransGPencil(bContext *C, TransInfo *t) for (gpf = init_gpf; gpf; gpf = gpf->next) { if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) { - /* if multiframe and falloff, recalculate and save value */ + /* If multi-frame and falloff, recalculate and save value. */ float falloff = 1.0f; /* by default no falloff */ if ((is_multiedit) && (use_multiframe_falloff)) { - /* Faloff depends on distance to active frame (relative to the overall frame range) */ + /* Falloff depends on distance to active frame + * (relative to the overall frame range). */ falloff = BKE_gpencil_multiframe_falloff_calc( gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff); } diff --git a/source/blender/editors/transform/transform_generics.c b/source/blender/editors/transform/transform_generics.c index bb4d50fcf54..716df24f195 100644 --- a/source/blender/editors/transform/transform_generics.c +++ b/source/blender/editors/transform/transform_generics.c @@ -1102,7 +1102,7 @@ static void recalcData_objects(TransInfo *t) if (motionpath_update) { /* Update motion paths once for all transformed objects. */ - ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CHANGED); + ED_objects_recalculate_paths(t->context, t->scene, OBJECT_PATH_CALC_RANGE_CURRENT_FRAME); } if (t->options & CTX_OBMODE_XFORM_SKIP_CHILDREN) { diff --git a/source/blender/editors/transform/transform_mode_mirror.c b/source/blender/editors/transform/transform_mode_mirror.c index 752d482fae2..2f305989f82 100644 --- a/source/blender/editors/transform/transform_mode_mirror.c +++ b/source/blender/editors/transform/transform_mode_mirror.c @@ -50,11 +50,9 @@ static void applyMirror(TransInfo *t, const int UNUSED(mval[2])) char str[UI_MAX_DRAW_STR]; copy_v3_v3(t->values_final, t->values); - /* - * OPTIMIZATION: - * This still recalcs transformation on mouse move - * while it should only recalc on constraint change - * */ + /* OPTIMIZATION: + * This still recalculates transformation on mouse move + * while it should only recalculate on constraint change. */ /* if an axis has been selected */ if (t->con.mode & CON_APPLY) { diff --git a/source/blender/gpu/GPU_draw.h b/source/blender/gpu/GPU_draw.h index 5ed27d9a648..f521fa3c702 100644 --- a/source/blender/gpu/GPU_draw.h +++ b/source/blender/gpu/GPU_draw.h @@ -95,18 +95,6 @@ void GPU_create_smoke_velocity(struct FluidModifierData *mmd); /* Delayed free of OpenGL buffers by main thread */ void GPU_free_unused_buffers(struct Main *bmain); -/* utilities */ -typedef enum eGPUAttrMask { - GPU_DEPTH_BUFFER_BIT = (1 << 0), - GPU_ENABLE_BIT = (1 << 1), - GPU_SCISSOR_BIT = (1 << 2), - GPU_VIEWPORT_BIT = (1 << 3), - GPU_BLEND_BIT = (1 << 4), -} eGPUAttrMask; - -void gpuPushAttr(eGPUAttrMask mask); -void gpuPopAttr(void); - #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_extensions.h b/source/blender/gpu/GPU_extensions.h index 245f7f47510..4ffe4a53a52 100644 --- a/source/blender/gpu/GPU_extensions.h +++ b/source/blender/gpu/GPU_extensions.h @@ -44,6 +44,7 @@ int GPU_max_ubo_size(void); float GPU_max_line_width(void); void GPU_get_dfdy_factors(float fac[2]); bool GPU_arb_base_instance_is_supported(void); +bool GPU_arb_texture_cube_map_array_is_supported(void); bool GPU_mip_render_workaround(void); bool GPU_depth_blitting_workaround(void); bool GPU_unused_fb_slot_workaround(void); diff --git a/source/blender/gpu/GPU_material.h b/source/blender/gpu/GPU_material.h index 37fe30bc96b..da00306bf9f 100644 --- a/source/blender/gpu/GPU_material.h +++ b/source/blender/gpu/GPU_material.h @@ -98,12 +98,9 @@ typedef enum eGPUBuiltin { GPU_LOC_TO_VIEW_MATRIX = (1 << 13), GPU_INVERSE_LOC_TO_VIEW_MATRIX = (1 << 14), GPU_OBJECT_INFO = (1 << 15), - GPU_VOLUME_DENSITY = (1 << 16), - GPU_VOLUME_FLAME = (1 << 17), - GPU_VOLUME_TEMPERATURE = (1 << 18), - GPU_BARYCENTRIC_TEXCO = (1 << 19), - GPU_BARYCENTRIC_DIST = (1 << 20), - GPU_WORLD_NORMAL = (1 << 21), + GPU_BARYCENTRIC_TEXCO = (1 << 16), + GPU_BARYCENTRIC_DIST = (1 << 17), + GPU_WORLD_NORMAL = (1 << 18), } eGPUBuiltin; typedef enum eGPUMatFlag { @@ -145,6 +142,7 @@ GPUNodeLink *GPU_image(GPUMaterial *mat, struct Image *ima, struct ImageUser *iu GPUNodeLink *GPU_image_tiled(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_image_tiled_mapping(GPUMaterial *mat, struct Image *ima, struct ImageUser *iuser); GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *layer); +GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name); GPUNodeLink *GPU_builtin(eGPUBuiltin builtin); bool GPU_link(GPUMaterial *mat, const char *name, ...); @@ -178,7 +176,8 @@ GPUMaterial *GPU_material_from_nodetree(struct Scene *scene, struct bNodeTree *ntree, struct ListBase *gpumaterials, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert_code, const char *geom_code, const char *frag_lib, @@ -191,7 +190,6 @@ void GPU_materials_free(struct Main *bmain); struct Scene *GPU_material_scene(GPUMaterial *material); struct GPUPass *GPU_material_get_pass(GPUMaterial *material); -struct ListBase *GPU_material_get_inputs(GPUMaterial *material); struct Material *GPU_material_get_material(GPUMaterial *material); eGPUMaterialStatus GPU_material_status(GPUMaterial *mat); @@ -199,8 +197,10 @@ struct GPUUniformBuffer *GPU_material_uniform_buffer_get(GPUMaterial *material); void GPU_material_uniform_buffer_create(GPUMaterial *material, ListBase *inputs); struct GPUUniformBuffer *GPU_material_create_sss_profile_ubo(void); -bool GPU_material_use_domain_surface(GPUMaterial *mat); -bool GPU_material_use_domain_volume(GPUMaterial *mat); +bool GPU_material_has_surface_output(GPUMaterial *mat); +bool GPU_material_has_volume_output(GPUMaterial *mat); + +bool GPU_material_is_volume_shader(GPUMaterial *mat); void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag); bool GPU_material_flag_get(GPUMaterial *mat, eGPUMatFlag flag); @@ -230,8 +230,16 @@ typedef struct GPUMaterialTexture { int users; } GPUMaterialTexture; +typedef struct GPUMaterialVolumeGrid { + struct GPUMaterialVolumeGrid *next, *prev; + char *name; + char sampler_name[32]; /* Name of sampler in GLSL. */ + int users; +} GPUMaterialVolumeGrid; + ListBase GPU_material_attributes(GPUMaterial *material); ListBase GPU_material_textures(GPUMaterial *material); +ListBase GPU_material_volume_grids(GPUMaterial *material); #ifdef __cplusplus } diff --git a/source/blender/gpu/GPU_state.h b/source/blender/gpu/GPU_state.h index 894ef22e963..9ce91d31d69 100644 --- a/source/blender/gpu/GPU_state.h +++ b/source/blender/gpu/GPU_state.h @@ -65,6 +65,18 @@ void GPU_finish(void); void GPU_logic_op_invert_set(bool enable); +/* Attribute push & pop. */ +typedef enum eGPUAttrMask { + GPU_DEPTH_BUFFER_BIT = (1 << 0), + GPU_ENABLE_BIT = (1 << 1), + GPU_SCISSOR_BIT = (1 << 2), + GPU_VIEWPORT_BIT = (1 << 3), + GPU_BLEND_BIT = (1 << 4), +} eGPUAttrMask; + +void gpuPushAttr(eGPUAttrMask mask); +void gpuPopAttr(void); + #ifdef __cplusplus } #endif diff --git a/source/blender/gpu/GPU_texture.h b/source/blender/gpu/GPU_texture.h index 50b7c23059d..892452a2738 100644 --- a/source/blender/gpu/GPU_texture.h +++ b/source/blender/gpu/GPU_texture.h @@ -162,6 +162,12 @@ GPUTexture *GPU_texture_create_nD(int w, int samples, const bool can_rescale, char err_out[256]); +GPUTexture *GPU_texture_cube_create(int w, + int d, + const void *pixels, + eGPUTextureFormat tex_format, + eGPUDataFormat gpu_data_format, + char err_out[256]); GPUTexture *GPU_texture_create_1d(int w, eGPUTextureFormat data_type, @@ -185,6 +191,9 @@ GPUTexture *GPU_texture_create_cube(int w, eGPUTextureFormat data_type, const float *pixels, char err_out[256]); +GPUTexture *GPU_texture_create_cube_array( + int w, int d, eGPUTextureFormat data_type, const float *pixels, char err_out[256]); + GPUTexture *GPU_texture_create_from_vertbuf(struct GPUVertBuf *vert); GPUTexture *GPU_texture_create_buffer(eGPUTextureFormat data_type, const uint buffer); @@ -238,6 +247,7 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat); void GPU_texture_filters(GPUTexture *tex, eGPUFilterFunction min_filter, eGPUFilterFunction mag_filter); +void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels); void GPU_texture_attach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb, int attachment); int GPU_texture_detach_framebuffer(GPUTexture *tex, struct GPUFrameBuffer *fb); @@ -251,6 +261,7 @@ void GPU_texture_orig_size_set(GPUTexture *tex, int w, int h); int GPU_texture_layers(const GPUTexture *tex); eGPUTextureFormat GPU_texture_format(const GPUTexture *tex); int GPU_texture_samples(const GPUTexture *tex); +bool GPU_texture_array(const GPUTexture *tex); bool GPU_texture_cube(const GPUTexture *tex); bool GPU_texture_depth(const GPUTexture *tex); bool GPU_texture_stencil(const GPUTexture *tex); diff --git a/source/blender/gpu/intern/gpu_codegen.c b/source/blender/gpu/intern/gpu_codegen.c index 553ecb65529..bcaa95c2f59 100644 --- a/source/blender/gpu/intern/gpu_codegen.c +++ b/source/blender/gpu/intern/gpu_codegen.c @@ -269,15 +269,6 @@ static const char *gpu_builtin_name(eGPUBuiltin builtin) else if (builtin == GPU_OBJECT_INFO) { return "unfobjectinfo"; } - else if (builtin == GPU_VOLUME_DENSITY) { - return "sampdensity"; - } - else if (builtin == GPU_VOLUME_FLAME) { - return "sampflame"; - } - else if (builtin == GPU_VOLUME_TEMPERATURE) { - return "unftemperature"; - } else if (builtin == GPU_BARYCENTRIC_TEXCO) { return "unfbarycentrictex"; } @@ -341,6 +332,11 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, } } + /* Volume Grids */ + for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) { + BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", grid->sampler_name); + } + /* Print other uniforms */ for (node = graph->nodes.first; node; node = node->next) { for (input = node->inputs.first; input; input = input->next) { @@ -350,12 +346,7 @@ static int codegen_process_uniforms_functions(GPUMaterial *material, builtins |= input->builtin; name = gpu_builtin_name(input->builtin); - if (BLI_str_startswith(name, "samp")) { - if ((input->builtin == GPU_VOLUME_DENSITY) || (input->builtin == GPU_VOLUME_FLAME)) { - BLI_dynstr_appendf(ds, "uniform sampler3D %s;\n", name); - } - } - else if (BLI_str_startswith(name, "unf")) { + if (BLI_str_startswith(name, "unf")) { BLI_dynstr_appendf(ds, "uniform %s %s;\n", gpu_data_type_to_string(input->type), name); } else { @@ -438,6 +429,9 @@ static void codegen_call_functions(DynStr *ds, GPUNodeGraph *graph, GPUOutput *f else if (input->source == GPU_SOURCE_TEX_TILED_MAPPING) { BLI_dynstr_append(ds, input->texture->tiled_mapping_name); } + else if (input->source == GPU_SOURCE_VOLUME_GRID) { + BLI_dynstr_append(ds, input->volume_grid->sampler_name); + } else if (input->source == GPU_SOURCE_OUTPUT) { codegen_convert_datatype( ds, input->link->output->type, input->type, "tmp", input->link->output->id); diff --git a/source/blender/gpu/intern/gpu_draw.c b/source/blender/gpu/intern/gpu_draw.c index d674f8600c2..33bc3ced5b2 100644 --- a/source/blender/gpu/intern/gpu_draw.c +++ b/source/blender/gpu/intern/gpu_draw.c @@ -861,6 +861,7 @@ static void gpu_texture_update_from_ibuf( * available. It is also required when requesting the GPUTexture for a render result. */ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, int textarget) { +#ifndef GPU_STANDALONE if (ima == NULL) { return NULL; } @@ -919,10 +920,13 @@ GPUTexture *GPU_texture_from_blender(Image *ima, ImageUser *iuser, ImBuf *ibuf, GPU_texture_orig_size_set(*tex, ibuf_intern->x, ibuf_intern->y); return *tex; +#endif + return NULL; } GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, int textarget) { +#ifndef GPU_STANDALONE if (clip == NULL) { return NULL; } @@ -945,6 +949,9 @@ GPUTexture *GPU_texture_from_movieclip(MovieClip *clip, MovieClipUser *cuser, in *tex = GPU_texture_from_bindcode(textarget, bindcode); return *tex; +#else + return NULL; +#endif } void GPU_free_texture_movieclip(struct MovieClip *clip) @@ -1270,6 +1277,7 @@ void GPU_create_gl_tex_compressed(unsigned int *bind, int textarget, Image *ima, * re-uploaded to OpenGL */ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) { +#ifndef GPU_STANDALONE if (!GTS.domipmap) { return; } @@ -1321,10 +1329,12 @@ void GPU_paint_set_mipmap(Main *bmain, bool mipmap) } } } +#endif /* GPU_STANDALONE */ } void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, int h) { +#ifndef GPU_STANDALONE ImBuf *ibuf = BKE_image_acquire_ibuf(ima, iuser, NULL); ImageTile *tile = BKE_image_get_tile_from_iuser(ima, iuser); @@ -1346,6 +1356,7 @@ void GPU_paint_update_image(Image *ima, ImageUser *iuser, int x, int y, int w, i } BKE_image_release_ibuf(ima, ibuf, NULL); +#endif } static LinkNode *image_free_queue = NULL; @@ -1526,177 +1537,3 @@ void GPU_state_init(void) glEnable(GL_PRIMITIVE_RESTART_FIXED_INDEX); } } - -/** \name Framebuffer color depth, for selection codes - * \{ */ - -#define STATE_STACK_DEPTH 16 - -typedef struct { - eGPUAttrMask mask; - - /* GL_ENABLE_BIT */ - uint is_blend : 1; - uint is_cull_face : 1; - uint is_depth_test : 1; - uint is_dither : 1; - uint is_lighting : 1; - uint is_line_smooth : 1; - uint is_color_logic_op : 1; - uint is_multisample : 1; - uint is_polygon_offset_line : 1; - uint is_polygon_offset_fill : 1; - uint is_polygon_smooth : 1; - uint is_sample_alpha_to_coverage : 1; - uint is_scissor_test : 1; - uint is_stencil_test : 1; - - bool is_clip_plane[6]; - - /* GL_DEPTH_BUFFER_BIT */ - /* uint is_depth_test : 1; */ - int depth_func; - double depth_clear_value; - bool depth_write_mask; - - /* GL_SCISSOR_BIT */ - int scissor_box[4]; - /* uint is_scissor_test : 1; */ - - /* GL_VIEWPORT_BIT */ - int viewport[4]; - double near_far[2]; -} GPUAttrValues; - -typedef struct { - GPUAttrValues attr_stack[STATE_STACK_DEPTH]; - uint top; -} GPUAttrStack; - -static GPUAttrStack state = { - .top = 0, -}; - -#define AttrStack state -#define Attr state.attr_stack[state.top] - -/** - * Replacement for glPush/PopAttributes - * - * We don't need to cover all the options of legacy OpenGL - * but simply the ones used by Blender. - */ -void gpuPushAttr(eGPUAttrMask mask) -{ - Attr.mask = mask; - - if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func); - glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value); - glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask); - } - - if ((mask & GPU_ENABLE_BIT) != 0) { - Attr.is_blend = glIsEnabled(GL_BLEND); - - for (int i = 0; i < 6; i++) { - Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); - } - - Attr.is_cull_face = glIsEnabled(GL_CULL_FACE); - Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); - Attr.is_dither = glIsEnabled(GL_DITHER); - Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); - Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); - Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE); - Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); - Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); - Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); - Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); - Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); - } - - if ((mask & GPU_SCISSOR_BIT) != 0) { - Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); - glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box); - } - - if ((mask & GPU_VIEWPORT_BIT) != 0) { - glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far); - glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport); - } - - if ((mask & GPU_BLEND_BIT) != 0) { - Attr.is_blend = glIsEnabled(GL_BLEND); - } - - BLI_assert(AttrStack.top < STATE_STACK_DEPTH); - AttrStack.top++; -} - -static void restore_mask(GLenum cap, const bool value) -{ - if (value) { - glEnable(cap); - } - else { - glDisable(cap); - } -} - -void gpuPopAttr(void) -{ - BLI_assert(AttrStack.top > 0); - AttrStack.top--; - - GLint mask = Attr.mask; - - if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { - restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); - glDepthFunc(Attr.depth_func); - glClearDepth(Attr.depth_clear_value); - glDepthMask(Attr.depth_write_mask); - } - - if ((mask & GPU_ENABLE_BIT) != 0) { - restore_mask(GL_BLEND, Attr.is_blend); - - for (int i = 0; i < 6; i++) { - restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]); - } - - restore_mask(GL_CULL_FACE, Attr.is_cull_face); - restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); - restore_mask(GL_DITHER, Attr.is_dither); - restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth); - restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op); - restore_mask(GL_MULTISAMPLE, Attr.is_multisample); - restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line); - restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill); - restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth); - restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage); - restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); - restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test); - } - - if ((mask & GPU_VIEWPORT_BIT) != 0) { - glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]); - glDepthRange(Attr.near_far[0], Attr.near_far[1]); - } - - if ((mask & GPU_SCISSOR_BIT) != 0) { - restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); - glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]); - } - - if ((mask & GPU_BLEND_BIT) != 0) { - restore_mask(GL_BLEND, Attr.is_blend); - } -} - -#undef Attr -#undef AttrStack - -/** \} */ diff --git a/source/blender/gpu/intern/gpu_draw_smoke.c b/source/blender/gpu/intern/gpu_draw_smoke.c index 5cca472148a..546faadbda4 100644 --- a/source/blender/gpu/intern/gpu_draw_smoke.c +++ b/source/blender/gpu/intern/gpu_draw_smoke.c @@ -122,13 +122,12 @@ static GPUTexture *create_transfer_function(int type, const struct ColorBand *co return tex; } -static void swizzle_texture_channel_rrrr(GPUTexture *tex) +static void swizzle_texture_channel_single(GPUTexture *tex) { + /* Swizzle texture channels so that we get useful RGBA values when sampling + * a texture with fewer channels, e.g. when using density as color. */ GPU_texture_bind(tex, 0); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, GL_RED); - glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, GL_RED); + GPU_texture_swizzle_channel_auto(tex, 1); GPU_texture_unbind(tex); } @@ -186,60 +185,59 @@ static GPUTexture *create_field_texture(FluidDomainSettings *mds) GPUTexture *tex = GPU_texture_create_nD( mds->res[0], mds->res[1], mds->res[2], 3, field, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); - swizzle_texture_channel_rrrr(tex); + swizzle_texture_channel_single(tex); return tex; } static GPUTexture *create_density_texture(FluidDomainSettings *mds, int highres) { - float *data = NULL, *source; - int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells; + int *dim = (highres) ? mds->res_noise : mds->res; + + float *data; + if (highres) { + data = manta_smoke_turbulence_get_density(mds->fluid); + } + else { + data = manta_smoke_get_density(mds->fluid); + } + + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, data, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); + + swizzle_texture_channel_single(tex); + + return tex; +} + +static GPUTexture *create_color_texture(FluidDomainSettings *mds, int highres) +{ const bool has_color = (highres) ? manta_smoke_turbulence_has_colors(mds->fluid) : manta_smoke_has_colors(mds->fluid); + + if (!has_color) { + return NULL; + } + + int cell_count = (highres) ? manta_smoke_turbulence_get_cells(mds->fluid) : mds->total_cells; int *dim = (highres) ? mds->res_noise : mds->res; - eGPUTextureFormat format = (has_color) ? GPU_RGBA8 : GPU_R8; + float *data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); - if (has_color) { - data = MEM_callocN(sizeof(float) * cell_count * 4, "smokeColorTexture"); + if (data == NULL) { + return NULL; } if (highres) { - if (has_color) { - manta_smoke_turbulence_get_rgba(mds->fluid, data, 0); - } - else { - source = manta_smoke_turbulence_get_density(mds->fluid); - } + manta_smoke_turbulence_get_rgba(mds->fluid, data, 0); } else { - if (has_color) { - manta_smoke_get_rgba(mds->fluid, data, 0); - } - else { - source = manta_smoke_get_density(mds->fluid); - } + manta_smoke_get_rgba(mds->fluid, data, 0); } - GPUTexture *tex = GPU_texture_create_nD(dim[0], - dim[1], - dim[2], - 3, - (has_color) ? data : source, - format, - GPU_DATA_FLOAT, - 0, - true, - NULL); - if (data) { - MEM_freeN(data); - } + GPUTexture *tex = GPU_texture_create_nD( + dim[0], dim[1], dim[2], 3, data, GPU_RGBA8, GPU_DATA_FLOAT, 0, true, NULL); + + MEM_freeN(data); - if (format == GPU_R8) { - /* Swizzle the RGBA components to read the Red channel so - * that the shader stay the same for colored and non color - * density textures. */ - swizzle_texture_channel_rrrr(tex); - } return tex; } @@ -264,7 +262,7 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres) GPUTexture *tex = GPU_texture_create_nD( dim[0], dim[1], dim[2], 3, source, GPU_R8, GPU_DATA_FLOAT, 0, true, NULL); - swizzle_texture_channel_rrrr(tex); + swizzle_texture_channel_single(tex); return tex; } @@ -280,35 +278,40 @@ static GPUTexture *create_flame_texture(FluidDomainSettings *mds, int highres) void GPU_free_smoke(FluidModifierData *mmd) { if (mmd->type & MOD_FLUID_TYPE_DOMAIN && mmd->domain) { - if (mmd->domain->tex) { - GPU_texture_free(mmd->domain->tex); + if (mmd->domain->tex_density) { + GPU_texture_free(mmd->domain->tex_density); + mmd->domain->tex_density = NULL; + } + + if (mmd->domain->tex_color) { + GPU_texture_free(mmd->domain->tex_color); + mmd->domain->tex_color = NULL; } - mmd->domain->tex = NULL; if (mmd->domain->tex_shadow) { GPU_texture_free(mmd->domain->tex_shadow); + mmd->domain->tex_shadow = NULL; } - mmd->domain->tex_shadow = NULL; if (mmd->domain->tex_flame) { GPU_texture_free(mmd->domain->tex_flame); + mmd->domain->tex_flame = NULL; } - mmd->domain->tex_flame = NULL; if (mmd->domain->tex_flame_coba) { GPU_texture_free(mmd->domain->tex_flame_coba); + mmd->domain->tex_flame_coba = NULL; } - mmd->domain->tex_flame_coba = NULL; if (mmd->domain->tex_coba) { GPU_texture_free(mmd->domain->tex_coba); + mmd->domain->tex_coba = NULL; } - mmd->domain->tex_coba = NULL; if (mmd->domain->tex_field) { GPU_texture_free(mmd->domain->tex_field); + mmd->domain->tex_field = NULL; } - mmd->domain->tex_field = NULL; } } @@ -338,8 +341,11 @@ void GPU_create_smoke(FluidModifierData *mmd, int highres) if (mmd->type & MOD_FLUID_TYPE_DOMAIN) { FluidDomainSettings *mds = mmd->domain; - if (!mds->tex) { - mds->tex = create_density_texture(mds, highres); + if (!mds->tex_density) { + mds->tex_density = create_density_texture(mds, highres); + } + if (!mds->tex_color) { + mds->tex_color = create_color_texture(mds, highres); } if (!mds->tex_flame) { mds->tex_flame = create_flame_texture(mds, highres); diff --git a/source/blender/gpu/intern/gpu_extensions.c b/source/blender/gpu/intern/gpu_extensions.c index 4676cc3b244..f497ed22bec 100644 --- a/source/blender/gpu/intern/gpu_extensions.c +++ b/source/blender/gpu/intern/gpu_extensions.c @@ -78,6 +78,8 @@ static struct GPUGlobal { /* Some Intel drivers have limited support for `GLEW_ARB_base_instance` so in * these cases it is best to indicate that it is not supported. See T67951 */ bool glew_arb_base_instance_is_supported; + /* Cubemap Array support. */ + bool glew_arb_texture_cube_map_array_is_supported; /* Some Intel drivers have issues with using mips as framebuffer targets if * GL_TEXTURE_MAX_LEVEL is higher than the target mip. * We need a workaround in this cases. */ @@ -197,6 +199,11 @@ bool GPU_arb_base_instance_is_supported(void) return GG.glew_arb_base_instance_is_supported; } +bool GPU_arb_texture_cube_map_array_is_supported(void) +{ + return GG.glew_arb_texture_cube_map_array_is_supported; +} + bool GPU_mip_render_workaround(void) { return GG.mip_render_workaround; @@ -281,6 +288,7 @@ void gpu_extensions_init(void) } GG.glew_arb_base_instance_is_supported = GLEW_ARB_base_instance; + GG.glew_arb_texture_cube_map_array_is_supported = GLEW_ARB_texture_cube_map_array; gpu_detect_mip_render_workaround(); if (G.debug & G_DEBUG_GPU_FORCE_WORKAROUNDS) { @@ -348,7 +356,11 @@ void gpu_extensions_exit(void) bool GPU_mem_stats_supported(void) { +#ifndef GPU_STANDALONE return (GLEW_NVX_gpu_memory_info || GLEW_ATI_meminfo) && (G.debug & G_DEBUG_GPU_MEM); +#else + return false; +#endif } void GPU_mem_stats_get(int *totalmem, int *freemem) diff --git a/source/blender/gpu/intern/gpu_immediate.c b/source/blender/gpu/intern/gpu_immediate.c index bd3de96d636..671335ca702 100644 --- a/source/blender/gpu/intern/gpu_immediate.c +++ b/source/blender/gpu/intern/gpu_immediate.c @@ -23,7 +23,9 @@ * GPU immediate mode work-alike */ -#include "UI_resources.h" +#ifndef GPU_STANDALONE +# include "UI_resources.h" +#endif #include "GPU_attr_binding.h" #include "GPU_immediate.h" @@ -910,6 +912,8 @@ void immUniformColor4ubv(const uchar rgba[4]) immUniformColor4ub(rgba[0], rgba[1], rgba[2], rgba[3]); } +#ifndef GPU_STANDALONE + void immUniformThemeColor(int color_id) { float color[4]; @@ -958,3 +962,5 @@ void immThemeColorShadeAlpha(int colorid, int coloffset, int alphaoffset) UI_GetThemeColorShadeAlpha4ubv(colorid, coloffset, alphaoffset, col); immUniformColor4ub(col[0], col[1], col[2], col[3]); } + +#endif /* GPU_STANDALONE */ diff --git a/source/blender/gpu/intern/gpu_init_exit.c b/source/blender/gpu/intern/gpu_init_exit.c index c99b7fc8a67..96dc437e10b 100644 --- a/source/blender/gpu/intern/gpu_init_exit.c +++ b/source/blender/gpu/intern/gpu_init_exit.c @@ -64,12 +64,16 @@ void GPU_init(void) immInit(); } +#ifndef GPU_STANDALONE gpu_pbvh_init(); +#endif } void GPU_exit(void) { +#ifndef GPU_STANDALONE gpu_pbvh_exit(); +#endif if (!G.background) { immDestroy(); diff --git a/source/blender/gpu/intern/gpu_material.c b/source/blender/gpu/intern/gpu_material.c index b2658839d67..8a4a88d0663 100644 --- a/source/blender/gpu/intern/gpu_material.c +++ b/source/blender/gpu/intern/gpu_material.c @@ -70,6 +70,7 @@ struct GPUMaterial { const void *engine_type; /* attached engine type */ int options; /* to identify shader variations (shadow, probe, world background...) */ + bool is_volume_shader; /* is volumetric shader */ /* Nodes */ GPUNodeGraph graph; @@ -80,7 +81,8 @@ struct GPUMaterial { /* XXX: Should be in Material. But it depends on the output node * used and since the output selection is different for GPUMaterial... */ - int domain; + bool has_volume_output; + bool has_surface_output; /* Only used by Eevee to know which bsdf are used. */ int flag; @@ -109,8 +111,8 @@ struct GPUMaterial { }; enum { - GPU_DOMAIN_SURFACE = (1 << 0), - GPU_DOMAIN_VOLUME = (1 << 1), + GPU_USE_SURFACE_OUTPUT = (1 << 0), + GPU_USE_VOLUME_OUTPUT = (1 << 1), }; /* Functions */ @@ -567,6 +569,11 @@ ListBase GPU_material_textures(GPUMaterial *material) return material->graph.textures; } +ListBase GPU_material_volume_grids(GPUMaterial *material) +{ + return material->graph.volume_grids; +} + void GPU_material_output_link(GPUMaterial *material, GPUNodeLink *link) { if (!material->graph.outlink) { @@ -592,14 +599,19 @@ eGPUMaterialStatus GPU_material_status(GPUMaterial *mat) /* Code generation */ -bool GPU_material_use_domain_surface(GPUMaterial *mat) +bool GPU_material_has_surface_output(GPUMaterial *mat) +{ + return mat->has_surface_output; +} + +bool GPU_material_has_volume_output(GPUMaterial *mat) { - return (mat->domain & GPU_DOMAIN_SURFACE); + return mat->has_volume_output; } -bool GPU_material_use_domain_volume(GPUMaterial *mat) +bool GPU_material_is_volume_shader(GPUMaterial *mat) { - return (mat->domain & GPU_DOMAIN_VOLUME); + return mat->is_volume_shader; } void GPU_material_flag_set(GPUMaterial *mat, eGPUMatFlag flag) @@ -636,7 +648,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, struct bNodeTree *ntree, ListBase *gpumaterials, const void *engine_type, - int options, + const int options, + const bool is_volume_shader, const char *vert_code, const char *geom_code, const char *frag_lib, @@ -655,6 +668,7 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, mat->scene = scene; mat->engine_type = engine_type; mat->options = options; + mat->is_volume_shader = is_volume_shader; #ifndef NDEBUG BLI_snprintf(mat->name, sizeof(mat->name), "%s", name); #else @@ -670,8 +684,8 @@ GPUMaterial *GPU_material_from_nodetree(Scene *scene, gpu_material_ramp_texture_build(mat); - SET_FLAG_FROM_TEST(mat->domain, has_surface_output, GPU_DOMAIN_SURFACE); - SET_FLAG_FROM_TEST(mat->domain, has_volume_output, GPU_DOMAIN_VOLUME); + mat->has_surface_output = has_surface_output; + mat->has_volume_output = has_volume_output; if (mat->graph.outlink) { /* HACK: this is only for eevee. We add the define here after the nodetree evaluation. */ diff --git a/source/blender/gpu/intern/gpu_node_graph.c b/source/blender/gpu/intern/gpu_node_graph.c index de35b43109f..0d5cc46c0b9 100644 --- a/source/blender/gpu/intern/gpu_node_graph.c +++ b/source/blender/gpu/intern/gpu_node_graph.c @@ -119,6 +119,10 @@ static void gpu_node_input_link(GPUNode *node, GPUNodeLink *link, const eGPUType input->source = GPU_SOURCE_TEX_TILED_MAPPING; input->texture = link->texture; break; + case GPU_NODE_LINK_VOLUME_GRID: + input->source = GPU_SOURCE_VOLUME_GRID; + input->volume_grid = link->volume_grid; + break; case GPU_NODE_LINK_ATTR: input->source = GPU_SOURCE_ATTR; input->attr = link->attr; @@ -321,6 +325,31 @@ static GPUMaterialTexture *gpu_node_graph_add_texture(GPUNodeGraph *graph, return tex; } +static GPUMaterialVolumeGrid *gpu_node_graph_add_volume_grid(GPUNodeGraph *graph, const char *name) +{ + /* Find existing volume grid. */ + int num_grids = 0; + GPUMaterialVolumeGrid *grid = graph->volume_grids.first; + for (; grid; grid = grid->next) { + if (STREQ(grid->name, name)) { + break; + } + num_grids++; + } + + /* Add new requested volume grid. */ + if (grid == NULL) { + grid = MEM_callocN(sizeof(*grid), __func__); + grid->name = BLI_strdup(name); + BLI_snprintf(grid->sampler_name, sizeof(grid->sampler_name), "vsamp%d", num_grids); + BLI_addtail(&graph->volume_grids, grid); + } + + grid->users++; + + return grid; +} + /* Creating Inputs */ GPUNodeLink *GPU_attribute(GPUMaterial *mat, const CustomDataType type, const char *name) @@ -394,6 +423,30 @@ GPUNodeLink *GPU_color_band(GPUMaterial *mat, int size, float *pixels, float *ro return link; } +GPUNodeLink *GPU_volume_grid(GPUMaterial *mat, const char *name) +{ + /* NOTE: this could be optimized by automatically merging duplicate + * lookups of the same attribute. */ + GPUNodeGraph *graph = gpu_material_node_graph(mat); + GPUNodeLink *link = gpu_node_link_create(); + link->link_type = GPU_NODE_LINK_VOLUME_GRID; + link->volume_grid = gpu_node_graph_add_volume_grid(graph, name); + + /* Two special cases, where we adjust the output values of smoke grids to + * bring the into standard range without having to modify the grid values. */ + if (strcmp(name, "color") == 0) { + GPU_link(mat, "node_attribute_volume_color", link, &link); + } + else if (strcmp(name, "temperature") == 0) { + GPU_link(mat, "node_attribute_volume_temperature", link, &link); + } + else { + GPU_link(mat, "node_attribute_volume", link, &link); + } + + return link; +} + GPUNodeLink *GPU_builtin(eGPUBuiltin builtin) { GPUNodeLink *link = gpu_node_link_create(); @@ -537,6 +590,9 @@ static void gpu_inputs_free(ListBase *inputs) else if (ELEM(input->source, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING)) { input->texture->users--; } + else if (ELEM(input->source, GPU_SOURCE_VOLUME_GRID)) { + input->volume_grid->users--; + } if (input->link) { gpu_node_link_free(input->link); @@ -579,6 +635,11 @@ void gpu_node_graph_free_nodes(GPUNodeGraph *graph) void gpu_node_graph_free(GPUNodeGraph *graph) { gpu_node_graph_free_nodes(graph); + + for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first; grid; grid = grid->next) { + MEM_SAFE_FREE(grid->name); + } + BLI_freelistN(&graph->volume_grids); BLI_freelistN(&graph->textures); BLI_freelistN(&graph->attributes); } @@ -637,4 +698,12 @@ void gpu_node_graph_prune_unused(GPUNodeGraph *graph) BLI_freelinkN(&graph->textures, tex); } } + + for (GPUMaterialVolumeGrid *grid = graph->volume_grids.first, *next = NULL; grid; grid = next) { + next = grid->next; + if (grid->users == 0) { + MEM_SAFE_FREE(grid->name); + BLI_freelinkN(&graph->volume_grids, grid); + } + } } diff --git a/source/blender/gpu/intern/gpu_node_graph.h b/source/blender/gpu/intern/gpu_node_graph.h index 9214bd7f1ba..ceaeea2bfa8 100644 --- a/source/blender/gpu/intern/gpu_node_graph.h +++ b/source/blender/gpu/intern/gpu_node_graph.h @@ -48,6 +48,8 @@ typedef enum eGPUDataSource { GPU_SOURCE_STRUCT, GPU_SOURCE_TEX, GPU_SOURCE_TEX_TILED_MAPPING, + GPU_SOURCE_VOLUME_GRID, + GPU_SOURCE_VOLUME_GRID_TRANSFORM, } eGPUDataSource; typedef enum { @@ -59,6 +61,7 @@ typedef enum { GPU_NODE_LINK_IMAGE, GPU_NODE_LINK_IMAGE_TILED, GPU_NODE_LINK_IMAGE_TILED_MAPPING, + GPU_NODE_LINK_VOLUME_GRID, GPU_NODE_LINK_OUTPUT, GPU_NODE_LINK_UNIFORM, } GPUNodeLinkType; @@ -88,6 +91,8 @@ struct GPUNodeLink { eGPUBuiltin builtin; /* GPU_NODE_LINK_COLORBAND */ struct GPUTexture **colorband; + /* GPU_NODE_LINK_VOLUME_GRID */ + struct GPUMaterialVolumeGrid *volume_grid; /* GPU_NODE_LINK_OUTPUT */ struct GPUOutput *output; /* GPU_NODE_LINK_ATTR */ @@ -126,6 +131,8 @@ typedef struct GPUInput { struct GPUMaterialTexture *texture; /* GPU_SOURCE_ATTR */ struct GPUMaterialAttribute *attr; + /* GPU_SOURCE_VOLUME_GRID */ + struct GPUMaterialVolumeGrid *volume_grid; }; } GPUInput; @@ -139,6 +146,7 @@ typedef struct GPUNodeGraph { /* Requested attributes and textures. */ ListBase attributes; ListBase textures; + ListBase volume_grids; } GPUNodeGraph; /* Node Graph */ diff --git a/source/blender/gpu/intern/gpu_select_pick.c b/source/blender/gpu/intern/gpu_select_pick.c index 1fb83b628e1..498de13e10f 100644 --- a/source/blender/gpu/intern/gpu_select_pick.c +++ b/source/blender/gpu/intern/gpu_select_pick.c @@ -30,6 +30,7 @@ #include "GPU_immediate.h" #include "GPU_draw.h" #include "GPU_select.h" +#include "GPU_state.h" #include "GPU_glew.h" #include "MEM_guardedalloc.h" diff --git a/source/blender/gpu/intern/gpu_select_sample_query.c b/source/blender/gpu/intern/gpu_select_sample_query.c index 6e8b062cff0..578546f3af9 100644 --- a/source/blender/gpu/intern/gpu_select_sample_query.c +++ b/source/blender/gpu/intern/gpu_select_sample_query.c @@ -26,9 +26,8 @@ #include <stdlib.h> -#include "GPU_immediate.h" -#include "GPU_draw.h" #include "GPU_select.h" +#include "GPU_state.h" #include "GPU_glew.h" #include "MEM_guardedalloc.h" @@ -37,10 +36,6 @@ #include "BLI_utildefines.h" -#include "PIL_time.h" - -#include "BKE_global.h" - #include "gpu_select_private.h" /* Ad hoc number of queries to allocate to skip doing many glGenQueries */ diff --git a/source/blender/gpu/intern/gpu_shader.c b/source/blender/gpu/intern/gpu_shader.c index c950a1daaa5..0993d69e14d 100644 --- a/source/blender/gpu/intern/gpu_shader.c +++ b/source/blender/gpu/intern/gpu_shader.c @@ -46,7 +46,7 @@ /* Adjust these constants as needed. */ #define MAX_DEFINE_LENGTH 256 -#define MAX_EXT_DEFINE_LENGTH 256 +#define MAX_EXT_DEFINE_LENGTH 512 /* Non-generated shaders */ extern char datatoc_gpu_shader_depth_only_frag_glsl[]; @@ -235,6 +235,10 @@ static void gpu_shader_standard_extensions(char defines[MAX_EXT_DEFINE_LENGTH]) if (GLEW_ARB_shader_draw_parameters) { strcat(defines, "#extension GL_ARB_shader_draw_parameters : enable\n"); } + if (GPU_arb_texture_cube_map_array_is_supported()) { + strcat(defines, "#extension GL_ARB_texture_cube_map_array : enable\n"); + strcat(defines, "#define GPU_ARB_texture_cube_map_array\n"); + } } static void gpu_shader_standard_defines(char defines[MAX_DEFINE_LENGTH]) diff --git a/source/blender/gpu/intern/gpu_state.c b/source/blender/gpu/intern/gpu_state.c index caf97a620ab..9ff518aec1b 100644 --- a/source/blender/gpu/intern/gpu_state.c +++ b/source/blender/gpu/intern/gpu_state.c @@ -18,7 +18,12 @@ * \ingroup gpu */ -#include "DNA_userdef_types.h" +#ifndef GPU_STANDALONE +# include "DNA_userdef_types.h" +# define PIXELSIZE (U.pixelsize) +#else +# define PIXELSIZE (1.0f) +#endif #include "BLI_utildefines.h" @@ -107,7 +112,7 @@ void GPU_line_smooth(bool enable) void GPU_line_width(float width) { float max_size = GPU_max_line_width(); - float final_size = width * U.pixelsize; + float final_size = width * PIXELSIZE; /* Fix opengl errors on certain platform / drivers. */ CLAMP(final_size, 1.0f, max_size); glLineWidth(final_size); @@ -115,7 +120,7 @@ void GPU_line_width(float width) void GPU_point_size(float size) { - glPointSize(size * U.pixelsize); + glPointSize(size * PIXELSIZE); } void GPU_polygon_smooth(bool enable) @@ -189,3 +194,177 @@ void GPU_logic_op_invert_set(bool enable) glEnable(GL_DITHER); } } + +/** \name GPU Push/Pop State + * \{ */ + +#define STATE_STACK_DEPTH 16 + +typedef struct { + eGPUAttrMask mask; + + /* GL_ENABLE_BIT */ + uint is_blend : 1; + uint is_cull_face : 1; + uint is_depth_test : 1; + uint is_dither : 1; + uint is_lighting : 1; + uint is_line_smooth : 1; + uint is_color_logic_op : 1; + uint is_multisample : 1; + uint is_polygon_offset_line : 1; + uint is_polygon_offset_fill : 1; + uint is_polygon_smooth : 1; + uint is_sample_alpha_to_coverage : 1; + uint is_scissor_test : 1; + uint is_stencil_test : 1; + + bool is_clip_plane[6]; + + /* GL_DEPTH_BUFFER_BIT */ + /* uint is_depth_test : 1; */ + int depth_func; + double depth_clear_value; + bool depth_write_mask; + + /* GL_SCISSOR_BIT */ + int scissor_box[4]; + /* uint is_scissor_test : 1; */ + + /* GL_VIEWPORT_BIT */ + int viewport[4]; + double near_far[2]; +} GPUAttrValues; + +typedef struct { + GPUAttrValues attr_stack[STATE_STACK_DEPTH]; + uint top; +} GPUAttrStack; + +static GPUAttrStack state = { + .top = 0, +}; + +#define AttrStack state +#define Attr state.attr_stack[state.top] + +/** + * Replacement for glPush/PopAttributes + * + * We don't need to cover all the options of legacy OpenGL + * but simply the ones used by Blender. + */ +void gpuPushAttr(eGPUAttrMask mask) +{ + Attr.mask = mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + glGetIntegerv(GL_DEPTH_FUNC, &Attr.depth_func); + glGetDoublev(GL_DEPTH_CLEAR_VALUE, &Attr.depth_clear_value); + glGetBooleanv(GL_DEPTH_WRITEMASK, (GLboolean *)&Attr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + Attr.is_blend = glIsEnabled(GL_BLEND); + + for (int i = 0; i < 6; i++) { + Attr.is_clip_plane[i] = glIsEnabled(GL_CLIP_PLANE0 + i); + } + + Attr.is_cull_face = glIsEnabled(GL_CULL_FACE); + Attr.is_depth_test = glIsEnabled(GL_DEPTH_TEST); + Attr.is_dither = glIsEnabled(GL_DITHER); + Attr.is_line_smooth = glIsEnabled(GL_LINE_SMOOTH); + Attr.is_color_logic_op = glIsEnabled(GL_COLOR_LOGIC_OP); + Attr.is_multisample = glIsEnabled(GL_MULTISAMPLE); + Attr.is_polygon_offset_line = glIsEnabled(GL_POLYGON_OFFSET_LINE); + Attr.is_polygon_offset_fill = glIsEnabled(GL_POLYGON_OFFSET_FILL); + Attr.is_polygon_smooth = glIsEnabled(GL_POLYGON_SMOOTH); + Attr.is_sample_alpha_to_coverage = glIsEnabled(GL_SAMPLE_ALPHA_TO_COVERAGE); + Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + Attr.is_stencil_test = glIsEnabled(GL_STENCIL_TEST); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + Attr.is_scissor_test = glIsEnabled(GL_SCISSOR_TEST); + glGetIntegerv(GL_SCISSOR_BOX, (GLint *)&Attr.scissor_box); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glGetDoublev(GL_DEPTH_RANGE, (GLdouble *)&Attr.near_far); + glGetIntegerv(GL_VIEWPORT, (GLint *)&Attr.viewport); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + Attr.is_blend = glIsEnabled(GL_BLEND); + } + + BLI_assert(AttrStack.top < STATE_STACK_DEPTH); + AttrStack.top++; +} + +static void restore_mask(GLenum cap, const bool value) +{ + if (value) { + glEnable(cap); + } + else { + glDisable(cap); + } +} + +void gpuPopAttr(void) +{ + BLI_assert(AttrStack.top > 0); + AttrStack.top--; + + GLint mask = Attr.mask; + + if ((mask & GPU_DEPTH_BUFFER_BIT) != 0) { + restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); + glDepthFunc(Attr.depth_func); + glClearDepth(Attr.depth_clear_value); + glDepthMask(Attr.depth_write_mask); + } + + if ((mask & GPU_ENABLE_BIT) != 0) { + restore_mask(GL_BLEND, Attr.is_blend); + + for (int i = 0; i < 6; i++) { + restore_mask(GL_CLIP_PLANE0 + i, Attr.is_clip_plane[i]); + } + + restore_mask(GL_CULL_FACE, Attr.is_cull_face); + restore_mask(GL_DEPTH_TEST, Attr.is_depth_test); + restore_mask(GL_DITHER, Attr.is_dither); + restore_mask(GL_LINE_SMOOTH, Attr.is_line_smooth); + restore_mask(GL_COLOR_LOGIC_OP, Attr.is_color_logic_op); + restore_mask(GL_MULTISAMPLE, Attr.is_multisample); + restore_mask(GL_POLYGON_OFFSET_LINE, Attr.is_polygon_offset_line); + restore_mask(GL_POLYGON_OFFSET_FILL, Attr.is_polygon_offset_fill); + restore_mask(GL_POLYGON_SMOOTH, Attr.is_polygon_smooth); + restore_mask(GL_SAMPLE_ALPHA_TO_COVERAGE, Attr.is_sample_alpha_to_coverage); + restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); + restore_mask(GL_STENCIL_TEST, Attr.is_stencil_test); + } + + if ((mask & GPU_VIEWPORT_BIT) != 0) { + glViewport(Attr.viewport[0], Attr.viewport[1], Attr.viewport[2], Attr.viewport[3]); + glDepthRange(Attr.near_far[0], Attr.near_far[1]); + } + + if ((mask & GPU_SCISSOR_BIT) != 0) { + restore_mask(GL_SCISSOR_TEST, Attr.is_scissor_test); + glScissor(Attr.scissor_box[0], Attr.scissor_box[1], Attr.scissor_box[2], Attr.scissor_box[3]); + } + + if ((mask & GPU_BLEND_BIT) != 0) { + restore_mask(GL_BLEND, Attr.is_blend); + } +} + +#undef Attr +#undef AttrStack + +/** \} */ diff --git a/source/blender/gpu/intern/gpu_texture.c b/source/blender/gpu/intern/gpu_texture.c index 9ef42592b55..7b51b03096f 100644 --- a/source/blender/gpu/intern/gpu_texture.c +++ b/source/blender/gpu/intern/gpu_texture.c @@ -109,7 +109,7 @@ static uint gpu_texture_memory_footprint_compute(GPUTexture *tex) return tex->bytesize * tex->w * tex->h * tex->d * samp; case GL_TEXTURE_CUBE_MAP: return tex->bytesize * 6 * tex->w * tex->h * samp; - case GL_TEXTURE_CUBE_MAP_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: return tex->bytesize * 6 * tex->w * tex->h * tex->d * samp; default: return 0; @@ -138,6 +138,7 @@ static const char *gl_enum_to_str(GLenum e) #define ENUM_TO_STRING(e) [GL_##e] = STRINGIFY_ARG(e) static const char *enum_strings[] = { ENUM_TO_STRING(TEXTURE_CUBE_MAP), + ENUM_TO_STRING(TEXTURE_CUBE_MAP_ARRAY), ENUM_TO_STRING(TEXTURE_2D), ENUM_TO_STRING(TEXTURE_2D_ARRAY), ENUM_TO_STRING(TEXTURE_1D), @@ -202,6 +203,25 @@ static int gpu_get_component_count(eGPUTextureFormat format) } } +static uint gpu_get_data_format_bytesize(int comp, eGPUDataFormat data_format) +{ + switch (data_format) { + case GPU_DATA_FLOAT: + return sizeof(float) * comp; + case GPU_DATA_INT: + case GPU_DATA_UNSIGNED_INT: + return sizeof(int) * comp; + case GPU_DATA_UNSIGNED_INT_24_8: + case GPU_DATA_10_11_11_REV: + return sizeof(int); + case GPU_DATA_UNSIGNED_BYTE: + return sizeof(char) * comp; + default: + BLI_assert(0); + return 0; + } +} + /* Definitely not complete, edit according to the gl specification. */ static void gpu_validate_data_format(eGPUTextureFormat tex_format, eGPUDataFormat data_format) { @@ -679,6 +699,7 @@ GPUTexture *GPU_texture_create_nD(int w, } else { tex->target_base = tex->target = GL_TEXTURE_2D_ARRAY; + tex->format_flag |= GPU_FORMAT_ARRAY; } } else if (n == 1) { @@ -687,6 +708,7 @@ GPUTexture *GPU_texture_create_nD(int w, } else { tex->target_base = tex->target = GL_TEXTURE_1D_ARRAY; + tex->format_flag |= GPU_FORMAT_ARRAY; } } else if (n == 3) { @@ -839,17 +861,12 @@ GPUTexture *GPU_texture_create_nD(int w, return tex; } -static GPUTexture *GPU_texture_cube_create(int w, - int d, - const float *fpixels_px, - const float *fpixels_py, - const float *fpixels_pz, - const float *fpixels_nx, - const float *fpixels_ny, - const float *fpixels_nz, - eGPUTextureFormat tex_format, - eGPUDataFormat gpu_data_format, - char err_out[256]) +GPUTexture *GPU_texture_cube_create(int w, + int d, + const void *pixels, + eGPUTextureFormat tex_format, + eGPUDataFormat gpu_data_format, + char err_out[256]) { GPUTexture *tex = MEM_callocN(sizeof(GPUTexture), "GPUTexture"); tex->w = w; @@ -867,8 +884,21 @@ static GPUTexture *GPU_texture_cube_create(int w, tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP; } else { - BLI_assert(false && "Cubemap array Not implemented yet"); - // tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY; + tex->target_base = tex->target = GL_TEXTURE_CUBE_MAP_ARRAY_ARB; + tex->format_flag |= GPU_FORMAT_ARRAY; + + if (!GPU_arb_texture_cube_map_array_is_supported()) { + fprintf(stderr, "ERROR: Attempt to create a cubemap array without hardware support!\n"); + BLI_assert(0); + GPU_texture_free(tex); + return NULL; + } + + if (d > GPU_max_texture_layers() / 6) { + BLI_assert(0); + GPU_texture_free(tex); + return NULL; + } } GLenum internalformat = gpu_get_gl_internalformat(tex_format); @@ -905,60 +935,42 @@ static GPUTexture *GPU_texture_cube_create(int w, glBindTexture(tex->target, tex->bindcode); /* Upload Texture */ - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_px); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_py); - glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_pz); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_nx); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_ny); - glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, - 0, - internalformat, - tex->w, - tex->h, - 0, - data_format, - data_type, - fpixels_nz); + if (d == 0) { + const char *pixels_px, *pixels_py, *pixels_pz, *pixels_nx, *pixels_ny, *pixels_nz; + + if (pixels) { + size_t face_ofs = w * w * gpu_get_data_format_bytesize(tex->components, gpu_data_format); + pixels_px = (char *)pixels + 0 * face_ofs; + pixels_nx = (char *)pixels + 1 * face_ofs; + pixels_py = (char *)pixels + 2 * face_ofs; + pixels_ny = (char *)pixels + 3 * face_ofs; + pixels_pz = (char *)pixels + 4 * face_ofs; + pixels_nz = (char *)pixels + 5 * face_ofs; + } + else { + pixels_px = pixels_py = pixels_pz = pixels_nx = pixels_ny = pixels_nz = NULL; + } + + GLuint face = GL_TEXTURE_CUBE_MAP_POSITIVE_X; + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_px); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nx); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_py); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_ny); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_pz); + glTexImage2D(face++, 0, internalformat, tex->w, tex->h, 0, data_format, data_type, pixels_nz); + } + else { + glTexImage3D(tex->target, + 0, + internalformat, + tex->w, + tex->h, + tex->d * 6, + 0, + data_format, + data_type, + pixels); + } /* Texture Parameters */ if (GPU_texture_stencil(tex) || /* Does not support filtering */ @@ -1131,33 +1143,16 @@ GPUTexture *GPU_texture_create_cube(int w, char err_out[256]) { BLI_assert(w > 0); - const float *fpixels_px, *fpixels_py, *fpixels_pz, *fpixels_nx, *fpixels_ny, *fpixels_nz; - const int channels = gpu_get_component_count(tex_format); - - if (fpixels) { - int face_ofs = w * w * channels; - fpixels_px = fpixels + 0 * face_ofs; - fpixels_nx = fpixels + 1 * face_ofs; - fpixels_py = fpixels + 2 * face_ofs; - fpixels_ny = fpixels + 3 * face_ofs; - fpixels_pz = fpixels + 4 * face_ofs; - fpixels_nz = fpixels + 5 * face_ofs; - } - else { - fpixels_px = fpixels_py = fpixels_pz = fpixels_nx = fpixels_ny = fpixels_nz = NULL; - } + eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format); + return GPU_texture_cube_create(w, 0, fpixels, tex_format, data_format, err_out); +} - return GPU_texture_cube_create(w, - 0, - fpixels_px, - fpixels_py, - fpixels_pz, - fpixels_nx, - fpixels_ny, - fpixels_nz, - tex_format, - GPU_DATA_FLOAT, - err_out); +GPUTexture *GPU_texture_create_cube_array( + int w, int d, eGPUTextureFormat tex_format, const float *fpixels, char err_out[256]) +{ + BLI_assert(w > 0 && d > 0); + eGPUDataFormat data_format = gpu_get_data_format_from_tex_format(tex_format); + return GPU_texture_cube_create(w, d, fpixels, tex_format, data_format, err_out); } GPUTexture *GPU_texture_create_from_vertbuf(GPUVertBuf *vert) @@ -1297,6 +1292,7 @@ void GPU_texture_add_mipmap(GPUTexture *tex, break; case GL_TEXTURE_3D: case GL_TEXTURE_2D_ARRAY: + case GL_TEXTURE_CUBE_MAP_ARRAY_ARB: glTexImage3D(tex->target, miplvl, internalformat, @@ -1385,29 +1381,13 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl gpu_validate_data_format(tex->format, gpu_data_format); - size_t buf_size = gpu_texture_memory_footprint_compute(tex); size_t samples_count = max_ii(1, tex->samples); - samples_count *= size[0]; samples_count *= max_ii(1, size[1]); samples_count *= max_ii(1, size[2]); - samples_count *= (GPU_texture_cube(tex)) ? 6 : 1; + samples_count *= (GPU_texture_cube(tex) && !GPU_texture_array(tex)) ? 6 : 1; - switch (gpu_data_format) { - case GPU_DATA_FLOAT: - buf_size = sizeof(float) * samples_count * tex->components; - break; - case GPU_DATA_INT: - case GPU_DATA_UNSIGNED_INT: - buf_size = sizeof(int) * samples_count * tex->components; - break; - case GPU_DATA_UNSIGNED_INT_24_8: - case GPU_DATA_10_11_11_REV: - buf_size = sizeof(int) * samples_count; - break; - case GPU_DATA_UNSIGNED_BYTE: - break; - } + size_t buf_size = samples_count * gpu_get_data_format_bytesize(tex->components, gpu_data_format); /* AMD Pro driver have a bug that write 8 bytes past buffer size * if the texture is big. (see T66573) */ @@ -1418,7 +1398,7 @@ void *GPU_texture_read(GPUTexture *tex, eGPUDataFormat gpu_data_format, int mipl glBindTexture(tex->target, tex->bindcode); - if (GPU_texture_cube(tex)) { + if (GPU_texture_cube(tex) && !GPU_texture_array(tex)) { int cube_face_size = buf_size / 6; for (int i = 0; i < 6; i++) { glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, @@ -1648,6 +1628,17 @@ void GPU_texture_wrap_mode(GPUTexture *tex, bool use_repeat) } } +void GPU_texture_swizzle_channel_auto(GPUTexture *tex, int channels) +{ + WARN_NOT_BOUND(tex); + + glActiveTexture(GL_TEXTURE0 + tex->number); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_R, GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_G, (channels >= 2) ? GL_GREEN : GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_B, (channels >= 3) ? GL_BLUE : GL_RED); + glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_SWIZZLE_A, (channels >= 4) ? GL_ALPHA : GL_ONE); +} + static GLenum gpu_get_gl_filterfunction(eGPUFilterFunction filter) { switch (filter) { @@ -1752,6 +1743,11 @@ int GPU_texture_samples(const GPUTexture *tex) return tex->samples; } +bool GPU_texture_array(const GPUTexture *tex) +{ + return (tex->format_flag & GPU_FORMAT_ARRAY) != 0; +} + bool GPU_texture_depth(const GPUTexture *tex) { return (tex->format_flag & GPU_FORMAT_DEPTH) != 0; @@ -1817,8 +1813,12 @@ void GPU_texture_get_mipmap_size(GPUTexture *tex, int lvl, int *size) size[1] = max_ii(1, tex->h / div); } - if (tex->target == GL_TEXTURE_2D_ARRAY) { + if (GPU_texture_array(tex)) { size[2] = tex->d; + /* Return the number of face layers. */ + if (GPU_texture_cube(tex)) { + size[2] *= 6; + } } else if (tex->d > 0) { size[2] = max_ii(1, tex->d / div); diff --git a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl index aa1d437c307..9e1527a9e7f 100644 --- a/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl +++ b/source/blender/gpu/shaders/gpu_shader_common_obinfos_lib.glsl @@ -1,7 +1,8 @@ -/* Need to be included after common_view_lib.glsl for resource_id. */ +#pragma BLENDER_REQUIRE(common_view_lib.glsl) + #ifndef GPU_OBINFOS_UBO -#define GPU_OBINFOS_UBO +# define GPU_OBINFOS_UBO struct ObjectInfos { vec4 drw_OrcoTexCoFactors[2]; vec4 drw_ObjectColor; @@ -13,7 +14,7 @@ layout(std140) uniform infoBlock /* DRW_RESOURCE_CHUNK_LEN = 512 */ ObjectInfos drw_infos[512]; }; -#define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) -#define ObjectInfo (drw_infos[resource_id].drw_Infos) -#define ObjectColor (drw_infos[resource_id].drw_ObjectColor) +# define OrcoTexCoFactors (drw_infos[resource_id].drw_OrcoTexCoFactors) +# define ObjectInfo (drw_infos[resource_id].drw_Infos) +# define ObjectColor (drw_infos[resource_id].drw_ObjectColor) #endif diff --git a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl index 501aeb6f34e..a80cd3cb329 100644 --- a/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl +++ b/source/blender/gpu/shaders/material/gpu_shader_material_volume_info.glsl @@ -1,18 +1,21 @@ -void node_attribute_volume_density(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) + +/* Uniforms to convert smoke grid values into standard range. */ +uniform vec3 volumeColor = vec3(1.0); +uniform vec2 volumeTemperature = vec2(0.0); + +/* Generic volume attribute. */ +void node_attribute_volume(sampler3D tex, out vec3 outvec) { #if defined(MESH_SHADER) && defined(VOLUMETRICS) vec3 cos = volumeObjectLocalCoord; #else vec3 cos = vec3(0.0); #endif - outvec = texture(tex, cos).aaa; - outcol = vec4(outvec, 1.0); - outf = avg(outvec); + outvec = texture(tex, cos).rgb; } -uniform vec3 volumeColor = vec3(1.0); - -void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +/* Special color attribute for smoke. */ +void node_attribute_volume_color(sampler3D tex, out vec3 outvec) { #if defined(MESH_SHADER) && defined(VOLUMETRICS) vec3 cos = volumeObjectLocalCoord; @@ -20,69 +23,31 @@ void node_attribute_volume_color(sampler3D tex, out vec4 outcol, out vec3 outvec vec3 cos = vec3(0.0); #endif - vec4 value = texture(tex, cos).rgba; /* Density is premultiplied for interpolation, divide it out here. */ + vec4 value = texture(tex, cos).rgba; if (value.a > 1e-8) { value.rgb /= value.a; } outvec = value.rgb * volumeColor; - outcol = vec4(outvec, 1.0); - outf = avg(outvec); } -void node_attribute_volume_flame(sampler3D tex, out vec4 outcol, out vec3 outvec, out float outf) +/* Special temperature attribute for smoke. */ +void node_attribute_volume_temperature(sampler3D tex, out float outf) { #if defined(MESH_SHADER) && defined(VOLUMETRICS) vec3 cos = volumeObjectLocalCoord; #else vec3 cos = vec3(0.0); #endif - outf = texture(tex, cos).r; - outvec = vec3(outf, outf, outf); - outcol = vec4(outf, outf, outf, 1.0); -} -void node_attribute_volume_temperature( - sampler3D tex, vec2 temperature, out vec4 outcol, out vec3 outvec, out float outf) -{ -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 cos = volumeObjectLocalCoord; -#else - vec3 cos = vec3(0.0); -#endif - float flame = texture(tex, cos).r; - - outf = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0; - outvec = vec3(outf, outf, outf); - outcol = vec4(outf, outf, outf, 1.0); -} - -void node_volume_info(sampler3D densitySampler, - sampler3D flameSampler, - vec2 temperature, - out vec4 outColor, - out float outDensity, - out float outFlame, - out float outTemprature) -{ -#if defined(MESH_SHADER) && defined(VOLUMETRICS) - vec3 p = volumeObjectLocalCoord; -#else - vec3 p = vec3(0.0); -#endif - - vec4 density = texture(densitySampler, p); - outDensity = density.a; - - /* Density is premultiplied for interpolation, divide it out here. */ - if (density.a > 1e-8) { - density.rgb /= density.a; + float value = texture(tex, cos).r; + if (volumeTemperature.x < volumeTemperature.y) { + outf = (value > 0.01) ? + volumeTemperature.x + value * (volumeTemperature.y - volumeTemperature.x) : + 0.0; + } + else { + outf = value; } - outColor = vec4(density.rgb * volumeColor, 1.0); - - float flame = texture(flameSampler, p).r; - outFlame = flame; - - outTemprature = (flame > 0.01) ? temperature.x + flame * (temperature.y - temperature.x) : 0.0; } diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc index a8ed2c5f2a5..a958a445a3d 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.cc @@ -164,7 +164,7 @@ void AbstractHierarchyIterator::debug_print_export_graph(const ExportGraph &grap } } } - printf(" (Total graph size: %lu objects\n", total_graph_size); + printf(" (Total graph size: %zu objects\n", total_graph_size); } void AbstractHierarchyIterator::export_graph_construct() @@ -345,7 +345,7 @@ void AbstractHierarchyIterator::visit_dupli_object(DupliObject *dupli_object, } else { /* The parent object is NOT part of the duplicated collection. This means that the world - * transform of this dupliobject can be influenced by objects that are not part of its + * transform of this dupli-object can be influenced by objects that are not part of its * export graph. */ animation_check_include_parent = true; context->export_parent = duplicator; diff --git a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h index 8bca2ddd447..c121e3b704d 100644 --- a/source/blender/io/usd/intern/abstract_hierarchy_iterator.h +++ b/source/blender/io/usd/intern/abstract_hierarchy_iterator.h @@ -65,8 +65,8 @@ struct HierarchyContext { /* When weak_export=true, the object will be exported only as transform, and only if is an * ancestor of an object with weak_export=false. * - * In other words: when weak_export=true but this object has no children, or all decendants also - * have weak_export=true, this object (and by recursive reasoning all its decendants) will be + * In other words: when weak_export=true but this object has no children, or all descendants also + * have weak_export=true, this object (and by recursive reasoning all its descendants) will be * excluded from the export. * * The export hierarchy is kept as close to the the hierarchy in Blender as possible. As such, an @@ -222,7 +222,7 @@ class AbstractHierarchyIterator { * * When this returns true, only a transform writer is created and marked as * 'weak export'. In this case, the transform writer will be removed before - * exporting starts, unless a decendant of this object is to be exported. + * exporting starts, unless a descendant of this object is to be exported. * Dupli-object generated from this object will also be skipped. * * See HierarchyContext::weak_export. diff --git a/source/blender/io/usd/intern/usd_writer_mesh.cc b/source/blender/io/usd/intern/usd_writer_mesh.cc index 74005afaf31..cbf51fc15b3 100644 --- a/source/blender/io/usd/intern/usd_writer_mesh.cc +++ b/source/blender/io/usd/intern/usd_writer_mesh.cc @@ -58,7 +58,7 @@ bool USDGenericMeshWriter::is_supported(const HierarchyContext *context) const int base_flag; if (is_dupli) { - /* Construct the object's base flags from its dupliparent, just like is done in + /* Construct the object's base flags from its dupli-parent, just like is done in * deg_objects_dupli_iterator_next(). Without this, the visibility check below will fail. Doing * this here, instead of a more suitable location in AbstractHierarchyIterator, prevents * copying the Object for every dupli. */ diff --git a/source/blender/makesdna/DNA_ID.h b/source/blender/makesdna/DNA_ID.h index 3ac93a96661..40916cbdc61 100644 --- a/source/blender/makesdna/DNA_ID.h +++ b/source/blender/makesdna/DNA_ID.h @@ -465,16 +465,20 @@ typedef enum ID_Type { if ((a) && (a)->id.newid) \ (a) = (void *)(a)->id.newid -/* id->flag (persitent). */ +/** id->flag (persitent). */ enum { - /* Don't delete the datablock even if unused. */ + /** Don't delete the datablock even if unused. */ LIB_FAKEUSER = 1 << 9, - /* The datablock structure is a sub-object of a different one. - * Direct persistent references are not allowed. */ - LIB_PRIVATE_DATA = 1 << 10, - /* Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT + /** + * The data-block is a sub-data of another one. + * Direct persistent references are not allowed. + */ + LIB_EMBEDDED_DATA = 1 << 10, + /** + * Datablock is from a library and linked indirectly, with LIB_TAG_INDIRECT * tag set. But the current .blend file also has a weak pointer to it that - * we want to restore if possible, and silently drop if it's missing. */ + * we want to restore if possible, and silently drop if it's missing. + */ LIB_INDIRECT_WEAK_LINK = 1 << 11, }; diff --git a/source/blender/makesdna/DNA_action_types.h b/source/blender/makesdna/DNA_action_types.h index 4b696e29a52..5b9340ab3d9 100644 --- a/source/blender/makesdna/DNA_action_types.h +++ b/source/blender/makesdna/DNA_action_types.h @@ -764,10 +764,6 @@ typedef enum eDopeSheet_FilterFlag { /** show only F-Curves which are disabled/have errors - for debugging drivers */ ADS_FILTER_ONLY_ERRORS = (1 << 28), - /* GPencil Mode */ - /** GP Mode - Only show datablocks used in the scene */ - ADS_FILTER_GP_3DONLY = (1 << 29), - #if 0 /** combination filters (some only used at runtime) */ ADS_FILTER_NOOBDATA = (ADS_FILTER_NOCAM | ADS_FILTER_NOMAT | ADS_FILTER_NOLAM | diff --git a/source/blender/makesdna/DNA_fluid_types.h b/source/blender/makesdna/DNA_fluid_types.h index 631c1b71732..f344e860d2e 100644 --- a/source/blender/makesdna/DNA_fluid_types.h +++ b/source/blender/makesdna/DNA_fluid_types.h @@ -256,7 +256,8 @@ typedef struct FluidDomainSettings { struct Collection *fluid_group; struct Collection *force_group; /* UNUSED */ struct Collection *effector_group; /* Effector objects group. */ - struct GPUTexture *tex; + struct GPUTexture *tex_density; + struct GPUTexture *tex_color; struct GPUTexture *tex_wt; struct GPUTexture *tex_shadow; struct GPUTexture *tex_flame; diff --git a/source/blender/makesdna/DNA_lightprobe_types.h b/source/blender/makesdna/DNA_lightprobe_types.h index 6ffdd60a094..d9cc549229d 100644 --- a/source/blender/makesdna/DNA_lightprobe_types.h +++ b/source/blender/makesdna/DNA_lightprobe_types.h @@ -160,6 +160,10 @@ typedef struct LightCacheTexture { typedef struct LightCache { int flag; + /** Version number to know if the cache data is compatible with this version of blender. */ + int version; + /** Type of data this cache contains. */ + int type; /* only a single cache for now */ /** Number of probes to use for rendering. */ int cube_len, grid_len; @@ -181,6 +185,14 @@ typedef struct LightCache { LightGridCache *grid_data; } LightCache; +/* Bump the version number for lightcache data structure changes. */ +#define LIGHTCACHE_STATIC_VERSION 1 + +/* LightCache->type */ +enum { + LIGHTCACHE_TYPE_STATIC = 0, +}; + /* LightCache->flag */ enum { LIGHTCACHE_BAKED = (1 << 0), diff --git a/source/blender/makesdna/DNA_modifier_types.h b/source/blender/makesdna/DNA_modifier_types.h index 042cf7e874f..13c5a0913c6 100644 --- a/source/blender/makesdna/DNA_modifier_types.h +++ b/source/blender/makesdna/DNA_modifier_types.h @@ -1255,6 +1255,19 @@ typedef struct OceanModifierData { float foam_coverage; float time; + char _pad1[4]; + + /* Spectrum being used. */ + int spectrum; + + /* Common JONSWAP parameters. */ + /** + * This is the distance from a lee shore, called the fetch, or the distance + * over which the wind blows with constant velocity. + */ + float fetch_jonswap; + float sharpen_peak_jonswap; + int bakestart; int bakeend; @@ -1287,6 +1300,13 @@ enum { }; enum { + MOD_OCEAN_SPECTRUM_PHILLIPS = 0, + MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ = 1, + MOD_OCEAN_SPECTRUM_JONSWAP = 2, + MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE = 3, +}; + +enum { MOD_OCEAN_GENERATE_FOAM = (1 << 0), MOD_OCEAN_GENERATE_NORMALS = (1 << 1), }; diff --git a/source/blender/makesdna/DNA_scene_defaults.h b/source/blender/makesdna/DNA_scene_defaults.h index db3566710b4..4b6f079aa28 100644 --- a/source/blender/makesdna/DNA_scene_defaults.h +++ b/source/blender/makesdna/DNA_scene_defaults.h @@ -224,7 +224,7 @@ .shadow_cube_size = 512, \ .shadow_cascade_size = 1024, \ \ - .light_cache = NULL, \ + .light_cache_data = NULL, \ .light_threshold = 0.01f, \ \ .overscan = 3.0f, \ diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h index 3a88cd0a33b..aac976fbabd 100644 --- a/source/blender/makesdna/DNA_scene_types.h +++ b/source/blender/makesdna/DNA_scene_types.h @@ -242,6 +242,7 @@ typedef struct SceneRenderLayer { #define SCE_LAY_STRAND (1 << 5) #define SCE_LAY_FRS (1 << 6) #define SCE_LAY_AO (1 << 7) +#define SCE_LAY_VOLUMES (1 << 8) /* flags between (1 << 8) and (1 << 15) are set to 1 already, for future options */ #define SCE_LAY_ALL_Z (1 << 15) @@ -1632,7 +1633,8 @@ typedef struct SceneEEVEE { int shadow_cube_size; int shadow_cascade_size; - struct LightCache *light_cache; + struct LightCache *light_cache DNA_DEPRECATED; + struct LightCache *light_cache_data; char light_cache_info[64]; float overscan; diff --git a/source/blender/makesdna/DNA_view3d_enums.h b/source/blender/makesdna/DNA_view3d_enums.h index 880a157cc3d..f8c772422bb 100644 --- a/source/blender/makesdna/DNA_view3d_enums.h +++ b/source/blender/makesdna/DNA_view3d_enums.h @@ -44,10 +44,6 @@ typedef enum eV3DShadingColorType { V3D_SHADING_TEXTURE_COLOR = 3, V3D_SHADING_OBJECT_COLOR = 4, V3D_SHADING_VERTEX_COLOR = 5, - - /* Is used to display the object using the error color. For example when in - * solid texture paint mode without any textures configured */ - V3D_SHADING_ERROR_COLOR = 999, } eV3DShadingColorType; /** #View3DShading.background_type */ diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c index e0f3aff6364..b2d02600124 100644 --- a/source/blender/makesrna/intern/makesrna.c +++ b/source/blender/makesrna/intern/makesrna.c @@ -4654,8 +4654,8 @@ static const char *cpp_classes = " operator void*() { return ptr.data; }\n" " operator bool() { return ptr.data != NULL; }\n" "\n" - " bool operator==(const Pointer &other) { return ptr.data == other.ptr.data; }\n" - " bool operator!=(const Pointer &other) { return ptr.data != other.ptr.data; }\n" + " bool operator==(const Pointer &other) const { return ptr.data == other.ptr.data; }\n" + " bool operator!=(const Pointer &other) const { return ptr.data != other.ptr.data; }\n" "\n" " PointerRNA ptr;\n" "};\n" diff --git a/source/blender/makesrna/intern/rna_access.c b/source/blender/makesrna/intern/rna_access.c index 8dd6e6982dd..33f9b2da280 100644 --- a/source/blender/makesrna/intern/rna_access.c +++ b/source/blender/makesrna/intern/rna_access.c @@ -5832,7 +5832,7 @@ ID *RNA_find_real_ID_and_path(Main *bmain, ID *id, const char **r_path) *r_path = ""; } - if ((id != NULL) && (id->flag & LIB_PRIVATE_DATA)) { + if ((id != NULL) && (id->flag & LIB_EMBEDDED_DATA)) { switch (GS(id->name)) { case ID_NT: if (r_path) { diff --git a/source/blender/makesrna/intern/rna_action.c b/source/blender/makesrna/intern/rna_action.c index 436e847b044..c85a94d9fc2 100644 --- a/source/blender/makesrna/intern/rna_action.c +++ b/source/blender/makesrna/intern/rna_action.c @@ -583,15 +583,6 @@ static void rna_def_dopesheet(BlenderRNA *brna) prop, "Display Movie Clips", "Include visualization of movie clip related animation data"); RNA_def_property_ui_icon(prop, ICON_TRACKER, 0); RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); - - /* GPencil Mode Settings */ - prop = RNA_def_property(srna, "show_gpencil_3d_only", PROP_BOOLEAN, PROP_NONE); - RNA_def_property_boolean_sdna(prop, NULL, "filterflag", ADS_FILTER_GP_3DONLY); - RNA_def_property_ui_text(prop, - "Active Scene Only", - "Only show Grease Pencil data-blocks used as part of the active scene"); - RNA_def_property_ui_icon(prop, ICON_SCENE_DATA, 0); - RNA_def_property_update(prop, NC_ANIMATION | ND_ANIMCHAN | NA_EDITED, NULL); } static void rna_def_action_group(BlenderRNA *brna) diff --git a/source/blender/makesrna/intern/rna_fluid.c b/source/blender/makesrna/intern/rna_fluid.c index 38ba7bcb047..7bd353cd441 100644 --- a/source/blender/makesrna/intern/rna_fluid.c +++ b/source/blender/makesrna/intern/rna_fluid.c @@ -720,7 +720,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values) manta_smoke_turbulence_get_rgba(mds->fluid, values, 0); } else { - manta_smoke_turbulence_get_rgba_from_density(mds->fluid, mds->active_color, values, 0); + manta_smoke_turbulence_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0); } } else { @@ -728,7 +728,7 @@ static void rna_FluidModifier_color_grid_get(PointerRNA *ptr, float *values) manta_smoke_get_rgba(mds->fluid, values, 0); } else { - manta_smoke_get_rgba_from_density(mds->fluid, mds->active_color, values, 0); + manta_smoke_get_rgba_fixed_color(mds->fluid, mds->active_color, values, 0); } } } diff --git a/source/blender/makesrna/intern/rna_modifier.c b/source/blender/makesrna/intern/rna_modifier.c index 396c5a4e854..6440b140183 100644 --- a/source/blender/makesrna/intern/rna_modifier.c +++ b/source/blender/makesrna/intern/rna_modifier.c @@ -5178,6 +5178,30 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) {0, NULL, 0, NULL, NULL}, }; + static const EnumPropertyItem spectrum_items[] = { + {MOD_OCEAN_SPECTRUM_PHILLIPS, + "PHILLIPS", + 0, + "Turbulent Ocean", + "Use for turbulent seas with foam"}, + {MOD_OCEAN_SPECTRUM_PIERSON_MOSKOWITZ, + "PIERSON_MOSKOWITZ", + 0, + "Established Ocean", + "Use for a large area, established ocean (Pierson-Moskowitz method)"}, + {MOD_OCEAN_SPECTRUM_JONSWAP, + "JONSWAP", + 0, + "Established Ocean (Sharp Peaks)", + "Use for sharp peaks ('JONSWAP', Pierson-Moskowitz method) with peak sharpening"}, + {MOD_OCEAN_SPECTRUM_TEXEL_MARSEN_ARSLOE, + "TEXEL_MARSEN_ARSLOE", + 0, + "Shallow Water", + "Use for shallow water ('JONSWAP', 'TMA' - Texel-Marsen-Arsloe method)"}, + {0, NULL, 0, NULL, NULL}, + }; + srna = RNA_def_struct(brna, "OceanModifier", "Modifier"); RNA_def_struct_ui_text(srna, "Ocean Modifier", "Simulate an ocean surface"); RNA_def_struct_sdna(srna, "OceanModifierData"); @@ -5324,6 +5348,29 @@ static void rna_def_modifier_ocean(BlenderRNA *brna) RNA_def_property_ui_range(prop, -FLT_MAX, FLT_MAX, 1, -1); RNA_def_property_update(prop, 0, "rna_Modifier_update"); + prop = RNA_def_property(srna, "spectrum", PROP_ENUM, PROP_NONE); + RNA_def_property_enum_sdna(prop, NULL, "spectrum"); + RNA_def_property_enum_items(prop, spectrum_items); + RNA_def_property_ui_text(prop, "Spectrum", "Spectrum to use"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop = RNA_def_property(srna, "fetch_jonswap", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "fetch_jonswap"); + RNA_def_property_range(prop, 0.0, FLT_MAX); + RNA_def_property_ui_text( + prop, + "Fetch", + "This is the distance from a lee shore, " + "called the fetch, or the distance over which the wind blows with constant velocity. " + "Used by 'JONSWAP' and 'TMA' models"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + + prop = RNA_def_property(srna, "sharpen_peak_jonswap", PROP_FLOAT, PROP_UNSIGNED); + RNA_def_property_float_sdna(prop, NULL, "sharpen_peak_jonswap"); + RNA_def_property_range(prop, 0.0, 10.0); + RNA_def_property_ui_text(prop, "Sharpen peak", "Peak sharpening for 'JONSWAP' and 'TMA' models"); + RNA_def_property_update(prop, 0, "rna_OceanModifier_init_update"); + prop = RNA_def_property(srna, "random_seed", PROP_INT, PROP_UNSIGNED); RNA_def_property_int_sdna(prop, NULL, "seed"); RNA_def_property_clear_flag(prop, PROP_ANIMATABLE); diff --git a/source/blender/makesrna/intern/rna_particle.c b/source/blender/makesrna/intern/rna_particle.c index 9aeaf4e83dd..3747dd53b97 100644 --- a/source/blender/makesrna/intern/rna_particle.c +++ b/source/blender/makesrna/intern/rna_particle.c @@ -188,9 +188,9 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, * not a very efficient way of getting hair key location data, * but it's the best we've got at the present * - * IDEAS: include additional information in pointerRNA beforehand, - * for example a pointer to the ParticleStstemModifierData to which the - * hairkey belongs. + * IDEAS: include additional information in PointerRNA beforehand, + * for example a pointer to the ParticleSystemModifierData to which the + * hair-key belongs. */ for (md = ob->modifiers.first; md; md = md->next) { @@ -199,9 +199,9 @@ static void rna_ParticleHairKey_location_object_info(PointerRNA *ptr, if (psmd && psmd->mesh_final && psmd->psys) { psys = psmd->psys; for (i = 0, pa = psys->particles; i < psys->totpart; i++, pa++) { - /* hairkeys are stored sequentially in memory, so we can + /* Hair-keys are stored sequentially in memory, so we can * find if it's the same particle by comparing pointers, - * without having to iterate over them all */ + * without having to iterate over them all. */ if ((hkey >= pa->hair) && (hkey < pa->hair + pa->totkey)) { *psmd_pt = psmd; *pa_pt = pa; diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c index 27d742fd33c..f974d5c563f 100644 --- a/source/blender/makesrna/intern/rna_scene.c +++ b/source/blender/makesrna/intern/rna_scene.c @@ -4018,6 +4018,16 @@ void rna_def_view_layer_common(StructRNA *srna, const bool scene) RNA_def_property_clear_flag(prop, PROP_EDITABLE); } + prop = RNA_def_property(srna, "use_volumes", PROP_BOOLEAN, PROP_NONE); + RNA_def_property_boolean_sdna(prop, NULL, "layflag", SCE_LAY_VOLUMES); + RNA_def_property_ui_text(prop, "Volumes", "Render volumes in this Layer"); + if (scene) { + RNA_def_property_update(prop, NC_SCENE | ND_RENDER_OPTIONS, NULL); + } + else { + RNA_def_property_clear_flag(prop, PROP_EDITABLE); + } + /* passes */ prop = RNA_def_property(srna, "use_pass_combined", PROP_BOOLEAN, PROP_NONE); RNA_def_property_boolean_sdna(prop, NULL, "passflag", SCE_PASS_COMBINED); diff --git a/source/blender/makesrna/intern/rna_userdef.c b/source/blender/makesrna/intern/rna_userdef.c index ac0376c72af..a153c1dda1e 100644 --- a/source/blender/makesrna/intern/rna_userdef.c +++ b/source/blender/makesrna/intern/rna_userdef.c @@ -5040,8 +5040,16 @@ static void rna_def_userdef_system(BlenderRNA *brna) {2048, "SAMPLES_2048", 0, "2048 Samples", "Set audio mixing buffer size to 2048 samples"}, {4096, "SAMPLES_4096", 0, "4096 Samples", "Set audio mixing buffer size to 4096 samples"}, {8192, "SAMPLES_8192", 0, "8192 Samples", "Set audio mixing buffer size to 8192 samples"}, - {16384, "SAMPLES_16384", 0, "16384 Samples", "Set audio mixing buffer size to 16384 samples"}, - {32768, "SAMPLES_32768", 0, "32768 Samples", "Set audio mixing buffer size to 32768 samples"}, + {16384, + "SAMPLES_16384", + 0, + "16384 Samples", + "Set audio mixing buffer size to 16384 samples"}, + {32768, + "SAMPLES_32768", + 0, + "32768 Samples", + "Set audio mixing buffer size to 32768 samples"}, {0, NULL, 0, NULL, NULL}, }; diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c index 9ec4d58eb61..de08533753e 100644 --- a/source/blender/modifiers/intern/MOD_bevel.c +++ b/source/blender/modifiers/intern/MOD_bevel.c @@ -206,7 +206,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes Object *ob = ctx->object; if (harden_normals && (ob->type == OB_MESH) && !(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) { - modifier_setError(md, "Enable 'Auto Smooth' option in mesh settings for hardening"); + modifier_setError(md, "Enable 'Auto Smooth' in Object Data Properties"); harden_normals = false; } diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c index 953b1b460c8..63c1b6f1ef0 100644 --- a/source/blender/modifiers/intern/MOD_cloth.c +++ b/source/blender/modifiers/intern/MOD_cloth.c @@ -179,7 +179,11 @@ static void copyData(const ModifierData *md, ModifierData *target, const int fla } else { tclmd->point_cache = BKE_ptcache_add(&tclmd->ptcaches); - tclmd->point_cache->step = 1; + if (clmd->point_cache != NULL) { + tclmd->point_cache->step = clmd->point_cache->step; + tclmd->point_cache->startframe = clmd->point_cache->startframe; + tclmd->point_cache->endframe = clmd->point_cache->endframe; + } } tclmd->sim_parms = MEM_dupallocN(clmd->sim_parms); diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c index 3e79dd91d2b..72cbe197251 100644 --- a/source/blender/modifiers/intern/MOD_datatransfer.c +++ b/source/blender/modifiers/intern/MOD_datatransfer.c @@ -220,7 +220,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes modifier_setError(md, "%s", BKE_reports_string(&reports, RPT_ERROR)); } else if ((dtmd->data_types & DT_TYPE_LNOR) && !(me->flag & ME_AUTOSMOOTH)) { - modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' option in mesh settings"); + modifier_setError((ModifierData *)dtmd, "Enable 'Auto Smooth' in Object Data Properties"); } else if (result->totvert > HIGH_POLY_WARNING || ((Mesh *)(ob_source->data))->totvert > HIGH_POLY_WARNING) { diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c index 720ca4ffa13..78d29edfd98 100644 --- a/source/blender/modifiers/intern/MOD_hook.c +++ b/source/blender/modifiers/intern/MOD_hook.c @@ -316,7 +316,7 @@ static void deformVerts_do(HookModifierData *hmd, * This should always be true and I don't generally like * "paranoid" style code like this, but old files can have * indices that are out of range because old blender did - * not correct them on exit editmode. - zr + * not correct them on exit edit-mode. - zr */ if (hmd->force == 0.0f) { diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c index 572d9505e4e..ace0c1b5eaf 100644 --- a/source/blender/modifiers/intern/MOD_normal_edit.c +++ b/source/blender/modifiers/intern/MOD_normal_edit.c @@ -494,7 +494,7 @@ static Mesh *normalEditModifier_do(NormalEditModifierData *enmd, if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) #endif { - modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' option in mesh settings"); + modifier_setError((ModifierData *)enmd, "Enable 'Auto Smooth' in Object Data Properties"); return mesh; } diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c index 62a5dd45e68..fec04e9916d 100644 --- a/source/blender/modifiers/intern/MOD_ocean.c +++ b/source/blender/modifiers/intern/MOD_ocean.c @@ -92,6 +92,10 @@ static void initData(ModifierData *md) omd->seed = 0; omd->time = 1.0; + omd->spectrum = MOD_OCEAN_SPECTRUM_PHILLIPS; + omd->sharpen_peak_jonswap = 0.0f; + omd->fetch_jonswap = 120.0f; + omd->size = 1.0; omd->repeat_x = 1; omd->repeat_y = 1; diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c index 48ccd9b83ed..af6de8447ec 100644 --- a/source/blender/modifiers/intern/MOD_softbody.c +++ b/source/blender/modifiers/intern/MOD_softbody.c @@ -69,6 +69,8 @@ static void updateDepsgraph(ModifierData *UNUSED(md), const ModifierUpdateDepsgr DEG_add_forcefield_relations( ctx->node, ctx->object, ctx->object->soft->effector_weights, true, 0, "Softbody Field"); } + /* We need own transformation as well. */ + DEG_add_modifier_to_transform_relation(ctx->node, "SoftBody Modifier"); } ModifierTypeInfo modifierType_Softbody = { diff --git a/source/blender/modifiers/intern/MOD_weighted_normal.c b/source/blender/modifiers/intern/MOD_weighted_normal.c index d9c05d8d4b4..04b503e588b 100644 --- a/source/blender/modifiers/intern/MOD_weighted_normal.c +++ b/source/blender/modifiers/intern/MOD_weighted_normal.c @@ -562,7 +562,7 @@ static Mesh *applyModifier(ModifierData *md, const ModifierEvalContext *ctx, Mes if (!(((Mesh *)ob->data)->flag & ME_AUTOSMOOTH)) #endif { - modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' option in mesh settings"); + modifier_setError((ModifierData *)wnmd, "Enable 'Auto Smooth' in Object Data Properties"); return mesh; } diff --git a/source/blender/nodes/shader/nodes/node_shader_attribute.c b/source/blender/nodes/shader/nodes/node_shader_attribute.c index 79f02f5c243..6b5d46e250b 100644 --- a/source/blender/nodes/shader/nodes/node_shader_attribute.c +++ b/source/blender/nodes/shader/nodes/node_shader_attribute.c @@ -42,28 +42,18 @@ static int node_shader_gpu_attribute(GPUMaterial *mat, { NodeShaderAttribute *attr = node->storage; - /* FIXME : if an attribute layer (like vertex color) has one of these names, - * it will not work as expected. */ - if (strcmp(attr->name, "density") == 0) { - return GPU_stack_link( - mat, node, "node_attribute_volume_density", in, out, GPU_builtin(GPU_VOLUME_DENSITY)); - } - else if (strcmp(attr->name, "color") == 0) { - return GPU_stack_link( - mat, node, "node_attribute_volume_color", in, out, GPU_builtin(GPU_VOLUME_DENSITY)); - } - else if (strcmp(attr->name, "flame") == 0) { - return GPU_stack_link( - mat, node, "node_attribute_volume_flame", in, out, GPU_builtin(GPU_VOLUME_FLAME)); - } - else if (strcmp(attr->name, "temperature") == 0) { - return GPU_stack_link(mat, - node, - "node_attribute_volume_temperature", - in, - out, - GPU_builtin(GPU_VOLUME_FLAME), - GPU_builtin(GPU_VOLUME_TEMPERATURE)); + if (GPU_material_is_volume_shader(mat)) { + if (out[0].hasoutput) { + out[0].link = GPU_volume_grid(mat, attr->name); + } + if (out[1].hasoutput) { + out[1].link = GPU_volume_grid(mat, attr->name); + } + if (out[2].hasoutput) { + out[2].link = GPU_volume_grid(mat, attr->name); + } + + return 1; } else { GPUNodeLink *cd_attr = GPU_attribute(mat, CD_AUTO_FROM_NAME, attr->name); diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_info.c b/source/blender/nodes/shader/nodes/node_shader_volume_info.c index 57fa2b7e582..7ccc00f1af3 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_info.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_info.c @@ -28,20 +28,25 @@ static bNodeSocketTemplate sh_node_volume_info_out[] = { }; static int node_shader_gpu_volume_info(GPUMaterial *mat, - bNode *node, + bNode *UNUSED(node), bNodeExecData *UNUSED(execdata), - GPUNodeStack *in, + GPUNodeStack *UNUSED(in), GPUNodeStack *out) { + if (out[0].hasoutput) { + out[0].link = GPU_volume_grid(mat, "color"); + } + if (out[1].hasoutput) { + out[1].link = GPU_volume_grid(mat, "density"); + } + if (out[2].hasoutput) { + out[2].link = GPU_volume_grid(mat, "flame"); + } + if (out[3].hasoutput) { + out[3].link = GPU_volume_grid(mat, "temperature"); + } - return GPU_stack_link(mat, - node, - "node_volume_info", - in, - out, - GPU_builtin(GPU_VOLUME_DENSITY), - GPU_builtin(GPU_VOLUME_FLAME), - GPU_builtin(GPU_VOLUME_TEMPERATURE)); + return true; } void register_node_type_sh_volume_info(void) diff --git a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c index dc41d6b2531..92e1b3435c8 100644 --- a/source/blender/nodes/shader/nodes/node_shader_volume_principled.c +++ b/source/blender/nodes/shader/nodes/node_shader_volume_principled.c @@ -54,42 +54,6 @@ static void node_shader_init_volume_principled(bNodeTree *UNUSED(ntree), bNode * } } -static void node_shader_gpu_volume_attribute(GPUMaterial *mat, - const char *name, - GPUNodeLink **outcol, - GPUNodeLink **outvec, - GPUNodeLink **outf) -{ - if (strcmp(name, "density") == 0) { - GPU_link(mat, - "node_attribute_volume_density", - GPU_builtin(GPU_VOLUME_DENSITY), - outcol, - outvec, - outf); - } - else if (strcmp(name, "color") == 0) { - GPU_link( - mat, "node_attribute_volume_color", GPU_builtin(GPU_VOLUME_DENSITY), outcol, outvec, outf); - } - else if (strcmp(name, "flame") == 0) { - GPU_link( - mat, "node_attribute_volume_flame", GPU_builtin(GPU_VOLUME_FLAME), outcol, outvec, outf); - } - else if (strcmp(name, "temperature") == 0) { - GPU_link(mat, - "node_attribute_volume_temperature", - GPU_builtin(GPU_VOLUME_FLAME), - GPU_builtin(GPU_VOLUME_TEMPERATURE), - outcol, - outvec, - outf); - } - else { - *outcol = *outvec = *outf = NULL; - } -} - static int node_shader_gpu_volume_principled(GPUMaterial *mat, bNode *node, bNodeExecData *UNUSED(execdata), @@ -108,16 +72,19 @@ static int node_shader_gpu_volume_principled(GPUMaterial *mat, } bNodeSocketValueString *value = sock->default_value; - GPUNodeLink *outcol, *outvec, *outf; + const char *attribute_name = value->value; + if (attribute_name[0] == '\0') { + continue; + } if (STREQ(sock->name, "Density Attribute")) { - node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &density); + density = GPU_volume_grid(mat, attribute_name); } else if (STREQ(sock->name, "Color Attribute")) { - node_shader_gpu_volume_attribute(mat, value->value, &color, &outvec, &outf); + color = GPU_volume_grid(mat, attribute_name); } else if (use_blackbody && STREQ(sock->name, "Temperature Attribute")) { - node_shader_gpu_volume_attribute(mat, value->value, &outcol, &outvec, &temperature); + temperature = GPU_volume_grid(mat, attribute_name); } } diff --git a/source/blender/python/intern/bpy_rna.c b/source/blender/python/intern/bpy_rna.c index ff81b4a15ff..c32ef3e6624 100644 --- a/source/blender/python/intern/bpy_rna.c +++ b/source/blender/python/intern/bpy_rna.c @@ -923,7 +923,7 @@ static PyObject *pyrna_struct_repr(BPy_StructRNA *self) if (DEG_get_original_id(id) != id) { ret = PyUnicode_FromFormat("Evaluated %s %R", BKE_idcode_to_name(GS(id->name)), tmp_str); } - else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_PRIVATE_DATA) == 0) { + else if (RNA_struct_is_ID(self->ptr.type) && (id->flag & LIB_EMBEDDED_DATA) == 0) { ret = PyUnicode_FromFormat( "bpy.data.%s[%R]", BKE_idcode_to_name_plural(GS(id->name)), tmp_str); } diff --git a/source/blender/python/intern/bpy_rna_id_collection.c b/source/blender/python/intern/bpy_rna_id_collection.c index 1c1a1a26e3b..6344ed39b1b 100644 --- a/source/blender/python/intern/bpy_rna_id_collection.c +++ b/source/blender/python/intern/bpy_rna_id_collection.c @@ -98,7 +98,7 @@ static int foreach_libblock_id_user_map_callback(LibraryIDLinkCallbackData *cb_d return IDWALK_RET_NOP; } - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { /* We skip private pointers themselves, like root node trees, we'll 'link' their own ID * pointers to their 'ID owner' instead. */ return IDWALK_RET_NOP; diff --git a/source/blender/windowmanager/intern/wm_event_system.c b/source/blender/windowmanager/intern/wm_event_system.c index 8728c887feb..c7556ec7516 100644 --- a/source/blender/windowmanager/intern/wm_event_system.c +++ b/source/blender/windowmanager/intern/wm_event_system.c @@ -2498,6 +2498,164 @@ static int wm_handlers_do_keymap_with_gizmo_handler( return action; } +static int wm_handlers_do_gizmo_handler(bContext *C, + wmWindowManager *wm, + wmEventHandler_Gizmo *handler, + wmEvent *event, + ListBase *handlers, + const bool do_debug_handler) +{ + int action = WM_HANDLER_CONTINUE; + ScrArea *area = CTX_wm_area(C); + ARegion *region = CTX_wm_region(C); + wmGizmoMap *gzmap = handler->gizmo_map; + BLI_assert(gzmap != NULL); + wmGizmo *gz = wm_gizmomap_highlight_get(gzmap); + + /* Needed so UI blocks over gizmos don't let events fall through to the gizmos, + * noticeable for the node editor - where dragging on a node should move it, see: T73212. */ + if (region->type->clip_gizmo_events_by_ui) { + if (UI_region_block_find_mouse_over(region, &event->x, true)) { + if (gz != NULL) { + WM_tooltip_clear(C, CTX_wm_window(C)); + wm_gizmomap_highlight_set(gzmap, C, NULL, 0); + } + return action; + } + } + + if (region->gizmo_map != handler->gizmo_map) { + WM_gizmomap_tag_refresh(handler->gizmo_map); + } + + wm_gizmomap_handler_context_gizmo(C, handler); + wm_region_mouse_co(C, event); + + /* Drag events use the previous click location to highlight the gizmos, + * Get the highlight again in case the user dragged off the gizmo. */ + const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG); + const bool is_event_modifier = ISKEYMODIFIER(event->type); + + bool handle_highlight = false; + bool handle_keymap = false; + + /* handle gizmo highlighting */ + if (!wm_gizmomap_modal_get(gzmap) && + ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) { + handle_highlight = true; + if (is_event_modifier || is_event_drag) { + handle_keymap = true; + } + } + else { + handle_keymap = true; + } + + if (handle_highlight) { + struct { + wmGizmo *gz; + int part; + } prev = { + .gz = gz, + .part = gz ? gz->highlight_part : 0, + }; + int part = -1; + gz = wm_gizmomap_highlight_find(gzmap, C, event, &part); + + /* If no gizmos are/were active, don't clear tool-tips. */ + if (gz || prev.gz) { + if ((prev.gz != gz) || (prev.part != part)) { + WM_tooltip_clear(C, CTX_wm_window(C)); + } + } + + if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { + if (gz != NULL) { + if (U.flag & USER_TOOLTIPS) { + WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); + } + } + } + } + + /* Don't use from now on. */ + bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL); + + if (handle_keymap) { + /* Handle highlight gizmo. */ + if (gz != NULL) { + bool keymap_poll = false; + wmGizmoGroup *gzgroup = gz->parent_gzgroup; + wmKeyMap *keymap = WM_keymap_active(wm, gz->keymap ? gz->keymap : gzgroup->type->keymap); + action |= wm_handlers_do_keymap_with_gizmo_handler( + C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll); + +#ifdef USE_GIZMO_MOUSE_PRIORITY_HACK + if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) { + if ((event->val == KM_PRESS) && ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { + + wmEvent event_test_click = *event; + event_test_click.val = KM_CLICK; + + wmEvent event_test_click_drag = *event; + event_test_click_drag.val = KM_CLICK_DRAG; + + wmEvent event_test_tweak = *event; + event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE); + event_test_tweak.val = KM_ANY; + + for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { + if ((kmi->flag & KMI_INACTIVE) == 0) { + if (wm_eventmatch(&event_test_click, kmi) || + wm_eventmatch(&event_test_click_drag, kmi) || + wm_eventmatch(&event_test_tweak, kmi)) { + wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); + if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { + is_event_handle_all = true; + break; + } + } + } + } + } + } +#endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */ + } + + /* Don't use from now on. */ + gz = NULL; + + /* Fallback to selected gizmo (when un-handled). */ + if ((action & WM_HANDLER_BREAK) == 0) { + if (WM_gizmomap_is_any_selected(gzmap)) { + const ListBase *groups = WM_gizmomap_group_list(gzmap); + for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) { + if (wm_gizmogroup_is_any_selected(gzgroup)) { + wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap); + action |= wm_handlers_do_keymap_with_gizmo_handler( + C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL); + if (action & WM_HANDLER_BREAK) { + break; + } + } + } + } + } + } + + if (is_event_handle_all) { + if (action == WM_HANDLER_CONTINUE) { + action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL; + } + } + + /* restore the area */ + CTX_wm_area_set(C, area); + CTX_wm_region_set(C, region); + + return action; +} + static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers) { const bool do_debug_handler = @@ -2609,142 +2767,7 @@ static int wm_handlers_do_intern(bContext *C, wmEvent *event, ListBase *handlers } else if (handler_base->type == WM_HANDLER_TYPE_GIZMO) { wmEventHandler_Gizmo *handler = (wmEventHandler_Gizmo *)handler_base; - ScrArea *area = CTX_wm_area(C); - ARegion *region = CTX_wm_region(C); - wmGizmoMap *gzmap = handler->gizmo_map; - BLI_assert(gzmap != NULL); - wmGizmo *gz = wm_gizmomap_highlight_get(gzmap); - - if (region->gizmo_map != handler->gizmo_map) { - WM_gizmomap_tag_refresh(handler->gizmo_map); - } - - wm_gizmomap_handler_context_gizmo(C, handler); - wm_region_mouse_co(C, event); - - /* Drag events use the previous click location to highlight the gizmos, - * Get the highlight again in case the user dragged off the gizmo. */ - const bool is_event_drag = ISTWEAK(event->type) || (event->val == KM_CLICK_DRAG); - const bool is_event_modifier = ISKEYMODIFIER(event->type); - - bool handle_highlight = false; - bool handle_keymap = false; - - /* handle gizmo highlighting */ - if (!wm_gizmomap_modal_get(gzmap) && - ((event->type == MOUSEMOVE) || is_event_modifier || is_event_drag)) { - handle_highlight = true; - if (is_event_modifier || is_event_drag) { - handle_keymap = true; - } - } - else { - handle_keymap = true; - } - - if (handle_highlight) { - struct { - wmGizmo *gz; - int part; - } prev = { - .gz = gz, - .part = gz ? gz->highlight_part : 0, - }; - int part = -1; - gz = wm_gizmomap_highlight_find(gzmap, C, event, &part); - - /* If no gizmos are/were active, don't clear tool-tips. */ - if (gz || prev.gz) { - if ((prev.gz != gz) || (prev.part != part)) { - WM_tooltip_clear(C, CTX_wm_window(C)); - } - } - - if (wm_gizmomap_highlight_set(gzmap, C, gz, part)) { - if (gz != NULL) { - if (U.flag & USER_TOOLTIPS) { - WM_tooltip_timer_init(C, CTX_wm_window(C), area, region, WM_gizmomap_tooltip_init); - } - } - } - } - - /* Don't use from now on. */ - bool is_event_handle_all = gz && (gz->flag & WM_GIZMO_EVENT_HANDLE_ALL); - - if (handle_keymap) { - /* Handle highlight gizmo. */ - if (gz != NULL) { - bool keymap_poll = false; - wmGizmoGroup *gzgroup = gz->parent_gzgroup; - wmKeyMap *keymap = WM_keymap_active(wm, - gz->keymap ? gz->keymap : gzgroup->type->keymap); - action |= wm_handlers_do_keymap_with_gizmo_handler( - C, event, handlers, handler, gzgroup, keymap, do_debug_handler, &keymap_poll); - -#ifdef USE_GIZMO_MOUSE_PRIORITY_HACK - if (((action & WM_HANDLER_BREAK) == 0) && !is_event_handle_all && keymap_poll) { - if ((event->val == KM_PRESS) && - ELEM(event->type, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE)) { - - wmEvent event_test_click = *event; - event_test_click.val = KM_CLICK; - - wmEvent event_test_click_drag = *event; - event_test_click_drag.val = KM_CLICK_DRAG; - - wmEvent event_test_tweak = *event; - event_test_tweak.type = EVT_TWEAK_L + (event->type - LEFTMOUSE); - event_test_tweak.val = KM_ANY; - - for (wmKeyMapItem *kmi = keymap->items.first; kmi; kmi = kmi->next) { - if ((kmi->flag & KMI_INACTIVE) == 0) { - if (wm_eventmatch(&event_test_click, kmi) || - wm_eventmatch(&event_test_click_drag, kmi) || - wm_eventmatch(&event_test_tweak, kmi)) { - wmOperatorType *ot = WM_operatortype_find(kmi->idname, 0); - if (WM_operator_poll_context(C, ot, WM_OP_INVOKE_DEFAULT)) { - is_event_handle_all = true; - break; - } - } - } - } - } - } -#endif /* USE_GIZMO_MOUSE_PRIORITY_HACK */ - } - - /* Don't use from now on. */ - gz = NULL; - - /* Fallback to selected gizmo (when un-handled). */ - if ((action & WM_HANDLER_BREAK) == 0) { - if (WM_gizmomap_is_any_selected(gzmap)) { - const ListBase *groups = WM_gizmomap_group_list(gzmap); - for (wmGizmoGroup *gzgroup = groups->first; gzgroup; gzgroup = gzgroup->next) { - if (wm_gizmogroup_is_any_selected(gzgroup)) { - wmKeyMap *keymap = WM_keymap_active(wm, gzgroup->type->keymap); - action |= wm_handlers_do_keymap_with_gizmo_handler( - C, event, handlers, handler, gzgroup, keymap, do_debug_handler, NULL); - if (action & WM_HANDLER_BREAK) { - break; - } - } - } - } - } - } - - if (is_event_handle_all) { - if (action == WM_HANDLER_CONTINUE) { - action |= WM_HANDLER_BREAK | WM_HANDLER_MODAL; - } - } - - /* restore the area */ - CTX_wm_area_set(C, area); - CTX_wm_region_set(C, region); + action |= wm_handlers_do_gizmo_handler(C, wm, handler, event, handlers, do_debug_handler); } else if (handler_base->type == WM_HANDLER_TYPE_OP) { wmEventHandler_Op *handler = (wmEventHandler_Op *)handler_base; @@ -2915,6 +2938,21 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers) } } } + else if (ISMOUSE_WHEEL(event->type) || ISMOUSE_GESTURE(event->type)) { + /* Modifiers which can trigger click event's, + * however we don't want this if the mouse wheel has been used, see T74607. */ + if (wm_action_not_handled(action)) { + /* pass */ + } + else { + wmWindow *win = CTX_wm_window(C); + if (win) { + if (ISKEYMODIFIER(win->eventstate->prevtype)) { + win->eventstate->check_click = 0; + } + } + } + } return action; } diff --git a/source/blender/windowmanager/intern/wm_operators.c b/source/blender/windowmanager/intern/wm_operators.c index 16f2f822338..aab2acaac76 100644 --- a/source/blender/windowmanager/intern/wm_operators.c +++ b/source/blender/windowmanager/intern/wm_operators.c @@ -3340,7 +3340,7 @@ static int previews_id_ensure_callback(LibraryIDLinkCallbackData *cb_data) { const int cb_flag = cb_data->cb_flag; - if (cb_flag & IDWALK_CB_PRIVATE) { + if (cb_flag & IDWALK_CB_EMBEDDED) { return IDWALK_RET_NOP; } |