Fix T92073: Cycles flicker when panning in camera view with border render

Panning in camera view makes the border to be modified, which was causing
the Cycles display to believe the rendered result is unusable.

The solution is to draw the render result at the display parameters it was
updated for. This allows to avoid flickering during panning, zooming, and
camera FOV changes. The suboptimal aspect of this is that it has some jelly
effect, although it is on the same level as jelly effect of object outline
so it is not terrible.

Differential Revision: https://developer.blender.org/D12970
This commit is contained in:
Sergey Sharybin 2021-10-22 17:24:18 +02:00
parent beea601e72
commit 31f6e78370
Notes: blender-bot 2023-02-14 00:37:17 +01:00
Referenced by issue #92073, Cycles: Viewport flashes when moving in the camera view with Render Region/Passepartout
4 changed files with 30 additions and 36 deletions

View File

@ -357,6 +357,8 @@ bool BlenderDisplayDriver::update_begin(const Params &params,
* centralized place. */
texture_.need_update = true;
texture_.params = params;
return true;
}
@ -717,8 +719,23 @@ void BlenderDisplayDriver::texture_update_if_needed()
texture_.need_update = false;
}
void BlenderDisplayDriver::vertex_buffer_update(const Params &params)
void BlenderDisplayDriver::vertex_buffer_update(const Params & /*params*/)
{
/* Draw at the parameters for which the texture has been updated for. This allows to always draw
* texture during bordered-rendered camera view without flickering. The validness of the display
* parameters for a texture is guaranteed by the initial "clear" state which makes drawing to
* have an early output.
*
* Such approach can cause some extra "jelly" effect during panning, but it is not more jelly
* than overlay of selected objects. Also, it's possible to redraw texture at an intersection of
* the texture draw parameters and the latest updated draw paaremters (altohoyugh, complexity of
* doing it might not worth it. */
const int x = texture_.params.full_offset.x;
const int y = texture_.params.full_offset.y;
const int width = texture_.params.size.x;
const int height = texture_.params.size.y;
/* Invalidate old contents - avoids stalling if the buffer is still waiting in queue to be
* rendered. */
glBufferData(GL_ARRAY_BUFFER, 16 * sizeof(float), NULL, GL_STREAM_DRAW);
@ -730,23 +747,23 @@ void BlenderDisplayDriver::vertex_buffer_update(const Params &params)
vpointer[0] = 0.0f;
vpointer[1] = 0.0f;
vpointer[2] = params.full_offset.x;
vpointer[3] = params.full_offset.y;
vpointer[2] = x;
vpointer[3] = y;
vpointer[4] = 1.0f;
vpointer[5] = 0.0f;
vpointer[6] = (float)params.size.x + params.full_offset.x;
vpointer[7] = params.full_offset.y;
vpointer[6] = x + width;
vpointer[7] = y;
vpointer[8] = 1.0f;
vpointer[9] = 1.0f;
vpointer[10] = (float)params.size.x + params.full_offset.x;
vpointer[11] = (float)params.size.y + params.full_offset.y;
vpointer[10] = x + width;
vpointer[11] = y + height;
vpointer[12] = 0.0f;
vpointer[13] = 1.0f;
vpointer[14] = params.full_offset.x;
vpointer[15] = (float)params.size.y + params.full_offset.y;
vpointer[14] = x;
vpointer[15] = y + height;
glUnmapBuffer(GL_ARRAY_BUFFER);
}

View File

@ -188,6 +188,9 @@ class BlenderDisplayDriver : public DisplayDriver {
/* Dimensions of the underlying PBO. */
int buffer_width = 0;
int buffer_height = 0;
/* Display parameters the texture has been updated for. */
Params params;
} texture_;
unique_ptr<BlenderDisplayShader> display_shader_;

View File

@ -30,29 +30,16 @@ void PathTraceDisplay::reset(const BufferParams &buffer_params)
{
thread_scoped_lock lock(mutex_);
const DisplayDriver::Params old_params = params_;
params_.full_offset = make_int2(buffer_params.full_x, buffer_params.full_y);
params_.full_size = make_int2(buffer_params.full_width, buffer_params.full_height);
params_.size = make_int2(buffer_params.width, buffer_params.height);
/* If the parameters did change tag texture as unusable. This avoids drawing old texture content
* in an updated configuration of the viewport. For example, avoids drawing old frame when render
* border did change.
* If the parameters did not change, allow drawing the current state of the texture, which will
* not count as an up-to-date redraw. This will avoid flickering when doping camera navigation by
* showing a previously rendered frame for until the new one is ready. */
if (old_params.modified(params_)) {
texture_state_.is_usable = false;
}
texture_state_.is_outdated = true;
}
void PathTraceDisplay::mark_texture_updated()
{
texture_state_.is_outdated = false;
texture_state_.is_usable = true;
}
/* --------------------------------------------------------------------
@ -248,19 +235,15 @@ bool PathTraceDisplay::draw()
* The drawing itself is non-blocking however, for better performance and to avoid
* potential deadlocks due to locks held by the subclass. */
DisplayDriver::Params params;
bool is_usable;
bool is_outdated;
{
thread_scoped_lock lock(mutex_);
params = params_;
is_usable = texture_state_.is_usable;
is_outdated = texture_state_.is_outdated;
}
if (is_usable) {
driver_->draw(params);
}
driver_->draw(params);
return !is_outdated;
}

View File

@ -174,15 +174,6 @@ class PathTraceDisplay {
/* State of the texture, which is needed for an integration with render session and interactive
* updates and navigation. */
struct {
/* Denotes whether possibly existing state of GPU side texture is still usable.
* It will not be usable in cases like render border did change (in this case we don't want
* previous texture to be rendered at all).
*
* However, if only navigation or object in scene did change, then the outdated state of the
* texture is still usable for draw, preventing display viewport flickering on navigation and
* object modifications. */
bool is_usable = false;
/* Texture is considered outdated after `reset()` until the next call of
* `copy_pixels_to_texture()`. */
bool is_outdated = true;