Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBrecht Van Lommel <brecht@blender.org>2021-12-07 22:49:34 +0300
committerBrecht Van Lommel <brecht@blender.org>2021-12-07 22:49:34 +0300
commit204ae33d755561e68ad3a6193d9a90d39d47d4da (patch)
treeb83e69f4b4deb024e848b2c45a346409779df26b
parentb81508841639aff7c0bc04accc2be265f554fdce (diff)
Revert "Fix T93350: Cycles renders shows black during rendering huge resolutions"
This reverts commit 5e37f70307bdacedd0f7da65f8b385bc1426f21d. It is leading to freezing of the entire desktop for a few seconds when stopping 3D viewport rendering on my Linux / NVIDIA system.
-rw-r--r--intern/cycles/blender/addon/properties.py2
-rw-r--r--intern/cycles/blender/display_driver.cpp720
-rw-r--r--intern/cycles/blender/display_driver.h67
-rw-r--r--intern/cycles/device/cuda/graphics_interop.cpp6
-rw-r--r--intern/cycles/integrator/path_trace.cpp11
-rw-r--r--intern/cycles/integrator/path_trace.h4
-rw-r--r--intern/cycles/integrator/path_trace_display.cpp11
-rw-r--r--intern/cycles/integrator/path_trace_display.h9
-rw-r--r--intern/cycles/integrator/path_trace_work.cpp8
-rw-r--r--intern/cycles/integrator/path_trace_work_gpu.cpp6
-rw-r--r--intern/cycles/session/display_driver.h13
-rw-r--r--intern/cycles/session/session.cpp5
-rw-r--r--intern/cycles/session/tile.cpp6
-rw-r--r--intern/cycles/session/tile.h6
14 files changed, 306 insertions, 568 deletions
diff --git a/intern/cycles/blender/addon/properties.py b/intern/cycles/blender/addon/properties.py
index 42f1e8f6f1a..0b1a86dfdc1 100644
--- a/intern/cycles/blender/addon/properties.py
+++ b/intern/cycles/blender/addon/properties.py
@@ -802,7 +802,7 @@ class CyclesRenderSettings(bpy.types.PropertyGroup):
name="Tile Size",
default=2048,
description="",
- min=8, max=8192,
+ min=8, max=16384,
)
# Various fine-tuning debug flags
diff --git a/intern/cycles/blender/display_driver.cpp b/intern/cycles/blender/display_driver.cpp
index d902edc4695..abf421983b3 100644
--- a/intern/cycles/blender/display_driver.cpp
+++ b/intern/cycles/blender/display_driver.cpp
@@ -273,299 +273,11 @@ uint BlenderDisplaySpaceShader::get_shader_program()
}
/* --------------------------------------------------------------------
- * DrawTile.
- */
-
-/* Higher level representation of a texture from the graphics library. */
-class GLTexture {
- public:
- /* Global counter for all allocated OpenGL textures used by instances of this class. */
- static inline std::atomic<int> num_used = 0;
-
- GLTexture() = default;
-
- ~GLTexture()
- {
- assert(gl_id == 0);
- }
-
- GLTexture(const GLTexture &other) = delete;
- GLTexture &operator=(GLTexture &other) = delete;
-
- GLTexture(GLTexture &&other) noexcept
- : gl_id(other.gl_id), width(other.width), height(other.height)
- {
- other.reset();
- }
-
- GLTexture &operator=(GLTexture &&other)
- {
- if (this == &other) {
- return *this;
- }
-
- gl_id = other.gl_id;
- width = other.width;
- height = other.height;
-
- other.reset();
-
- return *this;
- }
-
- bool gl_resources_ensure()
- {
- if (gl_id) {
- return true;
- }
-
- /* Create texture. */
- glGenTextures(1, &gl_id);
- if (!gl_id) {
- LOG(ERROR) << "Error creating texture.";
- return false;
- }
-
- /* Configure the texture. */
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, gl_id);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-
- /* Clamp to edge so that precision issues when zoomed out (which forces linear interpolation)
- * does not cause unwanted repetition. */
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-
- glBindTexture(GL_TEXTURE_2D, 0);
-
- ++num_used;
-
- return true;
- }
-
- void gl_resources_destroy()
- {
- if (!gl_id) {
- return;
- }
-
- glDeleteTextures(1, &gl_id);
-
- reset();
-
- --num_used;
- }
-
- /* OpenGL resource IDs of the texture.
- *
- * NOTE: Allocated on the render engine's context. */
- uint gl_id = 0;
-
- /* Dimensions of the texture in pixels. */
- int width = 0;
- int height = 0;
-
- protected:
- void reset()
- {
- gl_id = 0;
- width = 0;
- height = 0;
- }
-};
-
-/* Higher level representation of a Pixel Buffer Object (PBO) from the graphics library. */
-class GLPixelBufferObject {
- public:
- /* Global counter for all allocated OpenGL PBOs used by instances of this class. */
- static inline std::atomic<int> num_used = 0;
-
- GLPixelBufferObject() = default;
-
- ~GLPixelBufferObject()
- {
- assert(gl_id == 0);
- }
-
- GLPixelBufferObject(const GLPixelBufferObject &other) = delete;
- GLPixelBufferObject &operator=(GLPixelBufferObject &other) = delete;
-
- GLPixelBufferObject(GLPixelBufferObject &&other) noexcept
- : gl_id(other.gl_id), width(other.width), height(other.height)
- {
- other.reset();
- }
-
- GLPixelBufferObject &operator=(GLPixelBufferObject &&other)
- {
- if (this == &other) {
- return *this;
- }
-
- gl_id = other.gl_id;
- width = other.width;
- height = other.height;
-
- other.reset();
-
- return *this;
- }
-
- bool gl_resources_ensure()
- {
- if (gl_id) {
- return true;
- }
-
- glGenBuffers(1, &gl_id);
- if (!gl_id) {
- LOG(ERROR) << "Error creating texture pixel buffer object.";
- return false;
- }
-
- ++num_used;
-
- return true;
- }
-
- void gl_resources_destroy()
- {
- if (!gl_id) {
- return;
- }
-
- glDeleteBuffers(1, &gl_id);
-
- reset();
-
- --num_used;
- }
-
- /* OpenGL resource IDs of the PBO.
- *
- * NOTE: Allocated on the render engine's context. */
- uint gl_id = 0;
-
- /* Dimensions of the PBO. */
- int width = 0;
- int height = 0;
-
- protected:
- void reset()
- {
- gl_id = 0;
- width = 0;
- height = 0;
- }
-};
-
-class DrawTile {
- public:
- DrawTile() = default;
- ~DrawTile() = default;
-
- DrawTile(const DrawTile &other) = delete;
- DrawTile &operator=(const DrawTile &other) = delete;
-
- DrawTile(DrawTile &&other) noexcept = default;
-
- DrawTile &operator=(DrawTile &&other) = default;
-
- bool gl_resources_ensure()
- {
- if (!texture.gl_resources_ensure()) {
- gl_resources_destroy();
- return false;
- }
-
- if (!gl_vertex_buffer) {
- glGenBuffers(1, &gl_vertex_buffer);
- if (!gl_vertex_buffer) {
- LOG(ERROR) << "Error allocating tile VBO.";
- gl_resources_destroy();
- return false;
- }
- }
-
- return true;
- }
-
- void gl_resources_destroy()
- {
- texture.gl_resources_destroy();
-
- if (gl_vertex_buffer) {
- glDeleteBuffers(1, &gl_vertex_buffer);
- gl_vertex_buffer = 0;
- }
- }
-
- inline bool ready_to_draw() const
- {
- return texture.gl_id != 0;
- }
-
- /* Texture which contains pixels of the tile. */
- GLTexture texture;
-
- /* Display parameters the texture of this tile has been updated for. */
- BlenderDisplayDriver::Params params;
-
- /* OpenGL resources needed for drawing. */
- uint gl_vertex_buffer = 0;
-};
-
-class DrawTileAndPBO {
- public:
- bool gl_resources_ensure()
- {
- if (!tile.gl_resources_ensure() || !buffer_object.gl_resources_ensure()) {
- gl_resources_destroy();
- return false;
- }
-
- return true;
- }
-
- void gl_resources_destroy()
- {
- tile.gl_resources_destroy();
- buffer_object.gl_resources_destroy();
- }
-
- DrawTile tile;
- GLPixelBufferObject buffer_object;
-};
-
-/* --------------------------------------------------------------------
* BlenderDisplayDriver.
*/
-struct BlenderDisplayDriver::Tiles {
- /* Resources of a tile which is being currently rendered. */
- DrawTileAndPBO current_tile;
-
- /* All tiles which rendering is finished and which content will not be changed. */
- struct {
- vector<DrawTile> tiles;
-
- void gl_resources_destroy_and_clear()
- {
- for (DrawTile &tile : tiles) {
- tile.gl_resources_destroy();
- }
-
- tiles.clear();
- }
- } finished_tiles;
-};
-
BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
- : b_engine_(b_engine),
- display_shader_(BlenderDisplayShader::create(b_engine, b_scene)),
- tiles_(make_unique<Tiles>())
+ : b_engine_(b_engine), display_shader_(BlenderDisplayShader::create(b_engine, b_scene))
{
/* Create context while on the main thread. */
gl_context_create();
@@ -580,21 +292,6 @@ BlenderDisplayDriver::~BlenderDisplayDriver()
* Update procedure.
*/
-void BlenderDisplayDriver::next_tile_begin()
-{
- if (!tiles_->current_tile.tile.ready_to_draw()) {
- LOG(ERROR)
- << "Unexpectedly moving to the next tile without any data provided for current tile.";
- return;
- }
-
- /* Moving to the next tile without giving render data for the current tile is not an expected
- * situation. */
- DCHECK(!need_clear_);
-
- tiles_->finished_tiles.tiles.emplace_back(std::move(tiles_->current_tile.tile));
-}
-
bool BlenderDisplayDriver::update_begin(const Params &params,
int texture_width,
int texture_height)
@@ -615,33 +312,24 @@ bool BlenderDisplayDriver::update_begin(const Params &params,
glWaitSync((GLsync)gl_render_sync_, 0, GL_TIMEOUT_IGNORED);
}
- DrawTile &current_tile = tiles_->current_tile.tile;
- GLPixelBufferObject &current_tile_buffer_object = tiles_->current_tile.buffer_object;
-
- /* Clear storage of all finished tiles when display clear is requested.
- * Do it when new tile data is provided to handle the display clear flag in a single place.
- * It also makes the logic reliable from the whether drawing did happen or not point of view. */
- if (need_clear_) {
- tiles_->finished_tiles.gl_resources_destroy_and_clear();
- need_clear_ = false;
- }
-
- if (!tiles_->current_tile.gl_resources_ensure()) {
- tiles_->current_tile.gl_resources_destroy();
+ if (!gl_texture_resources_ensure()) {
gl_context_disable();
return false;
}
/* Update texture dimensions if needed. */
- if (current_tile.texture.width != texture_width ||
- current_tile.texture.height != texture_height) {
+ if (texture_.width != texture_width || texture_.height != texture_height) {
glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, current_tile.texture.gl_id);
+ glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
glTexImage2D(
GL_TEXTURE_2D, 0, GL_RGBA16F, texture_width, texture_height, 0, GL_RGBA, GL_HALF_FLOAT, 0);
- current_tile.texture.width = texture_width;
- current_tile.texture.height = texture_height;
+ texture_.width = texture_width;
+ texture_.height = texture_height;
glBindTexture(GL_TEXTURE_2D, 0);
+
+ /* Texture did change, and no pixel storage was provided. Tag for an explicit zeroing out to
+ * avoid undefined content. */
+ texture_.need_clear = true;
}
/* Update PBO dimensions if needed.
@@ -653,58 +341,29 @@ bool BlenderDisplayDriver::update_begin(const Params &params,
* sending too much data to GPU when resolution divider is not 1. */
/* TODO(sergey): Investigate whether keeping the PBO exact size of the texture makes non-interop
* mode faster. */
- const int buffer_width = params.size.x;
- const int buffer_height = params.size.y;
- if (current_tile_buffer_object.width != buffer_width ||
- current_tile_buffer_object.height != buffer_height) {
+ const int buffer_width = params.full_size.x;
+ const int buffer_height = params.full_size.y;
+ if (texture_.buffer_width != buffer_width || texture_.buffer_height != buffer_height) {
const size_t size_in_bytes = sizeof(half4) * buffer_width * buffer_height;
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, current_tile_buffer_object.gl_id);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
glBufferData(GL_PIXEL_UNPACK_BUFFER, size_in_bytes, 0, GL_DYNAMIC_DRAW);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- current_tile_buffer_object.width = buffer_width;
- current_tile_buffer_object.height = buffer_height;
+ texture_.buffer_width = buffer_width;
+ texture_.buffer_height = buffer_height;
}
- /* Store an updated parameters of the current tile.
- * In theory it is only needed once per update of the tile, but doing it on every update is
- * the easiest and is not expensive. */
- tiles_->current_tile.tile.params = params;
-
- return true;
-}
-
-static void update_tile_texture_pixels(const DrawTileAndPBO &tile)
-{
- const GLTexture &texture = tile.tile.texture;
-
- DCHECK_NE(tile.buffer_object.gl_id, 0);
+ /* New content will be provided to the texture in one way or another, so mark this in a
+ * centralized place. */
+ texture_.need_update = true;
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture.gl_id);
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, tile.buffer_object.gl_id);
-
- glTexSubImage2D(
- GL_TEXTURE_2D, 0, 0, 0, texture.width, texture.height, GL_RGBA, GL_HALF_FLOAT, 0);
+ texture_.params = params;
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
- glBindTexture(GL_TEXTURE_2D, 0);
+ return true;
}
void BlenderDisplayDriver::update_end()
{
- /* Unpack the PBO into the texture as soon as the new content is provided.
- *
- * This allows to ensure that the unpacking happens while resources like graphics interop (which
- * lifetime is outside of control of the display driver) are still valid, as well as allows to
- * move the tile from being current to finished immediately after this call.
- *
- * One concern with this approach is that if the update happens more often than drawing then
- * doing the unpack here occupies GPU transfer for no good reason. However, the render scheduler
- * takes care of ensuring updates don't happen that often. In regular applications redraw will
- * happen much more often than this update. */
- update_tile_texture_pixels(tiles_->current_tile);
-
gl_upload_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
@@ -717,11 +376,7 @@ void BlenderDisplayDriver::update_end()
half4 *BlenderDisplayDriver::map_texture_buffer()
{
- const uint pbo_gl_id = tiles_->current_tile.buffer_object.gl_id;
-
- DCHECK_NE(pbo_gl_id, 0);
-
- glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo_gl_id);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
half4 *mapped_rgba_pixels = reinterpret_cast<half4 *>(
glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY));
@@ -729,6 +384,15 @@ half4 *BlenderDisplayDriver::map_texture_buffer()
LOG(ERROR) << "Error mapping BlenderDisplayDriver pixel buffer object.";
}
+ if (texture_.need_clear) {
+ const int64_t texture_width = texture_.width;
+ const int64_t texture_height = texture_.height;
+ memset(reinterpret_cast<void *>(mapped_rgba_pixels),
+ 0,
+ texture_width * texture_height * sizeof(half4));
+ texture_.need_clear = false;
+ }
+
return mapped_rgba_pixels;
}
@@ -747,9 +411,12 @@ BlenderDisplayDriver::GraphicsInterop BlenderDisplayDriver::graphics_interop_get
{
GraphicsInterop interop_dst;
- interop_dst.buffer_width = tiles_->current_tile.buffer_object.width;
- interop_dst.buffer_height = tiles_->current_tile.buffer_object.height;
- interop_dst.opengl_pbo_id = tiles_->current_tile.buffer_object.gl_id;
+ interop_dst.buffer_width = texture_.buffer_width;
+ interop_dst.buffer_height = texture_.buffer_height;
+ interop_dst.opengl_pbo_id = texture_.gl_pbo_id;
+
+ interop_dst.need_clear = texture_.need_clear;
+ texture_.need_clear = false;
return interop_dst;
}
@@ -770,7 +437,7 @@ void BlenderDisplayDriver::graphics_interop_deactivate()
void BlenderDisplayDriver::clear()
{
- need_clear_ = true;
+ texture_.need_clear = true;
}
void BlenderDisplayDriver::set_zoom(float zoom_x, float zoom_y)
@@ -778,78 +445,42 @@ void BlenderDisplayDriver::set_zoom(float zoom_x, float zoom_y)
zoom_ = make_float2(zoom_x, zoom_y);
}
-/* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
- * This buffer is used to render texture in the viewport.
- *
- * NOTE: The buffer needs to be bound. */
-static void vertex_buffer_update(const DisplayDriver::Params &params)
+void BlenderDisplayDriver::draw(const Params &params)
{
- const int x = params.full_offset.x;
- const int y = params.full_offset.y;
-
- const int width = params.size.x;
- const int height = 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);
+ /* See do_update_begin() for why no locking is required here. */
+ const bool transparent = true; // TODO(sergey): Derive this from Film.
- float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
- if (!vpointer) {
+ if (!gl_draw_resources_ensure()) {
return;
}
- vpointer[0] = 0.0f;
- vpointer[1] = 0.0f;
- vpointer[2] = x;
- vpointer[3] = y;
-
- vpointer[4] = 1.0f;
- vpointer[5] = 0.0f;
- vpointer[6] = x + width;
- vpointer[7] = y;
-
- vpointer[8] = 1.0f;
- vpointer[9] = 1.0f;
- vpointer[10] = x + width;
- vpointer[11] = y + height;
-
- vpointer[12] = 0.0f;
- vpointer[13] = 1.0f;
- vpointer[14] = x;
- vpointer[15] = y + height;
-
- glUnmapBuffer(GL_ARRAY_BUFFER);
-}
+ if (use_gl_context_) {
+ gl_context_mutex_.lock();
+ }
-static void draw_tile(const float2 &zoom,
- const int texcoord_attribute,
- const int position_attribute,
- const DrawTile &draw_tile)
-{
- if (!draw_tile.ready_to_draw()) {
+ if (texture_.need_clear) {
+ /* Texture is requested to be cleared and was not yet cleared.
+ *
+ * Do early return which should be equivalent of drawing all-zero texture.
+ * Watch out for the lock though so that the clear happening during update is properly
+ * synchronized here. */
+ gl_context_mutex_.unlock();
return;
}
- const GLTexture &texture = draw_tile.texture;
-
- DCHECK_NE(texture.gl_id, 0);
- DCHECK_NE(draw_tile.gl_vertex_buffer, 0);
+ if (gl_upload_sync_) {
+ glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
+ }
- glBindBuffer(GL_ARRAY_BUFFER, draw_tile.gl_vertex_buffer);
+ if (transparent) {
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ }
- /* 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 parameters (although, complexity of
- * doing it might not worth it. */
- vertex_buffer_update(draw_tile.params);
+ display_shader_->bind(params.full_size.x, params.full_size.y);
- glBindTexture(GL_TEXTURE_2D, texture.gl_id);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture_.gl_id);
/* Trick to keep sharp rendering without jagged edges on all GPUs.
*
@@ -859,93 +490,53 @@ static void draw_tile(const float2 &zoom,
*
* Use explicit MIN assignment to make sure the driver does not have an undefined behavior at
* the zoom level 1. The MAG filter is always NEAREST. */
- const float zoomed_width = draw_tile.params.size.x * zoom.x;
- const float zoomed_height = draw_tile.params.size.y * zoom.y;
- if (texture.width != draw_tile.params.size.x || texture.height != draw_tile.params.size.y) {
+ 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 nearest interpolation. */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
}
- else if (zoomed_width - draw_tile.params.size.x > 0.5f ||
- zoomed_height - draw_tile.params.size.y > 0.5f) {
+ 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);
}
else {
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
}
- glVertexAttribPointer(
- texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
- glVertexAttribPointer(position_attribute,
- 2,
- GL_FLOAT,
- GL_FALSE,
- 4 * sizeof(float),
- (const GLvoid *)(sizeof(float) * 2));
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-}
+ glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_);
-void BlenderDisplayDriver::draw(const Params &params)
-{
- /* See do_update_begin() for why no locking is required here. */
- const bool transparent = true; // TODO(sergey): Derive this from Film.
-
- if (use_gl_context_) {
- gl_context_mutex_.lock();
- }
+ texture_update_if_needed();
+ vertex_buffer_update(params);
- if (need_clear_) {
- /* Texture is requested to be cleared and was not yet cleared.
- *
- * Do early return which should be equivalent of drawing all-zero texture.
- * Watch out for the lock though so that the clear happening during update is properly
- * synchronized here. */
- if (use_gl_context_) {
- gl_context_mutex_.unlock();
- }
- return;
- }
-
- if (gl_upload_sync_) {
- glWaitSync((GLsync)gl_upload_sync_, 0, GL_TIMEOUT_IGNORED);
- }
-
- if (transparent) {
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
- }
-
- glActiveTexture(GL_TEXTURE0);
-
- /* NOTE: THe VAO is to be allocated on the drawing context as it is not shared across contects.
- * Simplest is to allocate it on every redraw so that it is possible to destroy it from a
- * correct context. */
+ /* TODO(sergey): Does it make sense/possible to cache/reuse the VAO? */
GLuint vertex_array_object;
glGenVertexArrays(1, &vertex_array_object);
glBindVertexArray(vertex_array_object);
- display_shader_->bind(params.full_size.x, params.full_size.y);
-
const int texcoord_attribute = display_shader_->get_tex_coord_attrib_location();
const int position_attribute = display_shader_->get_position_attrib_location();
glEnableVertexAttribArray(texcoord_attribute);
glEnableVertexAttribArray(position_attribute);
- draw_tile(zoom_, texcoord_attribute, position_attribute, tiles_->current_tile.tile);
-
- for (const DrawTile &tile : tiles_->finished_tiles.tiles) {
- draw_tile(zoom_, texcoord_attribute, position_attribute, tile);
- }
+ glVertexAttribPointer(
+ texcoord_attribute, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (const GLvoid *)0);
+ glVertexAttribPointer(position_attribute,
+ 2,
+ GL_FLOAT,
+ GL_FALSE,
+ 4 * sizeof(float),
+ (const GLvoid *)(sizeof(float) * 2));
- display_shader_->unbind();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glBindTexture(GL_TEXTURE_2D, 0);
- glBindVertexArray(0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindTexture(GL_TEXTURE_2D, 0);
glDeleteVertexArrays(1, &vertex_array_object);
+ display_shader_->unbind();
+
if (transparent) {
glDisable(GL_BLEND);
}
@@ -953,11 +544,6 @@ void BlenderDisplayDriver::draw(const Params &params)
gl_render_sync_ = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
glFlush();
- if (VLOG_IS_ON(5)) {
- VLOG(5) << "Number of textures: " << GLTexture::num_used;
- VLOG(5) << "Number of PBOs: " << GLPixelBufferObject::num_used;
- }
-
if (use_gl_context_) {
gl_context_mutex_.unlock();
}
@@ -1032,16 +618,154 @@ void BlenderDisplayDriver::gl_context_dispose()
}
}
+bool BlenderDisplayDriver::gl_draw_resources_ensure()
+{
+ if (!texture_.gl_id) {
+ /* If there is no texture allocated, there is nothing to draw. Inform the draw call that it can
+ * can not continue. Note that this is not an unrecoverable error, so once the texture is known
+ * we will come back here and create all the GPU resources needed for draw. */
+ return false;
+ }
+
+ if (gl_draw_resource_creation_attempted_) {
+ return gl_draw_resources_created_;
+ }
+ gl_draw_resource_creation_attempted_ = true;
+
+ if (!vertex_buffer_) {
+ glGenBuffers(1, &vertex_buffer_);
+ if (!vertex_buffer_) {
+ LOG(ERROR) << "Error creating vertex buffer.";
+ return false;
+ }
+ }
+
+ gl_draw_resources_created_ = true;
+
+ return true;
+}
+
void BlenderDisplayDriver::gl_resources_destroy()
{
gl_context_enable();
- tiles_->current_tile.gl_resources_destroy();
- tiles_->finished_tiles.gl_resources_destroy_and_clear();
+ if (vertex_buffer_ != 0) {
+ glDeleteBuffers(1, &vertex_buffer_);
+ }
+
+ if (texture_.gl_pbo_id) {
+ glDeleteBuffers(1, &texture_.gl_pbo_id);
+ texture_.gl_pbo_id = 0;
+ }
+
+ if (texture_.gl_id) {
+ glDeleteTextures(1, &texture_.gl_id);
+ texture_.gl_id = 0;
+ }
gl_context_disable();
gl_context_dispose();
}
+bool BlenderDisplayDriver::gl_texture_resources_ensure()
+{
+ if (texture_.creation_attempted) {
+ return texture_.is_created;
+ }
+ texture_.creation_attempted = true;
+
+ DCHECK(!texture_.gl_id);
+ DCHECK(!texture_.gl_pbo_id);
+
+ /* Create texture. */
+ glGenTextures(1, &texture_.gl_id);
+ if (!texture_.gl_id) {
+ LOG(ERROR) << "Error creating texture.";
+ return false;
+ }
+
+ /* Configure the texture. */
+ glActiveTexture(GL_TEXTURE0);
+ 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);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ /* Create PBO for the texture. */
+ glGenBuffers(1, &texture_.gl_pbo_id);
+ if (!texture_.gl_pbo_id) {
+ LOG(ERROR) << "Error creating texture pixel buffer object.";
+ return false;
+ }
+
+ /* Creation finished with a success. */
+ texture_.is_created = true;
+
+ return true;
+}
+
+void BlenderDisplayDriver::texture_update_if_needed()
+{
+ if (!texture_.need_update) {
+ return;
+ }
+
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, texture_.gl_pbo_id);
+ glTexSubImage2D(
+ GL_TEXTURE_2D, 0, 0, 0, texture_.width, texture_.height, GL_RGBA, GL_HALF_FLOAT, 0);
+ glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
+
+ texture_.need_update = false;
+}
+
+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 parameters (although, 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);
+
+ float *vpointer = reinterpret_cast<float *>(glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY));
+ if (!vpointer) {
+ return;
+ }
+
+ vpointer[0] = 0.0f;
+ vpointer[1] = 0.0f;
+ vpointer[2] = x;
+ vpointer[3] = y;
+
+ vpointer[4] = 1.0f;
+ vpointer[5] = 0.0f;
+ vpointer[6] = x + width;
+ vpointer[7] = y;
+
+ vpointer[8] = 1.0f;
+ vpointer[9] = 1.0f;
+ vpointer[10] = x + width;
+ vpointer[11] = y + height;
+
+ vpointer[12] = 0.0f;
+ vpointer[13] = 1.0f;
+ vpointer[14] = x;
+ vpointer[15] = y + height;
+
+ glUnmapBuffer(GL_ARRAY_BUFFER);
+}
+
CCL_NAMESPACE_END
diff --git a/intern/cycles/blender/display_driver.h b/intern/cycles/blender/display_driver.h
index b9773f5eadf..66cfc8cffcc 100644
--- a/intern/cycles/blender/display_driver.h
+++ b/intern/cycles/blender/display_driver.h
@@ -26,7 +26,6 @@
#include "util/thread.h"
#include "util/unique_ptr.h"
-#include "util/vector.h"
CCL_NAMESPACE_BEGIN
@@ -113,8 +112,6 @@ class BlenderDisplayDriver : public DisplayDriver {
void set_zoom(float zoom_x, float zoom_y);
protected:
- virtual void next_tile_begin() override;
-
virtual bool update_begin(const Params &params, int texture_width, int texture_height) override;
virtual void update_end() override;
@@ -131,9 +128,27 @@ class BlenderDisplayDriver : public DisplayDriver {
void gl_context_disable();
void gl_context_dispose();
+ /* Make sure texture is allocated and its initial configuration is performed. */
+ bool gl_texture_resources_ensure();
+
+ /* Ensure all runtime GPU resources needed for drawing are allocated.
+ * Returns true if all resources needed for drawing are available. */
+ bool gl_draw_resources_ensure();
+
/* Destroy all GPU resources which are being used by this object. */
void gl_resources_destroy();
+ /* Update GPU texture dimensions and content if needed (new pixel data was provided).
+ *
+ * NOTE: The texture needs to be bound. */
+ void texture_update_if_needed();
+
+ /* Update vertex buffer with new coordinates of vertex positions and texture coordinates.
+ * This buffer is used to render texture in the viewport.
+ *
+ * NOTE: The buffer needs to be bound. */
+ void vertex_buffer_update(const Params &params);
+
BL::RenderEngine b_engine_;
/* OpenGL context which is used the render engine doesn't have its own. */
@@ -144,14 +159,50 @@ class BlenderDisplayDriver : public DisplayDriver {
/* Mutex used to guard the `gl_context_`. */
thread_mutex gl_context_mutex_;
- /* Content of the display is to be filled with zeroes. */
- std::atomic<bool> need_clear_ = true;
+ /* Texture which contains pixels of the render result. */
+ struct {
+ /* Indicates whether texture creation was attempted and succeeded.
+ * Used to avoid multiple attempts of texture creation on GPU issues or GPU context
+ * misconfiguration. */
+ bool creation_attempted = false;
+ bool is_created = false;
+
+ /* OpenGL resource IDs of the texture itself and Pixel Buffer Object (PBO) used to write
+ * pixels to it.
+ *
+ * NOTE: Allocated on the engine's context. */
+ uint gl_id = 0;
+ uint gl_pbo_id = 0;
+
+ /* Is true when new data was written to the PBO, meaning, the texture might need to be resized
+ * and new data is to be uploaded to the GPU. */
+ bool need_update = false;
+
+ /* Content of the texture is to be filled with zeroes. */
+ std::atomic<bool> need_clear = true;
+
+ /* Dimensions of the texture in pixels. */
+ int width = 0;
+ int height = 0;
+
+ /* 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_;
- /* Opaque storage for an internal state and data for tiles. */
- struct Tiles;
- unique_ptr<Tiles> tiles_;
+ /* Special track of whether GPU resources were attempted to be created, to avoid attempts of
+ * their re-creation on failure on every redraw. */
+ bool gl_draw_resource_creation_attempted_ = false;
+ bool gl_draw_resources_created_ = false;
+
+ /* Vertex buffer which hold vertices of a triangle fan which is textures with the texture
+ * holding the render result. */
+ uint vertex_buffer_ = 0;
void *gl_render_sync_ = nullptr;
void *gl_upload_sync_ = nullptr;
diff --git a/intern/cycles/device/cuda/graphics_interop.cpp b/intern/cycles/device/cuda/graphics_interop.cpp
index c75d7957460..30efefd9b6b 100644
--- a/intern/cycles/device/cuda/graphics_interop.cpp
+++ b/intern/cycles/device/cuda/graphics_interop.cpp
@@ -45,10 +45,8 @@ void CUDADeviceGraphicsInterop::set_display_interop(
need_clear_ = display_interop.need_clear;
- if (!display_interop.need_recreate) {
- if (opengl_pbo_id_ == display_interop.opengl_pbo_id && buffer_area_ == new_buffer_area) {
- return;
- }
+ if (opengl_pbo_id_ == display_interop.opengl_pbo_id && buffer_area_ == new_buffer_area) {
+ return;
}
CUDAContextScope scope(device_);
diff --git a/intern/cycles/integrator/path_trace.cpp b/intern/cycles/integrator/path_trace.cpp
index 28a012c2506..bdc18b1c0a1 100644
--- a/intern/cycles/integrator/path_trace.cpp
+++ b/intern/cycles/integrator/path_trace.cpp
@@ -115,9 +115,7 @@ bool PathTrace::ready_to_reset()
return false;
}
-void PathTrace::reset(const BufferParams &full_params,
- const BufferParams &big_tile_params,
- const bool reset_rendering)
+void PathTrace::reset(const BufferParams &full_params, const BufferParams &big_tile_params)
{
if (big_tile_params_.modified(big_tile_params)) {
big_tile_params_ = big_tile_params;
@@ -130,7 +128,7 @@ void PathTrace::reset(const BufferParams &full_params,
* It is requires to inform about reset whenever it happens, so that the redraw state tracking is
* properly updated. */
if (display_) {
- display_->reset(big_tile_params, reset_rendering);
+ display_->reset(full_params);
}
render_state_.has_denoised_result = false;
@@ -624,8 +622,9 @@ void PathTrace::update_display(const RenderWork &render_work)
if (display_) {
VLOG(3) << "Perform copy to GPUDisplay work.";
- const int texture_width = render_state_.effective_big_tile_params.window_width;
- const int texture_height = render_state_.effective_big_tile_params.window_height;
+ const int resolution_divider = render_work.resolution_divider;
+ const int texture_width = max(1, full_params_.width / resolution_divider);
+ const int texture_height = max(1, full_params_.height / resolution_divider);
if (!display_->update_begin(texture_width, texture_height)) {
LOG(ERROR) << "Error beginning GPUDisplay update.";
return;
diff --git a/intern/cycles/integrator/path_trace.h b/intern/cycles/integrator/path_trace.h
index 1ae48f82810..9b079352a63 100644
--- a/intern/cycles/integrator/path_trace.h
+++ b/intern/cycles/integrator/path_trace.h
@@ -72,9 +72,7 @@ class PathTrace {
* render result. */
bool ready_to_reset();
- void reset(const BufferParams &full_params,
- const BufferParams &big_tile_params,
- bool reset_rendering);
+ void reset(const BufferParams &full_params, const BufferParams &big_tile_params);
void device_free();
diff --git a/intern/cycles/integrator/path_trace_display.cpp b/intern/cycles/integrator/path_trace_display.cpp
index d6279f3298c..c1cade923b1 100644
--- a/intern/cycles/integrator/path_trace_display.cpp
+++ b/intern/cycles/integrator/path_trace_display.cpp
@@ -26,20 +26,15 @@ PathTraceDisplay::PathTraceDisplay(unique_ptr<DisplayDriver> driver) : driver_(m
{
}
-void PathTraceDisplay::reset(const BufferParams &buffer_params, const bool reset_rendering)
+void PathTraceDisplay::reset(const BufferParams &buffer_params)
{
thread_scoped_lock lock(mutex_);
- params_.full_offset = make_int2(buffer_params.full_x + buffer_params.window_x,
- buffer_params.full_y + buffer_params.window_y);
+ 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.window_width, buffer_params.window_height);
+ params_.size = make_int2(buffer_params.width, buffer_params.height);
texture_state_.is_outdated = true;
-
- if (!reset_rendering) {
- driver_->next_tile_begin();
- }
}
void PathTraceDisplay::mark_texture_updated()
diff --git a/intern/cycles/integrator/path_trace_display.h b/intern/cycles/integrator/path_trace_display.h
index be301e55359..47014f43afa 100644
--- a/intern/cycles/integrator/path_trace_display.h
+++ b/intern/cycles/integrator/path_trace_display.h
@@ -38,17 +38,14 @@ class BufferParams;
class PathTraceDisplay {
public:
- explicit PathTraceDisplay(unique_ptr<DisplayDriver> driver);
+ PathTraceDisplay(unique_ptr<DisplayDriver> driver);
virtual ~PathTraceDisplay() = default;
/* Reset the display for the new state of render session. Is called whenever session is reset,
* which happens on changes like viewport navigation or viewport dimension change.
*
- * This call will configure parameters for a changed buffer and reset the texture state.
- *
- * When the `reset_rendering` a complete displat reset happens. When it is false reset happens
- * for a new state of the buffer parameters which is assumed to correspond to the next tile. */
- void reset(const BufferParams &buffer_params, bool reset_rendering);
+ * This call will configure parameters for a changed buffer and reset the texture state. */
+ void reset(const BufferParams &buffer_params);
/* --------------------------------------------------------------------
* Update procedure.
diff --git a/intern/cycles/integrator/path_trace_work.cpp b/intern/cycles/integrator/path_trace_work.cpp
index 4ecc7d775ee..b0c40cfe15c 100644
--- a/intern/cycles/integrator/path_trace_work.cpp
+++ b/intern/cycles/integrator/path_trace_work.cpp
@@ -194,10 +194,10 @@ PassAccessor::Destination PathTraceWork::get_display_destination_template(
PassAccessor::Destination destination(film_->get_display_pass());
const int2 display_texture_size = display->get_texture_size();
- const int texture_x = effective_buffer_params_.full_x - effective_big_tile_params_.full_x +
- effective_buffer_params_.window_x - effective_big_tile_params_.window_x;
- const int texture_y = effective_buffer_params_.full_y - effective_big_tile_params_.full_y +
- effective_buffer_params_.window_y - effective_big_tile_params_.window_y;
+ const int texture_x = effective_buffer_params_.full_x - effective_full_params_.full_x +
+ effective_buffer_params_.window_x;
+ const int texture_y = effective_buffer_params_.full_y - effective_full_params_.full_y +
+ effective_buffer_params_.window_y;
destination.offset = texture_y * display_texture_size.x + texture_x;
destination.stride = display_texture_size.x;
diff --git a/intern/cycles/integrator/path_trace_work_gpu.cpp b/intern/cycles/integrator/path_trace_work_gpu.cpp
index 7a13447f2cf..e5062c6c47e 100644
--- a/intern/cycles/integrator/path_trace_work_gpu.cpp
+++ b/intern/cycles/integrator/path_trace_work_gpu.cpp
@@ -875,10 +875,8 @@ void PathTraceWorkGPU::copy_to_display_naive(PathTraceDisplay *display,
const int final_width = buffers_->params.window_width;
const int final_height = buffers_->params.window_height;
- const int texture_x = full_x - effective_big_tile_params_.full_x +
- effective_buffer_params_.window_x - effective_big_tile_params_.window_x;
- const int texture_y = full_y - effective_big_tile_params_.full_y +
- effective_buffer_params_.window_y - effective_big_tile_params_.window_y;
+ const int texture_x = full_x - effective_full_params_.full_x + effective_buffer_params_.window_x;
+ const int texture_y = full_y - effective_full_params_.full_y + effective_buffer_params_.window_y;
/* Re-allocate display memory if needed, and make sure the device pointer is allocated.
*
diff --git a/intern/cycles/session/display_driver.h b/intern/cycles/session/display_driver.h
index 5544ceee83d..77f89326fd0 100644
--- a/intern/cycles/session/display_driver.h
+++ b/intern/cycles/session/display_driver.h
@@ -54,8 +54,6 @@ class DisplayDriver {
}
};
- virtual void next_tile_begin() = 0;
-
/* Update the render from the rendering thread.
*
* Cycles periodically updates the render to be displayed. For multithreaded updates with
@@ -99,17 +97,6 @@ class DisplayDriver {
/* Clear the entire buffer before doing partial write to it. */
bool need_clear = false;
-
- /* Enforce re-creation of the graphics interop object.
- *
- * When this field is true then the graphics interop will be re-created no matter what the
- * rest of the configuration is.
- * When this field is false the graphics interop will be re-created if the PBO or buffer size
- * did change.
- *
- * This allows to ensure graphics interop is re-created when there is a possibility that an
- * underlying PBO was re-allocated but did not change its ID. */
- bool need_recreate = false;
};
virtual GraphicsInterop graphics_interop_get()
diff --git a/intern/cycles/session/session.cpp b/intern/cycles/session/session.cpp
index 4d8e3dfbfad..af5c6b3f1fd 100644
--- a/intern/cycles/session/session.cpp
+++ b/intern/cycles/session/session.cpp
@@ -303,7 +303,7 @@ RenderWork Session::run_update_for_next_iteration()
tile_params.update_offset_stride();
- path_trace_->reset(buffer_params_, tile_params, did_reset);
+ path_trace_->reset(buffer_params_, tile_params);
}
const int resolution = render_work.resolution_divider;
@@ -384,8 +384,7 @@ int2 Session::get_effective_tile_size() const
const int tile_size = tile_manager_.compute_render_tile_size(params.tile_size);
const int64_t actual_tile_area = static_cast<int64_t>(tile_size) * tile_size;
- if (actual_tile_area >= image_area && image_width <= TileManager::MAX_TILE_SIZE &&
- image_height <= TileManager::MAX_TILE_SIZE) {
+ if (actual_tile_area >= image_area) {
return make_int2(image_width, image_height);
}
diff --git a/intern/cycles/session/tile.cpp b/intern/cycles/session/tile.cpp
index afd1f334120..3b8482fa16f 100644
--- a/intern/cycles/session/tile.cpp
+++ b/intern/cycles/session/tile.cpp
@@ -341,10 +341,8 @@ int TileManager::compute_render_tile_size(const int suggested_tile_size) const
/* Must be a multiple of IMAGE_TILE_SIZE so that we can write render tiles into the image file
* aligned on image tile boundaries. We can't set IMAGE_TILE_SIZE equal to the render tile size
* because too big tile size leads to integer overflow inside OpenEXR. */
- const int computed_tile_size = (suggested_tile_size <= IMAGE_TILE_SIZE) ?
- suggested_tile_size :
- align_up(suggested_tile_size, IMAGE_TILE_SIZE);
- return min(computed_tile_size, MAX_TILE_SIZE);
+ return (suggested_tile_size <= IMAGE_TILE_SIZE) ? suggested_tile_size :
+ align_up(suggested_tile_size, IMAGE_TILE_SIZE);
}
void TileManager::reset_scheduling(const BufferParams &params, int2 tile_size)
diff --git a/intern/cycles/session/tile.h b/intern/cycles/session/tile.h
index 7c8f7570d3e..eace148eb0a 100644
--- a/intern/cycles/session/tile.h
+++ b/intern/cycles/session/tile.h
@@ -122,12 +122,6 @@ class TileManager {
/* Tile size in the image file. */
static const int IMAGE_TILE_SIZE = 128;
- /* Maximum supported tile size.
- * Needs to be safe from allocation on a GPU point of view: the display driver needs to be able
- * to allocate texture with the side size of this value.
- * Use conservative value which is safe for most of OpenGL drivers and GPUs. */
- static const int MAX_TILE_SIZE = 8192;
-
protected:
/* Get tile configuration for its index.
* The tile index must be within [0, state_.tile_state_). */