Merge branch 'blender-v3.1-release'
This commit is contained in:
@@ -480,26 +480,12 @@ class DrawTile {
|
|||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gl_resources_destroy()
|
void gl_resources_destroy()
|
||||||
{
|
{
|
||||||
texture.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
|
inline bool ready_to_draw() const
|
||||||
@@ -512,9 +498,6 @@ class DrawTile {
|
|||||||
|
|
||||||
/* Display parameters the texture of this tile has been updated for. */
|
/* Display parameters the texture of this tile has been updated for. */
|
||||||
BlenderDisplayDriver::Params params;
|
BlenderDisplayDriver::Params params;
|
||||||
|
|
||||||
/* OpenGL resources needed for drawing. */
|
|
||||||
uint gl_vertex_buffer = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DrawTileAndPBO {
|
class DrawTileAndPBO {
|
||||||
@@ -560,6 +543,30 @@ struct BlenderDisplayDriver::Tiles {
|
|||||||
tiles.clear();
|
tiles.clear();
|
||||||
}
|
}
|
||||||
} finished_tiles;
|
} finished_tiles;
|
||||||
|
|
||||||
|
/* OpenGL vertex buffer needed for drawing. */
|
||||||
|
uint gl_vertex_buffer = 0;
|
||||||
|
|
||||||
|
bool gl_resources_ensure()
|
||||||
|
{
|
||||||
|
if (!gl_vertex_buffer) {
|
||||||
|
glGenBuffers(1, &gl_vertex_buffer);
|
||||||
|
if (!gl_vertex_buffer) {
|
||||||
|
LOG(ERROR) << "Error allocating tile VBO.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void gl_resources_destroy()
|
||||||
|
{
|
||||||
|
if (gl_vertex_buffer) {
|
||||||
|
glDeleteBuffers(1, &gl_vertex_buffer);
|
||||||
|
gl_vertex_buffer = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
|
BlenderDisplayDriver::BlenderDisplayDriver(BL::RenderEngine &b_engine, BL::Scene &b_scene)
|
||||||
@@ -626,6 +633,12 @@ bool BlenderDisplayDriver::update_begin(const Params ¶ms,
|
|||||||
need_clear_ = false;
|
need_clear_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!tiles_->gl_resources_ensure()) {
|
||||||
|
tiles_->gl_resources_destroy();
|
||||||
|
gl_context_disable();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (!tiles_->current_tile.gl_resources_ensure()) {
|
if (!tiles_->current_tile.gl_resources_ensure()) {
|
||||||
tiles_->current_tile.gl_resources_destroy();
|
tiles_->current_tile.gl_resources_destroy();
|
||||||
gl_context_disable();
|
gl_context_disable();
|
||||||
@@ -825,7 +838,8 @@ static void vertex_buffer_update(const DisplayDriver::Params ¶ms)
|
|||||||
static void draw_tile(const float2 &zoom,
|
static void draw_tile(const float2 &zoom,
|
||||||
const int texcoord_attribute,
|
const int texcoord_attribute,
|
||||||
const int position_attribute,
|
const int position_attribute,
|
||||||
const DrawTile &draw_tile)
|
const DrawTile &draw_tile,
|
||||||
|
const uint gl_vertex_buffer)
|
||||||
{
|
{
|
||||||
if (!draw_tile.ready_to_draw()) {
|
if (!draw_tile.ready_to_draw()) {
|
||||||
return;
|
return;
|
||||||
@@ -834,9 +848,9 @@ static void draw_tile(const float2 &zoom,
|
|||||||
const GLTexture &texture = draw_tile.texture;
|
const GLTexture &texture = draw_tile.texture;
|
||||||
|
|
||||||
DCHECK_NE(texture.gl_id, 0);
|
DCHECK_NE(texture.gl_id, 0);
|
||||||
DCHECK_NE(draw_tile.gl_vertex_buffer, 0);
|
DCHECK_NE(gl_vertex_buffer, 0);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, draw_tile.gl_vertex_buffer);
|
glBindBuffer(GL_ARRAY_BUFFER, gl_vertex_buffer);
|
||||||
|
|
||||||
/* Draw at the parameters for which the texture has been updated for. This allows to always draw
|
/* 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
|
* texture during bordered-rendered camera view without flickering. The validness of the display
|
||||||
@@ -956,10 +970,14 @@ void BlenderDisplayDriver::draw(const Params ¶ms)
|
|||||||
glEnableVertexAttribArray(texcoord_attribute);
|
glEnableVertexAttribArray(texcoord_attribute);
|
||||||
glEnableVertexAttribArray(position_attribute);
|
glEnableVertexAttribArray(position_attribute);
|
||||||
|
|
||||||
draw_tile(zoom_, texcoord_attribute, position_attribute, tiles_->current_tile.tile);
|
draw_tile(zoom_,
|
||||||
|
texcoord_attribute,
|
||||||
|
position_attribute,
|
||||||
|
tiles_->current_tile.tile,
|
||||||
|
tiles_->gl_vertex_buffer);
|
||||||
|
|
||||||
for (const DrawTile &tile : tiles_->finished_tiles.tiles) {
|
for (const DrawTile &tile : tiles_->finished_tiles.tiles) {
|
||||||
draw_tile(zoom_, texcoord_attribute, position_attribute, tile);
|
draw_tile(zoom_, texcoord_attribute, position_attribute, tile, tiles_->gl_vertex_buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
display_shader_->unbind();
|
display_shader_->unbind();
|
||||||
@@ -1062,6 +1080,7 @@ void BlenderDisplayDriver::gl_resources_destroy()
|
|||||||
|
|
||||||
tiles_->current_tile.gl_resources_destroy();
|
tiles_->current_tile.gl_resources_destroy();
|
||||||
tiles_->finished_tiles.gl_resources_destroy_and_clear();
|
tiles_->finished_tiles.gl_resources_destroy_and_clear();
|
||||||
|
tiles_->gl_resources_destroy();
|
||||||
|
|
||||||
gl_context_disable();
|
gl_context_disable();
|
||||||
|
|
||||||
|
@@ -49,12 +49,9 @@ Session::Session(const SessionParams ¶ms_, const SceneParams &scene_params)
|
|||||||
{
|
{
|
||||||
TaskScheduler::init(params.threads);
|
TaskScheduler::init(params.threads);
|
||||||
|
|
||||||
session_thread_ = nullptr;
|
|
||||||
|
|
||||||
delayed_reset_.do_reset = false;
|
delayed_reset_.do_reset = false;
|
||||||
|
|
||||||
pause_ = false;
|
pause_ = false;
|
||||||
cancel_ = false;
|
|
||||||
new_work_added_ = false;
|
new_work_added_ = false;
|
||||||
|
|
||||||
device = Device::create(params.device, stats, profiler);
|
device = Device::create(params.device, stats, profiler);
|
||||||
@@ -73,48 +70,79 @@ Session::Session(const SessionParams ¶ms_, const SceneParams &scene_params)
|
|||||||
}
|
}
|
||||||
full_buffer_written_cb(filename);
|
full_buffer_written_cb(filename);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Create session thread. */
|
||||||
|
session_thread_ = new thread(function_bind(&Session::thread_run, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
Session::~Session()
|
Session::~Session()
|
||||||
{
|
{
|
||||||
|
/* Cancel any ongoing render operation. */
|
||||||
cancel();
|
cancel();
|
||||||
|
|
||||||
/* Make sure path tracer is destroyed before the device. This is needed because destruction might
|
/* Signal session thread to end. */
|
||||||
* need to access device for device memory free. */
|
{
|
||||||
/* TODO(sergey): Convert device to be unique_ptr, and rely on C++ to destruct objects in the
|
thread_scoped_lock session_thread_lock(session_thread_mutex_);
|
||||||
|
session_thread_state_ = SESSION_THREAD_END;
|
||||||
|
}
|
||||||
|
session_thread_cond_.notify_all();
|
||||||
|
|
||||||
|
/* Destroy session thread. */
|
||||||
|
session_thread_->join();
|
||||||
|
delete session_thread_;
|
||||||
|
|
||||||
|
/* Destroy path tracer, before the device. This is needed because destruction might need to
|
||||||
|
* access device for device memory free.
|
||||||
|
* TODO(sergey): Convert device to be unique_ptr, and rely on C++ to destruct objects in the
|
||||||
* pre-defined order. */
|
* pre-defined order. */
|
||||||
path_trace_.reset();
|
path_trace_.reset();
|
||||||
|
|
||||||
|
/* Destroy scene and device. */
|
||||||
delete scene;
|
delete scene;
|
||||||
delete device;
|
delete device;
|
||||||
|
|
||||||
|
/* Stop task scheduler. */
|
||||||
TaskScheduler::exit();
|
TaskScheduler::exit();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::start()
|
void Session::start()
|
||||||
{
|
{
|
||||||
if (!session_thread_) {
|
{
|
||||||
session_thread_ = new thread(function_bind(&Session::run, this));
|
/* Signal session thread to start rendering. */
|
||||||
|
thread_scoped_lock session_thread_lock(session_thread_mutex_);
|
||||||
|
assert(session_thread_state_ == SESSION_THREAD_WAIT);
|
||||||
|
session_thread_state_ = SESSION_THREAD_RENDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
session_thread_cond_.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::cancel(bool quick)
|
void Session::cancel(bool quick)
|
||||||
{
|
{
|
||||||
if (quick && path_trace_) {
|
/* Check if session thread is rendering. */
|
||||||
path_trace_->cancel();
|
bool rendering;
|
||||||
|
{
|
||||||
|
thread_scoped_lock session_thread_lock(session_thread_mutex_);
|
||||||
|
rendering = (session_thread_state_ == SESSION_THREAD_RENDER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (session_thread_) {
|
if (rendering) {
|
||||||
/* wait for session thread to end */
|
/* Cancel path trace operations. */
|
||||||
|
if (quick && path_trace_) {
|
||||||
|
path_trace_->cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Cancel other operations. */
|
||||||
progress.set_cancel("Exiting");
|
progress.set_cancel("Exiting");
|
||||||
|
|
||||||
|
/* Signal unpause in case the render was paused. */
|
||||||
{
|
{
|
||||||
thread_scoped_lock pause_lock(pause_mutex_);
|
thread_scoped_lock pause_lock(pause_mutex_);
|
||||||
pause_ = false;
|
pause_ = false;
|
||||||
cancel_ = true;
|
|
||||||
}
|
}
|
||||||
pause_cond_.notify_all();
|
pause_cond_.notify_all();
|
||||||
|
|
||||||
|
/* Wait for render thread to be cancelled or finished. */
|
||||||
wait();
|
wait();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -192,11 +220,46 @@ void Session::run_main_render_loop()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
path_trace_->flush_display();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Session::run()
|
void Session::thread_run()
|
||||||
|
{
|
||||||
|
while (true) {
|
||||||
|
{
|
||||||
|
thread_scoped_lock session_thread_lock(session_thread_mutex_);
|
||||||
|
|
||||||
|
if (session_thread_state_ == SESSION_THREAD_WAIT) {
|
||||||
|
/* Continue waiting for any signal from the main thread. */
|
||||||
|
session_thread_cond_.wait(session_thread_lock);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
else if (session_thread_state_ == SESSION_THREAD_END) {
|
||||||
|
/* End thread immediately. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Execute a render. */
|
||||||
|
thread_render();
|
||||||
|
|
||||||
|
/* Go back from rendering to waiting. */
|
||||||
|
{
|
||||||
|
thread_scoped_lock session_thread_lock(session_thread_mutex_);
|
||||||
|
if (session_thread_state_ == SESSION_THREAD_RENDER) {
|
||||||
|
session_thread_state_ = SESSION_THREAD_WAIT;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
session_thread_cond_.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flush any remaining operations and destroy display driver here. This ensure
|
||||||
|
* graphics API resources are created and destroyed all in the session thread,
|
||||||
|
* which can avoid problems contexts and multiple threads. */
|
||||||
|
path_trace_->flush_display();
|
||||||
|
path_trace_->set_display_driver(nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Session::thread_render()
|
||||||
{
|
{
|
||||||
if (params.use_profiling && (params.device.type == DEVICE_CPU)) {
|
if (params.use_profiling && (params.device.type == DEVICE_CPU)) {
|
||||||
profiler.start();
|
profiler.start();
|
||||||
@@ -338,9 +401,9 @@ bool Session::run_wait_for_work(const RenderWork &render_work)
|
|||||||
const bool no_work = !render_work;
|
const bool no_work = !render_work;
|
||||||
update_status_time(pause_, no_work);
|
update_status_time(pause_, no_work);
|
||||||
|
|
||||||
/* Only leave the loop when rendering is not paused. But even if the current render is un-paused
|
/* Only leave the loop when rendering is not paused. But even if the current render is
|
||||||
* but there is nothing to render keep waiting until new work is added. */
|
* un-paused but there is nothing to render keep waiting until new work is added. */
|
||||||
while (!cancel_) {
|
while (!progress.get_cancel()) {
|
||||||
scoped_timer pause_timer;
|
scoped_timer pause_timer;
|
||||||
|
|
||||||
if (!pause_ && (render_work || new_work_added_ || delayed_reset_.do_reset)) {
|
if (!pause_ && (render_work || new_work_added_ || delayed_reset_.do_reset)) {
|
||||||
@@ -427,7 +490,8 @@ void Session::do_delayed_reset()
|
|||||||
tile_manager_.update(buffer_params_, scene);
|
tile_manager_.update(buffer_params_, scene);
|
||||||
|
|
||||||
/* Update temp directory on reset.
|
/* Update temp directory on reset.
|
||||||
* This potentially allows to finish the existing rendering with a previously configure temporary
|
* This potentially allows to finish the existing rendering with a previously configure
|
||||||
|
* temporary
|
||||||
* directory in the host software and switch to a new temp directory when new render starts. */
|
* directory in the host software and switch to a new temp directory when new render starts. */
|
||||||
tile_manager_.set_temp_dir(params.temp_dir);
|
tile_manager_.set_temp_dir(params.temp_dir);
|
||||||
|
|
||||||
@@ -544,12 +608,14 @@ double Session::get_estimated_remaining_time() const
|
|||||||
|
|
||||||
void Session::wait()
|
void Session::wait()
|
||||||
{
|
{
|
||||||
if (session_thread_) {
|
/* Wait until session thread either is waiting or ending. */
|
||||||
session_thread_->join();
|
while (true) {
|
||||||
delete session_thread_;
|
thread_scoped_lock session_thread_lock(session_thread_mutex_);
|
||||||
|
if (session_thread_state_ != SESSION_THREAD_RENDER) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
session_thread_cond_.wait(session_thread_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
session_thread_ = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Session::update_scene(int width, int height)
|
bool Session::update_scene(int width, int height)
|
||||||
|
@@ -172,7 +172,8 @@ class Session {
|
|||||||
BufferParams buffer_params;
|
BufferParams buffer_params;
|
||||||
} delayed_reset_;
|
} delayed_reset_;
|
||||||
|
|
||||||
void run();
|
void thread_run();
|
||||||
|
void thread_render();
|
||||||
|
|
||||||
/* Update for the new iteration of the main loop in run implementation (run_cpu and run_gpu).
|
/* Update for the new iteration of the main loop in run implementation (run_cpu and run_gpu).
|
||||||
*
|
*
|
||||||
@@ -205,10 +206,19 @@ class Session {
|
|||||||
|
|
||||||
int2 get_effective_tile_size() const;
|
int2 get_effective_tile_size() const;
|
||||||
|
|
||||||
thread *session_thread_;
|
/* Session thread that performs rendering tasks decoupled from the thread
|
||||||
|
* controlling the sessions. The thread is created and destroyed along with
|
||||||
|
* the session. */
|
||||||
|
thread *session_thread_ = nullptr;
|
||||||
|
thread_condition_variable session_thread_cond_;
|
||||||
|
thread_mutex session_thread_mutex_;
|
||||||
|
enum {
|
||||||
|
SESSION_THREAD_WAIT,
|
||||||
|
SESSION_THREAD_RENDER,
|
||||||
|
SESSION_THREAD_END,
|
||||||
|
} session_thread_state_ = SESSION_THREAD_WAIT;
|
||||||
|
|
||||||
bool pause_ = false;
|
bool pause_ = false;
|
||||||
bool cancel_ = false;
|
|
||||||
bool new_work_added_ = false;
|
bool new_work_added_ = false;
|
||||||
|
|
||||||
thread_condition_variable pause_cond_;
|
thread_condition_variable pause_cond_;
|
||||||
|
@@ -683,19 +683,16 @@ if(WITH_CYCLES OR WITH_OPENGL_RENDER_TESTS)
|
|||||||
set(_cycles_render_tests bake;${render_tests};osl)
|
set(_cycles_render_tests bake;${render_tests};osl)
|
||||||
|
|
||||||
foreach(render_test ${_cycles_render_tests})
|
foreach(render_test ${_cycles_render_tests})
|
||||||
# Enable just one simple test for Metal until more tests are passing.
|
add_python_test(
|
||||||
if((NOT (_cycles_device MATCHES "METAL")) OR (render_test MATCHES "camera"))
|
cycles_${render_test}_${_cycles_device_lower}
|
||||||
add_python_test(
|
${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
|
||||||
cycles_${render_test}_${_cycles_device_lower}
|
-blender "${TEST_BLENDER_EXE}"
|
||||||
${CMAKE_CURRENT_LIST_DIR}/cycles_render_tests.py
|
-testdir "${TEST_SRC_DIR}/render/${render_test}"
|
||||||
-blender "${TEST_BLENDER_EXE}"
|
-idiff "${OPENIMAGEIO_IDIFF}"
|
||||||
-testdir "${TEST_SRC_DIR}/render/${render_test}"
|
-outdir "${TEST_OUT_DIR}/cycles"
|
||||||
-idiff "${OPENIMAGEIO_IDIFF}"
|
-device ${_cycles_device}
|
||||||
-outdir "${TEST_OUT_DIR}/cycles"
|
-blacklist ${_cycles_blacklist}
|
||||||
-device ${_cycles_device}
|
)
|
||||||
-blacklist ${_cycles_blacklist}
|
|
||||||
)
|
|
||||||
endif()
|
|
||||||
endforeach()
|
endforeach()
|
||||||
endforeach()
|
endforeach()
|
||||||
endif()
|
endif()
|
||||||
|
Reference in New Issue
Block a user