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 /intern/cycles/blender/display_driver.cpp
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.
Diffstat (limited to 'intern/cycles/blender/display_driver.cpp')
-rw-r--r--intern/cycles/blender/display_driver.cpp720
1 files changed, 222 insertions, 498 deletions
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