Realtime Compositor: Implement Texture node #107291
|
@ -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);
|
||||
|
|
|
@ -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}")
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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. */
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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_) {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue