diff options
Diffstat (limited to 'source')
11 files changed, 166 insertions, 92 deletions
diff --git a/source/blender/draw/engines/compositor/compositor_engine.cc b/source/blender/draw/engines/compositor/compositor_engine.cc index 13fc8dc0f64..c9f2a3dcac1 100644 --- a/source/blender/draw/engines/compositor/compositor_engine.cc +++ b/source/blender/draw/engines/compositor/compositor_engine.cc @@ -5,6 +5,7 @@ #include "BLT_translation.h" +#include "DNA_ID_enums.h" #include "DNA_scene_types.h" #include "DEG_depsgraph_query.h" @@ -30,18 +31,18 @@ class DRWTexturePool : public TexturePool { } }; -static const Scene *get_context_scene() -{ - return DRW_context_state_get()->scene; -} - class DRWContext : public Context { public: using Context::Context; const Scene *get_scene() override { - return get_context_scene(); + return DRW_context_state_get()->scene; + } + + int2 get_viewport_size() override + { + return int2(float2(DRW_viewport_size_get())); } GPUTexture *get_viewport_texture() override @@ -56,59 +57,116 @@ class DRWContext : public Context { } }; -/* It is sufficient to check for the scene node tree because the engine will not be enabled when - * the viewport shading option is disabled. */ -static bool is_compositor_enabled() -{ - const Scene *scene = get_context_scene(); - if (scene->use_nodes && scene->nodetree) { - return true; +class Engine { + private: + DRWTexturePool texture_pool_; + DRWContext context_; + Evaluator evaluator_; + /* Stores the viewport size at the time the last compositor evaluation happened. See the + * update_viewport_size method for more information. */ + int2 viewport_size_; + + public: + Engine() : context_(texture_pool_), evaluator_(context_, node_tree()) + { } - return false; -} -static void draw() -{ - if (!is_compositor_enabled()) { - return; + /* Update the viewport size and evaluate the compositor. */ + void draw() + { + update_viewport_size(); + evaluator_.evaluate(); } - /* Reset default view. */ - DRW_view_set_active(nullptr); + /* If the size of the viewport changed from the last time the compositor was evaluated, update + * the viewport size and reset the evaluator. That's because the evaluator compiles the node tree + * in a manner that is specifically optimized for the size of the viewport. This should be called + * before evaluating the compositor. */ + void update_viewport_size() + { + if (viewport_size_ == context_.get_viewport_size()) { + return; + } - DRWTexturePool texture_pool; - DRWContext context(texture_pool); - const Scene *scene = get_context_scene(); - Evaluator evaluator(context, *scene->nodetree); - evaluator.evaluate(); -} + viewport_size_ = context_.get_viewport_size(); + + evaluator_.reset(); + } + + /* If the compositor node tree changed, reset the evaluator. */ + void update(const Depsgraph *depsgraph) + { + if (DEG_id_type_updated(depsgraph, ID_NT)) { + evaluator_.reset(); + } + } + + /* Get a reference to the compositor node tree. */ + static bNodeTree &node_tree() + { + return *DRW_context_state_get()->scene->nodetree; + } +}; } // namespace blender::viewport_compositor -static void compositor_draw(void *UNUSED(data)) +using namespace blender::viewport_compositor; + +typedef struct CompositorData { + DrawEngineType *engine_type; + DRWViewportEmptyList *fbl; + DRWViewportEmptyList *txl; + DRWViewportEmptyList *psl; + DRWViewportEmptyList *stl; + Engine *instance_data; +} CompositorData; + +static void compositor_engine_init(void *data) +{ + CompositorData *compositor_data = static_cast<CompositorData *>(data); + + if (!compositor_data->instance_data) { + compositor_data->instance_data = new Engine(); + } +} + +static void compositor_engine_free(void *instance_data) +{ + Engine *engine = static_cast<Engine *>(instance_data); + delete engine; +} + +static void compositor_engine_draw(void *data) +{ + const CompositorData *compositor_data = static_cast<CompositorData *>(data); + compositor_data->instance_data->draw(); +} + +static void compositor_engine_update(void *data) { - blender::viewport_compositor::draw(); + const CompositorData *compositor_data = static_cast<CompositorData *>(data); + compositor_data->instance_data->update(DRW_context_state_get()->depsgraph); } extern "C" { -static const DrawEngineDataSize compositor_data_size = {}; +static const DrawEngineDataSize compositor_data_size = DRW_VIEWPORT_DATA_SIZE(CompositorData); DrawEngineType draw_engine_compositor_type = { - nullptr, - nullptr, - N_("Compositor"), - &compositor_data_size, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, - &compositor_draw, - nullptr, - nullptr, - nullptr, - nullptr, + nullptr, /* next */ + nullptr, /* prev */ + N_("Compositor"), /* idname */ + &compositor_data_size, /* vedata_size */ + &compositor_engine_init, /* engine_init */ + nullptr, /* engine_free */ + &compositor_engine_free, /* instance_free */ + nullptr, /* cache_init */ + nullptr, /* cache_populate */ + nullptr, /* cache_finish */ + &compositor_engine_draw, /* draw_scene */ + &compositor_engine_update, /* view_update */ + nullptr, /* id_update */ + nullptr, /* render_to_image */ + nullptr, /* store_metadata */ }; } diff --git a/source/blender/draw/engines/compositor/compositor_engine.h b/source/blender/draw/engines/compositor/compositor_engine.h index 4c76ad27bab..3d58d78105f 100644 --- a/source/blender/draw/engines/compositor/compositor_engine.h +++ b/source/blender/draw/engines/compositor/compositor_engine.h @@ -1,24 +1,5 @@ -/* - * 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 2021, Blender Foundation. - */ - -/** \file - * \ingroup draw_engine - */ +/* SPDX-License-Identifier: GPL-2.0-or-later + * Copyright 2022 Blender Foundation. All rights reserved. */ #pragma once diff --git a/source/blender/draw/intern/draw_manager.c b/source/blender/draw/intern/draw_manager.c index 4a372e264d8..6fbbf829b2b 100644 --- a/source/blender/draw/intern/draw_manager.c +++ b/source/blender/draw/intern/draw_manager.c @@ -1434,6 +1434,27 @@ static void drw_engines_enable_editors(void) } } +static bool is_compositor_enabled() +{ + if (!(DST.draw_ctx.v3d->shading.flag & V3D_SHADING_COMPOSITOR)) { + return false; + } + + if (!(DST.draw_ctx.v3d->shading.type > OB_MATERIAL)) { + return false; + } + + if (!DST.draw_ctx.scene->use_nodes) { + return false; + } + + if (!DST.draw_ctx.scene->nodetree) { + return false; + } + + return true; +} + /* Beware: This can go recursive if not handled properly. */ static void drw_compositor_scenes_render(DRWManager *drw, Scene *scene_active, @@ -1456,10 +1477,7 @@ static void drw_compositor_scenes_render(DRWManager *drw, int view = GPU_viewport_active_view_get(viewport); int prev_flag2 = v3d->flag2; - const eDrawType drawtype = drw->draw_ctx.v3d->shading.type; - const bool use_compositor = ((drw->draw_ctx.v3d->shading.flag & V3D_SHADING_COMPOSITOR) != 0) && - (drawtype > OB_MATERIAL) && (scene_active->nodetree != NULL) && - (scene_active->use_nodes != false); + const bool use_compositor = is_compositor_enabled(); if (!use_compositor) { /* Still setup the current active view. This way we get correct update without compositor. */ @@ -1581,7 +1599,7 @@ static void drw_engines_enable(ViewLayer *UNUSED(view_layer), } if (!DST.options.is_compositor_scene_render) { - if (((v3d->shading.flag & V3D_SHADING_COMPOSITOR) != 0) && (drawtype > OB_MATERIAL)) { + if (is_compositor_enabled()) { use_drw_engine(&draw_engine_compositor_type); } diff --git a/source/blender/nodes/composite/nodes/node_composite_composite.cc b/source/blender/nodes/composite/nodes/node_composite_composite.cc index 74c031d6366..9560c994a6e 100644 --- a/source/blender/nodes/composite/nodes/node_composite_composite.cc +++ b/source/blender/nodes/composite/nodes/node_composite_composite.cc @@ -61,7 +61,7 @@ class CompositeOperation : public NodeOperation { GPUTexture *viewport_texture = context().get_viewport_texture(); /* If the input image is a texture, copy the input texture to the viewport texture. */ - if (get_input("Image").is_texture()) { + if (input_image.is_texture()) { /* Make sure any prior writes to the texture are reflected before copying it. */ GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); @@ -77,8 +77,7 @@ class CompositeOperation : public NodeOperation { /* The operation domain have the same dimensions of the viewport without any transformations. */ Domain compute_domain() override { - GPUTexture *viewport_texture = context().get_viewport_texture(); - return Domain(int2(GPU_texture_width(viewport_texture), GPU_texture_height(viewport_texture))); + return Domain(context().get_viewport_size()); } }; diff --git a/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc index 2f041a5c70f..055a65888ea 100644 --- a/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_split_viewer.cc @@ -102,8 +102,7 @@ class ViewerOperation : public NodeOperation { /* The operation domain have the same dimensions of the viewport without any transformations. */ Domain compute_domain() override { - GPUTexture *viewport_texture = context().get_viewport_texture(); - return Domain(int2(GPU_texture_width(viewport_texture), GPU_texture_height(viewport_texture))); + return Domain(context().get_viewport_size()); } GPUShader *get_split_viewer_shader() diff --git a/source/blender/nodes/composite/nodes/node_composite_viewer.cc b/source/blender/nodes/composite/nodes/node_composite_viewer.cc index 86adc411689..0a79c9c6c10 100644 --- a/source/blender/nodes/composite/nodes/node_composite_viewer.cc +++ b/source/blender/nodes/composite/nodes/node_composite_viewer.cc @@ -88,7 +88,7 @@ class ViewerOperation : public NodeOperation { GPUTexture *viewport_texture = context().get_viewport_texture(); /* If the input image is a texture, copy the input texture to the viewport texture. */ - if (get_input("Image").is_texture()) { + if (input_image.is_texture()) { /* Make sure any prior writes to the texture are reflected before copying it. */ GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE); @@ -104,8 +104,7 @@ class ViewerOperation : public NodeOperation { /* The operation domain have the same dimensions of the viewport without any transformations. */ Domain compute_domain() override { - GPUTexture *viewport_texture = context().get_viewport_texture(); - return Domain(int2(GPU_texture_width(viewport_texture), GPU_texture_height(viewport_texture))); + return Domain(context().get_viewport_size()); } }; diff --git a/source/blender/viewport_compositor/VPC_context.hh b/source/blender/viewport_compositor/VPC_context.hh index 6d80510e48c..a6494936f4f 100644 --- a/source/blender/viewport_compositor/VPC_context.hh +++ b/source/blender/viewport_compositor/VPC_context.hh @@ -3,6 +3,8 @@ #pragma once +#include "BLI_math_vec_types.hh" + #include "DNA_scene_types.h" #include "GPU_texture.h" @@ -25,6 +27,9 @@ class Context { /* Get the active compositing scene. */ virtual const Scene *get_scene() = 0; + /* Get the dimensions of the viewport. */ + virtual int2 get_viewport_size() = 0; + /* Get the texture representing the viewport where the result of the compositor should be * written. This should be called by output nodes to get their target texture. */ virtual GPUTexture *get_viewport_texture() = 0; diff --git a/source/blender/viewport_compositor/VPC_texture_pool.hh b/source/blender/viewport_compositor/VPC_texture_pool.hh index bd762b3fa9c..cc5419c57aa 100644 --- a/source/blender/viewport_compositor/VPC_texture_pool.hh +++ b/source/blender/viewport_compositor/VPC_texture_pool.hh @@ -17,14 +17,17 @@ namespace blender::viewport_compositor { * Texture Pool Key. */ -/* A key structure used to identify a texture specification in a texture pool. Defines a hash and - * an equality operator for use in a hash map. */ +/* A key used to identify a texture specification in a texture pool. Defines a hash and an equality + * operator for use in a hash map. */ class TexturePoolKey { public: int2 size; eGPUTextureFormat format; + /* Construct a key from the given texture size and format. */ TexturePoolKey(int2 size, eGPUTextureFormat format); + + /* Construct a key from the size and format of the given texture. */ TexturePoolKey(const GPUTexture *texture); uint64_t hash() const; @@ -34,12 +37,12 @@ class TexturePoolKey { * Texture Pool. */ -/* A pool of textures that can be used to allocate textures and reused transparently throughout the - * evaluation of the compositor. This texture pool only pools textures throughout a single - * evaluation of the compositor and will reset after the evaluation without freeing any textures. - * Cross-evaluation pooling and freeing of unused textures is the responsibility of the back-end - * texture pool used by the allocate_texture method. In the case of the viewport compositor engine, - * this would be the global DRWTexturePool of the draw manager. */ +/* A pool of textures that can be used to allocate textures that can be reused transparently + * throughout the evaluation of the compositor. This texture pool only pools textures throughout a + * single evaluation of the compositor and will reset after the evaluation without freeing any + * textures. Cross-evaluation pooling and freeing of unused textures is the responsibility of the + * back-end texture pool used by the allocate_texture method. In the case of the viewport + * compositor engine, this would be the global DRWTexturePool of the draw manager. */ class TexturePool { private: /* The set of textures in the pool that are available to acquire for each distinct texture @@ -56,7 +59,7 @@ class TexturePool { GPUTexture *acquire_color(int2 size); /* Shorthand for acquire with GPU_RGBA16F format. Identical to acquire_color because vector - * textures are and should internally be stored in RGBA textures. */ + * are stored in RGBA textures because RGB texture have limited support. */ GPUTexture *acquire_vector(int2 size); /* Shorthand for acquire with GPU_R16F format. */ @@ -66,6 +69,11 @@ class TexturePool { * the texture to be one that was acquired using the same texture pool. */ void release(GPUTexture *texture); + /* Reset the texture pool by clearing all available textures. The textures are not freed. If they + * are not needed, they should be freed by the back-end texture pool used by the allocate_texture + * method. This should be called after the compositor is done evaluating. */ + void reset(); + private: /* Returns a newly allocated texture with the given specification. This method should be * implemented by the compositor engine and should use a global texture pool that is persistent diff --git a/source/blender/viewport_compositor/intern/evaluator.cc b/source/blender/viewport_compositor/intern/evaluator.cc index 14d3edc3b18..bc60a660f04 100644 --- a/source/blender/viewport_compositor/intern/evaluator.cc +++ b/source/blender/viewport_compositor/intern/evaluator.cc @@ -27,9 +27,13 @@ Evaluator::Evaluator(Context &context, bNodeTree &node_tree) void Evaluator::evaluate() { + /* Reset the texture pool that was potentially populated from a previous evaluation. */ + context_.texture_pool().reset(); + /* The node tree is not compiled yet, so compile and evaluate the node tree. */ if (!is_compiled_) { compile_and_evaluate(); + is_compiled_ = true; return; } @@ -80,9 +84,6 @@ void Evaluator::compile_and_evaluate() compile_and_evaluate_node(node, compile_state); } } - - /* Mark the node tree as compiled. */ - is_compiled_ = true; } void Evaluator::compile_and_evaluate_node(DNode node, CompileState &compile_state) diff --git a/source/blender/viewport_compositor/intern/operation.cc b/source/blender/viewport_compositor/intern/operation.cc index bd757af781b..7558fc9c51f 100644 --- a/source/blender/viewport_compositor/intern/operation.cc +++ b/source/blender/viewport_compositor/intern/operation.cc @@ -169,6 +169,7 @@ void Operation::evaluate_input_processors() /* The input processors are not added yet, so add and evaluate the input processors. */ if (!input_processors_added_) { add_and_evaluate_input_processors(); + input_processors_added_ = true; return; } diff --git a/source/blender/viewport_compositor/intern/texture_pool.cc b/source/blender/viewport_compositor/intern/texture_pool.cc index 2c08bf90335..7fcc5a4d010 100644 --- a/source/blender/viewport_compositor/intern/texture_pool.cc +++ b/source/blender/viewport_compositor/intern/texture_pool.cc @@ -61,9 +61,9 @@ GPUTexture *TexturePool::acquire_color(int2 size) return acquire(size, GPU_RGBA16F); } -/* Vectors are and should be stored in RGBA textures. */ GPUTexture *TexturePool::acquire_vector(int2 size) { + /* Vectors are stored in RGBA textures because RGB textures have limited support. */ return acquire(size, GPU_RGBA16F); } @@ -77,4 +77,9 @@ void TexturePool::release(GPUTexture *texture) textures_.lookup(TexturePoolKey(texture)).append(texture); } +void TexturePool::reset() +{ + textures_.clear(); +} + } // namespace blender::viewport_compositor |