Realtime Compositor: Implement Texture node #107291

Merged
Omar Emara merged 1 commits from OmarEmaraDev/blender:cached-texture into main 2023-04-25 09:04:41 +02:00
11 changed files with 308 additions and 12 deletions

View File

@ -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);

View File

@ -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}")

View File

@ -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;

View File

@ -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<MorphologicalDistanceFeatherWeightsKey, std::unique_ptr<MorphologicalDistanceFeatherWeights>>
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<std::string, Map<CachedTextureKey, std::unique_ptr<CachedTexture>>> cached_textures_;
/* A unique pointers that stores the cached SMAAPrecomputedTextures, if one is cached. */
std::unique_ptr<SMAAPrecomputedTextures> 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. */

View File

@ -0,0 +1,55 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
#include <cstdint>
#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

View File

@ -0,0 +1,102 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include <cstdint>
#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<float4> color_pixels(size.x * size.y);
Array<float> 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

View File

@ -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<ID *>(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<CachedTexture>(texture, scene, size, offset, scale); });
cached_texture.needed = true;
return cached_texture;
}
SMAAPrecomputedTextures &StaticCacheManager::get_smaa_precomputed_textures()
{
if (!smaa_precomputed_textures_) {

View File

@ -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 {

View File

@ -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 */

View File

@ -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

View File

@ -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<decl::Vector>(N_("Offset")).min(-2.0f).max(2.0f).subtype(PROP_TRANSLATION);
b.add_input<decl::Vector>(N_("Offset"))
.min(-2.0f)
.max(2.0f)
.subtype(PROP_TRANSLATION)
.compositor_expects_single_value();
b.add_input<decl::Vector>(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<decl::Float>(N_("Value"));
b.add_output<decl::Color>(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);
}