Compositor: Add experimental option for new CPU compositor
This patch introduces a new experimental option for the new CPU compositor under development. This is to make development easier such that it happens directly in main, but the compositor is not expected to work and will probably crash. Pull Request: https://projects.blender.org/blender/blender/pulls/125960
This commit is contained in:
@@ -848,6 +848,27 @@ class NODE_PT_quality(bpy.types.Panel):
|
||||
col = layout.column()
|
||||
col.prop(tree, "use_viewer_border")
|
||||
|
||||
class NODE_PT_compositor_debug(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
bl_region_type = 'UI'
|
||||
bl_category = "Options"
|
||||
bl_label = "Debug"
|
||||
bl_parent_id = "NODE_PT_quality"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
render_data = context.scene.render
|
||||
if render_data.compositor_device != "CPU":
|
||||
return False
|
||||
|
||||
preferences = context.preferences
|
||||
return preferences.view.show_developer_ui and preferences.experimental.enable_new_cpu_compositor
|
||||
|
||||
def draw(self, context):
|
||||
render_data = context.scene.render
|
||||
self.layout.prop(render_data, "use_new_cpu_compositor", text="Experimental CPU Implementation")
|
||||
|
||||
|
||||
class NODE_PT_overlay(Panel):
|
||||
bl_space_type = 'NODE_EDITOR'
|
||||
@@ -1072,6 +1093,7 @@ classes = (
|
||||
NODE_PT_active_tool,
|
||||
NODE_PT_backdrop,
|
||||
NODE_PT_quality,
|
||||
NODE_PT_compositor_debug,
|
||||
NODE_PT_annotation,
|
||||
NODE_PT_overlay,
|
||||
NODE_PT_active_node_properties,
|
||||
|
||||
@@ -2860,6 +2860,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
|
||||
({"property": "use_sculpt_texture_paint"}, ("blender/blender/issues/96225", "#96225")),
|
||||
({"property": "enable_overlay_next"}, ("blender/blender/issues/102179", "#102179")),
|
||||
({"property": "use_animation_baklava"}, ("/blender/blender/issues/120406", "#120406")),
|
||||
({"property": "enable_new_cpu_compositor"}, ("/blender/blender/issues/125968", "#125968")),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
#include "DNA_userdef_types.h"
|
||||
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_node_runtime.hh"
|
||||
#include "BKE_scene.hh"
|
||||
@@ -77,8 +79,10 @@ void COM_execute(Render *render,
|
||||
compositor_init_node_previews(render_data, node_tree);
|
||||
compositor_reset_node_tree_status(node_tree);
|
||||
|
||||
if (scene->r.compositor_device == SCE_COMPOSITOR_DEVICE_GPU) {
|
||||
/* GPU compositor. */
|
||||
if (scene->r.compositor_device == SCE_COMPOSITOR_DEVICE_GPU ||
|
||||
(USER_EXPERIMENTAL_TEST(&U, enable_new_cpu_compositor) && !scene->r.use_old_cpu_compositor))
|
||||
{
|
||||
/* Realtime compositor. */
|
||||
RE_compositor_execute(
|
||||
*render, *scene, *render_data, *node_tree, view_name, render_context, profiler);
|
||||
}
|
||||
|
||||
@@ -51,6 +51,9 @@ class Context {
|
||||
/* Get the node tree used for compositing. */
|
||||
virtual const bNodeTree &get_node_tree() const = 0;
|
||||
|
||||
/* True if the compositor should use GPU acceleration. */
|
||||
virtual bool use_gpu() const = 0;
|
||||
|
||||
/* True if the compositor should write file outputs, false otherwise. */
|
||||
virtual bool use_file_output() const = 0;
|
||||
|
||||
|
||||
@@ -182,7 +182,12 @@ void Result::allocate_texture(Domain domain)
|
||||
}
|
||||
|
||||
is_single_value_ = false;
|
||||
texture_ = context_->texture_pool().acquire(domain.size, get_texture_format());
|
||||
if (context_->use_gpu()) {
|
||||
texture_ = context_->texture_pool().acquire(domain.size, get_texture_format());
|
||||
}
|
||||
else {
|
||||
/* TODO: Host side allocation. */
|
||||
}
|
||||
domain_ = domain;
|
||||
}
|
||||
|
||||
@@ -191,7 +196,12 @@ void Result::allocate_single_value()
|
||||
is_single_value_ = true;
|
||||
/* Single values are stored in 1x1 textures as well as the single value members. */
|
||||
const int2 texture_size{1, 1};
|
||||
texture_ = context_->texture_pool().acquire(texture_size, get_texture_format());
|
||||
if (context_->use_gpu()) {
|
||||
texture_ = context_->texture_pool().acquire(texture_size, get_texture_format());
|
||||
}
|
||||
else {
|
||||
/* TODO: Host side allocation. */
|
||||
}
|
||||
domain_ = Domain::identity();
|
||||
}
|
||||
|
||||
|
||||
@@ -69,6 +69,11 @@ class Context : public realtime_compositor::Context {
|
||||
return *DRW_context_state_get()->scene->nodetree;
|
||||
}
|
||||
|
||||
bool use_gpu() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool use_file_output() const override
|
||||
{
|
||||
return false;
|
||||
|
||||
@@ -256,8 +256,8 @@ static void compo_initjob(void *cjv)
|
||||
compo_tag_output_nodes(cj->localtree, cj->recalc_flags);
|
||||
}
|
||||
|
||||
cj->re = RE_NewInteractiveCompositorRender(scene);
|
||||
if (scene->r.compositor_device == SCE_COMPOSITOR_DEVICE_GPU) {
|
||||
cj->re = RE_NewInteractiveCompositorRender(scene);
|
||||
RE_system_gpu_context_ensure(cj->re);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,6 +831,11 @@ typedef struct RenderData {
|
||||
|
||||
/** Precision used by the GPU execution of the compositor tree. */
|
||||
int compositor_precision; /* eCompositorPrecision */
|
||||
|
||||
/* If false and the experimental enable_new_cpu_compositor is true, use the new experimental
|
||||
* CPU compositor implementation, otherwise, use the old CPU compositor. */
|
||||
char use_old_cpu_compositor;
|
||||
char _pad10[7];
|
||||
} RenderData;
|
||||
|
||||
/** #RenderData::quality_flag */
|
||||
|
||||
@@ -757,7 +757,8 @@ typedef struct UserDef_Experimental {
|
||||
char use_shader_node_previews;
|
||||
char use_animation_baklava;
|
||||
char use_docking;
|
||||
char _pad[2];
|
||||
char enable_new_cpu_compositor;
|
||||
char _pad[1];
|
||||
/** `makesdna` does not allow empty structs. */
|
||||
} UserDef_Experimental;
|
||||
|
||||
|
||||
@@ -7537,6 +7537,12 @@ static void rna_def_scene_render_data(BlenderRNA *brna)
|
||||
prop, "Compositor Precision", "The precision of compositor intermediate result");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_Scene_compositor_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_new_cpu_compositor", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_negative_sdna(prop, nullptr, "use_old_cpu_compositor", 1);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Use New CPU Compositor", "Use the new CPU compositor implementation");
|
||||
RNA_def_property_update(prop, NC_NODE | ND_DISPLAY, "rna_Scene_compositor_update");
|
||||
|
||||
/* Nestled Data. */
|
||||
/* *** Non-Animated *** */
|
||||
RNA_define_animate_sdna(false);
|
||||
|
||||
@@ -7428,6 +7428,10 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Overlay Next", "Enable the new Overlay codebase, requires restart");
|
||||
|
||||
prop = RNA_def_property(srna, "enable_new_cpu_compositor", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, nullptr, "enable_new_cpu_compositor", 1);
|
||||
RNA_def_property_ui_text(prop, "CPU Compositor", "Enable the new CPU compositor");
|
||||
|
||||
prop = RNA_def_property(srna, "use_all_linked_data_direct", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
|
||||
@@ -193,6 +193,11 @@ class Context : public realtime_compositor::Context {
|
||||
return *input_data_.node_tree;
|
||||
}
|
||||
|
||||
bool use_gpu() const override
|
||||
{
|
||||
return this->get_render_data().compositor_device == SCE_COMPOSITOR_DEVICE_GPU;
|
||||
}
|
||||
|
||||
bool use_file_output() const override
|
||||
{
|
||||
return this->render_context() != nullptr;
|
||||
@@ -587,45 +592,52 @@ class RealtimeCompositor {
|
||||
|
||||
~RealtimeCompositor()
|
||||
{
|
||||
/* Free resources with GPU context enabled. Cleanup may happen from the
|
||||
* main thread, and we must use the main context there. */
|
||||
if (BLI_thread_is_main()) {
|
||||
DRW_gpu_context_enable();
|
||||
}
|
||||
else {
|
||||
DRW_render_context_enable(&render_);
|
||||
const bool use_gpu = context_->use_gpu();
|
||||
if (use_gpu) {
|
||||
/* Free resources with GPU context enabled. Cleanup may happen from the
|
||||
* main thread, and we must use the main context there. */
|
||||
if (BLI_thread_is_main()) {
|
||||
DRW_gpu_context_enable();
|
||||
}
|
||||
else {
|
||||
DRW_render_context_enable(&render_);
|
||||
}
|
||||
}
|
||||
|
||||
context_.reset();
|
||||
texture_pool_.reset();
|
||||
|
||||
if (BLI_thread_is_main()) {
|
||||
DRW_gpu_context_disable();
|
||||
}
|
||||
else {
|
||||
DRW_render_context_disable(&render_);
|
||||
if (use_gpu) {
|
||||
if (BLI_thread_is_main()) {
|
||||
DRW_gpu_context_disable();
|
||||
}
|
||||
else {
|
||||
DRW_render_context_disable(&render_);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Evaluate the compositor and output to the scene render result. */
|
||||
void execute(const ContextInputData &input_data)
|
||||
{
|
||||
/* For main thread rendering in background mode, blocking rendering, or when we do not have a
|
||||
* render system GPU context, use the DRW context directly, while for threaded rendering when
|
||||
* we have a render system GPU context, use the render's system GPU context to avoid blocking
|
||||
* with the global DST. */
|
||||
void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
|
||||
if (BLI_thread_is_main() || re_system_gpu_context == nullptr) {
|
||||
DRW_gpu_context_enable();
|
||||
}
|
||||
else {
|
||||
if (context_->use_gpu()) {
|
||||
/* For main thread rendering in background mode, blocking rendering, or when we do not have a
|
||||
* render system GPU context, use the DRW context directly, while for threaded rendering when
|
||||
* we have a render system GPU context, use the render's system GPU context to avoid blocking
|
||||
* with the global DST. */
|
||||
void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
|
||||
WM_system_gpu_context_activate(re_system_gpu_context);
|
||||
if (BLI_thread_is_main() || re_system_gpu_context == nullptr) {
|
||||
DRW_gpu_context_enable();
|
||||
}
|
||||
else {
|
||||
void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
|
||||
WM_system_gpu_context_activate(re_system_gpu_context);
|
||||
|
||||
void *re_blender_gpu_context = RE_blender_gpu_context_ensure(&render_);
|
||||
void *re_blender_gpu_context = RE_blender_gpu_context_ensure(&render_);
|
||||
|
||||
GPU_render_begin();
|
||||
GPU_context_active_set(static_cast<GPUContext *>(re_blender_gpu_context));
|
||||
GPU_render_begin();
|
||||
GPU_context_active_set(static_cast<GPUContext *>(re_blender_gpu_context));
|
||||
}
|
||||
}
|
||||
|
||||
context_->update_input_data(input_data);
|
||||
@@ -641,14 +653,17 @@ class RealtimeCompositor {
|
||||
context_->viewer_output_to_viewer_image();
|
||||
texture_pool_->free_unused_and_reset();
|
||||
|
||||
if (BLI_thread_is_main() || re_system_gpu_context == nullptr) {
|
||||
DRW_gpu_context_disable();
|
||||
}
|
||||
else {
|
||||
GPU_render_end();
|
||||
GPU_context_active_set(nullptr);
|
||||
if (context_->use_gpu()) {
|
||||
void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
|
||||
WM_system_gpu_context_release(re_system_gpu_context);
|
||||
if (BLI_thread_is_main() || re_system_gpu_context == nullptr) {
|
||||
DRW_gpu_context_disable();
|
||||
}
|
||||
else {
|
||||
GPU_render_end();
|
||||
GPU_context_active_set(nullptr);
|
||||
void *re_system_gpu_context = RE_system_gpu_context_get(&render_);
|
||||
WM_system_gpu_context_release(re_system_gpu_context);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -662,25 +677,25 @@ void Render::compositor_execute(const Scene &scene,
|
||||
blender::realtime_compositor::RenderContext *render_context,
|
||||
blender::realtime_compositor::Profiler *profiler)
|
||||
{
|
||||
std::unique_lock lock(gpu_compositor_mutex);
|
||||
std::unique_lock lock(this->compositor_mutex);
|
||||
|
||||
blender::render::ContextInputData input_data(
|
||||
scene, render_data, node_tree, view_name, render_context, profiler);
|
||||
|
||||
if (gpu_compositor == nullptr) {
|
||||
gpu_compositor = new blender::render::RealtimeCompositor(*this, input_data);
|
||||
if (this->compositor == nullptr) {
|
||||
this->compositor = new blender::render::RealtimeCompositor(*this, input_data);
|
||||
}
|
||||
|
||||
gpu_compositor->execute(input_data);
|
||||
this->compositor->execute(input_data);
|
||||
}
|
||||
|
||||
void Render::compositor_free()
|
||||
{
|
||||
std::unique_lock lock(gpu_compositor_mutex);
|
||||
std::unique_lock lock(this->compositor_mutex);
|
||||
|
||||
if (gpu_compositor != nullptr) {
|
||||
delete gpu_compositor;
|
||||
gpu_compositor = nullptr;
|
||||
if (this->compositor != nullptr) {
|
||||
delete this->compositor;
|
||||
this->compositor = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -650,7 +650,7 @@ void RE_FreeAllPersistentData()
|
||||
static void re_gpu_texture_caches_free(Render *re)
|
||||
{
|
||||
/* Free persistent compositor that may be using these textures. */
|
||||
if (re->gpu_compositor) {
|
||||
if (re->compositor) {
|
||||
RE_compositor_free(*re);
|
||||
}
|
||||
|
||||
|
||||
@@ -211,11 +211,11 @@ struct Render : public BaseRender {
|
||||
struct Depsgraph *pipeline_depsgraph = nullptr;
|
||||
Scene *pipeline_scene_eval = nullptr;
|
||||
|
||||
/* Realtime GPU Compositor.
|
||||
/* Realtime Compositor.
|
||||
* NOTE: Use bare pointer instead of smart pointer because the RealtimeCompositor is a fully
|
||||
* opaque type. */
|
||||
blender::render::RealtimeCompositor *gpu_compositor = nullptr;
|
||||
std::mutex gpu_compositor_mutex;
|
||||
blender::render::RealtimeCompositor *compositor = nullptr;
|
||||
std::mutex compositor_mutex;
|
||||
|
||||
/* Callbacks for the corresponding base class method implementation. */
|
||||
void (*display_init_cb)(void *handle, RenderResult *rr) = nullptr;
|
||||
|
||||
Reference in New Issue
Block a user