Compositor: first steps to use realtime compositor outside viewport #108629
|
@ -764,20 +764,26 @@ class NODE_PT_quality(bpy.types.Panel):
|
|||
tree = snode.node_tree
|
||||
prefs = bpy.context.preferences
|
||||
|
||||
use_realtime = False
|
||||
col = layout.column()
|
||||
if prefs.experimental.use_full_frame_compositor:
|
||||
if prefs.experimental.use_experimental_compositors:
|
||||
col.prop(tree, "execution_mode")
|
||||
use_realtime = tree.execution_mode == 'REALTIME'
|
||||
|
||||
col = layout.column()
|
||||
col.active = not use_realtime
|
||||
col.prop(tree, "render_quality", text="Render")
|
||||
col.prop(tree, "edit_quality", text="Edit")
|
||||
col.prop(tree, "chunk_size")
|
||||
|
||||
col = layout.column()
|
||||
col.active = not use_realtime
|
||||
col.prop(tree, "use_opencl")
|
||||
col.prop(tree, "use_groupnode_buffer")
|
||||
col.prop(tree, "use_two_pass")
|
||||
col.prop(tree, "use_viewer_border")
|
||||
col.separator()
|
||||
|
||||
col = layout.column()
|
||||
col.prop(snode, "use_auto_render")
|
||||
|
||||
|
||||
|
|
|
@ -2423,7 +2423,7 @@ class USERPREF_PT_experimental_prototypes(ExperimentalPanel, Panel):
|
|||
({"property": "use_new_curves_tools"}, ("blender/blender/issues/68981", "#68981")),
|
||||
({"property": "use_new_point_cloud_type"}, ("blender/blender/issues/75717", "#75717")),
|
||||
({"property": "use_sculpt_texture_paint"}, ("blender/blender/issues/96225", "#96225")),
|
||||
({"property": "use_full_frame_compositor"}, ("blender/blender/issues/88150", "#88150")),
|
||||
({"property": "use_experimental_compositors"}, ("blender/blender/issues/88150", "#88150")),
|
||||
({"property": "enable_eevee_next"}, ("blender/blender/issues/93220", "#93220")),
|
||||
({"property": "enable_workbench_next"}, ("blender/blender/issues/101619", "#101619")),
|
||||
({"property": "use_grease_pencil_version3"}, ("blender/blender/projects/40", "Grease Pencil 3.0")),
|
||||
|
|
|
@ -75,15 +75,13 @@ bool BKE_texture_dependsOnTime(const struct Tex *texture);
|
|||
*/
|
||||
bool BKE_texture_is_image_user(const struct Tex *tex);
|
||||
|
||||
void BKE_texture_get_value_ex(const struct Scene *scene,
|
||||
struct Tex *texture,
|
||||
void BKE_texture_get_value_ex(struct Tex *texture,
|
||||
const float *tex_co,
|
||||
struct TexResult *texres,
|
||||
struct ImagePool *pool,
|
||||
bool use_color_management);
|
||||
|
||||
void BKE_texture_get_value(const struct Scene *scene,
|
||||
struct Tex *texture,
|
||||
void BKE_texture_get_value(struct Tex *texture,
|
||||
const float *tex_co,
|
||||
struct TexResult *texres,
|
||||
bool use_color_management);
|
||||
|
|
|
@ -1931,7 +1931,7 @@ static void sample_mesh(FluidFlowSettings *ffs,
|
|||
tex_co[1] = tex_co[1] * 2.0f - 1.0f;
|
||||
tex_co[2] = ffs->texture_offset;
|
||||
}
|
||||
BKE_texture_get_value(nullptr, ffs->noise_texture, tex_co, &texres, false);
|
||||
BKE_texture_get_value(ffs->noise_texture, tex_co, &texres, false);
|
||||
emission_strength *= texres.tin;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -705,22 +705,15 @@ bool BKE_texture_dependsOnTime(const Tex *texture)
|
|||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
void BKE_texture_get_value_ex(const Scene *scene,
|
||||
Tex *texture,
|
||||
void BKE_texture_get_value_ex(Tex *texture,
|
||||
const float *tex_co,
|
||||
TexResult *texres,
|
||||
ImagePool *pool,
|
||||
bool use_color_management)
|
||||
{
|
||||
int result_type;
|
||||
bool do_color_manage = false;
|
||||
|
||||
if (scene && use_color_management) {
|
||||
do_color_manage = BKE_scene_check_color_management_enabled(scene);
|
||||
}
|
||||
|
||||
/* no node textures for now */
|
||||
result_type = multitex_ext_safe(texture, tex_co, texres, pool, do_color_manage, false);
|
||||
const int result_type = multitex_ext_safe(
|
||||
texture, tex_co, texres, pool, use_color_management, false);
|
||||
|
||||
/* if the texture gave an RGB value, we assume it didn't give a valid
|
||||
* intensity, since this is in the context of modifiers don't use perceptual color conversion.
|
||||
|
@ -734,13 +727,12 @@ void BKE_texture_get_value_ex(const Scene *scene,
|
|||
}
|
||||
}
|
||||
|
||||
void BKE_texture_get_value(const Scene *scene,
|
||||
Tex *texture,
|
||||
void BKE_texture_get_value(Tex *texture,
|
||||
const float *tex_co,
|
||||
TexResult *texres,
|
||||
bool use_color_management)
|
||||
{
|
||||
BKE_texture_get_value_ex(scene, texture, tex_co, texres, nullptr, use_color_management);
|
||||
BKE_texture_get_value_ex(texture, tex_co, texres, nullptr, use_color_management);
|
||||
}
|
||||
|
||||
static void texture_nodes_fetch_images_for_pool(Tex *texture, bNodeTree *ntree, ImagePool *pool)
|
||||
|
|
|
@ -11,6 +11,8 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Render;
|
||||
|
||||
/* Keep ascii art. */
|
||||
/* clang-format off */
|
||||
|
||||
|
@ -294,6 +296,9 @@ extern "C" {
|
|||
* It can be executed during editing (blenkernel/node.cc) or rendering
|
||||
* (renderer/pipeline.c)
|
||||
*
|
||||
* \param render: [struct Render]
|
||||
* Render instance for GPU context.
|
||||
*
|
||||
* \param render_data: [struct RenderData]
|
||||
* Render data for this composite, this won't always belong to a scene.
|
||||
*
|
||||
|
@ -305,10 +310,10 @@ extern "C" {
|
|||
* (true) or editing (false).
|
||||
* based on this setting the system will work differently:
|
||||
* - during rendering only Composite & the File output node will be calculated
|
||||
* \see NodeOperation.is_output_program(int rendering) of the specific operations
|
||||
* \see NodeOperation.is_output_program(bool rendering) of the specific operations
|
||||
*
|
||||
* - during editing all output nodes will be calculated
|
||||
* \see NodeOperation.is_output_program(int rendering) of the specific operations
|
||||
* \see NodeOperation.is_output_program(bool rendering) of the specific operations
|
||||
*
|
||||
* - another quality setting can be used bNodeTree.
|
||||
* The quality is determined by the bNodeTree fields.
|
||||
|
@ -326,10 +331,11 @@ extern "C" {
|
|||
*/
|
||||
/* clang-format off */
|
||||
|
||||
void COM_execute(RenderData *render_data,
|
||||
void COM_execute(Render *render,
|
||||
RenderData *render_data,
|
||||
Scene *scene,
|
||||
bNodeTree *node_tree,
|
||||
int rendering,
|
||||
bool rendering,
|
||||
const char *view_name);
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,6 +14,8 @@
|
|||
#include "COM_WorkScheduler.h"
|
||||
#include "COM_compositor.h"
|
||||
|
||||
#include "RE_compositor.hh"
|
||||
|
||||
static struct {
|
||||
bool is_initialized = false;
|
||||
ThreadMutex mutex;
|
||||
|
@ -47,10 +49,11 @@ static void compositor_reset_node_tree_status(bNodeTree *node_tree)
|
|||
node_tree->runtime->stats_draw(node_tree->runtime->sdh, IFACE_("Compositing"));
|
||||
}
|
||||
|
||||
void COM_execute(RenderData *render_data,
|
||||
void COM_execute(Render *render,
|
||||
RenderData *render_data,
|
||||
Scene *scene,
|
||||
bNodeTree *node_tree,
|
||||
int rendering,
|
||||
bool rendering,
|
||||
const char *view_name)
|
||||
{
|
||||
/* Initialize mutex, TODO: this mutex init is actually not thread safe and
|
||||
|
@ -73,9 +76,23 @@ void COM_execute(RenderData *render_data,
|
|||
compositor_init_node_previews(render_data, node_tree);
|
||||
compositor_reset_node_tree_status(node_tree);
|
||||
|
||||
if (U.experimental.use_full_frame_compositor &&
|
||||
node_tree->execution_mode == NTREE_EXECUTION_MODE_REALTIME)
|
||||
{
|
||||
/* Realtime GPU compositer. */
|
||||
|
||||
/* TODO: add persistence and depsgraph updates for better performance. */
|
||||
blender::render::RealtimeCompositor compositer(
|
||||
*render, *scene, *render_data, *node_tree, rendering, view_name);
|
||||
compositer.execute();
|
||||
}
|
||||
else {
|
||||
/* Tiled and Full Frame compositers. */
|
||||
|
||||
/* Initialize workscheduler. */
|
||||
const bool use_opencl = (node_tree->flag & NTREE_COM_OPENCL) != 0;
|
||||
blender::compositor::WorkScheduler::initialize(use_opencl, BKE_render_num_threads(render_data));
|
||||
blender::compositor::WorkScheduler::initialize(use_opencl,
|
||||
BKE_render_num_threads(render_data));
|
||||
|
||||
/* Execute. */
|
||||
const bool twopass = (node_tree->flag & NTREE_TWO_PASS) && !rendering;
|
||||
|
@ -93,6 +110,7 @@ void COM_execute(RenderData *render_data,
|
|||
blender::compositor::ExecutionSystem system(
|
||||
render_data, scene, node_tree, rendering, false, view_name);
|
||||
system.execute();
|
||||
}
|
||||
|
||||
BLI_mutex_unlock(&g_compositor.mutex);
|
||||
}
|
||||
|
|
|
@ -9,6 +9,7 @@ set(INC
|
|||
../../blenkernel
|
||||
../../blenlib
|
||||
../../blentranslation
|
||||
../../draw
|
||||
../../gpu
|
||||
../../imbuf
|
||||
../../makesdna
|
||||
|
|
|
@ -42,8 +42,17 @@ class Context {
|
|||
public:
|
||||
Context(TexturePool &texture_pool);
|
||||
|
||||
/* Get the active compositing scene. */
|
||||
virtual const Scene *get_scene() const = 0;
|
||||
/* Get the node tree used for compositing. */
|
||||
virtual const bNodeTree &get_node_tree() const = 0;
|
||||
|
||||
/* True if compositor should do write file outputs, false if only running for viewing. */
|
||||
virtual bool use_file_output() const = 0;
|
||||
|
||||
/* True if color management should be used for texture evaluation. */
|
||||
virtual bool use_texture_color_management() const = 0;
|
||||
|
||||
/* Get the render settings for compositing. */
|
||||
virtual const RenderData &get_render_data() const = 0;
|
||||
|
||||
/* Get the width and height of the render passes and of the output texture returned by the
|
||||
* get_input_texture and get_output_texture methods respectively. */
|
||||
|
@ -63,7 +72,7 @@ class Context {
|
|||
|
||||
/* Get the texture where the given render pass is stored. This should be called by the Render
|
||||
* Layer node to populate its outputs. */
|
||||
virtual GPUTexture *get_input_texture(int view_layer, eScenePassType pass_type) = 0;
|
||||
virtual GPUTexture *get_input_texture(int view_layer, const char *pass_name) = 0;
|
||||
|
||||
/* Get the name of the view currently being rendered. */
|
||||
virtual StringRef get_view_name() = 0;
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
|
||||
#include "GPU_texture.h"
|
||||
|
||||
#include "DNA_scene_types.h"
|
||||
#include "DNA_texture_types.h"
|
||||
|
||||
#include "COM_cached_resource.hh"
|
||||
|
@ -49,7 +48,7 @@ class CachedTexture : public CachedResource {
|
|||
GPUTexture *value_texture_ = nullptr;
|
||||
|
||||
public:
|
||||
CachedTexture(Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale);
|
||||
CachedTexture(Tex *texture, bool use_color_management, int2 size, float2 offset, float2 scale);
|
||||
|
||||
~CachedTexture();
|
||||
|
||||
|
@ -74,8 +73,12 @@ class CachedTextureContainer : CachedResourceContainer {
|
|||
* CachedTexture cached resource with the 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. */
|
||||
CachedTexture &get(
|
||||
Context &context, Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale);
|
||||
CachedTexture &get(Context &context,
|
||||
Tex *texture,
|
||||
bool use_color_management,
|
||||
int2 size,
|
||||
float2 offset,
|
||||
float2 scale);
|
||||
};
|
||||
|
||||
} // namespace blender::realtime_compositor
|
||||
|
|
|
@ -51,7 +51,7 @@ bool operator==(const CachedTextureKey &a, const CachedTextureKey &b)
|
|||
*/
|
||||
|
||||
CachedTexture::CachedTexture(
|
||||
Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale)
|
||||
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);
|
||||
|
@ -67,7 +67,8 @@ CachedTexture::CachedTexture(
|
|||
/* Note that it is expected that the offset is scaled by the scale. */
|
||||
coordinates = (coordinates + offset) * scale;
|
||||
TexResult texture_result;
|
||||
BKE_texture_get_value_ex(scene, texture, coordinates, &texture_result, image_pool, true);
|
||||
BKE_texture_get_value_ex(
|
||||
texture, coordinates, &texture_result, image_pool, use_color_management);
|
||||
color_pixels[y * size.x + x] = float4(texture_result.trgba);
|
||||
value_pixels[y * size.x + x] = texture_result.talpha ? texture_result.trgba[3] :
|
||||
texture_result.tin;
|
||||
|
@ -131,8 +132,12 @@ void CachedTextureContainer::reset()
|
|||
}
|
||||
}
|
||||
|
||||
CachedTexture &CachedTextureContainer::get(
|
||||
Context &context, Tex *texture, const Scene *scene, int2 size, float2 offset, float2 scale)
|
||||
CachedTexture &CachedTextureContainer::get(Context &context,
|
||||
Tex *texture,
|
||||
bool use_color_management,
|
||||
int2 size,
|
||||
float2 offset,
|
||||
float2 scale)
|
||||
{
|
||||
const CachedTextureKey key(size, offset, scale);
|
||||
|
||||
|
@ -143,8 +148,9 @@ CachedTexture &CachedTextureContainer::get(
|
|||
cached_textures_for_id.clear();
|
||||
}
|
||||
|
||||
auto &cached_texture = *cached_textures_for_id.lookup_or_add_cb(
|
||||
key, [&]() { return std::make_unique<CachedTexture>(texture, scene, size, offset, scale); });
|
||||
auto &cached_texture = *cached_textures_for_id.lookup_or_add_cb(key, [&]() {
|
||||
return std::make_unique<CachedTexture>(texture, use_color_management, size, offset, scale);
|
||||
});
|
||||
|
||||
cached_texture.needed = true;
|
||||
return cached_texture;
|
||||
|
|
|
@ -23,18 +23,19 @@ int2 Context::get_compositing_region_size() const
|
|||
|
||||
float Context::get_render_percentage() const
|
||||
{
|
||||
return get_scene()->r.size / 100.0f;
|
||||
return get_render_data().size / 100.0f;
|
||||
}
|
||||
|
||||
int Context::get_frame_number() const
|
||||
{
|
||||
return get_scene()->r.cfra;
|
||||
return get_render_data().cfra;
|
||||
}
|
||||
|
||||
float Context::get_time() const
|
||||
{
|
||||
const float frame_number = float(get_frame_number());
|
||||
const float frame_rate = float(get_scene()->r.frs_sec) / float(get_scene()->r.frs_sec_base);
|
||||
const float frame_rate = float(get_render_data().frs_sec) /
|
||||
float(get_render_data().frs_sec_base);
|
||||
return frame_number / frame_rate;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,7 @@ bool Evaluator::validate_node_tree()
|
|||
|
||||
void Evaluator::compile_and_evaluate()
|
||||
{
|
||||
derived_node_tree_ = std::make_unique<DerivedNodeTree>(*context_.get_scene()->nodetree);
|
||||
derived_node_tree_ = std::make_unique<DerivedNodeTree>(context_.get_node_tree());
|
||||
|
||||
if (!validate_node_tree()) {
|
||||
return;
|
||||
|
|
|
@ -58,9 +58,24 @@ class Context : public realtime_compositor::Context {
|
|||
{
|
||||
}
|
||||
|
||||
const Scene *get_scene() const override
|
||||
const bNodeTree &get_node_tree() const override
|
||||
{
|
||||
return DRW_context_state_get()->scene;
|
||||
return *DRW_context_state_get()->scene->nodetree;
|
||||
}
|
||||
|
||||
bool use_file_output() const override
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool use_texture_color_management() const override
|
||||
{
|
||||
return BKE_scene_check_color_management_enabled(DRW_context_state_get()->scene);
|
||||
}
|
||||
|
||||
const RenderData &get_render_data() const override
|
||||
{
|
||||
return DRW_context_state_get()->scene->r;
|
||||
}
|
||||
|
||||
int2 get_render_size() const override
|
||||
|
@ -130,15 +145,20 @@ class Context : public realtime_compositor::Context {
|
|||
return DRW_viewport_texture_list_get()->color;
|
||||
}
|
||||
|
||||
GPUTexture *get_input_texture(int /*view_layer*/, eScenePassType /*pass_type*/) override
|
||||
GPUTexture *get_input_texture(int view_layer, const char *pass_name) override
|
||||
{
|
||||
if (view_layer == 0 && STREQ(pass_name, RE_PASSNAME_COMBINED)) {
|
||||
return get_output_texture();
|
||||
}
|
||||
else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
StringRef get_view_name() override
|
||||
{
|
||||
const SceneRenderView *view = static_cast<SceneRenderView *>(
|
||||
BLI_findlink(&get_scene()->r.views, DRW_context_state_get()->v3d->multiview_eye));
|
||||
BLI_findlink(&get_render_data().views, DRW_context_state_get()->v3d->multiview_eye));
|
||||
return view->name;
|
||||
}
|
||||
|
||||
|
|
|
@ -1086,7 +1086,7 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
|
|||
/* Fill in image buffer. */
|
||||
float *rect_float = rv->combined_buffer.data;
|
||||
float tex_coord[3] = {0.0f, 0.0f, 0.0f};
|
||||
bool color_manage = true;
|
||||
bool color_manage = BKE_scene_check_color_management_enabled(sce);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
/* Tex coords between -1.0f and 1.0f. */
|
||||
|
@ -1097,7 +1097,7 @@ static void shader_preview_texture(ShaderPreview *sp, Tex *tex, Scene *sce, Rend
|
|||
|
||||
/* Evaluate texture at tex_coord. */
|
||||
TexResult texres = {0};
|
||||
BKE_texture_get_value_ex(sce, tex, tex_coord, &texres, img_pool, color_manage);
|
||||
BKE_texture_get_value_ex(tex, tex_coord, &texres, img_pool, color_manage);
|
||||
copy_v4_fl4(rect_float,
|
||||
texres.trgba[0],
|
||||
texres.trgba[1],
|
||||
|
|
|
@ -3327,6 +3327,12 @@ static bool realtime_compositor_is_in_use(const bContext &context)
|
|||
return false;
|
||||
}
|
||||
|
||||
if (U.experimental.use_full_frame_compositor &&
|
||||
scene->nodetree->execution_mode == NTREE_EXECUTION_MODE_REALTIME)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
const Main *main = CTX_data_main(&context);
|
||||
LISTBASE_FOREACH (const bScreen *, screen, &main->screens) {
|
||||
LISTBASE_FOREACH (const ScrArea *, area, &screen->areabase) {
|
||||
|
|
|
@ -95,6 +95,8 @@ struct CompoJob {
|
|||
/* Evaluated state/ */
|
||||
Depsgraph *compositor_depsgraph;
|
||||
bNodeTree *localtree;
|
||||
/* Render instance. */
|
||||
Render *re;
|
||||
/* Jon system integration. */
|
||||
const bool *stop;
|
||||
bool *do_update;
|
||||
|
@ -239,6 +241,9 @@ static void compo_initjob(void *cjv)
|
|||
if (cj->recalc_flags) {
|
||||
compo_tag_output_nodes(cj->localtree, cj->recalc_flags);
|
||||
}
|
||||
|
||||
cj->re = RE_NewSceneRender(scene);
|
||||
RE_gl_context_create(cj->re);
|
||||
}
|
||||
|
||||
/* Called before redraw notifiers, it moves finished previews over. */
|
||||
|
@ -286,17 +291,19 @@ static void compo_startjob(void *cjv,
|
|||
BKE_callback_exec_id(cj->bmain, &scene->id, BKE_CB_EVT_COMPOSITE_PRE);
|
||||
|
||||
if ((cj->scene->r.scemode & R_MULTIVIEW) == 0) {
|
||||
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, "");
|
||||
ntreeCompositExecTree(cj->re, cj->scene, ntree, &cj->scene->r, false, true, "");
|
||||
}
|
||||
else {
|
||||
LISTBASE_FOREACH (SceneRenderView *, srv, &scene->r.views) {
|
||||
if (BKE_scene_multiview_is_render_view_active(&scene->r, srv) == false) {
|
||||
continue;
|
||||
}
|
||||
ntreeCompositExecTree(cj->scene, ntree, &cj->scene->r, false, true, srv->name);
|
||||
ntreeCompositExecTree(cj->re, cj->scene, ntree, &cj->scene->r, false, true, srv->name);
|
||||
}
|
||||
}
|
||||
|
||||
RE_gl_context_destroy(cj->re);
|
||||
|
||||
ntree->runtime->test_break = nullptr;
|
||||
ntree->runtime->stats_draw = nullptr;
|
||||
ntree->runtime->progress = nullptr;
|
||||
|
|
|
@ -684,6 +684,7 @@ typedef struct bNodeTree {
|
|||
typedef enum eNodeTreeExecutionMode {
|
||||
NTREE_EXECUTION_MODE_TILED = 0,
|
||||
NTREE_EXECUTION_MODE_FULL_FRAME = 1,
|
||||
NTREE_EXECUTION_MODE_REALTIME = 2,
|
||||
} eNodeTreeExecutionMode;
|
||||
|
||||
typedef enum eNodeTreeRuntimeFlag {
|
||||
|
|
|
@ -136,6 +136,11 @@ static const EnumPropertyItem rna_enum_execution_mode_items[] = {
|
|||
0,
|
||||
"Full Frame",
|
||||
"Composites full image result as fast as possible"},
|
||||
{NTREE_EXECUTION_MODE_REALTIME,
|
||||
"REALTIME",
|
||||
0,
|
||||
"Realtime GPU",
|
||||
"Use GPU accelerated compositing with more limited functionality"},
|
||||
{0, NULL, 0, NULL, NULL},
|
||||
};
|
||||
|
||||
|
|
|
@ -6650,11 +6650,12 @@ static void rna_def_userdef_experimental(BlenderRNA *brna)
|
|||
RNA_def_property_ui_text(
|
||||
prop, "New Point Cloud Type", "Enable the new point cloud type in the ui");
|
||||
|
||||
prop = RNA_def_property(srna, "use_full_frame_compositor", PROP_BOOLEAN, PROP_NONE);
|
||||
prop = RNA_def_property(srna, "use_experimental_compositors", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(prop, NULL, "use_full_frame_compositor", 1);
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Full Frame Compositor",
|
||||
"Enable compositor full frame execution mode option (no tiling, "
|
||||
RNA_def_property_ui_text(
|
||||
prop,
|
||||
"Experimental Compositors",
|
||||
"Enable compositor full frame and realtime GPU execution mode options (no tiling, "
|
||||
"reduces execution time and memory usage)");
|
||||
RNA_def_property_update(prop, 0, "rna_userdef_update");
|
||||
|
||||
|
|
|
@ -194,8 +194,7 @@ static void displaceModifier_do_task(void *__restrict userdata,
|
|||
}
|
||||
|
||||
if (data->tex_target) {
|
||||
BKE_texture_get_value_ex(
|
||||
data->scene, data->tex_target, tex_co[iter], &texres, data->pool, false);
|
||||
BKE_texture_get_value_ex(data->tex_target, tex_co[iter], &texres, data->pool, false);
|
||||
delta = texres.tin - dmd->midlevel;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -170,8 +170,7 @@ template<typename GridType> struct DisplaceOp {
|
|||
openvdb::Vec3d evaluate_texture(const openvdb::Vec3f &pos) const
|
||||
{
|
||||
TexResult texture_result = {0};
|
||||
BKE_texture_get_value(
|
||||
nullptr, this->texture, const_cast<float *>(pos.asV()), &texture_result, false);
|
||||
BKE_texture_get_value(this->texture, const_cast<float *>(pos.asV()), &texture_result, false);
|
||||
return {texture_result.trgba[0], texture_result.trgba[1], texture_result.trgba[2]};
|
||||
}
|
||||
};
|
||||
|
|
|
@ -299,9 +299,8 @@ static void warpModifier_do(WarpModifierData *wmd,
|
|||
fac *= weight;
|
||||
|
||||
if (tex_co) {
|
||||
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||
TexResult texres;
|
||||
BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
|
||||
BKE_texture_get_value(tex_target, tex_co[i], &texres, false);
|
||||
fac *= texres.tin;
|
||||
}
|
||||
|
||||
|
|
|
@ -258,9 +258,8 @@ static void waveModifier_do(WaveModifierData *md,
|
|||
|
||||
/* Apply texture. */
|
||||
if (tex_co) {
|
||||
Scene *scene = DEG_get_evaluated_scene(ctx->depsgraph);
|
||||
TexResult texres;
|
||||
BKE_texture_get_value(scene, tex_target, tex_co[i], &texres, false);
|
||||
BKE_texture_get_value(tex_target, tex_co[i], &texres, false);
|
||||
amplit *= texres.tin;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include "BKE_customdata.h"
|
||||
#include "BKE_deform.h"
|
||||
#include "BKE_modifier.h"
|
||||
#include "BKE_scene.h"
|
||||
#include "BKE_texture.h" /* Texture masking. */
|
||||
|
||||
#include "UI_interface.h"
|
||||
|
@ -160,11 +161,10 @@ void weightvg_do_mask(const ModifierEvalContext *ctx,
|
|||
int idx = indices ? indices[i] : i;
|
||||
TexResult texres;
|
||||
float hsv[3]; /* For HSV color space. */
|
||||
bool do_color_manage;
|
||||
bool do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT &&
|
||||
BKE_scene_check_color_management_enabled(scene);
|
||||
|
||||
do_color_manage = tex_use_channel != MOD_WVG_MASK_TEX_USE_INT;
|
||||
|
||||
BKE_texture_get_value(scene, texture, tex_co[idx], &texres, do_color_manage);
|
||||
BKE_texture_get_value(texture, tex_co[idx], &texres, do_color_manage);
|
||||
/* Get the good channel value... */
|
||||
switch (tex_use_channel) {
|
||||
case MOD_WVG_MASK_TEX_USE_INT:
|
||||
|
|
|
@ -14,6 +14,11 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
struct Scene;
|
||||
struct RenderData;
|
||||
struct Render;
|
||||
struct ViewLayer;
|
||||
|
||||
extern struct bNodeTreeType *ntreeType_Composite;
|
||||
|
||||
void node_cmp_rlayers_outputs(struct bNodeTree *ntree, struct bNode *node);
|
||||
|
@ -27,10 +32,11 @@ const char *node_cmp_rlayers_sock_to_pass(int sock_index);
|
|||
|
||||
void register_node_type_cmp_custom_group(bNodeType *ntype);
|
||||
|
||||
void ntreeCompositExecTree(struct Scene *scene,
|
||||
void ntreeCompositExecTree(struct Render *render,
|
||||
struct Scene *scene,
|
||||
struct bNodeTree *ntree,
|
||||
struct RenderData *rd,
|
||||
int rendering,
|
||||
bool rendering,
|
||||
int do_previews,
|
||||
const char *view_name);
|
||||
|
||||
|
|
|
@ -171,15 +171,16 @@ void register_node_tree_type_cmp()
|
|||
ntreeTypeAdd(tt);
|
||||
}
|
||||
|
||||
void ntreeCompositExecTree(Scene *scene,
|
||||
void ntreeCompositExecTree(Render *render,
|
||||
Scene *scene,
|
||||
bNodeTree *ntree,
|
||||
RenderData *rd,
|
||||
int rendering,
|
||||
bool rendering,
|
||||
int do_preview,
|
||||
const char *view_name)
|
||||
{
|
||||
#ifdef WITH_COMPOSITOR_CPU
|
||||
COM_execute(rd, scene, ntree, rendering, view_name);
|
||||
COM_execute(render, rd, scene, ntree, rendering, view_name);
|
||||
#else
|
||||
UNUSED_VARS(scene, ntree, rd, rendering, view_name);
|
||||
#endif
|
||||
|
|
|
@ -825,7 +825,7 @@ class RenderLayerOperation : public NodeOperation {
|
|||
void execute() override
|
||||
{
|
||||
const int view_layer = bnode().custom1;
|
||||
GPUTexture *pass_texture = context().get_input_texture(view_layer, SCE_PASS_COMBINED);
|
||||
GPUTexture *pass_texture = context().get_input_texture(view_layer, RE_PASSNAME_COMBINED);
|
||||
|
||||
execute_image(pass_texture);
|
||||
execute_alpha(pass_texture);
|
||||
|
@ -848,6 +848,11 @@ class RenderLayerOperation : public NodeOperation {
|
|||
if (!image_result.should_compute()) {
|
||||
return;
|
||||
}
|
||||
if (pass_texture == nullptr) {
|
||||
/* Pass not rendered (yet). */
|
||||
image_result.allocate_invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_read_pass");
|
||||
GPU_shader_bind(shader);
|
||||
|
@ -878,6 +883,11 @@ class RenderLayerOperation : public NodeOperation {
|
|||
if (!alpha_result.should_compute()) {
|
||||
return;
|
||||
}
|
||||
if (pass_texture == nullptr) {
|
||||
/* Pass not rendered (yet). */
|
||||
alpha_result.allocate_invalid();
|
||||
return;
|
||||
}
|
||||
|
||||
GPUShader *shader = shader_manager().get("compositor_read_pass_alpha");
|
||||
GPU_shader_bind(shader);
|
||||
|
|
|
@ -449,8 +449,10 @@ class OutputFileOperation : public NodeOperation {
|
|||
|
||||
void execute() override
|
||||
{
|
||||
if (context().use_file_output()) {
|
||||
context().set_info_message("Viewport compositor setup not fully supported");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
static NodeOperation *get_compositor_operation(Context &context, DNode node)
|
||||
|
|
|
@ -57,7 +57,7 @@ class TextureOperation : public NodeOperation {
|
|||
CachedTexture &cached_texture = context().cache_manager().cached_textures.get(
|
||||
context(),
|
||||
get_texture(),
|
||||
context().get_scene(),
|
||||
context().use_texture_color_management(),
|
||||
domain.size,
|
||||
get_input("Offset").get_vector_value_default(float4(0.0f)).xy(),
|
||||
get_input("Scale").get_vector_value_default(float4(0.0f)).xy());
|
||||
|
|
|
@ -9,9 +9,12 @@ set(INC
|
|||
../blenkernel
|
||||
../blenlib
|
||||
../blentranslation
|
||||
../compositor/realtime_compositor
|
||||
../compositor/realtime_compositor/cached_resources
|
||||
../depsgraph
|
||||
../draw
|
||||
../gpu
|
||||
../gpu/intern
|
||||
../imbuf
|
||||
../makesdna
|
||||
../makesrna
|
||||
|
@ -30,6 +33,7 @@ set(INC_SYS
|
|||
|
||||
set(SRC
|
||||
intern/bake.cc
|
||||
intern/compositor.cc
|
||||
intern/engine.cc
|
||||
intern/initrender.cc
|
||||
intern/multires_bake.cc
|
||||
|
@ -42,6 +46,7 @@ set(SRC
|
|||
intern/zbuf.c
|
||||
|
||||
RE_bake.h
|
||||
RE_compositor.hh
|
||||
RE_engine.h
|
||||
RE_multires_bake.h
|
||||
RE_pipeline.h
|
||||
|
@ -56,6 +61,7 @@ set(SRC
|
|||
)
|
||||
|
||||
set(LIB
|
||||
bf_realtime_compositor
|
||||
)
|
||||
|
||||
if(WITH_PYTHON)
|
||||
|
|
|
@ -0,0 +1,59 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
struct bNodeTree;
|
||||
struct Depsgraph;
|
||||
struct Render;
|
||||
struct RenderData;
|
||||
struct Scene;
|
||||
|
||||
namespace blender {
|
||||
|
||||
namespace realtime_compositor {
|
||||
class Evaluator;
|
||||
}
|
||||
|
||||
namespace render {
|
||||
class Context;
|
||||
class TexturePool;
|
||||
|
||||
/* ------------------------------------------------------------------------------------------------
|
||||
* Render Realtime Compositor
|
||||
*
|
||||
* Implementation of the compositor for final rendering, as opposed to the viewport compositor
|
||||
* that is part of the draw manager. The input and output of this is pre-existing RenderResult
|
||||
* buffers in scenes, that are uploaded to and read back from the GPU. */
|
||||
|
||||
class RealtimeCompositor {
|
||||
private:
|
||||
/* Render instance for GPU context to run compositor in. */
|
||||
Render &render_;
|
||||
|
||||
std::unique_ptr<TexturePool> texture_pool_;
|
||||
std::unique_ptr<Context> context_;
|
||||
std::unique_ptr<realtime_compositor::Evaluator> evaluator_;
|
||||
|
||||
public:
|
||||
RealtimeCompositor(Render &render,
|
||||
const Scene &scene,
|
||||
const RenderData &render_data,
|
||||
const bNodeTree &node_tree,
|
||||
const bool use_file_output,
|
||||
const char *view_name);
|
||||
|
||||
~RealtimeCompositor();
|
||||
|
||||
/* Evaluate the compositor and output to the scene render result. */
|
||||
void execute();
|
||||
|
||||
/* If the compositor node tree changed, reset the evaluator. */
|
||||
void update(const Depsgraph *depsgraph);
|
||||
};
|
||||
|
||||
} // namespace render
|
||||
} // namespace blender
|
|
@ -0,0 +1,300 @@
|
|||
/* SPDX-FileCopyrightText: 2023 Blender Foundation
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "BLI_threads.h"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
#include "BKE_global.h"
|
||||
#include "BKE_image.h"
|
||||
#include "BKE_node.hh"
|
||||
#include "BKE_scene.h"
|
||||
|
||||
#include "DRW_engine.h"
|
||||
|
||||
#include "COM_context.hh"
|
||||
#include "COM_evaluator.hh"
|
||||
|
||||
#include "RE_compositor.hh"
|
||||
#include "RE_pipeline.h"
|
||||
|
||||
namespace blender::render {
|
||||
|
||||
/* Render Texture Pool */
|
||||
|
||||
class TexturePool : public realtime_compositor::TexturePool {
|
||||
public:
|
||||
Vector<GPUTexture *> textures_;
|
||||
|
||||
virtual ~TexturePool()
|
||||
{
|
||||
for (GPUTexture *texture : textures_) {
|
||||
GPU_texture_free(texture);
|
||||
}
|
||||
}
|
||||
|
||||
GPUTexture *allocate_texture(int2 size, eGPUTextureFormat format) override
|
||||
{
|
||||
/* TODO: should share pool with draw manager. It needs some globals
|
||||
* initialization figured out there first. */
|
||||
#if 0
|
||||
DrawEngineType *owner = (DrawEngineType *)this;
|
||||
return DRW_texture_pool_query_2d(size.x, size.y, format, owner);
|
||||
#else
|
||||
GPUTexture *texture = GPU_texture_create_2d(
|
||||
"compositor_texture_pool", size.x, size.y, 1, format, GPU_TEXTURE_USAGE_GENERAL, NULL);
|
||||
textures_.append(texture);
|
||||
return texture;
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
/* Render Context */
|
||||
|
||||
class Context : public realtime_compositor::Context {
|
||||
private:
|
||||
/* Input data. */
|
||||
const Scene &scene_;
|
||||
const RenderData &render_data_;
|
||||
const bNodeTree &node_tree_;
|
||||
const bool use_file_output_;
|
||||
const char *view_name_;
|
||||
|
||||
/* Output combined texture. */
|
||||
GPUTexture *output_texture_ = nullptr;
|
||||
|
||||
public:
|
||||
Context(const Scene &scene,
|
||||
const RenderData &render_data,
|
||||
const bNodeTree &node_tree,
|
||||
const bool use_file_output,
|
||||
const char *view_name,
|
||||
TexturePool &texture_pool)
|
||||
: realtime_compositor::Context(texture_pool),
|
||||
scene_(scene),
|
||||
render_data_(render_data),
|
||||
node_tree_(node_tree),
|
||||
use_file_output_(use_file_output),
|
||||
view_name_(view_name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~Context()
|
||||
{
|
||||
GPU_texture_free(output_texture_);
|
||||
}
|
||||
|
||||
const bNodeTree &get_node_tree() const override
|
||||
{
|
||||
return node_tree_;
|
||||
}
|
||||
|
||||
bool use_file_output() const override
|
||||
{
|
||||
return use_file_output_;
|
||||
}
|
||||
|
||||
bool use_texture_color_management() const override
|
||||
{
|
||||
return BKE_scene_check_color_management_enabled(&scene_);
|
||||
}
|
||||
|
||||
const RenderData &get_render_data() const override
|
||||
{
|
||||
return render_data_;
|
||||
}
|
||||
|
||||
int2 get_render_size() const override
|
||||
{
|
||||
int width, height;
|
||||
BKE_render_resolution(&render_data_, false, &width, &height);
|
||||
return int2(width, height);
|
||||
}
|
||||
|
||||
rcti get_compositing_region() const override
|
||||
{
|
||||
const int2 render_size = get_render_size();
|
||||
const rcti render_region = rcti{0, render_size.x, 0, render_size.y};
|
||||
|
||||
return render_region;
|
||||
}
|
||||
|
||||
GPUTexture *get_output_texture() override
|
||||
{
|
||||
/* TODO: support outputting for viewers and previews.
|
||||
* TODO: just a temporary hack, needs to get stored in RenderResult,
|
||||
* 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,
|
||||
NULL);
|
||||
}
|
||||
|
||||
return output_texture_;
|
||||
}
|
||||
|
||||
GPUTexture *get_input_texture(int view_layer_id, const char *pass_name) override
|
||||
{
|
||||
/* TODO: eventually this should get cached on the RenderResult itself when
|
||||
* it supports storing GPU buffers, for faster updates. But will also need
|
||||
* some eviction strategy to avoid too much GPU memory usage. */
|
||||
Render *re = RE_GetSceneRender(&scene_);
|
||||
RenderResult *rr = nullptr;
|
||||
GPUTexture *input_texture = nullptr;
|
||||
|
||||
if (re) {
|
||||
rr = RE_AcquireResultRead(re);
|
||||
}
|
||||
|
||||
if (rr) {
|
||||
ViewLayer *view_layer = (ViewLayer *)BLI_findlink(&scene_.view_layers, view_layer_id);
|
||||
if (view_layer) {
|
||||
RenderLayer *rl = RE_GetRenderLayer(rr, view_layer->name);
|
||||
if (rl) {
|
||||
RenderPass *rpass = (RenderPass *)BLI_findstring(
|
||||
&rl->passes, pass_name, offsetof(RenderPass, name));
|
||||
|
||||
if (rpass && rpass->buffer.data) {
|
||||
const int2 size(rl->rectx, rl->recty);
|
||||
|
||||
if (rpass->channels == 1) {
|
||||
input_texture = texture_pool().acquire_float(size);
|
||||
if (input_texture) {
|
||||
GPU_texture_update(input_texture, GPU_DATA_FLOAT, rpass->buffer.data);
|
||||
}
|
||||
}
|
||||
else if (rpass->channels == 3) {
|
||||
input_texture = texture_pool().acquire_color(size);
|
||||
if (input_texture) {
|
||||
/* TODO: conversion could be done as part of GPU upload somehow? */
|
||||
const float *rgb_buffer = rpass->buffer.data;
|
||||
Vector<float> rgba_buffer(4 * size.x * size.y);
|
||||
for (size_t i = 0; (size_t)size.x * (size_t)size.y; i++) {
|
||||
rgba_buffer[i * 4 + 0] = rgb_buffer[i * 3 + 0];
|
||||
rgba_buffer[i * 4 + 1] = rgb_buffer[i * 3 + 1];
|
||||
rgba_buffer[i * 4 + 2] = rgb_buffer[i * 3 + 2];
|
||||
rgba_buffer[i * 4 + 3] = 1.0f;
|
||||
}
|
||||
GPU_texture_update(input_texture, GPU_DATA_FLOAT, rgba_buffer.data());
|
||||
}
|
||||
}
|
||||
else if (rpass->channels == 4) {
|
||||
input_texture = texture_pool().acquire_color(size);
|
||||
if (input_texture) {
|
||||
GPU_texture_update(input_texture, GPU_DATA_FLOAT, rpass->buffer.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (re) {
|
||||
RE_ReleaseResult(re);
|
||||
re = nullptr;
|
||||
}
|
||||
|
||||
return input_texture;
|
||||
}
|
||||
|
||||
StringRef get_view_name() override
|
||||
{
|
||||
return view_name_;
|
||||
}
|
||||
|
||||
void set_info_message(StringRef /* message */) const override
|
||||
{
|
||||
/* TODO: ignored for now. Currently only used to communicate incomplete node support
|
||||
* which is already shown on the node itself.
|
||||
*
|
||||
* Perhaps this overall info message could be replaced by a boolean indicating
|
||||
* incomplete support, and leave more specific message to individual nodes? */
|
||||
}
|
||||
|
||||
IDRecalcFlag query_id_recalc_flag(ID *id) const override
|
||||
{
|
||||
/* TODO: implement? */
|
||||
return IDRecalcFlag(0);
|
||||
}
|
||||
|
||||
void output_to_render_result()
|
||||
{
|
||||
Render *re = RE_GetSceneRender(&scene_);
|
||||
RenderResult *rr = RE_AcquireResultWrite(re);
|
||||
|
||||
if (rr) {
|
||||
RenderView *rv = RE_RenderViewGetByName(rr, view_name_);
|
||||
|
||||
GPU_memory_barrier(GPU_BARRIER_TEXTURE_UPDATE);
|
||||
float *output_buffer = (float *)GPU_texture_read(output_texture_, GPU_DATA_FLOAT, 0);
|
||||
|
||||
if (output_buffer) {
|
||||
RE_RenderBuffer_assign_data(&rv->combined_buffer, output_buffer);
|
||||
}
|
||||
|
||||
/* TODO: z-buffer output. */
|
||||
|
||||
rr->have_combined = true;
|
||||
}
|
||||
|
||||
if (re) {
|
||||
RE_ReleaseResult(re);
|
||||
re = nullptr;
|
||||
}
|
||||
|
||||
Image *image = BKE_image_ensure_viewer(G.main, IMA_TYPE_R_RESULT, "Render Result");
|
||||
BKE_image_partial_update_mark_full_update(image);
|
||||
BLI_thread_lock(LOCK_DRAW_IMAGE);
|
||||
BKE_image_signal(G.main, image, nullptr, IMA_SIGNAL_FREE);
|
||||
BLI_thread_unlock(LOCK_DRAW_IMAGE);
|
||||
}
|
||||
};
|
||||
|
||||
/* Render Realtime Compositor */
|
||||
|
||||
RealtimeCompositor::RealtimeCompositor(Render &render,
|
||||
const Scene &scene,
|
||||
const RenderData &render_data,
|
||||
const bNodeTree &node_tree,
|
||||
const bool use_file_output,
|
||||
const char *view_name)
|
||||
: render_(render)
|
||||
{
|
||||
/* Create resources with GPU context enabled. */
|
||||
DRW_render_context_enable(&render_);
|
||||
texture_pool_ = std::make_unique<TexturePool>();
|
||||
context_ = std::make_unique<Context>(
|
||||
scene, render_data, node_tree, use_file_output, view_name, *texture_pool_);
|
||||
evaluator_ = std::make_unique<realtime_compositor::Evaluator>(*context_);
|
||||
DRW_render_context_disable(&render_);
|
||||
}
|
||||
|
||||
RealtimeCompositor::~RealtimeCompositor()
|
||||
{
|
||||
/* Free resources with GPU context enabled. */
|
||||
DRW_render_context_enable(&render_);
|
||||
evaluator_.reset();
|
||||
context_.reset();
|
||||
texture_pool_.reset();
|
||||
DRW_render_context_disable(&render_);
|
||||
}
|
||||
|
||||
void RealtimeCompositor::execute()
|
||||
{
|
||||
DRW_render_context_enable(&render_);
|
||||
evaluator_->evaluate();
|
||||
context_->output_to_render_result();
|
||||
DRW_render_context_disable(&render_);
|
||||
}
|
||||
|
||||
void RealtimeCompositor::update(const Depsgraph *depsgraph)
|
||||
{
|
||||
/* TODO: implement */
|
||||
}
|
||||
|
||||
} // namespace blender::render
|
|
@ -1194,7 +1194,7 @@ static void do_render_compositor(Render *re)
|
|||
|
||||
LISTBASE_FOREACH (RenderView *, rv, &re->result->views) {
|
||||
ntreeCompositExecTree(
|
||||
re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name);
|
||||
re, re->pipeline_scene_eval, ntree, &re->r, true, G.background == 0, rv->name);
|
||||
}
|
||||
|
||||
ntree->runtime->stats_draw = nullptr;
|
||||
|
|
Loading…
Reference in New Issue