commit 6cab742eefabc7b685967f7e2dd9bb735da4cf49 Author: Sergey Sharybin Date: Wed Sep 22 10:59:49 2021 +0200 Fix bad image drawing during rendering on certain GPUs Reported by Thomas DInges: the default cube render in Cycles has jagged edges during rendering. Happens on AMD Radeon RX 5500 XT. diff --git a/intern/cycles/blender/blender_gpu_display.cpp b/intern/cycles/blender/blender_gpu_display.cpp index aa2a9c17a8a..ad3e6c8b777 100644 --- a/intern/cycles/blender/blender_gpu_display.cpp +++ b/intern/cycles/blender/blender_gpu_display.cpp @@ -20,6 +20,9 @@ #include "util/util_logging.h" #include "util/util_opengl.h" +#define USE_SOLUTION_1 1 +#define USE_SOLUTION_2 0 + extern "C" { struct RenderEngine; @@ -475,6 +478,11 @@ void BlenderGPUDisplay::clear() texture_.need_clear = true; } +void BlenderGPUDisplay::set_zoom(float zoom_x, float zoom_y) +{ + zoom_ = make_float2(zoom_x, zoom_y); +} + void BlenderGPUDisplay::do_draw(const GPUDisplayParams ¶ms) { /* See do_update_begin() for why no locking is required here. */ @@ -508,6 +516,31 @@ void BlenderGPUDisplay::do_draw(const GPUDisplayParams ¶ms) glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture_.gl_id); + /* Solution 1: Filter. */ +#if USE_SOLUTION_1 + /* Trick to keep sharp rendering without jagged edges on all GPUs. + * + * The idea here is to enforce driver to use linear interpolation when the image is not zoomed + * in. + * For the render result with a resolution divider in effect we always use nearest interpolation. + */ + const float zoomed_width = params.size.x * zoom_.x; + const float zoomed_height = params.size.y * zoom_.y; + if (texture_.width != params.size.x || texture_.height != params.size.y) { + /* Resolution divider is different from 1, force enarest interpolation. */ + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else if (zoomed_width - params.size.x > 0.5f || zoomed_height - params.size.y > 0.5f) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + } + else { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + } +#endif + glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_); texture_update_if_needed(); @@ -695,6 +728,10 @@ bool BlenderGPUDisplay::gl_texture_resources_ensure() glBindTexture(GL_TEXTURE_2D, texture_.gl_id); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); +#if USE_SOLUTION_2 + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); +#endif glBindTexture(GL_TEXTURE_2D, 0); /* Create PBO for the texture. */ @@ -735,23 +772,33 @@ void BlenderGPUDisplay::vertex_buffer_update(const GPUDisplayParams ¶ms) return; } - vpointer[0] = 0.0f; - vpointer[1] = 0.0f; + /* Solution 2: Offset. */ +#if USE_SOLUTION_2 + constexpr float GLA_PIXEL_OFS = 0.375f; + const float uv_offset_x = GLA_PIXEL_OFS / zoom_.x / params.size.x; + const float uv_offset_y = GLA_PIXEL_OFS / zoom_.y / params.size.y; +#else + const float uv_offset_x = 0.0f; + const float uv_offset_y = 0.0f; +#endif + + vpointer[0] = uv_offset_x; + vpointer[1] = uv_offset_y; vpointer[2] = params.offset.x; vpointer[3] = params.offset.y; - vpointer[4] = 1.0f; - vpointer[5] = 0.0f; + vpointer[4] = 1.0f + uv_offset_x; + vpointer[5] = uv_offset_y; vpointer[6] = (float)params.size.x + params.offset.x; vpointer[7] = params.offset.y; - vpointer[8] = 1.0f; - vpointer[9] = 1.0f; + vpointer[8] = 1.0f + uv_offset_x; + vpointer[9] = 1.0f + uv_offset_y; vpointer[10] = (float)params.size.x + params.offset.x; vpointer[11] = (float)params.size.y + params.offset.y; - vpointer[12] = 0.0f; - vpointer[13] = 1.0f; + vpointer[12] = uv_offset_x; + vpointer[13] = 1.0f + uv_offset_y; vpointer[14] = params.offset.x; vpointer[15] = (float)params.size.y + params.offset.y; diff --git a/intern/cycles/blender/blender_gpu_display.h b/intern/cycles/blender/blender_gpu_display.h index 1014c96cee4..89420567037 100644 --- a/intern/cycles/blender/blender_gpu_display.h +++ b/intern/cycles/blender/blender_gpu_display.h @@ -107,6 +107,8 @@ class BlenderGPUDisplay : public GPUDisplay { virtual void clear() override; + void set_zoom(float zoom_x, float zoom_y); + protected: virtual bool do_update_begin(const GPUDisplayParams ¶ms, int texture_width, @@ -206,6 +208,8 @@ class BlenderGPUDisplay : public GPUDisplay { void *gl_render_sync_ = nullptr; void *gl_upload_sync_ = nullptr; + + float2 zoom_ = make_float2(1.0f, 1.0f); }; CCL_NAMESPACE_END diff --git a/intern/cycles/blender/blender_session.cpp b/intern/cycles/blender/blender_session.cpp index 5aafa605526..d65d89a7ddd 100644 --- a/intern/cycles/blender/blender_session.cpp +++ b/intern/cycles/blender/blender_session.cpp @@ -158,7 +158,9 @@ void BlenderSession::create_session() /* Create GPU display. */ if (!b_engine.is_preview() && !headless) { - session->set_gpu_display(make_unique(b_engine, b_scene)); + unique_ptr gpu_display = make_unique(b_engine, b_scene); + gpu_display_ = gpu_display.get(); + session->set_gpu_display(move(gpu_display)); } /* Viewport and preview (as in, material preview) does not do tiled rendering, so can inform @@ -878,6 +880,9 @@ void BlenderSession::draw(BL::SpaceImageEditor &space_image) draw_state_.last_pass_index = pass_index; } + BL::Array zoom = space_image.zoom(); + gpu_display_->set_zoom(zoom[0], zoom[1]); + session->draw(); } diff --git a/intern/cycles/blender/blender_session.h b/intern/cycles/blender/blender_session.h index cf52359ea5d..11e2657a325 100644 --- a/intern/cycles/blender/blender_session.h +++ b/intern/cycles/blender/blender_session.h @@ -29,6 +29,7 @@ CCL_NAMESPACE_BEGIN +class BlenderGPUDisplay; class BlenderSync; class ImageMetaData; class Scene; @@ -159,6 +160,9 @@ class BlenderSession { int last_pass_index = -1; } draw_state_; + /* NOTE: The BlenderSession references the GPU display. */ + BlenderGPUDisplay *gpu_display_ = nullptr; + vector full_buffer_files_; };