diff --git a/source/blender/blenkernel/intern/texture.cc b/source/blender/blenkernel/intern/texture.cc index d2cb4c4b201..7f9e4bbdc07 100644 --- a/source/blender/blenkernel/intern/texture.cc +++ b/source/blender/blenkernel/intern/texture.cc @@ -56,6 +56,8 @@ #include "RE_texture.h" +#include "DRW_engine.h" + #include "BLO_read_write.h" static void texture_init_data(ID *id) @@ -100,6 +102,8 @@ static void texture_copy_data(Main *bmain, ID *id_dst, const ID *id_src, const i texture_dst->nodetree->owner_id = &texture_dst->id; } + BLI_listbase_clear((ListBase *)&texture_dst->drawdata); + if ((flag & LIB_ID_COPY_NO_PREVIEW) == 0) { BKE_previewimg_id_copy(&texture_dst->id, &texture_src->id); } @@ -112,6 +116,8 @@ static void texture_free_data(ID *id) { Tex *texture = (Tex *)id; + DRW_drawdata_free(id); + /* is no lib link block, but texture extension */ if (texture->nodetree) { ntreeFreeEmbeddedTree(texture->nodetree); diff --git a/source/blender/compositor/realtime_compositor/CMakeLists.txt b/source/blender/compositor/realtime_compositor/CMakeLists.txt index ab584423dd1..914d6c3e220 100644 --- a/source/blender/compositor/realtime_compositor/CMakeLists.txt +++ b/source/blender/compositor/realtime_compositor/CMakeLists.txt @@ -70,12 +70,14 @@ set(SRC algorithms/COM_algorithm_smaa.hh algorithms/COM_algorithm_symmetric_separable_blur.hh + cached_resources/intern/cached_texture.cc cached_resources/intern/morphological_distance_feather_weights.cc cached_resources/intern/smaa_precomputed_textures.cc cached_resources/intern/symmetric_blur_weights.cc cached_resources/intern/symmetric_separable_blur_weights.cc cached_resources/COM_cached_resource.hh + cached_resources/COM_cached_texture.hh cached_resources/COM_morphological_distance_feather_weights.hh cached_resources/COM_smaa_precomputed_textures.hh cached_resources/COM_symmetric_blur_weights.hh @@ -248,4 +250,16 @@ endforeach() set(shader_create_info_list_file "${CMAKE_CURRENT_BINARY_DIR}/compositor_shader_create_info_list.hh") file(GENERATE OUTPUT ${shader_create_info_list_file} CONTENT "${SHADER_CREATE_INFOS_CONTENT}") +if(WITH_TBB) + list(APPEND INC_SYS + ${TBB_INCLUDE_DIRS} + ) + add_definitions(-DWITH_TBB) + if(WIN32) + # TBB includes Windows.h which will define min/max macros + # that will collide with the stl versions. + add_definitions(-DNOMINMAX) + endif() +endif() + blender_add_lib(bf_realtime_compositor "${SRC}" "${INC}" "${INC_SYS}" "${LIB}") diff --git a/source/blender/compositor/realtime_compositor/COM_context.hh b/source/blender/compositor/realtime_compositor/COM_context.hh index 99eac679640..58a422416d6 100644 --- a/source/blender/compositor/realtime_compositor/COM_context.hh +++ b/source/blender/compositor/realtime_compositor/COM_context.hh @@ -5,6 +5,7 @@ #include "BLI_math_vector_types.hh" #include "BLI_string_ref.hh" +#include "DNA_ID.h" #include "DNA_scene_types.h" #include "DNA_vec_types.h" @@ -70,6 +71,14 @@ class Context { * appropriate place, which can be directly in the UI or just logged to the output stream. */ virtual void set_info_message(StringRef message) const = 0; + /* Returns the ID recalculate flag of the given ID and reset it to zero. The given ID is assumed + * to be one that has a DrawDataList and conforms to the IdDdtTemplate. + * + * The ID recalculate flag is a mechanism through which one can identify if an ID has changed + * since the last time the flag was reset, hence why the method reset the flag after querying it, + * that is, to ready it to track the next change. */ + virtual IDRecalcFlag query_id_recalc_flag(ID *id) const = 0; + /* Get the size of the compositing region. See get_compositing_region(). */ int2 get_compositing_region_size() const; diff --git a/source/blender/compositor/realtime_compositor/COM_static_cache_manager.hh b/source/blender/compositor/realtime_compositor/COM_static_cache_manager.hh index 37d95624f2b..ee0c7ee4bfc 100644 --- a/source/blender/compositor/realtime_compositor/COM_static_cache_manager.hh +++ b/source/blender/compositor/realtime_compositor/COM_static_cache_manager.hh @@ -7,6 +7,11 @@ #include "BLI_map.hh" #include "BLI_math_vector_types.hh" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "COM_cached_texture.hh" +#include "COM_context.hh" #include "COM_morphological_distance_feather_weights.hh" #include "COM_smaa_precomputed_textures.hh" #include "COM_symmetric_blur_weights.hh" @@ -14,6 +19,8 @@ namespace blender::realtime_compositor { +class Context; + /* ------------------------------------------------------------------------------------------------- * Static Cache Manager * @@ -48,6 +55,11 @@ class StaticCacheManager { Map> morphological_distance_feather_weights_; + /* A nested map that stores all CachedTexture cached resources. The outer map identifies the + * textures using their ID name, while the inner map identifies the textures using their + * parameters. */ + Map>> cached_textures_; + /* A unique pointers that stores the cached SMAAPrecomputedTextures, if one is cached. */ std::unique_ptr smaa_precomputed_textures_; @@ -77,6 +89,15 @@ class StaticCacheManager { MorphologicalDistanceFeatherWeights &get_morphological_distance_feather_weights(int type, int radius); + /* Check if the given texture ID has changed since the last time it was retrieved through its + * recalculate flag, and if so, invalidate its corresponding cached textures and reset the + * recalculate flag to ready it to track the next change. Then, check if there is an available + * CachedTexture cached resource with the given parameters in the manager, if one exists, return + * it, otherwise, return a newly created one and add it to the manager. In both cases, tag the + * cached resource as needed to keep it cached for the next evaluation. */ + CachedTexture &get_cached_texture( + Context &context, Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale); + /* Check if a cached SMAA precomputed texture exists, if it does, return it, otherwise, return * a newly created one and store it in the manager. In both cases, tag the cached resource as * needed to keep it cached for the next evaluation. */ diff --git a/source/blender/compositor/realtime_compositor/cached_resources/COM_cached_texture.hh b/source/blender/compositor/realtime_compositor/cached_resources/COM_cached_texture.hh new file mode 100644 index 00000000000..2c79ff6b322 --- /dev/null +++ b/source/blender/compositor/realtime_compositor/cached_resources/COM_cached_texture.hh @@ -0,0 +1,55 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#pragma once + +#include + +#include "BLI_math_vector_types.hh" + +#include "GPU_texture.h" + +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "COM_cached_resource.hh" + +namespace blender::realtime_compositor { + +/* ------------------------------------------------------------------------------------------------ + * Cached Texture Key. + */ +class CachedTextureKey { + public: + int2 size; + float2 offset; + float2 scale; + + CachedTextureKey(int2 size, float2 offset, float2 scale); + + uint64_t hash() const; +}; + +bool operator==(const CachedTextureKey &a, const CachedTextureKey &b); + +/* ------------------------------------------------------------------------------------------------- + * Cached Texture. + * + * A cached resource that computes and caches a GPU texture containing the the result of evaluating + * the given texture ID on a space that spans the given size, modified by the given offset and + * scale. */ +class CachedTexture : public CachedResource { + private: + GPUTexture *color_texture_ = nullptr; + GPUTexture *value_texture_ = nullptr; + + public: + CachedTexture(Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale); + + ~CachedTexture(); + + GPUTexture *color_texture(); + + GPUTexture *value_texture(); +}; + +} // namespace blender::realtime_compositor diff --git a/source/blender/compositor/realtime_compositor/cached_resources/intern/cached_texture.cc b/source/blender/compositor/realtime_compositor/cached_resources/intern/cached_texture.cc new file mode 100644 index 00000000000..c0a80045a8f --- /dev/null +++ b/source/blender/compositor/realtime_compositor/cached_resources/intern/cached_texture.cc @@ -0,0 +1,102 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include + +#include "BLI_array.hh" +#include "BLI_hash.hh" +#include "BLI_index_range.hh" +#include "BLI_math_vector_types.hh" +#include "BLI_task.hh" + +#include "GPU_texture.h" + +#include "BKE_texture.h" + +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "RE_texture.h" + +#include "COM_cached_texture.hh" + +namespace blender::realtime_compositor { + +/* -------------------------------------------------------------------- + * Cached Texture Key. + */ + +CachedTextureKey::CachedTextureKey(int2 size, float2 offset, float2 scale) + : size(size), offset(offset), scale(scale) +{ +} + +uint64_t CachedTextureKey::hash() const +{ + return get_default_hash_3(size, offset, scale); +} + +bool operator==(const CachedTextureKey &a, const CachedTextureKey &b) +{ + return a.size == b.size && a.offset == b.offset && a.scale == b.scale; +} + +/* -------------------------------------------------------------------- + * Cached Texture. + */ + +CachedTexture::CachedTexture( + Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale) +{ + Array color_pixels(size.x * size.y); + Array value_pixels(size.x * size.y); + threading::parallel_for(IndexRange(size.y), 1, [&](const IndexRange sub_y_range) { + for (const int64_t y : sub_y_range) { + for (const int64_t x : IndexRange(size.x)) { + /* Compute the coordinates in the [0, 1] range and add 0.5 to evaluate the texture at the + * center of pixels in case it was interpolated. */ + float2 coordinates = ((float2(x, y) + 0.5f) / float2(size)) * 2.0f - 1.0f; + /* Note that it is expected that the offset is scaled by the scale. */ + coordinates = (coordinates + offset) * scale; + TexResult texture_result; + BKE_texture_get_value(scene, texture, coordinates, &texture_result, true); + color_pixels[y * size.x + x] = float4(texture_result.trgba); + value_pixels[y * size.x + x] = texture_result.talpha ? texture_result.trgba[3] : + texture_result.tin; + } + } + }); + + color_texture_ = GPU_texture_create_2d("Cached Color Texture", + size.x, + size.y, + 1, + GPU_RGBA16F, + GPU_TEXTURE_USAGE_SHADER_READ, + *color_pixels.data()); + + value_texture_ = GPU_texture_create_2d("Cached Value Texture", + size.x, + size.y, + 1, + GPU_R16F, + GPU_TEXTURE_USAGE_SHADER_READ, + value_pixels.data()); +} + +CachedTexture::~CachedTexture() +{ + GPU_texture_free(color_texture_); + GPU_texture_free(value_texture_); +} + +GPUTexture *CachedTexture::color_texture() +{ + return color_texture_; +} + +GPUTexture *CachedTexture::value_texture() +{ + return value_texture_; +} + +} // namespace blender::realtime_compositor diff --git a/source/blender/compositor/realtime_compositor/intern/static_cache_manager.cc b/source/blender/compositor/realtime_compositor/intern/static_cache_manager.cc index 55f86b7d0fe..8d723d4a985 100644 --- a/source/blender/compositor/realtime_compositor/intern/static_cache_manager.cc +++ b/source/blender/compositor/realtime_compositor/intern/static_cache_manager.cc @@ -4,6 +4,11 @@ #include "BLI_math_vector_types.hh" +#include "DNA_ID.h" +#include "DNA_scene_types.h" +#include "DNA_texture_types.h" + +#include "COM_context.hh" #include "COM_morphological_distance_feather_weights.hh" #include "COM_smaa_precomputed_textures.hh" #include "COM_symmetric_blur_weights.hh" @@ -23,6 +28,12 @@ void StaticCacheManager::reset() symmetric_blur_weights_.remove_if([](auto item) { return !item.value->needed; }); symmetric_separable_blur_weights_.remove_if([](auto item) { return !item.value->needed; }); morphological_distance_feather_weights_.remove_if([](auto item) { return !item.value->needed; }); + + for (auto &cached_textures_for_id : cached_textures_.values()) { + cached_textures_for_id.remove_if([](auto item) { return !item.value->needed; }); + } + cached_textures_.remove_if([](auto item) { return item.value.is_empty(); }); + if (smaa_precomputed_textures_ && !smaa_precomputed_textures_->needed) { smaa_precomputed_textures_.reset(); } @@ -38,6 +49,11 @@ void StaticCacheManager::reset() for (auto &value : morphological_distance_feather_weights_.values()) { value->needed = false; } + for (auto &cached_textures_for_id : cached_textures_.values()) { + for (auto &value : cached_textures_for_id.values()) { + value->needed = false; + } + } if (smaa_precomputed_textures_) { smaa_precomputed_textures_->needed = false; } @@ -78,6 +94,24 @@ MorphologicalDistanceFeatherWeights &StaticCacheManager:: return weights; } +CachedTexture &StaticCacheManager::get_cached_texture( + Context &context, Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale) +{ + const CachedTextureKey key(size, offset, scale); + + auto &cached_textures_for_id = cached_textures_.lookup_or_add_default(texture->id.name); + + if (context.query_id_recalc_flag(reinterpret_cast(texture)) & ID_RECALC_ALL) { + cached_textures_for_id.clear(); + } + + auto &cached_texture = *cached_textures_for_id.lookup_or_add_cb( + key, [&]() { return std::make_unique(texture, scene, size, offset, scale); }); + + cached_texture.needed = true; + return cached_texture; +} + SMAAPrecomputedTextures &StaticCacheManager::get_smaa_precomputed_textures() { if (!smaa_precomputed_textures_) { diff --git a/source/blender/draw/engines/compositor/compositor_engine.cc b/source/blender/draw/engines/compositor/compositor_engine.cc index f024bc706b7..3c6a9bab765 100644 --- a/source/blender/draw/engines/compositor/compositor_engine.cc +++ b/source/blender/draw/engines/compositor/compositor_engine.cc @@ -8,6 +8,7 @@ #include "BLT_translation.h" +#include "DNA_ID.h" #include "DNA_ID_enums.h" #include "DNA_camera_types.h" #include "DNA_object_types.h" @@ -143,6 +144,15 @@ class Context : public realtime_compositor::Context { { message.copy(info_message_, GPU_INFO_SIZE); } + + IDRecalcFlag query_id_recalc_flag(ID *id) const override + { + DrawEngineType *owner = &draw_engine_compositor_type; + DrawData *draw_data = DRW_drawdata_ensure(id, owner, sizeof(DrawData), nullptr, nullptr); + IDRecalcFlag recalc_flag = IDRecalcFlag(draw_data->recalc); + draw_data->recalc = IDRecalcFlag(0); + return recalc_flag; + } }; class Engine { diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 9ea93637b01..15c63bf6560 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -832,6 +832,7 @@ static bool id_type_can_have_drawdata(const short id_type) case ID_OB: case ID_WO: case ID_SCE: + case ID_TE: return true; /* no DrawData */ diff --git a/source/blender/makesdna/DNA_texture_types.h b/source/blender/makesdna/DNA_texture_types.h index 4b3daf92d8b..f37c62f862d 100644 --- a/source/blender/makesdna/DNA_texture_types.h +++ b/source/blender/makesdna/DNA_texture_types.h @@ -153,6 +153,8 @@ typedef struct Tex { ID id; /** Animation data (must be immediately after id for utilities to use it). */ struct AnimData *adt; + /* runtime (must be immediately after id for utilities to use it). */ + DrawDataList drawdata; float noisesize, turbul; float bright, contrast, saturation, rfac, gfac, bfac; @@ -264,14 +266,14 @@ typedef struct ColorMapping { #define TEX_STUCCI 6 #define TEX_NOISE 7 #define TEX_IMAGE 8 -//#define TEX_PLUGIN 9 /* Deprecated */ -//#define TEX_ENVMAP 10 /* Deprecated */ +// #define TEX_PLUGIN 9 /* Deprecated */ +// #define TEX_ENVMAP 10 /* Deprecated */ #define TEX_MUSGRAVE 11 #define TEX_VORONOI 12 #define TEX_DISTNOISE 13 -//#define TEX_POINTDENSITY 14 /* Deprecated */ -//#define TEX_VOXELDATA 15 /* Deprecated */ -//#define TEX_OCEAN 16 /* Deprecated */ +// #define TEX_POINTDENSITY 14 /* Deprecated */ +// #define TEX_VOXELDATA 15 /* Deprecated */ +// #define TEX_OCEAN 16 /* Deprecated */ /* musgrave stype */ #define TEX_MFRACTAL 0 diff --git a/source/blender/nodes/composite/nodes/node_composite_texture.cc b/source/blender/nodes/composite/nodes/node_composite_texture.cc index 64acbc6ed27..c5f41fbbae1 100644 --- a/source/blender/nodes/composite/nodes/node_composite_texture.cc +++ b/source/blender/nodes/composite/nodes/node_composite_texture.cc @@ -7,7 +7,9 @@ #include "BLT_translation.h" +#include "COM_cached_texture.hh" #include "COM_node_operation.hh" +#include "COM_utilities.hh" #include "node_composite_util.hh" @@ -17,12 +19,17 @@ namespace blender::nodes::node_composite_texture_cc { static void cmp_node_texture_declare(NodeDeclarationBuilder &b) { - b.add_input(N_("Offset")).min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION); + b.add_input(N_("Offset")) + .min(-2.0f) + .max(2.0f) + .subtype(PROP_TRANSLATION) + .compositor_expects_single_value(); b.add_input(N_("Scale")) .default_value({1.0f, 1.0f, 1.0f}) .min(-10.0f) .max(10.0f) - .subtype(PROP_XYZ); + .subtype(PROP_XYZ) + .compositor_expects_single_value(); b.add_output(N_("Value")); b.add_output(N_("Color")); } @@ -35,9 +42,46 @@ class TextureOperation : public NodeOperation { void execute() override { - get_result("Value").allocate_invalid(); - get_result("Color").allocate_invalid(); - context().set_info_message("Viewport compositor setup not fully supported"); + Result &color_result = get_result("Color"); + Result &value_result = get_result("Value"); + if (!get_texture()) { + if (color_result.should_compute()) { + color_result.allocate_invalid(); + } + if (value_result.should_compute()) { + value_result.allocate_invalid(); + } + return; + } + + const Domain domain = compute_domain(); + CachedTexture &cached_texture = context().cache_manager().get_cached_texture( + context(), + get_texture(), + context().get_scene(), + domain.size, + get_input("Offset").get_vector_value_default(float4(0.0f)).xy(), + get_input("Scale").get_vector_value_default(float4(0.0f)).xy()); + + if (color_result.should_compute()) { + color_result.allocate_texture(domain); + GPU_texture_copy(color_result.texture(), cached_texture.color_texture()); + } + + if (value_result.should_compute()) { + value_result.allocate_texture(domain); + GPU_texture_copy(value_result.texture(), cached_texture.value_texture()); + } + } + + Domain compute_domain() override + { + return Domain(context().get_compositing_region_size()); + } + + Tex *get_texture() + { + return (Tex *)bnode().id; } }; @@ -58,8 +102,6 @@ void register_node_type_cmp_texture() ntype.declare = file_ns::cmp_node_texture_declare; ntype.flag |= NODE_PREVIEW; ntype.get_compositor_operation = file_ns::get_compositor_operation; - ntype.realtime_compositor_unsupported_message = N_( - "Node not supported in the Viewport compositor"); nodeRegisterType(&ntype); }