Realtime Compositor: Support full precision compositing
This patch adds support for full precision compositing for the Realtime Compositor. A new precision option was added to the compositor to change between half and full precision compositing, where the Auto option uses half for the viewport compositor and the interactive render compositor, while full is used for final renders. The compositor context now need to implement the get_precision() method to indicate its preferred precision. Intermediate results will be stored using the context's precision, with a number of exceptions that can use a different precision regardless of the context's precision. For instance, summed area tables are always stored in full float results even if the context specified half float. Conversely, jump flooding tables are always stored in half integer results even if the context specified full. The former requires full float while the latter has no use for it. Since shaders are created for a specific precision, we need two variants of each compositor shader to account for the context's possible precision. However, to avoid doubling the shader info count and reduce boilerplate code and development time, an automated mechanism was employed. A single shader info of whatever precision needs to be added, then, at runtime, the shader info can be adjusted to change the precision of the outputs. That shader variant is then cached in the static cache manager for future processing-free shader retrieval. Therefore, the shader manager was removed in favor of a cached shader container in the static cache manager. A number of utilities were added to make the creation of results as well as the retrieval of shader with the target precision easier. Further, a number of precision-specific shaders were removed in favor of more generic ones that utilizes the aforementioned shader retrieval mechanism. Pull Request: https://projects.blender.org/blender/blender/pulls/113476
This commit is contained in:
@@ -830,6 +830,7 @@ class NODE_PT_quality(bpy.types.Panel):
|
||||
if prefs.experimental.use_experimental_compositors:
|
||||
col.prop(tree, "execution_mode")
|
||||
use_realtime = tree.execution_mode == 'REALTIME'
|
||||
col.prop(tree, "precision")
|
||||
|
||||
col = layout.column()
|
||||
col.active = not use_realtime
|
||||
|
||||
@@ -38,7 +38,6 @@ set(SRC
|
||||
intern/shader_operation.cc
|
||||
intern/simple_operation.cc
|
||||
intern/static_cache_manager.cc
|
||||
intern/static_shader_manager.cc
|
||||
intern/texture_pool.cc
|
||||
intern/utilities.cc
|
||||
|
||||
@@ -59,7 +58,6 @@ set(SRC
|
||||
COM_shader_operation.hh
|
||||
COM_simple_operation.hh
|
||||
COM_static_cache_manager.hh
|
||||
COM_static_shader_manager.hh
|
||||
COM_texture_pool.hh
|
||||
COM_utilities.hh
|
||||
|
||||
@@ -84,6 +82,7 @@ set(SRC
|
||||
algorithms/COM_algorithm_transform.hh
|
||||
|
||||
cached_resources/intern/cached_mask.cc
|
||||
cached_resources/intern/cached_shader.cc
|
||||
cached_resources/intern/cached_texture.cc
|
||||
cached_resources/intern/distortion_grid.cc
|
||||
cached_resources/intern/keying_screen.cc
|
||||
@@ -95,6 +94,7 @@ set(SRC
|
||||
|
||||
cached_resources/COM_cached_mask.hh
|
||||
cached_resources/COM_cached_resource.hh
|
||||
cached_resources/COM_cached_shader.hh
|
||||
cached_resources/COM_cached_texture.hh
|
||||
cached_resources/COM_distortion_grid.hh
|
||||
cached_resources/COM_keying_screen.hh
|
||||
|
||||
@@ -11,10 +11,11 @@
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_vec_types.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_result.hh"
|
||||
#include "COM_static_cache_manager.hh"
|
||||
#include "COM_static_shader_manager.hh"
|
||||
#include "COM_texture_pool.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -27,14 +28,12 @@ namespace blender::realtime_compositor {
|
||||
* providing input data like render passes and the active scene, as well as references to the data
|
||||
* where the output of the evaluator will be written. The class also provides a reference to the
|
||||
* texture pool which should be implemented by the caller and provided during construction.
|
||||
* Finally, the class have an instance of a static shader manager and a static resource manager
|
||||
* for acquiring cached shaders and resources efficiently. */
|
||||
* Finally, the class have an instance of a static resource manager for acquiring cached resources
|
||||
* efficiently. */
|
||||
class Context {
|
||||
private:
|
||||
/* A texture pool that can be used to allocate textures for the compositor efficiently. */
|
||||
TexturePool &texture_pool_;
|
||||
/* A static shader manager that can be used to acquire shaders for the compositor efficiently. */
|
||||
StaticShaderManager shader_manager_;
|
||||
/* A static cache manager that can be used to acquire cached resources for the compositor
|
||||
* efficiently. */
|
||||
StaticCacheManager cache_manager_;
|
||||
@@ -89,6 +88,9 @@ class Context {
|
||||
/* Get the name of the view currently being rendered. */
|
||||
virtual StringRef get_view_name() = 0;
|
||||
|
||||
/* Get the precision of the intermediate results of the compositor. */
|
||||
virtual ResultPrecision get_precision() const = 0;
|
||||
|
||||
/* Set an info message. This is called by the compositor evaluator to inform or warn the user
|
||||
* about something, typically an error. The implementation should display the message in an
|
||||
* appropriate place, which can be directly in the UI or just logged to the output stream. */
|
||||
@@ -114,12 +116,29 @@ class Context {
|
||||
/* Get the current time in seconds of the active scene. */
|
||||
float get_time() const;
|
||||
|
||||
/* Get a GPU shader with the given info name and precision. */
|
||||
GPUShader *get_shader(const char *info_name, ResultPrecision precision);
|
||||
|
||||
/* Get a GPU shader with the given info name and context's precision. */
|
||||
GPUShader *get_shader(const char *info_name);
|
||||
|
||||
/* Create a result of the given type and precision using the context's texture pool. */
|
||||
Result create_result(ResultType type, ResultPrecision precision);
|
||||
|
||||
/* Create a result of the given type using the context's texture pool and precision. */
|
||||
Result create_result(ResultType type);
|
||||
|
||||
/* Create a temporary result of the given type and precision using the context's texture pool.
|
||||
* See Result::Temporary for more information. */
|
||||
Result create_temporary_result(ResultType type, ResultPrecision precision);
|
||||
|
||||
/* Create a temporary result of the given type using the context's texture pool and precision.
|
||||
* See Result::Temporary for more information. */
|
||||
Result create_temporary_result(ResultType type);
|
||||
|
||||
/* Get a reference to the texture pool of this context. */
|
||||
TexturePool &texture_pool();
|
||||
|
||||
/* Get a reference to the static shader manager of this context. */
|
||||
StaticShaderManager &shader_manager();
|
||||
|
||||
/* Get a reference to the static cache manager of this context. */
|
||||
StaticCacheManager &cache_manager();
|
||||
};
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "COM_domain.hh"
|
||||
#include "COM_input_descriptor.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_static_shader_manager.hh"
|
||||
#include "COM_texture_pool.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -155,14 +154,11 @@ class Operation {
|
||||
InputDescriptor &get_input_descriptor(StringRef identifier);
|
||||
|
||||
/* Returns a reference to the compositor context. */
|
||||
Context &context();
|
||||
Context &context() const;
|
||||
|
||||
/* Returns a reference to the texture pool of the compositor context. */
|
||||
TexturePool &texture_pool() const;
|
||||
|
||||
/* Returns a reference to the shader manager of the compositor context. */
|
||||
StaticShaderManager &shader_manager() const;
|
||||
|
||||
private:
|
||||
/* Evaluate the input processors. If the input processors were already added they will be
|
||||
* evaluated directly. Otherwise, the input processors will be added and evaluated. */
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* To add a new type, update the get_texture_format() and change_texture_format_precision()
|
||||
* functions. */
|
||||
enum class ResultType : uint8_t {
|
||||
/* The following types are user facing and can be used as inputs and outputs of operations. They
|
||||
* either represent the base type of the result texture or a single value result. The color type
|
||||
@@ -28,8 +30,9 @@ enum class ResultType : uint8_t {
|
||||
/* The following types are for internal use only, not user facing, and can't be used as inputs
|
||||
* and outputs of operations. Furthermore, they can't be single values and thus always need to be
|
||||
* allocated as textures. It follows that they needn't be handled in implicit operations like
|
||||
* type conversion, shader, or single value reduction operations. To add a new type, just add a
|
||||
* new case in the get_texture_format() function. */
|
||||
* type conversion, shader, or single value reduction operations. */
|
||||
Float2,
|
||||
Float3,
|
||||
Int2,
|
||||
};
|
||||
|
||||
@@ -121,16 +124,18 @@ class Result {
|
||||
public:
|
||||
/* Construct a result of the given type and precision with the given texture pool that will be
|
||||
* used to allocate and release the result's texture. */
|
||||
Result(ResultType type,
|
||||
TexturePool &texture_pool,
|
||||
ResultPrecision precision = ResultPrecision::Half);
|
||||
Result(ResultType type, TexturePool &texture_pool, ResultPrecision precision);
|
||||
|
||||
/* Identical to the standard constructor but initializes the reference count to 1. This is useful
|
||||
* to construct temporary results that are created and released by the developer manually, which
|
||||
* are typically used in operations that need temporary intermediate results. */
|
||||
static Result Temporary(ResultType type,
|
||||
TexturePool &texture_pool,
|
||||
ResultPrecision precision = ResultPrecision::Half);
|
||||
static Result Temporary(ResultType type, TexturePool &texture_pool, ResultPrecision precision);
|
||||
|
||||
/* Returns the appropriate texture format based on the given result type and precision. */
|
||||
static eGPUTextureFormat texture_format(ResultType type, ResultPrecision precision);
|
||||
|
||||
/* Returns the appropriate texture format based on the result's type and precision. */
|
||||
eGPUTextureFormat get_texture_format() const;
|
||||
|
||||
/* Declare the result to be a texture result, allocate a texture of an appropriate type with
|
||||
* the size of the given domain from the result's texture pool, and set the domain of the result
|
||||
@@ -290,10 +295,6 @@ class Result {
|
||||
|
||||
/* Returns a reference to the domain of the result. See the Domain class. */
|
||||
const Domain &domain() const;
|
||||
|
||||
private:
|
||||
/* Returns the appropriate texture format based on the result's type and precision. */
|
||||
eGPUTextureFormat get_texture_format() const;
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "COM_cached_mask.hh"
|
||||
#include "COM_cached_shader.hh"
|
||||
#include "COM_cached_texture.hh"
|
||||
#include "COM_distortion_grid.hh"
|
||||
#include "COM_keying_screen.hh"
|
||||
@@ -49,6 +50,7 @@ class StaticCacheManager {
|
||||
OCIOColorSpaceConversionShaderContainer ocio_color_space_conversion_shaders;
|
||||
DistortionGridContainer distortion_grids;
|
||||
KeyingScreenContainer keying_screens;
|
||||
CachedShaderContainer cached_shaders;
|
||||
|
||||
/* Reset the cache manager by deleting the cached resources that are no longer needed because
|
||||
* they weren't used in the last evaluation and prepare the remaining cached resources to track
|
||||
|
||||
@@ -1,35 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Static Shader Manager
|
||||
*
|
||||
* A static shader manager is a map of shaders identified by their info name that can be acquired
|
||||
* and reused throughout the evaluation of the compositor and are only freed when the shader
|
||||
* manager is destroyed. Once a shader is acquired for the first time, it will be cached in the
|
||||
* manager to be potentially acquired later if needed without the shader creation overhead. */
|
||||
class StaticShaderManager {
|
||||
private:
|
||||
/* The set of shaders identified by their info name that are currently available in the manager
|
||||
* to be acquired. */
|
||||
Map<StringRef, GPUShader *> shaders_;
|
||||
|
||||
public:
|
||||
~StaticShaderManager();
|
||||
|
||||
/* Check if there is an available shader with the given info name in the manager, if such shader
|
||||
* exists, return it, otherwise, return a newly created shader and add it to the manager. */
|
||||
GPUShader *get(const char *info_name);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
@@ -20,7 +20,7 @@ namespace blender::realtime_compositor {
|
||||
|
||||
static void jump_flooding_pass(Context &context, Result &input, Result &output, int step_size)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_jump_flooding");
|
||||
GPUShader *shader = context.get_shader("compositor_jump_flooding", ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "step_size", step_size);
|
||||
@@ -42,13 +42,15 @@ void jump_flooding(Context &context, Result &input, Result &output)
|
||||
|
||||
/* First, run a jump flooding pass with a step size of 1. This initial pass is proposed by the
|
||||
* 1+FJA variant to improve accuracy. */
|
||||
Result initial_flooded_result = Result::Temporary(ResultType::Int2, context.texture_pool());
|
||||
Result initial_flooded_result = context.create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
initial_flooded_result.allocate_texture(input.domain());
|
||||
jump_flooding_pass(context, input, initial_flooded_result, 1);
|
||||
|
||||
/* We compute the result using a ping-pong buffer, so create an intermediate result. */
|
||||
Result *result_to_flood = &initial_flooded_result;
|
||||
Result intermediate_result = Result::Temporary(ResultType::Int2, context.texture_pool());
|
||||
Result intermediate_result = context.create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
intermediate_result.allocate_texture(input.domain());
|
||||
Result *result_after_flooding = &intermediate_result;
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ static const char *get_shader_name(int distance)
|
||||
|
||||
void morphological_distance(Context &context, Result &input, Result &output, int distance)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(get_shader_name(distance));
|
||||
GPUShader *shader = context.get_shader(get_shader_name(distance));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Pass the absolute value of the distance. We have specialized shaders for each sign. */
|
||||
|
||||
@@ -27,14 +27,14 @@ static const char *get_shader_name(int distance)
|
||||
|
||||
static Result horizontal_pass(Context &context, Result &input, int distance, int falloff_type)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(get_shader_name(distance));
|
||||
GPUShader *shader = context.get_shader(get_shader_name(distance));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
const MorphologicalDistanceFeatherWeights &weights =
|
||||
context.cache_manager().morphological_distance_feather_weights.get(falloff_type,
|
||||
math::abs(distance));
|
||||
context.cache_manager().morphological_distance_feather_weights.get(
|
||||
context, falloff_type, math::abs(distance));
|
||||
weights.bind_weights_as_texture(shader, "weights_tx");
|
||||
weights.bind_distance_falloffs_as_texture(shader, "falloffs_tx");
|
||||
|
||||
@@ -49,7 +49,7 @@ static Result horizontal_pass(Context &context, Result &input, int distance, int
|
||||
const Domain domain = input.domain();
|
||||
const int2 transposed_domain = int2(domain.size.y, domain.size.x);
|
||||
|
||||
Result output = Result::Temporary(ResultType::Float, context.texture_pool());
|
||||
Result output = context.create_temporary_result(ResultType::Float);
|
||||
output.allocate_texture(transposed_domain);
|
||||
output.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -71,14 +71,14 @@ static void vertical_pass(Context &context,
|
||||
int distance,
|
||||
int falloff_type)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(get_shader_name(distance));
|
||||
GPUShader *shader = context.get_shader(get_shader_name(distance));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
horizontal_pass_result.bind_as_texture(shader, "input_tx");
|
||||
|
||||
const MorphologicalDistanceFeatherWeights &weights =
|
||||
context.cache_manager().morphological_distance_feather_weights.get(falloff_type,
|
||||
math::abs(distance));
|
||||
context.cache_manager().morphological_distance_feather_weights.get(
|
||||
context, falloff_type, math::abs(distance));
|
||||
weights.bind_weights_as_texture(shader, "weights_tx");
|
||||
weights.bind_distance_falloffs_as_texture(shader, "falloffs_tx");
|
||||
|
||||
|
||||
@@ -84,10 +84,11 @@ static float *parallel_reduction_dispatch(Context &context,
|
||||
|
||||
float sum_red(Context &context, GPUTexture *texture)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_red");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_red", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -97,10 +98,11 @@ float sum_red(Context &context, GPUTexture *texture)
|
||||
|
||||
float sum_green(Context &context, GPUTexture *texture)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_green");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_green", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -110,10 +112,11 @@ float sum_green(Context &context, GPUTexture *texture)
|
||||
|
||||
float sum_blue(Context &context, GPUTexture *texture)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_blue");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_blue", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -123,12 +126,13 @@ float sum_blue(Context &context, GPUTexture *texture)
|
||||
|
||||
float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_luminance");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_luminance", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -138,12 +142,13 @@ float sum_luminance(Context &context, GPUTexture *texture, float3 luminance_coef
|
||||
|
||||
float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_log_luminance");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_log_luminance", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -153,10 +158,11 @@ float sum_log_luminance(Context &context, GPUTexture *texture, float3 luminance_
|
||||
|
||||
float4 sum_color(Context &context, GPUTexture *texture)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_color");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_color", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_RGBA32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Color, ResultPrecision::Full));
|
||||
const float4 sum = float4(reduced_value);
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -170,12 +176,14 @@ float4 sum_color(Context &context, GPUTexture *texture)
|
||||
|
||||
float sum_red_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_red_squared_difference");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_red_squared_difference",
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -185,12 +193,14 @@ float sum_red_squared_difference(Context &context, GPUTexture *texture, float su
|
||||
|
||||
float sum_green_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_green_squared_difference");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_green_squared_difference",
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -200,12 +210,14 @@ float sum_green_squared_difference(Context &context, GPUTexture *texture, float
|
||||
|
||||
float sum_blue_squared_difference(Context &context, GPUTexture *texture, float subtrahend)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_blue_squared_difference");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_blue_squared_difference",
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -218,13 +230,15 @@ float sum_luminance_squared_difference(Context &context,
|
||||
float3 luminance_coefficients,
|
||||
float subtrahend)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_sum_luminance_squared_difference");
|
||||
GPUShader *shader = context.get_shader("compositor_sum_luminance_squared_difference",
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
GPU_shader_uniform_1f(shader, "subtrahend", subtrahend);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float sum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -238,12 +252,13 @@ float sum_luminance_squared_difference(Context &context,
|
||||
|
||||
float maximum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_maximum_luminance");
|
||||
GPUShader *shader = context.get_shader("compositor_maximum_luminance", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float maximum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -256,13 +271,15 @@ float maximum_float_in_range(Context &context,
|
||||
float lower_bound,
|
||||
float upper_bound)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_maximum_float_in_range");
|
||||
GPUShader *shader = context.get_shader("compositor_maximum_float_in_range",
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "lower_bound", lower_bound);
|
||||
GPU_shader_uniform_1f(shader, "upper_bound", upper_bound);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float maximum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -276,12 +293,13 @@ float maximum_float_in_range(Context &context,
|
||||
|
||||
float minimum_luminance(Context &context, GPUTexture *texture, float3 luminance_coefficients)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_minimum_luminance");
|
||||
GPUShader *shader = context.get_shader("compositor_minimum_luminance", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float minimum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
@@ -294,13 +312,15 @@ float minimum_float_in_range(Context &context,
|
||||
float lower_bound,
|
||||
float upper_bound)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_minimum_float_in_range");
|
||||
GPUShader *shader = context.get_shader("compositor_minimum_float_in_range",
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "lower_bound", lower_bound);
|
||||
GPU_shader_uniform_1f(shader, "upper_bound", upper_bound);
|
||||
|
||||
float *reduced_value = parallel_reduction_dispatch(context, texture, shader, GPU_R32F);
|
||||
float *reduced_value = parallel_reduction_dispatch(
|
||||
context, texture, shader, Result::texture_format(ResultType::Float, ResultPrecision::Full));
|
||||
const float minimum = *reduced_value;
|
||||
MEM_freeN(reduced_value);
|
||||
GPU_shader_unbind();
|
||||
|
||||
@@ -33,7 +33,9 @@ static const char *get_realization_shader(Result &input,
|
||||
case ResultType::Float:
|
||||
return "compositor_realize_on_domain_bicubic_float";
|
||||
case ResultType::Int2:
|
||||
/* Realization does not support integer images. */
|
||||
case ResultType::Float2:
|
||||
case ResultType::Float3:
|
||||
/* Realization does not support internal image types. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -46,7 +48,9 @@ static const char *get_realization_shader(Result &input,
|
||||
case ResultType::Float:
|
||||
return "compositor_realize_on_domain_float";
|
||||
case ResultType::Int2:
|
||||
/* Realization does not support integer images. */
|
||||
case ResultType::Float2:
|
||||
case ResultType::Float3:
|
||||
/* Realization does not support internal image types. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -69,8 +73,7 @@ void realize_on_domain(Context &context,
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = context.shader_manager().get(
|
||||
get_realization_shader(input, realization_options));
|
||||
GPUShader *shader = context.get_shader(get_realization_shader(input, realization_options));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Transform the input space into the domain space. */
|
||||
|
||||
@@ -38,10 +38,17 @@ static void set_shader_luminance_coefficients(GPUShader *shader, ResultType type
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
return;
|
||||
}
|
||||
case ResultType::Int2: {
|
||||
case ResultType::Float2: {
|
||||
float luminance_coefficients[3] = {1.0f, 1.0f, 0.0f};
|
||||
GPU_shader_uniform_3fv(shader, "luminance_coefficients", luminance_coefficients);
|
||||
return;
|
||||
}
|
||||
case ResultType::Float3:
|
||||
/* GPU module does not support float3 outputs. */
|
||||
break;
|
||||
case ResultType::Int2:
|
||||
/* SMAA does not support integer types. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
@@ -52,7 +59,7 @@ static Result detect_edges(Context &context,
|
||||
float threshold,
|
||||
float local_contrast_adaptation_factor)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_smaa_edge_detection");
|
||||
GPUShader *shader = context.get_shader("compositor_smaa_edge_detection");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
set_shader_luminance_coefficients(shader, input.type());
|
||||
@@ -63,7 +70,7 @@ static Result detect_edges(Context &context,
|
||||
GPU_texture_filter_mode(input.texture(), true);
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
Result edges = Result::Temporary(ResultType::Color, context.texture_pool());
|
||||
Result edges = context.create_temporary_result(ResultType::Color);
|
||||
edges.allocate_texture(input.domain());
|
||||
edges.bind_as_image(shader, "edges_img");
|
||||
|
||||
@@ -78,7 +85,7 @@ static Result detect_edges(Context &context,
|
||||
|
||||
static Result calculate_blending_weights(Context &context, Result &edges, int corner_rounding)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get("compositor_smaa_blending_weight_calculation");
|
||||
GPUShader *shader = context.get_shader("compositor_smaa_blending_weight_calculation");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "smaa_corner_rounding", corner_rounding);
|
||||
@@ -91,7 +98,7 @@ static Result calculate_blending_weights(Context &context, Result &edges, int co
|
||||
smaa_precomputed_textures.bind_area_texture(shader, "area_tx");
|
||||
smaa_precomputed_textures.bind_search_texture(shader, "search_tx");
|
||||
|
||||
Result weights = Result::Temporary(ResultType::Color, context.texture_pool());
|
||||
Result weights = context.create_temporary_result(ResultType::Color);
|
||||
weights.allocate_texture(edges.domain());
|
||||
weights.bind_as_image(shader, "weights_img");
|
||||
|
||||
@@ -106,11 +113,31 @@ static Result calculate_blending_weights(Context &context, Result &edges, int co
|
||||
return weights;
|
||||
}
|
||||
|
||||
static const char *get_blend_shader_name(ResultType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ResultType::Color:
|
||||
case ResultType::Vector:
|
||||
return "compositor_smaa_neighborhood_blending_float4";
|
||||
case ResultType::Float2:
|
||||
return "compositor_smaa_neighborhood_blending_float2";
|
||||
case ResultType::Float:
|
||||
return "compositor_smaa_neighborhood_blending_float";
|
||||
case ResultType::Float3:
|
||||
/* GPU module does not support float3 outputs. */
|
||||
break;
|
||||
case ResultType::Int2:
|
||||
/* SMAA does not support integer types. */
|
||||
break;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return "";
|
||||
}
|
||||
|
||||
static void blend_neighborhood(Context &context, Result &input, Result &weights, Result &output)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(
|
||||
input.type() == ResultType::Float ? "compositor_smaa_neighborhood_blending_float" :
|
||||
"compositor_smaa_neighborhood_blending_color");
|
||||
GPUShader *shader = context.get_shader(get_blend_shader_name(input.type()));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_texture_filter_mode(input.texture(), true);
|
||||
|
||||
@@ -57,8 +57,8 @@ static void compute_incomplete_prologues(Context &context,
|
||||
Result &incomplete_x_prologues,
|
||||
Result &incomplete_y_prologues)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(
|
||||
get_compute_incomplete_prologues_shader(operation));
|
||||
GPUShader *shader = context.get_shader(get_compute_incomplete_prologues_shader(operation),
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
@@ -94,8 +94,8 @@ static void compute_complete_x_prologues(Context &context,
|
||||
Result &complete_x_prologues,
|
||||
Result &complete_x_prologues_sum)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(
|
||||
"compositor_summed_area_table_compute_complete_x_prologues");
|
||||
GPUShader *shader = context.get_shader(
|
||||
"compositor_summed_area_table_compute_complete_x_prologues", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
incomplete_x_prologues.bind_as_texture(shader, "incomplete_x_prologues_tx");
|
||||
@@ -129,8 +129,8 @@ static void compute_complete_y_prologues(Context &context,
|
||||
Result &complete_x_prologues_sum,
|
||||
Result &complete_y_prologues)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(
|
||||
"compositor_summed_area_table_compute_complete_y_prologues");
|
||||
GPUShader *shader = context.get_shader(
|
||||
"compositor_summed_area_table_compute_complete_y_prologues", ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
incomplete_y_prologues.bind_as_texture(shader, "incomplete_y_prologues_tx");
|
||||
@@ -175,7 +175,8 @@ static void compute_complete_blocks(Context &context,
|
||||
SummedAreaTableOperation operation,
|
||||
Result &output)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(get_compute_complete_blocks_shader(operation));
|
||||
GPUShader *shader = context.get_shader(get_compute_complete_blocks_shader(operation),
|
||||
ResultPrecision::Full);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
@@ -203,23 +204,23 @@ void summed_area_table(Context &context,
|
||||
Result &output,
|
||||
SummedAreaTableOperation operation)
|
||||
{
|
||||
Result incomplete_x_prologues = Result::Temporary(
|
||||
ResultType::Color, context.texture_pool(), ResultPrecision::Full);
|
||||
Result incomplete_y_prologues = Result::Temporary(
|
||||
ResultType::Color, context.texture_pool(), ResultPrecision::Full);
|
||||
Result incomplete_x_prologues = context.create_temporary_result(ResultType::Color,
|
||||
ResultPrecision::Full);
|
||||
Result incomplete_y_prologues = context.create_temporary_result(ResultType::Color,
|
||||
ResultPrecision::Full);
|
||||
compute_incomplete_prologues(
|
||||
context, input, operation, incomplete_x_prologues, incomplete_y_prologues);
|
||||
|
||||
Result complete_x_prologues = Result::Temporary(
|
||||
ResultType::Color, context.texture_pool(), ResultPrecision::Full);
|
||||
Result complete_x_prologues_sum = Result::Temporary(
|
||||
ResultType::Color, context.texture_pool(), ResultPrecision::Full);
|
||||
Result complete_x_prologues = context.create_temporary_result(ResultType::Color,
|
||||
ResultPrecision::Full);
|
||||
Result complete_x_prologues_sum = context.create_temporary_result(ResultType::Color,
|
||||
ResultPrecision::Full);
|
||||
compute_complete_x_prologues(
|
||||
context, input, incomplete_x_prologues, complete_x_prologues, complete_x_prologues_sum);
|
||||
incomplete_x_prologues.release();
|
||||
|
||||
Result complete_y_prologues = Result::Temporary(
|
||||
ResultType::Color, context.texture_pool(), ResultPrecision::Full);
|
||||
Result complete_y_prologues = context.create_temporary_result(ResultType::Color,
|
||||
ResultPrecision::Full);
|
||||
compute_complete_y_prologues(
|
||||
context, input, incomplete_y_prologues, complete_x_prologues_sum, complete_y_prologues);
|
||||
incomplete_y_prologues.release();
|
||||
|
||||
@@ -25,9 +25,14 @@ static const char *get_blur_shader(ResultType type)
|
||||
switch (type) {
|
||||
case ResultType::Float:
|
||||
return "compositor_symmetric_separable_blur_float";
|
||||
case ResultType::Float2:
|
||||
return "compositor_symmetric_separable_blur_float2";
|
||||
case ResultType::Vector:
|
||||
case ResultType::Color:
|
||||
return "compositor_symmetric_separable_blur_color";
|
||||
return "compositor_symmetric_separable_blur_float4";
|
||||
case ResultType::Float3:
|
||||
/* GPU module does not support float3 outputs. */
|
||||
break;
|
||||
case ResultType::Int2:
|
||||
/* Blur does not support integer types. */
|
||||
break;
|
||||
@@ -44,7 +49,7 @@ static Result horizontal_pass(Context &context,
|
||||
bool extend_bounds,
|
||||
bool gamma_correct)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(get_blur_shader(input.type()));
|
||||
GPUShader *shader = context.get_shader(get_blur_shader(input.type()));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "extend_bounds", extend_bounds);
|
||||
@@ -54,7 +59,7 @@ static Result horizontal_pass(Context &context,
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
const SymmetricSeparableBlurWeights &weights =
|
||||
context.cache_manager().symmetric_separable_blur_weights.get(filter_type, radius);
|
||||
context.cache_manager().symmetric_separable_blur_weights.get(context, filter_type, radius);
|
||||
weights.bind_as_texture(shader, "weights_tx");
|
||||
|
||||
Domain domain = input.domain();
|
||||
@@ -72,7 +77,7 @@ static Result horizontal_pass(Context &context,
|
||||
* pass. */
|
||||
const int2 transposed_domain = int2(domain.size.y, domain.size.x);
|
||||
|
||||
Result output = Result::Temporary(input.type(), context.texture_pool());
|
||||
Result output = context.create_temporary_result(input.type());
|
||||
output.allocate_texture(transposed_domain);
|
||||
output.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -95,7 +100,7 @@ static void vertical_pass(Context &context,
|
||||
bool extend_bounds,
|
||||
bool gamma_correct)
|
||||
{
|
||||
GPUShader *shader = context.shader_manager().get(get_blur_shader(original_input.type()));
|
||||
GPUShader *shader = context.get_shader(get_blur_shader(original_input.type()));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "extend_bounds", extend_bounds);
|
||||
@@ -105,7 +110,7 @@ static void vertical_pass(Context &context,
|
||||
horizontal_pass_result.bind_as_texture(shader, "input_tx");
|
||||
|
||||
const SymmetricSeparableBlurWeights &weights =
|
||||
context.cache_manager().symmetric_separable_blur_weights.get(filter_type, radius.y);
|
||||
context.cache_manager().symmetric_separable_blur_weights.get(context, filter_type, radius.y);
|
||||
weights.bind_as_texture(shader, "weights_tx");
|
||||
|
||||
Domain domain = original_input.domain();
|
||||
|
||||
@@ -49,7 +49,8 @@ class CachedMask : public CachedResource {
|
||||
GPUTexture *texture_ = nullptr;
|
||||
|
||||
public:
|
||||
CachedMask(Mask *mask,
|
||||
CachedMask(Context &context,
|
||||
Mask *mask,
|
||||
int2 size,
|
||||
int frame,
|
||||
bool use_feather,
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "BLI_map.hh"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "COM_cached_resource.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Cached Shader Key.
|
||||
*/
|
||||
|
||||
class CachedShaderKey {
|
||||
public:
|
||||
std::string info_name;
|
||||
ResultPrecision precision;
|
||||
|
||||
CachedShaderKey(const char *info_name, ResultPrecision precision);
|
||||
|
||||
uint64_t hash() const;
|
||||
};
|
||||
|
||||
bool operator==(const CachedShaderKey &a, const CachedShaderKey &b);
|
||||
|
||||
/* -------------------------------------------------------------------------------------------------
|
||||
* Cached Shader.
|
||||
*
|
||||
* A cached resource that constructs and caches a GPU shader from the given info name with its
|
||||
* output images' precision changed to the given precision. */
|
||||
class CachedShader : public CachedResource {
|
||||
private:
|
||||
GPUShader *shader_ = nullptr;
|
||||
|
||||
public:
|
||||
CachedShader(const char *info_name, ResultPrecision precision);
|
||||
|
||||
~CachedShader();
|
||||
|
||||
GPUShader *shader() const;
|
||||
};
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Cached Shader Container.
|
||||
*/
|
||||
class CachedShaderContainer : public CachedResourceContainer {
|
||||
private:
|
||||
Map<CachedShaderKey, std::unique_ptr<CachedShader>> map_;
|
||||
|
||||
public:
|
||||
void reset() override;
|
||||
|
||||
/* Check if there is an available CachedShader cached resource with the given parameters in the
|
||||
* container, if one exists, return its shader, otherwise, return the shader of a newly created
|
||||
* one and add it to the container. In both cases, tag the cached resource as needed to keep it
|
||||
* cached for the next evaluation. */
|
||||
GPUShader *get(const char *info_name, ResultPrecision precision);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
@@ -48,7 +48,12 @@ class CachedTexture : public CachedResource {
|
||||
GPUTexture *value_texture_ = nullptr;
|
||||
|
||||
public:
|
||||
CachedTexture(Tex *texture, bool use_color_management, int2 size, float2 offset, float2 scale);
|
||||
CachedTexture(Context &context,
|
||||
Tex *texture,
|
||||
bool use_color_management,
|
||||
int2 size,
|
||||
float2 offset,
|
||||
float2 scale);
|
||||
|
||||
~CachedTexture();
|
||||
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
class Context;
|
||||
|
||||
enum class DistortionType : uint8_t {
|
||||
Distort,
|
||||
Undistort,
|
||||
@@ -57,7 +59,11 @@ class DistortionGrid : public CachedResource {
|
||||
public:
|
||||
/* The calibration size is the size of the image where the tracking camera was calibrated, this
|
||||
* is the size of the movie clip in most cases. */
|
||||
DistortionGrid(MovieClip *movie_clip, int2 size, DistortionType type, int2 calibration_size);
|
||||
DistortionGrid(Context &context,
|
||||
MovieClip *movie_clip,
|
||||
int2 size,
|
||||
DistortionType type,
|
||||
int2 calibration_size);
|
||||
|
||||
~DistortionGrid();
|
||||
|
||||
@@ -80,7 +86,8 @@ class DistortionGridContainer : CachedResourceContainer {
|
||||
* container, if one exists, return it, otherwise, return a newly created one and add it to the
|
||||
* container. In both cases, tag the cached resource as needed to keep it cached for the next
|
||||
* evaluation. */
|
||||
DistortionGrid &get(MovieClip *movie_clip, int2 size, DistortionType type, int frame_number);
|
||||
DistortionGrid &get(
|
||||
Context &context, MovieClip *movie_clip, int2 size, DistortionType type, int frame_number);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
class Context;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Morphological Distance Feather Key.
|
||||
*/
|
||||
@@ -46,13 +48,13 @@ class MorphologicalDistanceFeatherWeights : public CachedResource {
|
||||
GPUTexture *distance_falloffs_texture_ = nullptr;
|
||||
|
||||
public:
|
||||
MorphologicalDistanceFeatherWeights(int type, int radius);
|
||||
MorphologicalDistanceFeatherWeights(Context &context, int type, int radius);
|
||||
|
||||
~MorphologicalDistanceFeatherWeights();
|
||||
|
||||
void compute_weights(int radius);
|
||||
void compute_weights(Context &context, int radius);
|
||||
|
||||
void compute_distance_falloffs(int type, int radius);
|
||||
void compute_distance_falloffs(Context &context, int type, int radius);
|
||||
|
||||
void bind_weights_as_texture(GPUShader *shader, const char *texture_name) const;
|
||||
|
||||
@@ -78,7 +80,7 @@ class MorphologicalDistanceFeatherWeightsContainer : CachedResourceContainer {
|
||||
* given parameters in the container, if one exists, return it, otherwise, return a newly created
|
||||
* one and add it to the container. In both cases, tag the cached resource as needed to keep it
|
||||
* cached for the next evaluation. */
|
||||
MorphologicalDistanceFeatherWeights &get(int type, int radius);
|
||||
MorphologicalDistanceFeatherWeights &get(Context &context, int type, int radius);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
class Context;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* OCIO Color Space Conversion Shader Key.
|
||||
*/
|
||||
@@ -42,7 +44,7 @@ class OCIOColorSpaceConversionShader : public CachedResource {
|
||||
std::shared_ptr<GPUShaderCreator> shader_creator_;
|
||||
|
||||
public:
|
||||
OCIOColorSpaceConversionShader(std::string source, std::string target);
|
||||
OCIOColorSpaceConversionShader(Context &context, std::string source, std::string target);
|
||||
|
||||
GPUShader *bind_shader_and_resources();
|
||||
|
||||
@@ -67,7 +69,7 @@ class OCIOColorSpaceConversionShaderContainer : CachedResourceContainer {
|
||||
* parameters in the container, if one exists, return it, otherwise, return a newly created one
|
||||
* and add it to the container. In both cases, tag the cached resource as needed to keep it
|
||||
* cached for the next evaluation. */
|
||||
OCIOColorSpaceConversionShader &get(std::string source, std::string target);
|
||||
OCIOColorSpaceConversionShader &get(Context &context, std::string source, std::string target);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
class Context;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Symmetric Blur Weights Key.
|
||||
*/
|
||||
@@ -44,7 +46,7 @@ class SymmetricBlurWeights : public CachedResource {
|
||||
GPUTexture *texture_ = nullptr;
|
||||
|
||||
public:
|
||||
SymmetricBlurWeights(int type, float2 radius);
|
||||
SymmetricBlurWeights(Context &context, int type, float2 radius);
|
||||
|
||||
~SymmetricBlurWeights();
|
||||
|
||||
@@ -67,7 +69,7 @@ class SymmetricBlurWeightsContainer : public CachedResourceContainer {
|
||||
* in the container, if one exists, return it, otherwise, return a newly created one and add it
|
||||
* to the container. In both cases, tag the cached resource as needed to keep it cached for the
|
||||
* next evaluation. */
|
||||
SymmetricBlurWeights &get(int type, float2 radius);
|
||||
SymmetricBlurWeights &get(Context &context, int type, float2 radius);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
class Context;
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Symmetric Separable Blur Weights Key
|
||||
* \{ */
|
||||
@@ -50,7 +52,7 @@ class SymmetricSeparableBlurWeights : public CachedResource {
|
||||
GPUTexture *texture_ = nullptr;
|
||||
|
||||
public:
|
||||
SymmetricSeparableBlurWeights(int type, float radius);
|
||||
SymmetricSeparableBlurWeights(Context &context, int type, float radius);
|
||||
|
||||
~SymmetricSeparableBlurWeights();
|
||||
|
||||
@@ -76,7 +78,7 @@ class SymmetricSeparableBlurWeightsContainer : public CachedResourceContainer {
|
||||
* parameters in the container, if one exists, return it, otherwise, return a newly created one
|
||||
* and add it to the container. In both cases, tag the cached resource as needed to keep it
|
||||
* cached for the next evaluation. */
|
||||
SymmetricSeparableBlurWeights &get(int type, float radius);
|
||||
SymmetricSeparableBlurWeights &get(Context &context, int type, float radius);
|
||||
};
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include "COM_cached_mask.hh"
|
||||
#include "COM_context.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
@@ -99,7 +100,8 @@ static Vector<MaskRasterHandle *> get_mask_raster_handles(Mask *mask,
|
||||
return handles;
|
||||
}
|
||||
|
||||
CachedMask::CachedMask(Mask *mask,
|
||||
CachedMask::CachedMask(Context &context,
|
||||
Mask *mask,
|
||||
int2 size,
|
||||
int frame,
|
||||
bool use_feather,
|
||||
@@ -129,13 +131,14 @@ CachedMask::CachedMask(Mask *mask,
|
||||
BKE_maskrasterize_handle_free(handle);
|
||||
}
|
||||
|
||||
texture_ = GPU_texture_create_2d("Cached Mask",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
GPU_R16F,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
evaluated_mask.data());
|
||||
texture_ = GPU_texture_create_2d(
|
||||
"Cached Mask",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
evaluated_mask.data());
|
||||
}
|
||||
|
||||
CachedMask::~CachedMask()
|
||||
@@ -186,7 +189,8 @@ CachedMask &CachedMaskContainer::get(Context &context,
|
||||
}
|
||||
|
||||
auto &cached_mask = *cached_masks_for_id.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<CachedMask>(mask,
|
||||
return std::make_unique<CachedMask>(context,
|
||||
mask,
|
||||
size,
|
||||
context.get_frame_number(),
|
||||
use_feather,
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "BLI_hash.hh"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_cached_shader.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Cached Shader Key.
|
||||
*/
|
||||
|
||||
CachedShaderKey::CachedShaderKey(const char *info_name, ResultPrecision precision)
|
||||
: info_name(info_name), precision(precision)
|
||||
{
|
||||
}
|
||||
|
||||
uint64_t CachedShaderKey::hash() const
|
||||
{
|
||||
return get_default_hash_2(info_name, precision);
|
||||
}
|
||||
|
||||
bool operator==(const CachedShaderKey &a, const CachedShaderKey &b)
|
||||
{
|
||||
return a.info_name == b.info_name && a.precision == b.precision;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Cached Shader.
|
||||
*/
|
||||
|
||||
/* Given a texture format, return a corresponding texture format with the target precision. */
|
||||
static eGPUTextureFormat change_texture_format_precision(eGPUTextureFormat format,
|
||||
ResultPrecision target_precision)
|
||||
{
|
||||
switch (target_precision) {
|
||||
case ResultPrecision::Half:
|
||||
switch (format) {
|
||||
/* Already half precision, return the input format. */
|
||||
case GPU_R16F:
|
||||
case GPU_RG16F:
|
||||
case GPU_RGB16F:
|
||||
case GPU_RGBA16F:
|
||||
case GPU_RG16I:
|
||||
return format;
|
||||
|
||||
case GPU_R32F:
|
||||
return GPU_R16F;
|
||||
case GPU_RG32F:
|
||||
return GPU_RG16F;
|
||||
case GPU_RGB32F:
|
||||
return GPU_RGB16F;
|
||||
case GPU_RGBA32F:
|
||||
return GPU_RGBA16F;
|
||||
case GPU_RG32I:
|
||||
return GPU_RG16I;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ResultPrecision::Full:
|
||||
switch (format) {
|
||||
/* Already full precision, return the input format. */
|
||||
case GPU_R32F:
|
||||
case GPU_RG32F:
|
||||
case GPU_RGB32F:
|
||||
case GPU_RGBA32F:
|
||||
case GPU_RG32I:
|
||||
return format;
|
||||
|
||||
case GPU_R16F:
|
||||
return GPU_R32F;
|
||||
case GPU_RG16F:
|
||||
return GPU_RG32F;
|
||||
case GPU_RGB16F:
|
||||
return GPU_RGB32F;
|
||||
case GPU_RGBA16F:
|
||||
return GPU_RGBA32F;
|
||||
case GPU_RG16I:
|
||||
return GPU_RG32I;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return format;
|
||||
}
|
||||
|
||||
CachedShader::CachedShader(const char *info_name, ResultPrecision precision)
|
||||
{
|
||||
using namespace gpu::shader;
|
||||
ShaderCreateInfo info = *reinterpret_cast<const ShaderCreateInfo *>(
|
||||
GPU_shader_create_info_get(info_name));
|
||||
|
||||
/* Finalize first in case the create info had additional info. */
|
||||
info.finalize();
|
||||
|
||||
/* Change the format of image resource to the target precision. */
|
||||
for (ShaderCreateInfo::Resource &resource : info.pass_resources_) {
|
||||
if (resource.bind_type != ShaderCreateInfo::Resource::BindType::IMAGE) {
|
||||
continue;
|
||||
}
|
||||
resource.image.format = change_texture_format_precision(resource.image.format, precision);
|
||||
}
|
||||
|
||||
shader_ = GPU_shader_create_from_info(reinterpret_cast<const GPUShaderCreateInfo *>(&info));
|
||||
}
|
||||
|
||||
CachedShader::~CachedShader()
|
||||
{
|
||||
GPU_shader_free(shader_);
|
||||
}
|
||||
|
||||
GPUShader *CachedShader::shader() const
|
||||
{
|
||||
return shader_;
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------
|
||||
* Cached Shader Container.
|
||||
*/
|
||||
|
||||
void CachedShaderContainer::reset()
|
||||
{
|
||||
/* First, delete all resources that are no longer needed. */
|
||||
map_.remove_if([](auto item) { return !item.value->needed; });
|
||||
|
||||
/* Second, reset the needed status of the remaining resources to false to ready them to track
|
||||
* their needed status for the next evaluation. */
|
||||
for (auto &value : map_.values()) {
|
||||
value->needed = false;
|
||||
}
|
||||
}
|
||||
|
||||
GPUShader *CachedShaderContainer::get(const char *info_name, ResultPrecision precision)
|
||||
{
|
||||
const CachedShaderKey key(info_name, precision);
|
||||
|
||||
auto &cached_shader = *map_.lookup_or_add_cb(
|
||||
key, [&]() { return std::make_unique<CachedShader>(info_name, precision); });
|
||||
|
||||
cached_shader.needed = true;
|
||||
return cached_shader.shader();
|
||||
}
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "COM_cached_texture.hh"
|
||||
#include "COM_context.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
@@ -50,8 +51,12 @@ bool operator==(const CachedTextureKey &a, const CachedTextureKey &b)
|
||||
* Cached Texture.
|
||||
*/
|
||||
|
||||
CachedTexture::CachedTexture(
|
||||
Tex *texture, bool use_color_management, int2 size, float2 offset, float2 scale)
|
||||
CachedTexture::CachedTexture(Context &context,
|
||||
Tex *texture,
|
||||
bool use_color_management,
|
||||
int2 size,
|
||||
float2 offset,
|
||||
float2 scale)
|
||||
{
|
||||
ImagePool *image_pool = BKE_image_pool_new();
|
||||
BKE_texture_fetch_images_for_pool(texture, image_pool);
|
||||
@@ -78,21 +83,23 @@ CachedTexture::CachedTexture(
|
||||
|
||||
BKE_image_pool_free(image_pool);
|
||||
|
||||
color_texture_ = GPU_texture_create_2d("Cached Color Texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
GPU_RGBA16F,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
*color_pixels.data());
|
||||
color_texture_ = GPU_texture_create_2d(
|
||||
"Cached Color Texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
Result::texture_format(ResultType::Color, context.get_precision()),
|
||||
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());
|
||||
value_texture_ = GPU_texture_create_2d(
|
||||
"Cached Value Texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
value_pixels.data());
|
||||
}
|
||||
|
||||
CachedTexture::~CachedTexture()
|
||||
@@ -149,7 +156,8 @@ CachedTexture &CachedTextureContainer::get(Context &context,
|
||||
}
|
||||
|
||||
auto &cached_texture = *cached_textures_for_id.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<CachedTexture>(texture, use_color_management, size, offset, scale);
|
||||
return std::make_unique<CachedTexture>(
|
||||
context, texture, use_color_management, size, offset, scale);
|
||||
});
|
||||
|
||||
cached_texture.needed = true;
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
#include "BKE_movieclip.h"
|
||||
#include "BKE_tracking.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_distortion_grid.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
@@ -52,10 +54,8 @@ bool operator==(const DistortionGridKey &a, const DistortionGridKey &b)
|
||||
* Distortion Grid.
|
||||
*/
|
||||
|
||||
DistortionGrid::DistortionGrid(MovieClip *movie_clip,
|
||||
int2 size,
|
||||
DistortionType type,
|
||||
int2 calibration_size)
|
||||
DistortionGrid::DistortionGrid(
|
||||
Context &context, MovieClip *movie_clip, int2 size, DistortionType type, int2 calibration_size)
|
||||
{
|
||||
MovieDistortion *distortion = BKE_tracking_distortion_new(
|
||||
&movie_clip->tracking, calibration_size.x, calibration_size.y);
|
||||
@@ -88,13 +88,14 @@ DistortionGrid::DistortionGrid(MovieClip *movie_clip,
|
||||
|
||||
BKE_tracking_distortion_free(distortion);
|
||||
|
||||
texture_ = GPU_texture_create_2d("Distortion Grid",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
GPU_RG16F,
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
*distortion_grid.data());
|
||||
texture_ = GPU_texture_create_2d(
|
||||
"Distortion Grid",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float2, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
*distortion_grid.data());
|
||||
}
|
||||
|
||||
DistortionGrid::~DistortionGrid()
|
||||
@@ -140,17 +141,15 @@ static int2 get_movie_clip_size(MovieClip *movie_clip, int frame_number)
|
||||
return size;
|
||||
}
|
||||
|
||||
DistortionGrid &DistortionGridContainer::get(MovieClip *movie_clip,
|
||||
int2 size,
|
||||
DistortionType type,
|
||||
int frame_number)
|
||||
DistortionGrid &DistortionGridContainer::get(
|
||||
Context &context, MovieClip *movie_clip, int2 size, DistortionType type, int frame_number)
|
||||
{
|
||||
const int2 calibration_size = get_movie_clip_size(movie_clip, frame_number);
|
||||
|
||||
const DistortionGridKey key(movie_clip->tracking.camera, size, type, calibration_size);
|
||||
|
||||
auto &distortion_grid = *map_.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<DistortionGrid>(movie_clip, size, type, calibration_size);
|
||||
return std::make_unique<DistortionGrid>(context, movie_clip, size, type, calibration_size);
|
||||
});
|
||||
|
||||
distortion_grid.needed = true;
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_keying_screen.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_utilities.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -137,7 +138,7 @@ KeyingScreen::KeyingScreen(Context &context,
|
||||
compute_marker_points(
|
||||
movie_clip, movie_clip_user, movie_tracking_object, marker_positions, marker_colors);
|
||||
|
||||
GPUShader *shader = context.shader_manager().get("compositor_keying_screen");
|
||||
GPUShader *shader = context.get_shader("compositor_keying_screen");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "smoothness", smoothness);
|
||||
@@ -168,7 +169,13 @@ KeyingScreen::KeyingScreen(Context &context,
|
||||
GPU_storagebuf_bind(colors_ssbo, colors_ssbo_location);
|
||||
|
||||
texture_ = GPU_texture_create_2d(
|
||||
"Keying Screen", size.x, size.y, 1, GPU_RGBA16F, GPU_TEXTURE_USAGE_SHADER_READ, nullptr);
|
||||
"Keying Screen",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
Result::texture_format(ResultType::Color, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
nullptr);
|
||||
const int image_unit = GPU_shader_get_sampler_binding(shader, "output_img");
|
||||
GPU_texture_image_bind(texture_, image_unit);
|
||||
|
||||
|
||||
@@ -17,7 +17,9 @@
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_morphological_distance_feather_weights.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
@@ -46,10 +48,12 @@ bool operator==(const MorphologicalDistanceFeatherWeightsKey &a,
|
||||
* Morphological Distance Feather Weights.
|
||||
*/
|
||||
|
||||
MorphologicalDistanceFeatherWeights::MorphologicalDistanceFeatherWeights(int type, int radius)
|
||||
MorphologicalDistanceFeatherWeights::MorphologicalDistanceFeatherWeights(Context &context,
|
||||
int type,
|
||||
int radius)
|
||||
{
|
||||
compute_weights(radius);
|
||||
compute_distance_falloffs(type, radius);
|
||||
compute_weights(context, radius);
|
||||
compute_distance_falloffs(context, type, radius);
|
||||
}
|
||||
|
||||
MorphologicalDistanceFeatherWeights::~MorphologicalDistanceFeatherWeights()
|
||||
@@ -58,7 +62,7 @@ MorphologicalDistanceFeatherWeights::~MorphologicalDistanceFeatherWeights()
|
||||
GPU_texture_free(distance_falloffs_texture_);
|
||||
}
|
||||
|
||||
void MorphologicalDistanceFeatherWeights::compute_weights(int radius)
|
||||
void MorphologicalDistanceFeatherWeights::compute_weights(Context &context, int radius)
|
||||
{
|
||||
/* The size of filter is double the radius plus 1, but since the filter is symmetric, we only
|
||||
* compute half of it and no doubling happens. We add 1 to make sure the filter size is always
|
||||
@@ -89,7 +93,12 @@ void MorphologicalDistanceFeatherWeights::compute_weights(int radius)
|
||||
}
|
||||
|
||||
weights_texture_ = GPU_texture_create_1d(
|
||||
"Weights", size, 1, GPU_R16F, GPU_TEXTURE_USAGE_GENERAL, weights.data());
|
||||
"Weights",
|
||||
size,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
weights.data());
|
||||
}
|
||||
|
||||
/* Computes a falloff that is equal to 1 at an input of zero and decrease to zero at an input of 1,
|
||||
@@ -117,7 +126,9 @@ static float compute_distance_falloff(int type, float x)
|
||||
}
|
||||
}
|
||||
|
||||
void MorphologicalDistanceFeatherWeights::compute_distance_falloffs(int type, int radius)
|
||||
void MorphologicalDistanceFeatherWeights::compute_distance_falloffs(Context &context,
|
||||
int type,
|
||||
int radius)
|
||||
{
|
||||
/* The size of the distance falloffs is double the radius plus 1, but since the falloffs are
|
||||
* symmetric, we only compute half of them and no doubling happens. We add 1 to make sure the
|
||||
@@ -133,7 +144,12 @@ void MorphologicalDistanceFeatherWeights::compute_distance_falloffs(int type, in
|
||||
}
|
||||
|
||||
distance_falloffs_texture_ = GPU_texture_create_1d(
|
||||
"Distance Factors", size, 1, GPU_R16F, GPU_TEXTURE_USAGE_GENERAL, falloffs.data());
|
||||
"Distance Factors",
|
||||
size,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
falloffs.data());
|
||||
}
|
||||
|
||||
void MorphologicalDistanceFeatherWeights::bind_weights_as_texture(GPUShader *shader,
|
||||
@@ -176,13 +192,14 @@ void MorphologicalDistanceFeatherWeightsContainer::reset()
|
||||
}
|
||||
}
|
||||
|
||||
MorphologicalDistanceFeatherWeights &MorphologicalDistanceFeatherWeightsContainer::get(int type,
|
||||
int radius)
|
||||
MorphologicalDistanceFeatherWeights &MorphologicalDistanceFeatherWeightsContainer::get(
|
||||
Context &context, int type, int radius)
|
||||
{
|
||||
const MorphologicalDistanceFeatherWeightsKey key(type, radius);
|
||||
|
||||
auto &weights = *map_.lookup_or_add_cb(
|
||||
key, [&]() { return std::make_unique<MorphologicalDistanceFeatherWeights>(type, radius); });
|
||||
auto &weights = *map_.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<MorphologicalDistanceFeatherWeights>(context, type, radius);
|
||||
});
|
||||
|
||||
weights.needed = true;
|
||||
return weights;
|
||||
|
||||
@@ -20,7 +20,9 @@
|
||||
|
||||
#include "gpu_shader_create_info.hh"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_ocio_color_space_conversion_shader.hh"
|
||||
#include "COM_result.hh"
|
||||
|
||||
#if defined(WITH_OCIO)
|
||||
# include <OpenColorIO/OpenColorIO.h>
|
||||
@@ -74,10 +76,11 @@ using namespace blender::gpu::shader;
|
||||
* finally create the shader. */
|
||||
class GPUShaderCreator : public OCIO::GpuShaderCreator {
|
||||
public:
|
||||
static std::shared_ptr<GPUShaderCreator> Create()
|
||||
static std::shared_ptr<GPUShaderCreator> Create(ResultPrecision precision)
|
||||
{
|
||||
std::shared_ptr<GPUShaderCreator> instance = std::make_shared<GPUShaderCreator>();
|
||||
instance->setLanguage(OCIO::GPU_LANGUAGE_GLSL_4_0);
|
||||
instance->precision_ = precision;
|
||||
return instance;
|
||||
}
|
||||
|
||||
@@ -229,7 +232,9 @@ class GPUShaderCreator : public OCIO::GpuShaderCreator {
|
||||
std::string &resource_name = *resource_names_[resource_names_.size() - 1];
|
||||
|
||||
GPUTexture *texture;
|
||||
eGPUTextureFormat texture_format = (channel == TEXTURE_RGB_CHANNEL) ? GPU_RGB16F : GPU_R16F;
|
||||
const ResultType result_type = (channel == TEXTURE_RGB_CHANNEL) ? ResultType::Float3 :
|
||||
ResultType::Float;
|
||||
const eGPUTextureFormat texture_format = Result::texture_format(result_type, precision_);
|
||||
/* A height of 1 indicates a 1D texture according to the OCIO API. */
|
||||
# if OCIO_VERSION_HEX >= 0x02030000
|
||||
if (dimensions == OCIO::GpuShaderDesc::TEXTURE_1D) {
|
||||
@@ -267,7 +272,14 @@ class GPUShaderCreator : public OCIO::GpuShaderCreator {
|
||||
shader_create_info_.sampler(textures_.size() + 1, ImageType::FLOAT_3D, resource_name);
|
||||
|
||||
GPUTexture *texture = GPU_texture_create_3d(
|
||||
texture_name, size, size, size, 1, GPU_RGB16F, GPU_TEXTURE_USAGE_SHADER_READ, values);
|
||||
texture_name,
|
||||
size,
|
||||
size,
|
||||
size,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float3, precision_),
|
||||
GPU_TEXTURE_USAGE_SHADER_READ,
|
||||
values);
|
||||
GPU_texture_filter_mode(texture, interpolation != OCIO::INTERP_NEAREST);
|
||||
|
||||
textures_.add(sampler_name, texture);
|
||||
@@ -297,8 +309,11 @@ class GPUShaderCreator : public OCIO::GpuShaderCreator {
|
||||
|
||||
shader_create_info_.local_group_size(16, 16);
|
||||
shader_create_info_.sampler(0, ImageType::FLOAT_2D, input_sampler_name());
|
||||
shader_create_info_.image(
|
||||
0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, output_image_name());
|
||||
shader_create_info_.image(0,
|
||||
Result::texture_format(ResultType::Color, precision_),
|
||||
Qualifier::WRITE,
|
||||
ImageType::FLOAT_2D,
|
||||
output_image_name());
|
||||
shader_create_info_.compute_source("gpu_shader_compositor_ocio_processor.glsl");
|
||||
shader_create_info_.compute_source_generated += shader_code_;
|
||||
|
||||
@@ -422,6 +437,9 @@ class GPUShaderCreator : public OCIO::GpuShaderCreator {
|
||||
/* Allow creating 1D textures, or only use 2D textures. */
|
||||
bool allow_texture_1D_ = true;
|
||||
# endif
|
||||
|
||||
/* The precision of the OCIO resources as well as the output image. */
|
||||
ResultPrecision precision_;
|
||||
};
|
||||
|
||||
#else
|
||||
@@ -453,7 +471,8 @@ class GPUShaderCreator {
|
||||
* OCIO Color Space Conversion Shader.
|
||||
*/
|
||||
|
||||
OCIOColorSpaceConversionShader::OCIOColorSpaceConversionShader(std::string source,
|
||||
OCIOColorSpaceConversionShader::OCIOColorSpaceConversionShader(Context &context,
|
||||
std::string source,
|
||||
std::string target)
|
||||
{
|
||||
#if defined(WITH_OCIO)
|
||||
@@ -464,7 +483,7 @@ OCIOColorSpaceConversionShader::OCIOColorSpaceConversionShader(std::string sourc
|
||||
|
||||
/* Create a GPU shader creator and construct it based on the transforms in the default GPU
|
||||
* processor. */
|
||||
shader_creator_ = GPUShaderCreator::Create();
|
||||
shader_creator_ = GPUShaderCreator::Create(context.get_precision());
|
||||
auto ocio_shader_creator = std::static_pointer_cast<OCIO::GpuShaderCreator>(shader_creator_);
|
||||
gpu_processor->extractGpuShaderInfo(ocio_shader_creator);
|
||||
#else
|
||||
@@ -508,7 +527,8 @@ void OCIOColorSpaceConversionShaderContainer::reset()
|
||||
}
|
||||
}
|
||||
|
||||
OCIOColorSpaceConversionShader &OCIOColorSpaceConversionShaderContainer::get(std::string source,
|
||||
OCIOColorSpaceConversionShader &OCIOColorSpaceConversionShaderContainer::get(Context &context,
|
||||
std::string source,
|
||||
std::string target)
|
||||
{
|
||||
#if defined(WITH_OCIO)
|
||||
@@ -520,8 +540,9 @@ OCIOColorSpaceConversionShader &OCIOColorSpaceConversionShaderContainer::get(std
|
||||
|
||||
const OCIOColorSpaceConversionShaderKey key(source, target, config_cache_id);
|
||||
|
||||
OCIOColorSpaceConversionShader &shader = *map_.lookup_or_add_cb(
|
||||
key, [&]() { return std::make_unique<OCIOColorSpaceConversionShader>(source, target); });
|
||||
OCIOColorSpaceConversionShader &shader = *map_.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<OCIOColorSpaceConversionShader>(context, source, target);
|
||||
});
|
||||
|
||||
shader.needed = true;
|
||||
return shader;
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_symmetric_blur_weights.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -43,7 +45,7 @@ bool operator==(const SymmetricBlurWeightsKey &a, const SymmetricBlurWeightsKey
|
||||
* Symmetric Blur Weights.
|
||||
*/
|
||||
|
||||
SymmetricBlurWeights::SymmetricBlurWeights(int type, float2 radius)
|
||||
SymmetricBlurWeights::SymmetricBlurWeights(Context &context, int type, float2 radius)
|
||||
{
|
||||
/* The full size of filter is double the radius plus 1, but since the filter is symmetric, we
|
||||
* only compute a single quadrant of it and so no doubling happens. We add 1 to make sure the
|
||||
@@ -97,7 +99,13 @@ SymmetricBlurWeights::SymmetricBlurWeights(int type, float2 radius)
|
||||
}
|
||||
|
||||
texture_ = GPU_texture_create_2d(
|
||||
"Weights", size.x, size.y, 1, GPU_R16F, GPU_TEXTURE_USAGE_GENERAL, weights.data());
|
||||
"Weights",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
weights.data());
|
||||
}
|
||||
|
||||
SymmetricBlurWeights::~SymmetricBlurWeights()
|
||||
@@ -132,12 +140,12 @@ void SymmetricBlurWeightsContainer::reset()
|
||||
}
|
||||
}
|
||||
|
||||
SymmetricBlurWeights &SymmetricBlurWeightsContainer::get(int type, float2 radius)
|
||||
SymmetricBlurWeights &SymmetricBlurWeightsContainer::get(Context &context, int type, float2 radius)
|
||||
{
|
||||
const SymmetricBlurWeightsKey key(type, radius);
|
||||
|
||||
auto &weights = *map_.lookup_or_add_cb(
|
||||
key, [&]() { return std::make_unique<SymmetricBlurWeights>(type, radius); });
|
||||
key, [&]() { return std::make_unique<SymmetricBlurWeights>(context, type, radius); });
|
||||
|
||||
weights.needed = true;
|
||||
return weights;
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "GPU_shader.h"
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_symmetric_separable_blur_weights.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -43,7 +45,9 @@ bool operator==(const SymmetricSeparableBlurWeightsKey &a,
|
||||
* Symmetric Separable Blur Weights.
|
||||
*/
|
||||
|
||||
SymmetricSeparableBlurWeights::SymmetricSeparableBlurWeights(int type, float radius)
|
||||
SymmetricSeparableBlurWeights::SymmetricSeparableBlurWeights(Context &context,
|
||||
int type,
|
||||
float radius)
|
||||
{
|
||||
/* The size of filter is double the radius plus 1, but since the filter is symmetric, we only
|
||||
* compute half of it and no doubling happens. We add 1 to make sure the filter size is always
|
||||
@@ -74,7 +78,12 @@ SymmetricSeparableBlurWeights::SymmetricSeparableBlurWeights(int type, float rad
|
||||
}
|
||||
|
||||
texture_ = GPU_texture_create_1d(
|
||||
"Weights", size, 1, GPU_R16F, GPU_TEXTURE_USAGE_GENERAL, weights.data());
|
||||
"Weights",
|
||||
size,
|
||||
1,
|
||||
Result::texture_format(ResultType::Float, context.get_precision()),
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
weights.data());
|
||||
}
|
||||
|
||||
SymmetricSeparableBlurWeights::~SymmetricSeparableBlurWeights()
|
||||
@@ -110,12 +119,15 @@ void SymmetricSeparableBlurWeightsContainer::reset()
|
||||
}
|
||||
}
|
||||
|
||||
SymmetricSeparableBlurWeights &SymmetricSeparableBlurWeightsContainer::get(int type, float radius)
|
||||
SymmetricSeparableBlurWeights &SymmetricSeparableBlurWeightsContainer::get(Context &context,
|
||||
int type,
|
||||
float radius)
|
||||
{
|
||||
const SymmetricSeparableBlurWeightsKey key(type, radius);
|
||||
|
||||
auto &weights = *map_.lookup_or_add_cb(
|
||||
key, [&]() { return std::make_unique<SymmetricSeparableBlurWeights>(type, radius); });
|
||||
auto &weights = *map_.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<SymmetricSeparableBlurWeights>(context, type, radius);
|
||||
});
|
||||
|
||||
weights.needed = true;
|
||||
return weights;
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
|
||||
#include "DNA_vec_types.h"
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_static_cache_manager.hh"
|
||||
#include "COM_static_shader_manager.hh"
|
||||
#include "COM_texture_pool.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -39,16 +40,41 @@ float Context::get_time() const
|
||||
return frame_number / frame_rate;
|
||||
}
|
||||
|
||||
GPUShader *Context::get_shader(const char *info_name, ResultPrecision precision)
|
||||
{
|
||||
return cache_manager().cached_shaders.get(info_name, precision);
|
||||
}
|
||||
|
||||
GPUShader *Context::get_shader(const char *info_name)
|
||||
{
|
||||
return get_shader(info_name, get_precision());
|
||||
}
|
||||
|
||||
Result Context::create_result(ResultType type, ResultPrecision precision)
|
||||
{
|
||||
return Result::Temporary(type, texture_pool_, precision);
|
||||
}
|
||||
|
||||
Result Context::create_result(ResultType type)
|
||||
{
|
||||
return create_result(type, get_precision());
|
||||
}
|
||||
|
||||
Result Context::create_temporary_result(ResultType type, ResultPrecision precision)
|
||||
{
|
||||
return Result::Temporary(type, texture_pool_, precision);
|
||||
}
|
||||
|
||||
Result Context::create_temporary_result(ResultType type)
|
||||
{
|
||||
return create_temporary_result(type, get_precision());
|
||||
}
|
||||
|
||||
TexturePool &Context::texture_pool()
|
||||
{
|
||||
return texture_pool_;
|
||||
}
|
||||
|
||||
StaticShaderManager &Context::shader_manager()
|
||||
{
|
||||
return shader_manager_;
|
||||
}
|
||||
|
||||
StaticCacheManager &Context::cache_manager()
|
||||
{
|
||||
return cache_manager_;
|
||||
|
||||
@@ -93,7 +93,7 @@ ConvertFloatToVectorOperation::ConvertFloatToVectorOperation(Context &context)
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = ResultType::Float;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(ResultType::Vector, texture_pool()));
|
||||
populate_result(context.create_result(ResultType::Vector));
|
||||
}
|
||||
|
||||
void ConvertFloatToVectorOperation::execute_single(const Result &input, Result &output)
|
||||
@@ -103,7 +103,7 @@ void ConvertFloatToVectorOperation::execute_single(const Result &input, Result &
|
||||
|
||||
GPUShader *ConvertFloatToVectorOperation::get_conversion_shader() const
|
||||
{
|
||||
return shader_manager().get("compositor_convert_float_to_vector");
|
||||
return context().get_shader("compositor_convert_float_to_vector");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -118,7 +118,7 @@ ConvertFloatToColorOperation::ConvertFloatToColorOperation(Context &context)
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = ResultType::Float;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(ResultType::Color, texture_pool()));
|
||||
populate_result(context.create_result(ResultType::Color));
|
||||
}
|
||||
|
||||
void ConvertFloatToColorOperation::execute_single(const Result &input, Result &output)
|
||||
@@ -130,7 +130,7 @@ void ConvertFloatToColorOperation::execute_single(const Result &input, Result &o
|
||||
|
||||
GPUShader *ConvertFloatToColorOperation::get_conversion_shader() const
|
||||
{
|
||||
return shader_manager().get("compositor_convert_float_to_color");
|
||||
return context().get_shader("compositor_convert_float_to_color");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -145,7 +145,7 @@ ConvertColorToFloatOperation::ConvertColorToFloatOperation(Context &context)
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = ResultType::Color;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(ResultType::Float, texture_pool()));
|
||||
populate_result(context.create_result(ResultType::Float));
|
||||
}
|
||||
|
||||
void ConvertColorToFloatOperation::execute_single(const Result &input, Result &output)
|
||||
@@ -156,7 +156,7 @@ void ConvertColorToFloatOperation::execute_single(const Result &input, Result &o
|
||||
|
||||
GPUShader *ConvertColorToFloatOperation::get_conversion_shader() const
|
||||
{
|
||||
return shader_manager().get("compositor_convert_color_to_float");
|
||||
return context().get_shader("compositor_convert_color_to_float");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -171,7 +171,7 @@ ConvertColorToVectorOperation::ConvertColorToVectorOperation(Context &context)
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = ResultType::Color;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(ResultType::Vector, texture_pool()));
|
||||
populate_result(context.create_result(ResultType::Vector));
|
||||
}
|
||||
|
||||
void ConvertColorToVectorOperation::execute_single(const Result &input, Result &output)
|
||||
@@ -182,7 +182,7 @@ void ConvertColorToVectorOperation::execute_single(const Result &input, Result &
|
||||
|
||||
GPUShader *ConvertColorToVectorOperation::get_conversion_shader() const
|
||||
{
|
||||
return shader_manager().get("compositor_convert_color_to_vector");
|
||||
return context().get_shader("compositor_convert_color_to_vector");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -197,7 +197,7 @@ ConvertVectorToFloatOperation::ConvertVectorToFloatOperation(Context &context)
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = ResultType::Vector;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(ResultType::Float, texture_pool()));
|
||||
populate_result(context.create_result(ResultType::Float));
|
||||
}
|
||||
|
||||
void ConvertVectorToFloatOperation::execute_single(const Result &input, Result &output)
|
||||
@@ -208,7 +208,7 @@ void ConvertVectorToFloatOperation::execute_single(const Result &input, Result &
|
||||
|
||||
GPUShader *ConvertVectorToFloatOperation::get_conversion_shader() const
|
||||
{
|
||||
return shader_manager().get("compositor_convert_vector_to_float");
|
||||
return context().get_shader("compositor_convert_vector_to_float");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
@@ -223,7 +223,7 @@ ConvertVectorToColorOperation::ConvertVectorToColorOperation(Context &context)
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = ResultType::Vector;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(ResultType::Color, texture_pool()));
|
||||
populate_result(context.create_result(ResultType::Color));
|
||||
}
|
||||
|
||||
void ConvertVectorToColorOperation::execute_single(const Result &input, Result &output)
|
||||
@@ -233,7 +233,7 @@ void ConvertVectorToColorOperation::execute_single(const Result &input, Result &
|
||||
|
||||
GPUShader *ConvertVectorToColorOperation::get_conversion_shader() const
|
||||
{
|
||||
return shader_manager().get("compositor_convert_vector_to_color");
|
||||
return context().get_shader("compositor_convert_vector_to_color");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
@@ -18,7 +18,7 @@ InputSingleValueOperation::InputSingleValueOperation(Context &context, DInputSoc
|
||||
: Operation(context), input_socket_(input_socket)
|
||||
{
|
||||
const ResultType result_type = get_node_socket_result_type(input_socket_.bsocket());
|
||||
Result result = Result(result_type, texture_pool());
|
||||
Result result = context.create_result(result_type);
|
||||
|
||||
/* The result of an input single value operation is guaranteed to have a single user. */
|
||||
result.set_initial_reference_count(1);
|
||||
|
||||
@@ -38,8 +38,7 @@ NodeOperation::NodeOperation(Context &context, DNode node) : Operation(context),
|
||||
{
|
||||
for (const bNodeSocket *output : node->output_sockets()) {
|
||||
const ResultType result_type = get_node_socket_result_type(output);
|
||||
const Result result = Result(result_type, texture_pool());
|
||||
populate_result(output->identifier, result);
|
||||
populate_result(output->identifier, context.create_result(result_type));
|
||||
}
|
||||
|
||||
for (const bNodeSocket *input : node->input_sockets()) {
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "COM_reduce_to_single_value_operation.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_simple_operation.hh"
|
||||
#include "COM_static_shader_manager.hh"
|
||||
#include "COM_texture_pool.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
@@ -165,7 +164,7 @@ InputDescriptor &Operation::get_input_descriptor(StringRef identifier)
|
||||
return input_descriptors_.lookup(identifier);
|
||||
}
|
||||
|
||||
Context &Operation::context()
|
||||
Context &Operation::context() const
|
||||
{
|
||||
return context_;
|
||||
}
|
||||
@@ -175,11 +174,6 @@ TexturePool &Operation::texture_pool() const
|
||||
return context_.texture_pool();
|
||||
}
|
||||
|
||||
StaticShaderManager &Operation::shader_manager() const
|
||||
{
|
||||
return context_.shader_manager();
|
||||
}
|
||||
|
||||
void Operation::evaluate_input_processors()
|
||||
{
|
||||
if (!input_processors_added_) {
|
||||
|
||||
@@ -24,7 +24,7 @@ RealizeOnDomainOperation::RealizeOnDomainOperation(Context &context,
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = type;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(type, texture_pool()));
|
||||
populate_result(context.create_result(type));
|
||||
}
|
||||
|
||||
void RealizeOnDomainOperation::execute()
|
||||
|
||||
@@ -22,7 +22,7 @@ ReduceToSingleValueOperation::ReduceToSingleValueOperation(Context &context, Res
|
||||
InputDescriptor input_descriptor;
|
||||
input_descriptor.type = type;
|
||||
declare_input_descriptor(input_descriptor);
|
||||
populate_result(Result(type, texture_pool()));
|
||||
populate_result(context.create_result(type));
|
||||
}
|
||||
|
||||
void ReduceToSingleValueOperation::execute()
|
||||
|
||||
@@ -29,27 +29,35 @@ Result Result::Temporary(ResultType type, TexturePool &texture_pool, ResultPreci
|
||||
return result;
|
||||
}
|
||||
|
||||
eGPUTextureFormat Result::get_texture_format() const
|
||||
eGPUTextureFormat Result::texture_format(ResultType type, ResultPrecision precision)
|
||||
{
|
||||
switch (precision_) {
|
||||
switch (precision) {
|
||||
case ResultPrecision::Half:
|
||||
switch (type_) {
|
||||
switch (type) {
|
||||
case ResultType::Float:
|
||||
return GPU_R16F;
|
||||
case ResultType::Vector:
|
||||
case ResultType::Color:
|
||||
return GPU_RGBA16F;
|
||||
case ResultType::Float2:
|
||||
return GPU_RG16F;
|
||||
case ResultType::Float3:
|
||||
return GPU_RGB16F;
|
||||
case ResultType::Int2:
|
||||
return GPU_RG16I;
|
||||
}
|
||||
break;
|
||||
case ResultPrecision::Full:
|
||||
switch (type_) {
|
||||
switch (type) {
|
||||
case ResultType::Float:
|
||||
return GPU_R32F;
|
||||
case ResultType::Vector:
|
||||
case ResultType::Color:
|
||||
return GPU_RGBA32F;
|
||||
case ResultType::Float2:
|
||||
return GPU_RG32F;
|
||||
case ResultType::Float3:
|
||||
return GPU_RGB32F;
|
||||
case ResultType::Int2:
|
||||
return GPU_RG32I;
|
||||
}
|
||||
@@ -60,6 +68,11 @@ eGPUTextureFormat Result::get_texture_format() const
|
||||
return GPU_RGBA32F;
|
||||
}
|
||||
|
||||
eGPUTextureFormat Result::get_texture_format() const
|
||||
{
|
||||
return Result::texture_format(type_, precision_);
|
||||
}
|
||||
|
||||
void Result::allocate_texture(Domain domain)
|
||||
{
|
||||
/* The result is not actually needed, so allocate a dummy single value texture instead. See the
|
||||
|
||||
@@ -331,7 +331,7 @@ void ShaderOperation::populate_operation_result(DOutputSocket output_socket, GPU
|
||||
std::string output_identifier = "output" + std::to_string(output_id);
|
||||
|
||||
const ResultType result_type = get_node_socket_result_type(output_socket.bsocket());
|
||||
const Result result = Result(result_type, texture_pool());
|
||||
const Result result = context().create_result(result_type);
|
||||
populate_result(output_identifier, result);
|
||||
|
||||
/* Map the output socket to the identifier of the newly populated result. */
|
||||
@@ -400,24 +400,6 @@ void ShaderOperation::generate_code(void *thunk,
|
||||
shader_create_info.compute_source_generated += "}\n";
|
||||
}
|
||||
|
||||
static eGPUTextureFormat texture_format_from_result_type(ResultType type)
|
||||
{
|
||||
switch (type) {
|
||||
case ResultType::Float:
|
||||
return GPU_R16F;
|
||||
case ResultType::Vector:
|
||||
return GPU_RGBA16F;
|
||||
case ResultType::Color:
|
||||
return GPU_RGBA16F;
|
||||
default:
|
||||
/* Other types are internal and needn't be handled by operations. */
|
||||
break;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return GPU_RGBA16F;
|
||||
}
|
||||
|
||||
/* Texture storers in the shader always take a vec4 as an argument, so encode each type in a vec4
|
||||
* appropriately. */
|
||||
static const char *glsl_store_expression_from_result_type(ResultType type)
|
||||
@@ -470,11 +452,11 @@ void ShaderOperation::generate_code_for_outputs(ShaderCreateInfo &shader_create_
|
||||
|
||||
/* Add a write-only image for this output where its values will be written. */
|
||||
shader_create_info.image(0,
|
||||
texture_format_from_result_type(result.type()),
|
||||
result.get_texture_format(),
|
||||
Qualifier::WRITE,
|
||||
ImageType::FLOAT_2D,
|
||||
output_identifier,
|
||||
Frequency::BATCH);
|
||||
Frequency::PASS);
|
||||
|
||||
/* Add a case for the index of this output followed by a break statement. */
|
||||
std::stringstream case_code;
|
||||
@@ -563,7 +545,7 @@ void ShaderOperation::generate_code_for_inputs(GPUMaterial *material,
|
||||
|
||||
/* Add a texture sampler for each of the inputs with the same name as the attribute. */
|
||||
LISTBASE_FOREACH (GPUMaterialAttribute *, attribute, &attributes) {
|
||||
shader_create_info.sampler(0, ImageType::FLOAT_2D, attribute->name, Frequency::BATCH);
|
||||
shader_create_info.sampler(0, ImageType::FLOAT_2D, attribute->name, Frequency::PASS);
|
||||
}
|
||||
|
||||
/* Declare a struct called var_attrs that includes an appropriately typed member for each of the
|
||||
|
||||
@@ -17,6 +17,7 @@ void StaticCacheManager::reset()
|
||||
ocio_color_space_conversion_shaders.reset();
|
||||
distortion_grids.reset();
|
||||
keying_screens.reset();
|
||||
cached_shaders.reset();
|
||||
}
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "GPU_shader.h"
|
||||
|
||||
#include "COM_static_shader_manager.hh"
|
||||
|
||||
namespace blender::realtime_compositor {
|
||||
|
||||
StaticShaderManager::~StaticShaderManager()
|
||||
{
|
||||
for (GPUShader *shader : shaders_.values()) {
|
||||
GPU_shader_free(shader);
|
||||
}
|
||||
}
|
||||
|
||||
GPUShader *StaticShaderManager::get(const char *info_name)
|
||||
{
|
||||
/* If a shader with the same info name already exists in the manager, return it, otherwise,
|
||||
* create a new shader from the info name and return it. */
|
||||
return shaders_.lookup_or_add_cb(
|
||||
info_name, [info_name]() { return GPU_shader_create_from_info_name(info_name); });
|
||||
}
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
@@ -193,7 +193,7 @@ void compute_preview_from_result(Context &context, const DNode &node, Result &in
|
||||
bNodePreview *preview = bke::node_preview_verify(
|
||||
root_tree->previews, node.instance_key(), preview_size.x, preview_size.y, true);
|
||||
|
||||
GPUShader *shader = context.shader_manager().get("compositor_compute_preview");
|
||||
GPUShader *shader = context.get_shader("compositor_compute_preview");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
if (input_result.type() == ResultType::Float) {
|
||||
@@ -202,7 +202,7 @@ void compute_preview_from_result(Context &context, const DNode &node, Result &in
|
||||
|
||||
input_result.bind_as_texture(shader, "input_tx");
|
||||
|
||||
Result preview_result = Result::Temporary(ResultType::Color, context.texture_pool());
|
||||
Result preview_result = context.create_temporary_result(ResultType::Color);
|
||||
preview_result.allocate_texture(Domain(preview_size));
|
||||
preview_result.bind_as_image(shader, "preview_img");
|
||||
|
||||
|
||||
@@ -43,11 +43,16 @@ GPU_SHADER_CREATE_INFO(compositor_smaa_neighborhood_blending_shared)
|
||||
.sampler(1, ImageType::FLOAT_2D, "weights_tx")
|
||||
.compute_source("compositor_smaa_neighborhood_blending.glsl");
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_smaa_neighborhood_blending_color)
|
||||
GPU_SHADER_CREATE_INFO(compositor_smaa_neighborhood_blending_float4)
|
||||
.additional_info("compositor_smaa_neighborhood_blending_shared")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_smaa_neighborhood_blending_float2)
|
||||
.additional_info("compositor_smaa_neighborhood_blending_shared")
|
||||
.image(0, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_smaa_neighborhood_blending_float)
|
||||
.additional_info("compositor_smaa_neighborhood_blending_shared")
|
||||
.image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
|
||||
@@ -18,7 +18,12 @@ GPU_SHADER_CREATE_INFO(compositor_symmetric_separable_blur_float)
|
||||
.image(0, GPU_R16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_symmetric_separable_blur_color)
|
||||
GPU_SHADER_CREATE_INFO(compositor_symmetric_separable_blur_float2)
|
||||
.additional_info("compositor_symmetric_separable_blur_shared")
|
||||
.image(0, GPU_RG16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.do_static_compilation(true);
|
||||
|
||||
GPU_SHADER_CREATE_INFO(compositor_symmetric_separable_blur_float4)
|
||||
.additional_info("compositor_symmetric_separable_blur_shared")
|
||||
.image(0, GPU_RGBA16F, Qualifier::WRITE, ImageType::FLOAT_2D, "output_img")
|
||||
.do_static_compilation(true);
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_evaluator.hh"
|
||||
#include "COM_result.hh"
|
||||
#include "COM_texture_pool.hh"
|
||||
|
||||
#include "GPU_context.h"
|
||||
@@ -178,6 +179,19 @@ class Context : public realtime_compositor::Context {
|
||||
return view->name;
|
||||
}
|
||||
|
||||
realtime_compositor::ResultPrecision get_precision() const override
|
||||
{
|
||||
switch (get_node_tree().precision) {
|
||||
case NODE_TREE_COMPOSITOR_PRECISION_AUTO:
|
||||
return realtime_compositor::ResultPrecision::Half;
|
||||
case NODE_TREE_COMPOSITOR_PRECISION_FULL:
|
||||
return realtime_compositor::ResultPrecision::Full;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return realtime_compositor::ResultPrecision::Half;
|
||||
}
|
||||
|
||||
void set_info_message(StringRef message) const override
|
||||
{
|
||||
message.copy(info_message_, GPU_INFO_SIZE);
|
||||
|
||||
@@ -669,6 +669,10 @@ typedef struct bNodeTree {
|
||||
int chunksize;
|
||||
/** Execution mode to use for compositor engine. */
|
||||
int execution_mode;
|
||||
/** Execution mode to use for compositor engine. */
|
||||
int precision;
|
||||
|
||||
char _pad[4];
|
||||
|
||||
rctf viewer_border;
|
||||
|
||||
@@ -836,6 +840,12 @@ typedef enum eNodeTreeExecutionMode {
|
||||
NTREE_EXECUTION_MODE_REALTIME = 2,
|
||||
} eNodeTreeExecutionMode;
|
||||
|
||||
/* tree->precision */
|
||||
typedef enum eNodeTreePrecision {
|
||||
NODE_TREE_COMPOSITOR_PRECISION_AUTO = 0,
|
||||
NODE_TREE_COMPOSITOR_PRECISION_FULL = 1,
|
||||
} eNodeTreePrecision;
|
||||
|
||||
typedef enum eNodeTreeRuntimeFlag {
|
||||
/** There is a node that references an image with animation. */
|
||||
NTREE_RUNTIME_FLAG_HAS_IMAGE_ANIMATION = 1 << 0,
|
||||
|
||||
@@ -150,6 +150,16 @@ static const EnumPropertyItem rna_enum_execution_mode_items[] = {
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static const EnumPropertyItem rna_enum_precision_items[] = {
|
||||
{NODE_TREE_COMPOSITOR_PRECISION_AUTO,
|
||||
"AUTO",
|
||||
0,
|
||||
"Auto",
|
||||
"Full precision for final renders, half precision otherwise"},
|
||||
{NODE_TREE_COMPOSITOR_PRECISION_FULL, "FULL", 0, "Full", "Full precision"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
const EnumPropertyItem rna_enum_mapping_type_items[] = {
|
||||
{NODE_MAPPING_TYPE_POINT, "POINT", 0, "Point", "Transform a point"},
|
||||
{NODE_MAPPING_TYPE_TEXTURE,
|
||||
@@ -10148,6 +10158,12 @@ static void rna_def_composite_nodetree(BlenderRNA *brna)
|
||||
RNA_def_struct_sdna(srna, "bNodeTree");
|
||||
RNA_def_struct_ui_icon(srna, ICON_RENDERLAYERS);
|
||||
|
||||
prop = RNA_def_property(srna, "precision", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "precision");
|
||||
RNA_def_property_enum_items(prop, rna_enum_precision_items);
|
||||
RNA_def_property_ui_text(prop, "Precision", "The precision of compositor intermediate result");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_NodeTree_update");
|
||||
|
||||
prop = RNA_def_property(srna, "execution_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "execution_mode");
|
||||
RNA_def_property_enum_items(prop, rna_enum_execution_mode_items);
|
||||
|
||||
@@ -69,7 +69,7 @@ class BilateralBlurOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_bilateral_blur");
|
||||
GPUShader *shader = context().get_shader("compositor_bilateral_blur");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "radius", get_blur_radius());
|
||||
|
||||
@@ -126,7 +126,7 @@ class BlurOperation : public NodeOperation {
|
||||
|
||||
void execute_constant_size()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_symmetric_blur");
|
||||
GPUShader *shader = context().get_shader("compositor_symmetric_blur");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
|
||||
@@ -138,7 +138,7 @@ class BlurOperation : public NodeOperation {
|
||||
const float2 blur_radius = compute_blur_radius();
|
||||
|
||||
const SymmetricBlurWeights &weights = context().cache_manager().symmetric_blur_weights.get(
|
||||
node_storage(bnode()).filtertype, blur_radius);
|
||||
context(), node_storage(bnode()).filtertype, blur_radius);
|
||||
weights.bind_as_texture(shader, "weights_tx");
|
||||
|
||||
Domain domain = compute_domain();
|
||||
@@ -161,7 +161,7 @@ class BlurOperation : public NodeOperation {
|
||||
|
||||
void execute_variable_size()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_symmetric_blur_variable_size");
|
||||
GPUShader *shader = context().get_shader("compositor_symmetric_blur_variable_size");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "extend_bounds", get_extend_bounds());
|
||||
@@ -173,7 +173,7 @@ class BlurOperation : public NodeOperation {
|
||||
const float2 blur_radius = compute_blur_radius();
|
||||
|
||||
const SymmetricBlurWeights &weights = context().cache_manager().symmetric_blur_weights.get(
|
||||
node_storage(bnode()).filtertype, blur_radius);
|
||||
context(), node_storage(bnode()).filtertype, blur_radius);
|
||||
weights.bind_as_texture(shader, "weights_tx");
|
||||
|
||||
const Result &input_size = get_input("Size");
|
||||
|
||||
@@ -81,7 +81,7 @@ class BokehBlurOperation : public NodeOperation {
|
||||
|
||||
void execute_constant_size()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_blur");
|
||||
GPUShader *shader = context().get_shader("compositor_blur");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "radius", int(compute_blur_radius()));
|
||||
@@ -117,7 +117,7 @@ class BokehBlurOperation : public NodeOperation {
|
||||
|
||||
void execute_variable_size()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_blur_variable_size");
|
||||
GPUShader *shader = context().get_shader("compositor_blur_variable_size");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "base_size", compute_blur_radius());
|
||||
|
||||
@@ -64,7 +64,7 @@ class BokehImageOperation : public NodeOperation {
|
||||
|
||||
void execute() override
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_bokeh_image");
|
||||
GPUShader *shader = context().get_shader("compositor_bokeh_image");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "exterior_angle", get_exterior_angle());
|
||||
|
||||
@@ -76,7 +76,7 @@ class BoxMaskOperation : public NodeOperation {
|
||||
|
||||
void execute() override
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(get_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
|
||||
@@ -81,7 +81,8 @@ class CompositeOperation : public NodeOperation {
|
||||
/* Executes when the alpha channel of the image is ignored. */
|
||||
void execute_ignore_alpha()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_write_output_opaque");
|
||||
GPUShader *shader = context().get_shader("compositor_write_output_opaque",
|
||||
ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a subset of the output texture, so only write into
|
||||
@@ -109,7 +110,7 @@ class CompositeOperation : public NodeOperation {
|
||||
* to the output texture. */
|
||||
void execute_copy()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_write_output");
|
||||
GPUShader *shader = context().get_shader("compositor_write_output", ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a subset of the output texture, so only write into
|
||||
@@ -136,7 +137,8 @@ class CompositeOperation : public NodeOperation {
|
||||
/* Executes when the alpha channel of the image is set as the value of the input alpha. */
|
||||
void execute_set_alpha()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_write_output_alpha");
|
||||
GPUShader *shader = context().get_shader("compositor_write_output_alpha",
|
||||
ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a subset of the output texture, so only write into
|
||||
|
||||
@@ -84,7 +84,8 @@ class ConvertColorSpaceOperation : public NodeOperation {
|
||||
const char *target = node_storage(bnode()).to_color_space;
|
||||
|
||||
OCIOColorSpaceConversionShader &ocio_shader =
|
||||
context().cache_manager().ocio_color_space_conversion_shaders.get(source, target);
|
||||
context().cache_manager().ocio_color_space_conversion_shaders.get(
|
||||
context(), source, target);
|
||||
|
||||
GPUShader *shader = ocio_shader.bind_shader_and_resources();
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ class CornerPinOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_plane_deform");
|
||||
GPUShader *shader = context().get_shader("compositor_plane_deform");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_mat3_as_mat4(shader, "homography_matrix", homography_matrix.ptr());
|
||||
|
||||
@@ -96,7 +96,7 @@ class CropOperation : public NodeOperation {
|
||||
* same domain as the input image. */
|
||||
void execute_alpha_crop()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_alpha_crop");
|
||||
GPUShader *shader = context().get_shader("compositor_alpha_crop");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
int2 lower_bound, upper_bound;
|
||||
@@ -133,7 +133,7 @@ class CropOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_image_crop");
|
||||
GPUShader *shader = context().get_shader("compositor_image_crop");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_2iv(shader, "lower_bound", lower_bound);
|
||||
|
||||
@@ -64,7 +64,7 @@ class DespeckleOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_despeckle");
|
||||
GPUShader *shader = context().get_shader("compositor_despeckle");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "threshold", get_threshold());
|
||||
|
||||
@@ -104,7 +104,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
|
||||
Result execute_step_horizontal_pass()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(get_morphological_step_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_morphological_step_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Pass the absolute value of the distance. We have specialized shaders for each sign. */
|
||||
@@ -124,7 +124,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
const Domain domain = compute_domain();
|
||||
const int2 transposed_domain = int2(domain.size.y, domain.size.x);
|
||||
|
||||
Result horizontal_pass_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result horizontal_pass_result = context().create_temporary_result(ResultType::Color);
|
||||
horizontal_pass_result.allocate_texture(transposed_domain);
|
||||
horizontal_pass_result.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -139,7 +139,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
|
||||
void execute_step_vertical_pass(Result &horizontal_pass_result)
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(get_morphological_step_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_morphological_step_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Pass the absolute value of the distance. We have specialized shaders for each sign. */
|
||||
@@ -184,7 +184,7 @@ class DilateErodeOperation : public NodeOperation {
|
||||
|
||||
void execute_distance_threshold()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_morphological_distance_threshold");
|
||||
GPUShader *shader = context().get_shader("compositor_morphological_distance_threshold");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "inset", get_inset());
|
||||
|
||||
@@ -76,7 +76,7 @@ class DirectionalBlurOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_directional_blur");
|
||||
GPUShader *shader = context().get_shader("compositor_directional_blur");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The number of iterations does not cover the original image, that is, the image with no
|
||||
|
||||
@@ -57,7 +57,7 @@ class DisplaceOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_displace");
|
||||
GPUShader *shader = context().get_shader("compositor_displace");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Result &input_image = get_input("Image");
|
||||
|
||||
@@ -66,14 +66,18 @@ class DoubleEdgeMaskOperation : public NodeOperation {
|
||||
|
||||
/* Compute an image that marks the boundary pixels of the masks as seed pixels in the format
|
||||
* expected by the jump flooding algorithm. */
|
||||
Result inner_boundary = Result::Temporary(ResultType::Int2, texture_pool());
|
||||
Result outer_boundary = Result::Temporary(ResultType::Int2, texture_pool());
|
||||
Result inner_boundary = context().create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
Result outer_boundary = context().create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
compute_boundary(inner_boundary, outer_boundary);
|
||||
|
||||
/* Compute a jump flooding table for each mask boundary to get a distance transform to each of
|
||||
* the boundaries. */
|
||||
Result flooded_inner_boundary = Result::Temporary(ResultType::Int2, texture_pool());
|
||||
Result flooded_outer_boundary = Result::Temporary(ResultType::Int2, texture_pool());
|
||||
Result flooded_inner_boundary = context().create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
Result flooded_outer_boundary = context().create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
jump_flooding(context(), inner_boundary, flooded_inner_boundary);
|
||||
jump_flooding(context(), outer_boundary, flooded_outer_boundary);
|
||||
inner_boundary.release();
|
||||
@@ -87,7 +91,8 @@ class DoubleEdgeMaskOperation : public NodeOperation {
|
||||
|
||||
void compute_boundary(Result &inner_boundary, Result &outer_boundary)
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_double_edge_mask_compute_boundary");
|
||||
GPUShader *shader = context().get_shader("compositor_double_edge_mask_compute_boundary",
|
||||
ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "include_all_inner_edges", include_all_inner_edges());
|
||||
@@ -118,7 +123,7 @@ class DoubleEdgeMaskOperation : public NodeOperation {
|
||||
|
||||
void compute_gradient(Result &flooded_inner_boundary, Result &flooded_outer_boundary)
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_double_edge_mask_compute_gradient");
|
||||
GPUShader *shader = context().get_shader("compositor_double_edge_mask_compute_gradient");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Result &inner_mask = get_input("Inner Mask");
|
||||
|
||||
@@ -74,7 +74,7 @@ class EllipseMaskOperation : public NodeOperation {
|
||||
|
||||
void execute() override
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(get_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
|
||||
@@ -47,7 +47,7 @@ class FilterOperation : public NodeOperation {
|
||||
|
||||
void execute() override
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(get_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_mat3_as_mat4(shader, "ukernel", get_filter_kernel().ptr());
|
||||
|
||||
@@ -54,7 +54,7 @@ class FlipOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_flip");
|
||||
GPUShader *shader = context().get_shader("compositor_flip");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(
|
||||
|
||||
@@ -150,7 +150,7 @@ class GlareOperation : public NodeOperation {
|
||||
return execute_ghost(highlights_result);
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
return Result(ResultType::Color, texture_pool());
|
||||
return context().create_temporary_result(ResultType::Color);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ class GlareOperation : public NodeOperation {
|
||||
|
||||
Result execute_highlights()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_highlights");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_highlights");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
float luminance_coefficients[3];
|
||||
@@ -173,7 +173,7 @@ class GlareOperation : public NodeOperation {
|
||||
GPU_texture_filter_mode(input_image.texture(), true);
|
||||
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result highlights_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result highlights_result = context().create_temporary_result(ResultType::Color);
|
||||
highlights_result.allocate_texture(glare_size);
|
||||
highlights_result.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -208,7 +208,7 @@ class GlareOperation : public NodeOperation {
|
||||
* so just use it as the pass result. */
|
||||
Result &vertical_pass_result = highlights_result;
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_simple_star_vertical_pass");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_simple_star_vertical_pass");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "iterations", get_number_of_iterations());
|
||||
@@ -236,12 +236,12 @@ class GlareOperation : public NodeOperation {
|
||||
/* The horizontal pass is applied in-plane, so copy the highlights to a new image since the
|
||||
* highlights result is still needed by the vertical pass. */
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result horizontal_pass_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result horizontal_pass_result = context().create_temporary_result(ResultType::Color);
|
||||
horizontal_pass_result.allocate_texture(glare_size);
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
GPU_texture_copy(horizontal_pass_result.texture(), highlights_result.texture());
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_simple_star_horizontal_pass");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_simple_star_horizontal_pass");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "iterations", get_number_of_iterations());
|
||||
@@ -266,7 +266,7 @@ class GlareOperation : public NodeOperation {
|
||||
* so just use it as the pass result. */
|
||||
Result &anti_diagonal_pass_result = highlights_result;
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_simple_star_anti_diagonal_pass");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_simple_star_anti_diagonal_pass");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "iterations", get_number_of_iterations());
|
||||
@@ -293,12 +293,12 @@ class GlareOperation : public NodeOperation {
|
||||
/* The diagonal pass is applied in-plane, so copy the highlights to a new image since the
|
||||
* highlights result is still needed by the anti-diagonal pass. */
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result diagonal_pass_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result diagonal_pass_result = context().create_temporary_result(ResultType::Color);
|
||||
diagonal_pass_result.allocate_texture(glare_size);
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
GPU_texture_copy(diagonal_pass_result.texture(), highlights_result.texture());
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_simple_star_diagonal_pass");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_simple_star_diagonal_pass");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "iterations", get_number_of_iterations());
|
||||
@@ -334,7 +334,7 @@ class GlareOperation : public NodeOperation {
|
||||
/* Create an initially zero image where streaks will be accumulated. */
|
||||
const float4 zero_color = float4(0.0f);
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result accumulated_streaks_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result accumulated_streaks_result = context().create_temporary_result(ResultType::Color);
|
||||
accumulated_streaks_result.allocate_texture(glare_size);
|
||||
GPU_texture_clear(accumulated_streaks_result.texture(), GPU_DATA_FLOAT, zero_color);
|
||||
|
||||
@@ -344,7 +344,7 @@ class GlareOperation : public NodeOperation {
|
||||
const float2 streak_direction = compute_streak_direction(streak_index);
|
||||
Result streak_result = apply_streak_filter(highlights_result, streak_direction);
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_streaks_accumulate");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_streaks_accumulate");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const float attenuation_factor = compute_streak_attenuation_factor();
|
||||
@@ -367,18 +367,18 @@ class GlareOperation : public NodeOperation {
|
||||
|
||||
Result apply_streak_filter(Result &highlights_result, const float2 &streak_direction)
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_streaks_filter");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_streaks_filter");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Copy the highlights result into a new image because the output will be copied to the input
|
||||
* after each iteration and the highlights result is still needed to compute other streaks. */
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result input_streak_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result input_streak_result = context().create_temporary_result(ResultType::Color);
|
||||
input_streak_result.allocate_texture(glare_size);
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
GPU_texture_copy(input_streak_result.texture(), highlights_result.texture());
|
||||
|
||||
Result output_streak_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result output_streak_result = context().create_temporary_result(ResultType::Color);
|
||||
output_streak_result.allocate_texture(glare_size);
|
||||
|
||||
/* For the given number of iterations, apply the streak filter in the given direction. The
|
||||
@@ -504,7 +504,7 @@ class GlareOperation : public NodeOperation {
|
||||
{
|
||||
Result base_ghost_result = compute_base_ghost(highlights_result);
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_ghost_accumulate");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_ghost_accumulate");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* Color modulators are constant across iterations. */
|
||||
@@ -517,7 +517,7 @@ class GlareOperation : public NodeOperation {
|
||||
/* Create an initially zero image where ghosts will be accumulated. */
|
||||
const float4 zero_color = float4(0.0f);
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result accumulated_ghosts_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result accumulated_ghosts_result = context().create_temporary_result(ResultType::Color);
|
||||
accumulated_ghosts_result.allocate_texture(glare_size);
|
||||
GPU_texture_clear(accumulated_ghosts_result.texture(), GPU_DATA_FLOAT, zero_color);
|
||||
|
||||
@@ -559,7 +559,7 @@ class GlareOperation : public NodeOperation {
|
||||
* the center of the image. */
|
||||
Result compute_base_ghost(Result &highlights_result)
|
||||
{
|
||||
Result small_ghost_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result small_ghost_result = context().create_temporary_result(ResultType::Color);
|
||||
symmetric_separable_blur(context(),
|
||||
highlights_result,
|
||||
small_ghost_result,
|
||||
@@ -568,7 +568,7 @@ class GlareOperation : public NodeOperation {
|
||||
false,
|
||||
false);
|
||||
|
||||
Result big_ghost_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result big_ghost_result = context().create_temporary_result(ResultType::Color);
|
||||
symmetric_separable_blur(context(),
|
||||
highlights_result,
|
||||
big_ghost_result,
|
||||
@@ -579,7 +579,7 @@ class GlareOperation : public NodeOperation {
|
||||
|
||||
highlights_result.release();
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_ghost_base");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_ghost_base");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
small_ghost_result.bind_as_texture(shader, "small_ghost_tx");
|
||||
@@ -591,7 +591,7 @@ class GlareOperation : public NodeOperation {
|
||||
GPU_texture_extend_mode(big_ghost_result.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
|
||||
const int2 glare_size = get_glare_size();
|
||||
Result base_ghost_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result base_ghost_result = context().create_temporary_result(ResultType::Color);
|
||||
base_ghost_result.allocate_texture(glare_size);
|
||||
base_ghost_result.bind_as_image(shader, "combined_ghost_img");
|
||||
|
||||
@@ -732,7 +732,7 @@ class GlareOperation : public NodeOperation {
|
||||
|
||||
/* Notice that for a chain length of n, we need (n - 1) up-sampling passes. */
|
||||
const IndexRange upsample_passes_range(chain_length - 1);
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_fog_glow_upsample");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_fog_glow_upsample");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
for (const int i : upsample_passes_range) {
|
||||
@@ -763,7 +763,7 @@ class GlareOperation : public NodeOperation {
|
||||
* one pixel. */
|
||||
Array<Result> compute_fog_glow_downsample_chain(Result &highlights_result, int chain_length)
|
||||
{
|
||||
const Result downsampled_result = Result::Temporary(ResultType::Color, texture_pool());
|
||||
const Result downsampled_result = context().create_temporary_result(ResultType::Color);
|
||||
Array<Result> downsample_chain(chain_length, downsampled_result);
|
||||
|
||||
/* We assign the original highlights result to the first result of the chain to make the code
|
||||
@@ -779,11 +779,11 @@ class GlareOperation : public NodeOperation {
|
||||
* more information. Later passes use a simple average down-sampling filter because fireflies
|
||||
* doesn't service the first pass. */
|
||||
if (i == downsample_passes_range.first()) {
|
||||
shader = shader_manager().get("compositor_glare_fog_glow_downsample_karis_average");
|
||||
shader = context().get_shader("compositor_glare_fog_glow_downsample_karis_average");
|
||||
GPU_shader_bind(shader);
|
||||
}
|
||||
else {
|
||||
shader = shader_manager().get("compositor_glare_fog_glow_downsample_simple_average");
|
||||
shader = context().get_shader("compositor_glare_fog_glow_downsample_simple_average");
|
||||
GPU_shader_bind(shader);
|
||||
}
|
||||
|
||||
@@ -826,7 +826,7 @@ class GlareOperation : public NodeOperation {
|
||||
|
||||
void execute_mix(Result &glare_result)
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_glare_mix");
|
||||
GPUShader *shader = context().get_shader("compositor_glare_mix");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "mix_factor", node_storage(bnode()).mix);
|
||||
|
||||
@@ -53,7 +53,7 @@ class IDMaskOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_id_mask");
|
||||
GPUShader *shader = context().get_shader("compositor_id_mask");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "index", get_index());
|
||||
@@ -62,7 +62,7 @@ class IDMaskOperation : public NodeOperation {
|
||||
|
||||
/* If anti-aliasing is disabled, write to the output directly, otherwise, write to a temporary
|
||||
* result to later perform anti-aliasing. */
|
||||
Result non_anti_aliased_mask = Result::Temporary(ResultType::Float, texture_pool());
|
||||
Result non_anti_aliased_mask = context().create_temporary_result(ResultType::Float);
|
||||
Result &output_mask = use_anti_aliasing() ? non_anti_aliased_mask : get_result("Alpha");
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
|
||||
@@ -514,7 +514,7 @@ class ImageOperation : public NodeOperation {
|
||||
Result &result = get_result(identifier);
|
||||
result.allocate_texture(Domain(size));
|
||||
|
||||
GPUShader *shader = shader_manager().get(get_shader_name(identifier));
|
||||
GPUShader *shader = context().get_shader(get_shader_name(identifier));
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const int2 lower_bound = int2(0);
|
||||
@@ -905,7 +905,7 @@ class RenderLayerOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get(shader_name);
|
||||
GPUShader *shader = context().get_shader(shader_name);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a subset of the pass texture, so only read that
|
||||
|
||||
@@ -56,7 +56,8 @@ class InpaintOperation : public NodeOperation {
|
||||
Result inpainting_boundary = compute_inpainting_boundary();
|
||||
|
||||
/* Compute a jump flooding table to get the closest boundary pixel to each pixel. */
|
||||
Result flooded_boundary = Result::Temporary(ResultType::Int2, texture_pool());
|
||||
Result flooded_boundary = context().create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
jump_flooding(context(), inpainting_boundary, flooded_boundary);
|
||||
inpainting_boundary.release();
|
||||
|
||||
@@ -67,13 +68,15 @@ class InpaintOperation : public NodeOperation {
|
||||
|
||||
Result compute_inpainting_boundary()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_inpaint_compute_boundary");
|
||||
GPUShader *shader = context().get_shader("compositor_inpaint_compute_boundary",
|
||||
ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Result &input = get_input("Image");
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
Result inpainting_boundary = Result::Temporary(ResultType::Int2, texture_pool());
|
||||
Result inpainting_boundary = context().create_temporary_result(ResultType::Int2,
|
||||
ResultPrecision::Half);
|
||||
const Domain domain = compute_domain();
|
||||
inpainting_boundary.allocate_texture(domain);
|
||||
inpainting_boundary.bind_as_image(shader, "boundary_img");
|
||||
@@ -89,7 +92,7 @@ class InpaintOperation : public NodeOperation {
|
||||
|
||||
void compute_inpainting_region(Result &flooded_boundary)
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_inpaint_compute_region");
|
||||
GPUShader *shader = context().get_shader("compositor_inpaint_compute_region");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "max_distance", get_distance());
|
||||
@@ -103,7 +106,8 @@ class InpaintOperation : public NodeOperation {
|
||||
* inpainting boundary. So the maximum possible blur radius is the user supplied distance. */
|
||||
const float max_radius = float(get_distance());
|
||||
const SymmetricSeparableBlurWeights &gaussian_weights =
|
||||
context().cache_manager().symmetric_separable_blur_weights.get(R_FILTER_GAUSS, max_radius);
|
||||
context().cache_manager().symmetric_separable_blur_weights.get(
|
||||
context(), R_FILTER_GAUSS, max_radius);
|
||||
gaussian_weights.bind_as_texture(shader, "gaussian_weights_tx");
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
|
||||
@@ -135,7 +135,7 @@ class KeyingOperation : public NodeOperation {
|
||||
|
||||
Result chroma = extract_input_chroma();
|
||||
|
||||
Result blurred_chroma = Result::Temporary(ResultType::Color, context().texture_pool());
|
||||
Result blurred_chroma = context().create_temporary_result(ResultType::Color);
|
||||
symmetric_separable_blur(context(), chroma, blurred_chroma, float2(blur_size), R_FILTER_BOX);
|
||||
chroma.release();
|
||||
|
||||
@@ -147,13 +147,13 @@ class KeyingOperation : public NodeOperation {
|
||||
|
||||
Result extract_input_chroma()
|
||||
{
|
||||
GPUShader *shader = context().shader_manager().get("compositor_keying_extract_chroma");
|
||||
GPUShader *shader = context().get_shader("compositor_keying_extract_chroma");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
Result &input = get_input("Image");
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
Result output = Result::Temporary(ResultType::Color, context().texture_pool());
|
||||
Result output = context().create_temporary_result(ResultType::Color);
|
||||
output.allocate_texture(input.domain());
|
||||
output.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -168,7 +168,7 @@ class KeyingOperation : public NodeOperation {
|
||||
|
||||
Result replace_input_chroma(Result &new_chroma)
|
||||
{
|
||||
GPUShader *shader = context().shader_manager().get("compositor_keying_replace_chroma");
|
||||
GPUShader *shader = context().get_shader("compositor_keying_replace_chroma");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
Result &input = get_input("Image");
|
||||
@@ -176,7 +176,7 @@ class KeyingOperation : public NodeOperation {
|
||||
|
||||
new_chroma.bind_as_texture(shader, "new_chroma_tx");
|
||||
|
||||
Result output = Result::Temporary(ResultType::Color, context().texture_pool());
|
||||
Result output = context().create_temporary_result(ResultType::Color);
|
||||
output.allocate_texture(input.domain());
|
||||
output.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -192,7 +192,7 @@ class KeyingOperation : public NodeOperation {
|
||||
|
||||
Result compute_matte(Result &input)
|
||||
{
|
||||
GPUShader *shader = context().shader_manager().get("compositor_keying_compute_matte");
|
||||
GPUShader *shader = context().get_shader("compositor_keying_compute_matte");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "key_balance", node_storage(bnode()).screen_balance);
|
||||
@@ -202,7 +202,7 @@ class KeyingOperation : public NodeOperation {
|
||||
Result &key_color = get_input("Key Color");
|
||||
key_color.bind_as_texture(shader, "key_tx");
|
||||
|
||||
Result output = Result::Temporary(ResultType::Float, context().texture_pool());
|
||||
Result output = context().create_temporary_result(ResultType::Float);
|
||||
output.allocate_texture(input.domain());
|
||||
output.bind_as_image(shader, "output_img");
|
||||
|
||||
@@ -238,7 +238,7 @@ class KeyingOperation : public NodeOperation {
|
||||
return output_matte;
|
||||
}
|
||||
|
||||
GPUShader *shader = context().shader_manager().get("compositor_keying_tweak_matte");
|
||||
GPUShader *shader = context().get_shader("compositor_keying_tweak_matte");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "compute_edges", output_edges.should_compute());
|
||||
@@ -257,7 +257,7 @@ class KeyingOperation : public NodeOperation {
|
||||
Result &core_matte = get_input("Core Matte");
|
||||
core_matte.bind_as_texture(shader, "core_matte_tx");
|
||||
|
||||
Result output_matte = Result::Temporary(ResultType::Float, context().texture_pool());
|
||||
Result output_matte = context().create_temporary_result(ResultType::Float);
|
||||
output_matte.allocate_texture(input_matte.domain());
|
||||
output_matte.bind_as_image(shader, "output_matte_img");
|
||||
|
||||
@@ -288,7 +288,7 @@ class KeyingOperation : public NodeOperation {
|
||||
return output_matte;
|
||||
}
|
||||
|
||||
Result blurred_matte = Result::Temporary(ResultType::Float, context().texture_pool());
|
||||
Result blurred_matte = context().create_temporary_result(ResultType::Float);
|
||||
symmetric_separable_blur(context(), input_matte, blurred_matte, float2(blur_size));
|
||||
|
||||
return blurred_matte;
|
||||
@@ -306,7 +306,7 @@ class KeyingOperation : public NodeOperation {
|
||||
return output_matte;
|
||||
}
|
||||
|
||||
Result morphed_matte = Result::Temporary(ResultType::Float, context().texture_pool());
|
||||
Result morphed_matte = context().create_temporary_result(ResultType::Float);
|
||||
morphological_distance(context(), input_matte, morphed_matte, distance);
|
||||
|
||||
return morphed_matte;
|
||||
@@ -324,7 +324,7 @@ class KeyingOperation : public NodeOperation {
|
||||
return output_matte;
|
||||
}
|
||||
|
||||
Result feathered_matte = Result::Temporary(ResultType::Float, context().texture_pool());
|
||||
Result feathered_matte = context().create_temporary_result(ResultType::Float);
|
||||
morphological_distance_feather(
|
||||
context(), input_matte, feathered_matte, distance, node_storage(bnode()).feather_falloff);
|
||||
|
||||
@@ -333,7 +333,7 @@ class KeyingOperation : public NodeOperation {
|
||||
|
||||
void compute_image(Result &matte)
|
||||
{
|
||||
GPUShader *shader = context().shader_manager().get("compositor_keying_compute_image");
|
||||
GPUShader *shader = context().get_shader("compositor_keying_compute_image");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "despill_factor", node_storage(bnode()).despill_factor);
|
||||
|
||||
@@ -95,7 +95,7 @@ class ConvertKuwaharaOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get(get_classic_convolution_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_classic_convolution_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Result &input_image = get_input("Image");
|
||||
@@ -122,15 +122,15 @@ class ConvertKuwaharaOperation : public NodeOperation {
|
||||
|
||||
void execute_classic_summed_area_table()
|
||||
{
|
||||
Result table = Result::Temporary(ResultType::Color, texture_pool(), ResultPrecision::Full);
|
||||
Result table = context().create_temporary_result(ResultType::Color, ResultPrecision::Full);
|
||||
summed_area_table(context(), get_input("Image"), table);
|
||||
|
||||
Result squared_table = Result::Temporary(
|
||||
ResultType::Color, texture_pool(), ResultPrecision::Full);
|
||||
Result squared_table = context().create_temporary_result(ResultType::Color,
|
||||
ResultPrecision::Full);
|
||||
summed_area_table(
|
||||
context(), get_input("Image"), squared_table, SummedAreaTableOperation::Square);
|
||||
|
||||
GPUShader *shader = shader_manager().get(get_classic_summed_area_table_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_classic_summed_area_table_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
Result &size_input = get_input("Size");
|
||||
@@ -168,14 +168,14 @@ class ConvertKuwaharaOperation : public NodeOperation {
|
||||
void execute_anisotropic()
|
||||
{
|
||||
Result structure_tensor = compute_structure_tensor();
|
||||
Result smoothed_structure_tensor = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result smoothed_structure_tensor = context().create_temporary_result(ResultType::Color);
|
||||
symmetric_separable_blur(context(),
|
||||
structure_tensor,
|
||||
smoothed_structure_tensor,
|
||||
float2(node_storage(bnode()).uniformity));
|
||||
structure_tensor.release();
|
||||
|
||||
GPUShader *shader = shader_manager().get(get_anisotropic_shader_name());
|
||||
GPUShader *shader = context().get_shader(get_anisotropic_shader_name());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "eccentricity", get_eccentricity());
|
||||
@@ -211,7 +211,7 @@ class ConvertKuwaharaOperation : public NodeOperation {
|
||||
|
||||
Result compute_structure_tensor()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(
|
||||
GPUShader *shader = context().get_shader(
|
||||
"compositor_kuwahara_anisotropic_compute_structure_tensor");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
@@ -219,7 +219,7 @@ class ConvertKuwaharaOperation : public NodeOperation {
|
||||
input.bind_as_texture(shader, "input_tx");
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
Result structure_tensor = Result::Temporary(ResultType::Color, texture_pool());
|
||||
Result structure_tensor = context().create_temporary_result(ResultType::Color);
|
||||
structure_tensor.allocate_texture(domain);
|
||||
structure_tensor.bind_as_image(shader, "structure_tensor_img");
|
||||
|
||||
|
||||
@@ -96,7 +96,7 @@ class LensDistortionOperation : public NodeOperation {
|
||||
|
||||
void execute_projector_distortion()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_projector_lens_distortion");
|
||||
GPUShader *shader = context().get_shader("compositor_projector_lens_distortion");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Result &input_image = get_input("Image");
|
||||
@@ -123,7 +123,7 @@ class LensDistortionOperation : public NodeOperation {
|
||||
|
||||
void execute_screen_distortion()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get(get_screen_distortion_shader());
|
||||
GPUShader *shader = context().get_shader(get_screen_distortion_shader());
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const Result &input_image = get_input("Image");
|
||||
|
||||
@@ -52,7 +52,7 @@ class MapUVOperation : public NodeOperation {
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_map_uv");
|
||||
GPUShader *shader = context().get_shader("compositor_map_uv");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(
|
||||
|
||||
@@ -126,7 +126,7 @@ class MovieClipOperation : public NodeOperation {
|
||||
GPU_texture_height(movie_clip_texture));
|
||||
result.allocate_texture(Domain(size));
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_read_input_color");
|
||||
GPUShader *shader = context().get_shader("compositor_read_input_color");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const int2 lower_bound = int2(0);
|
||||
@@ -163,7 +163,7 @@ class MovieClipOperation : public NodeOperation {
|
||||
GPU_texture_height(movie_clip_texture));
|
||||
result.allocate_texture(Domain(size));
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_read_input_alpha");
|
||||
GPUShader *shader = context().get_shader("compositor_read_input_alpha");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
const int2 lower_bound = int2(0);
|
||||
|
||||
@@ -112,9 +112,13 @@ class MovieDistortionOperation : public NodeOperation {
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
const DistortionGrid &distortion_grid = context().cache_manager().distortion_grids.get(
|
||||
get_movie_clip(), domain.size, get_distortion_type(), context().get_frame_number());
|
||||
context(),
|
||||
get_movie_clip(),
|
||||
domain.size,
|
||||
get_distortion_type(),
|
||||
context().get_frame_number());
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_movie_distortion");
|
||||
GPUShader *shader = context().get_shader("compositor_movie_distortion");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_texture_extend_mode(input_image.texture(), GPU_SAMPLER_EXTEND_MODE_CLAMP_TO_BORDER);
|
||||
|
||||
@@ -55,7 +55,7 @@ class NormalizeOperation : public NodeOperation {
|
||||
context(), input_image.texture(), -range_, range_);
|
||||
const float scale = (maximum != minimum) ? (1.0f / (maximum - minimum)) : 0.0f;
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_normalize");
|
||||
GPUShader *shader = context().get_shader("compositor_normalize");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "minimum", minimum);
|
||||
|
||||
@@ -145,7 +145,7 @@ class PlaneTrackDeformOperation : public NodeOperation {
|
||||
|
||||
const Array<float4x4> homography_matrices = compute_homography_matrices(plane_track);
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_plane_deform_motion_blur");
|
||||
GPUShader *shader = context().get_shader("compositor_plane_deform_motion_blur");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1i(shader, "number_of_motion_blur_samples", homography_matrices.size());
|
||||
|
||||
@@ -106,10 +106,10 @@ class ViewerOperation : public NodeOperation {
|
||||
GPUShader *get_split_viewer_shader()
|
||||
{
|
||||
if (get_split_axis() == CMP_NODE_SPLIT_VIEWER_HORIZONTAL) {
|
||||
return shader_manager().get("compositor_split_viewer_horizontal");
|
||||
return context().get_shader("compositor_split_viewer_horizontal", ResultPrecision::Half);
|
||||
}
|
||||
|
||||
return shader_manager().get("compositor_split_viewer_vertical");
|
||||
return context().get_shader("compositor_split_viewer_vertical", ResultPrecision::Half);
|
||||
}
|
||||
|
||||
CMPNodeSplitViewerAxis get_split_axis()
|
||||
|
||||
@@ -56,7 +56,7 @@ class SunBeamsOperation : public NodeOperation {
|
||||
|
||||
void execute() override
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_sun_beams");
|
||||
GPUShader *shader = context().get_shader("compositor_sun_beams");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_2fv(shader, "source", node_storage(bnode()).source);
|
||||
|
||||
@@ -114,7 +114,7 @@ class ToneMapOperation : public NodeOperation {
|
||||
const float gamma = node_storage(bnode()).gamma;
|
||||
const float inverse_gamma = gamma != 0.0f ? 1.0f / gamma : 0.0f;
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_tone_map_simple");
|
||||
GPUShader *shader = context().get_shader("compositor_tone_map_simple");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1f(shader, "luminance_scale", luminance_scale);
|
||||
@@ -175,7 +175,7 @@ class ToneMapOperation : public NodeOperation {
|
||||
const float chromatic_adaptation = get_chromatic_adaptation();
|
||||
const float light_adaptation = get_light_adaptation();
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_tone_map_photoreceptor");
|
||||
GPUShader *shader = context().get_shader("compositor_tone_map_photoreceptor");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_4fv(shader, "global_adaptation_level", global_adaptation_level);
|
||||
|
||||
@@ -111,7 +111,8 @@ class ViewerOperation : public NodeOperation {
|
||||
/* Executes when the alpha channel of the image is ignored. */
|
||||
void execute_ignore_alpha()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_write_output_opaque");
|
||||
GPUShader *shader = context().get_shader("compositor_write_output_opaque",
|
||||
ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a smaller region of the output texture, so only
|
||||
@@ -139,7 +140,7 @@ class ViewerOperation : public NodeOperation {
|
||||
* to the output texture. */
|
||||
void execute_copy()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_write_output");
|
||||
GPUShader *shader = context().get_shader("compositor_write_output", ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a smaller region of the output texture, so only
|
||||
@@ -166,7 +167,8 @@ class ViewerOperation : public NodeOperation {
|
||||
/* Executes when the alpha channel of the image is set as the value of the input alpha. */
|
||||
void execute_set_alpha()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_write_output_alpha");
|
||||
GPUShader *shader = context().get_shader("compositor_write_output_alpha",
|
||||
ResultPrecision::Half);
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
/* The compositing space might be limited to a smaller region of the output texture, so only
|
||||
|
||||
@@ -111,7 +111,7 @@ class ZCombineOperation : public NodeOperation {
|
||||
|
||||
void execute_simple()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_z_combine_simple");
|
||||
GPUShader *shader = context().get_shader("compositor_z_combine_simple");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "use_alpha", use_alpha());
|
||||
@@ -149,7 +149,7 @@ class ZCombineOperation : public NodeOperation {
|
||||
{
|
||||
Result mask = compute_mask();
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_z_combine_from_mask");
|
||||
GPUShader *shader = context().get_shader("compositor_z_combine_from_mask");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "use_alpha", use_alpha());
|
||||
@@ -189,7 +189,7 @@ class ZCombineOperation : public NodeOperation {
|
||||
|
||||
Result compute_mask()
|
||||
{
|
||||
GPUShader *shader = shader_manager().get("compositor_z_combine_compute_mask");
|
||||
GPUShader *shader = context().get_shader("compositor_z_combine_compute_mask");
|
||||
GPU_shader_bind(shader);
|
||||
|
||||
GPU_shader_uniform_1b(shader, "use_alpha", use_alpha());
|
||||
@@ -202,7 +202,7 @@ class ZCombineOperation : public NodeOperation {
|
||||
second_z.bind_as_texture(shader, "second_z_tx");
|
||||
|
||||
const Domain domain = compute_domain();
|
||||
Result mask = Result::Temporary(ResultType::Float, texture_pool());
|
||||
Result mask = context().create_temporary_result(ResultType::Float);
|
||||
mask.allocate_texture(domain);
|
||||
mask.bind_as_image(shader, "mask_img");
|
||||
|
||||
@@ -214,7 +214,7 @@ class ZCombineOperation : public NodeOperation {
|
||||
mask.unbind_as_image();
|
||||
GPU_shader_unbind();
|
||||
|
||||
Result anti_aliased_mask = Result::Temporary(ResultType::Float, texture_pool());
|
||||
Result anti_aliased_mask = context().create_temporary_result(ResultType::Float);
|
||||
smaa(context(), mask, anti_aliased_mask);
|
||||
mask.release();
|
||||
|
||||
|
||||
@@ -216,13 +216,15 @@ class Context : public realtime_compositor::Context {
|
||||
* once that supports GPU buffers. */
|
||||
if (output_texture_ == nullptr) {
|
||||
const int2 size = get_render_size();
|
||||
output_texture_ = GPU_texture_create_2d("compositor_output_texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
GPU_RGBA16F,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
output_texture_ = GPU_texture_create_2d(
|
||||
"compositor_output_texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
get_precision() == realtime_compositor::ResultPrecision::Half ? GPU_RGBA16F :
|
||||
GPU_RGBA32F,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
return output_texture_;
|
||||
@@ -244,13 +246,15 @@ class Context : public realtime_compositor::Context {
|
||||
/* TODO: just a temporary hack, needs to get stored in RenderResult,
|
||||
* once that supports GPU buffers. */
|
||||
if (viewer_output_texture_ == nullptr) {
|
||||
viewer_output_texture_ = GPU_texture_create_2d("compositor_viewer_output_texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
GPU_RGBA16F,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
viewer_output_texture_ = GPU_texture_create_2d(
|
||||
"compositor_viewer_output_texture",
|
||||
size.x,
|
||||
size.y,
|
||||
1,
|
||||
get_precision() == realtime_compositor::ResultPrecision::Half ? GPU_RGBA16F :
|
||||
GPU_RGBA32F,
|
||||
GPU_TEXTURE_USAGE_GENERAL,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
return viewer_output_texture_;
|
||||
@@ -301,6 +305,26 @@ class Context : public realtime_compositor::Context {
|
||||
return input_data_.view_name;
|
||||
}
|
||||
|
||||
realtime_compositor::ResultPrecision get_precision() const override
|
||||
{
|
||||
switch (input_data_.node_tree->precision) {
|
||||
case NODE_TREE_COMPOSITOR_PRECISION_AUTO:
|
||||
/* Auto uses full precision for final renders and half procession otherwise. File outputs
|
||||
* are only used in final renders, so use that as a condition. */
|
||||
if (use_file_output()) {
|
||||
return realtime_compositor::ResultPrecision::Full;
|
||||
}
|
||||
else {
|
||||
return realtime_compositor::ResultPrecision::Half;
|
||||
}
|
||||
case NODE_TREE_COMPOSITOR_PRECISION_FULL:
|
||||
return realtime_compositor::ResultPrecision::Full;
|
||||
}
|
||||
|
||||
BLI_assert_unreachable();
|
||||
return realtime_compositor::ResultPrecision::Full;
|
||||
}
|
||||
|
||||
void set_info_message(StringRef /*message*/) const override
|
||||
{
|
||||
/* TODO: ignored for now. Currently only used to communicate incomplete node support
|
||||
|
||||
Reference in New Issue
Block a user