Fix #126604: Legacy Cryptomatte doesn't work in GPU

The Legacy Cryptomatte node doesn't work in GPU execution mode if
Precision is set to Auto. That's because the colors picked from the Pick
layer might be in half precision and thus will not match the colors in
the Cryptomatte layers. This is due to the compositor using the
context's precision for Viewer outputs as opposed to the precision of
the image that actually needs to be viewed in the Viewer node.

To fix this, we set the Viewer node precision to be the precision of its
input, that way, the Cryptomatte pick layer will be output in full
precision as intended.

Pull Request: https://projects.blender.org/blender/blender/pulls/128495
This commit is contained in:
Omar Emara
2024-10-04 14:25:16 +02:00
committed by Omar Emara
parent 70c7fb6da2
commit ccab8005f6
4 changed files with 34 additions and 17 deletions

View File

@@ -85,8 +85,11 @@ class Context {
virtual Result get_output_result() = 0;
/* Get the result where the result of the compositor viewer should be written, given the domain
* of the result to be viewed and whether the output is a non-color data image. */
virtual Result get_viewer_output_result(Domain domain, bool is_data) = 0;
* of the result to be viewed, its precision, and whether the output is a non-color data image
* that should be displayed without view transform. */
virtual Result get_viewer_output_result(Domain domain,
bool is_data,
ResultPrecision precision) = 0;
/* Get the texture where the given render pass is stored. This should be called by the Render
* Layer node to populate its outputs. */

View File

@@ -141,8 +141,10 @@ class Context : public realtime_compositor::Context {
return result;
}
realtime_compositor::Result get_viewer_output_result(realtime_compositor::Domain /*domain*/,
bool /*is_data*/) override
realtime_compositor::Result get_viewer_output_result(
realtime_compositor::Domain /*domain*/,
bool /*is_data*/,
realtime_compositor::ResultPrecision /*precision*/) override
{
realtime_compositor::Result result = this->create_result(
realtime_compositor::ResultType::Color, realtime_compositor::ResultPrecision::Half);

View File

@@ -94,7 +94,8 @@ class ViewerOperation : public NodeOperation {
}
const Domain domain = compute_domain();
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
if (this->context().use_gpu()) {
GPU_texture_clear(output, GPU_DATA_FLOAT, color);
}
@@ -118,7 +119,8 @@ class ViewerOperation : public NodeOperation {
{
const Result &image = get_input("Image");
const Domain domain = compute_domain();
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
GPUShader *shader = context().get_shader("compositor_write_output_opaque", output.precision());
GPU_shader_bind(shader);
@@ -142,7 +144,8 @@ class ViewerOperation : public NodeOperation {
{
const Domain domain = compute_domain();
const Result &image = get_input("Image");
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
const Bounds<int2> bounds = get_output_bounds();
parallel_for(domain.size, [&](const int2 texel) {
@@ -170,7 +173,8 @@ class ViewerOperation : public NodeOperation {
{
const Result &image = get_input("Image");
const Domain domain = compute_domain();
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
GPUShader *shader = context().get_shader("compositor_write_output", output.precision());
GPU_shader_bind(shader);
@@ -194,7 +198,8 @@ class ViewerOperation : public NodeOperation {
{
const Domain domain = compute_domain();
const Result &image = get_input("Image");
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
const Bounds<int2> bounds = get_output_bounds();
parallel_for(domain.size, [&](const int2 texel) {
@@ -221,7 +226,8 @@ class ViewerOperation : public NodeOperation {
{
const Result &image = get_input("Image");
const Domain domain = compute_domain();
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
GPUShader *shader = context().get_shader("compositor_write_output_alpha", output.precision());
GPU_shader_bind(shader);
@@ -250,7 +256,8 @@ class ViewerOperation : public NodeOperation {
const Domain domain = compute_domain();
const Result &image = get_input("Image");
const Result &alpha = get_input("Alpha");
Result output = context().get_viewer_output_result(domain, image.meta_data.is_non_color_data);
Result output = context().get_viewer_output_result(
domain, image.meta_data.is_non_color_data, image.precision());
const Bounds<int2> bounds = get_output_bounds();
parallel_for(domain.size, [&](const int2 texel) {

View File

@@ -256,25 +256,30 @@ class Context : public realtime_compositor::Context {
return output_result_;
}
realtime_compositor::Result get_viewer_output_result(realtime_compositor::Domain domain,
const bool is_data) override
realtime_compositor::Result get_viewer_output_result(
realtime_compositor::Domain domain,
const bool is_data,
realtime_compositor::ResultPrecision precision) override
{
viewer_output_result_.set_transformation(domain.transformation);
viewer_output_result_.meta_data.is_non_color_data = is_data;
if (viewer_output_result_.is_allocated()) {
/* If the allocated result have the same size as the requested domain, return it as is. */
if (domain.size == viewer_output_result_.domain().size) {
/* If the allocated result have the same size and precision as requested, return it as is. */
if (domain.size == viewer_output_result_.domain().size &&
precision == viewer_output_result_.precision())
{
return viewer_output_result_;
}
else {
/* Otherwise, the size changed, so release its data and reset it, then we reallocate it on
* the new domain below. */
/* Otherwise, the size or precision changed, so release its data and reset it, then we
* reallocate it on the new domain below. */
viewer_output_result_.release();
viewer_output_result_.reset();
}
}
viewer_output_result_.set_precision(precision);
viewer_output_result_.allocate_texture(domain, false);
return viewer_output_result_;
}