|
|
@@ -1134,47 +1134,9 @@ flip_frame() {
|
|
|
*/
|
|
|
bool GraphicsEngine::
|
|
|
extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) {
|
|
|
- ReMutexHolder holder(_lock);
|
|
|
-
|
|
|
- string draw_name = gsg->get_threading_model().get_draw_name();
|
|
|
- if (draw_name.empty()) {
|
|
|
- // A single-threaded environment. No problem.
|
|
|
+ return run_on_draw_thread([=] () {
|
|
|
return gsg->extract_texture_data(tex);
|
|
|
-
|
|
|
- } else {
|
|
|
- // A multi-threaded environment. We have to wait until the draw thread
|
|
|
- // has finished its current task.
|
|
|
- WindowRenderer *wr = get_window_renderer(draw_name, 0);
|
|
|
- RenderThread *thread = (RenderThread *)wr;
|
|
|
- MutexHolder cv_holder(thread->_cv_mutex);
|
|
|
-
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- // Temporarily set this so that it accesses data from the current thread.
|
|
|
- int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
|
- int draw_pipeline_stage = thread->get_pipeline_stage();
|
|
|
- thread->set_pipeline_stage(pipeline_stage);
|
|
|
-
|
|
|
- // Now that the draw thread is idle, signal it to do the extraction task.
|
|
|
- thread->_gsg = gsg;
|
|
|
- thread->_texture = tex;
|
|
|
- thread->_thread_state = TS_do_extract_texture_data;
|
|
|
- thread->_cv_mutex.release();
|
|
|
- thread->_cv_start.notify();
|
|
|
- thread->_cv_mutex.acquire();
|
|
|
-
|
|
|
- // Wait for it to finish the extraction.
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- thread->set_pipeline_stage(draw_pipeline_stage);
|
|
|
- thread->_gsg = nullptr;
|
|
|
- thread->_texture = nullptr;
|
|
|
- return thread->_result;
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1189,56 +1151,13 @@ extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg) {
|
|
|
*/
|
|
|
vector_uchar GraphicsEngine::
|
|
|
extract_shader_buffer_data(ShaderBuffer *buffer, GraphicsStateGuardian *gsg) {
|
|
|
- ReMutexHolder holder(_lock);
|
|
|
-
|
|
|
- string draw_name = gsg->get_threading_model().get_draw_name();
|
|
|
- if (draw_name.empty()) {
|
|
|
- // A single-threaded environment. No problem.
|
|
|
+ return run_on_draw_thread([=] () {
|
|
|
vector_uchar data;
|
|
|
if (!gsg->extract_shader_buffer_data(buffer, data)) {
|
|
|
data.clear();
|
|
|
}
|
|
|
return data;
|
|
|
- }
|
|
|
-
|
|
|
- // A multi-threaded environment. We have to wait until the draw thread
|
|
|
- // has finished its current task.
|
|
|
- WindowRenderer *wr = get_window_renderer(draw_name, 0);
|
|
|
- RenderThread *thread = (RenderThread *)wr;
|
|
|
- MutexHolder cv_holder(thread->_cv_mutex);
|
|
|
-
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- // Temporarily set this so that it accesses data from the current thread.
|
|
|
- int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
|
- int draw_pipeline_stage = thread->get_pipeline_stage();
|
|
|
- thread->set_pipeline_stage(pipeline_stage);
|
|
|
-
|
|
|
- // Now that the draw thread is idle, signal it to do the extraction task.
|
|
|
- vector_uchar data;
|
|
|
- thread->_gsg = gsg;
|
|
|
- thread->_buffer = buffer;
|
|
|
- thread->_buffer_result = &data;
|
|
|
- thread->_thread_state = TS_do_extract_shader_buffer_data;
|
|
|
- thread->_cv_mutex.release();
|
|
|
- thread->_cv_start.notify();
|
|
|
- thread->_cv_mutex.acquire();
|
|
|
-
|
|
|
- // Wait for it to finish the extraction.
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- thread->set_pipeline_stage(draw_pipeline_stage);
|
|
|
- thread->_gsg = nullptr;
|
|
|
- thread->_buffer = nullptr;
|
|
|
- thread->_buffer_result = nullptr;
|
|
|
- if (!thread->_result) {
|
|
|
- data.clear();
|
|
|
- }
|
|
|
- return data;
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1263,50 +1182,12 @@ dispatch_compute(const LVecBase3i &work_groups, const RenderState *state, Graphi
|
|
|
nassertv(shader != nullptr);
|
|
|
nassertv(gsg != nullptr);
|
|
|
|
|
|
- ReMutexHolder holder(_lock);
|
|
|
-
|
|
|
- string draw_name = gsg->get_threading_model().get_draw_name();
|
|
|
- if (draw_name.empty()) {
|
|
|
- // A single-threaded environment. No problem.
|
|
|
+ run_on_draw_thread([=] () {
|
|
|
gsg->push_group_marker(std::string("Compute ") + shader->get_filename(Shader::ST_compute).get_basename());
|
|
|
gsg->set_state_and_transform(state, TransformState::make_identity());
|
|
|
gsg->dispatch_compute(work_groups[0], work_groups[1], work_groups[2]);
|
|
|
gsg->pop_group_marker();
|
|
|
-
|
|
|
- } else {
|
|
|
- // A multi-threaded environment. We have to wait until the draw thread
|
|
|
- // has finished its current task.
|
|
|
- WindowRenderer *wr = get_window_renderer(draw_name, 0);
|
|
|
- RenderThread *thread = (RenderThread *)wr;
|
|
|
- MutexHolder cv_holder(thread->_cv_mutex);
|
|
|
-
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- // Temporarily set this so that it accesses data from the current thread.
|
|
|
- int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
|
- int draw_pipeline_stage = thread->get_pipeline_stage();
|
|
|
- thread->set_pipeline_stage(pipeline_stage);
|
|
|
-
|
|
|
- // Now that the draw thread is idle, signal it to do the compute task.
|
|
|
- thread->_gsg = gsg;
|
|
|
- thread->_state = state;
|
|
|
- thread->_work_groups = work_groups;
|
|
|
- thread->_thread_state = TS_do_compute;
|
|
|
- thread->_cv_mutex.release();
|
|
|
- thread->_cv_start.notify();
|
|
|
- thread->_cv_mutex.acquire();
|
|
|
-
|
|
|
- // Wait for it to finish the compute task.
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- thread->set_pipeline_stage(draw_pipeline_stage);
|
|
|
- thread->_gsg = nullptr;
|
|
|
- thread->_state = nullptr;
|
|
|
- }
|
|
|
+ });
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -1342,43 +1223,6 @@ texture_uploaded(Texture *tex) {
|
|
|
// Usually only called by DisplayRegion::do_cull.
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Called by DisplayRegion::do_get_screenshot
|
|
|
- */
|
|
|
-PT(Texture) GraphicsEngine::
|
|
|
-do_get_screenshot(DisplayRegion *region, GraphicsStateGuardian *gsg) {
|
|
|
- // A multi-threaded environment. We have to wait until the draw thread
|
|
|
- // has finished its current task.
|
|
|
-
|
|
|
- ReMutexHolder holder(_lock);
|
|
|
-
|
|
|
- const std::string &draw_name = gsg->get_threading_model().get_draw_name();
|
|
|
- WindowRenderer *wr = get_window_renderer(draw_name, 0);
|
|
|
- RenderThread *thread = (RenderThread *)wr;
|
|
|
- MutexHolder cv_holder(thread->_cv_mutex);
|
|
|
-
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- // Now that the draw thread is idle, signal it to do the extraction task.
|
|
|
- thread->_region = region;
|
|
|
- thread->_thread_state = TS_do_screenshot;
|
|
|
- thread->_cv_mutex.release();
|
|
|
- thread->_cv_start.notify();
|
|
|
- thread->_cv_mutex.acquire();
|
|
|
-
|
|
|
- // Wait for it to finish the extraction.
|
|
|
- while (thread->_thread_state != TS_wait) {
|
|
|
- thread->_cv_done.wait();
|
|
|
- }
|
|
|
-
|
|
|
- PT(Texture) tex = std::move(thread->_texture);
|
|
|
- thread->_region = nullptr;
|
|
|
- thread->_texture = nullptr;
|
|
|
- return tex;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* Fires off a cull traversal using the indicated camera.
|
|
|
*/
|
|
|
@@ -2867,31 +2711,9 @@ thread_main() {
|
|
|
do_pending(_engine, current_thread);
|
|
|
break;
|
|
|
|
|
|
- case TS_do_compute:
|
|
|
- nassertd(_gsg != nullptr && _state != nullptr) break;
|
|
|
- {
|
|
|
- const ShaderAttrib *sattr;
|
|
|
- _state->get_attrib(sattr);
|
|
|
- _gsg->push_group_marker(std::string("Compute ") + sattr->get_shader()->get_filename(Shader::ST_compute).get_basename());
|
|
|
- _gsg->set_state_and_transform(_state, TransformState::make_identity());
|
|
|
- _gsg->dispatch_compute(_work_groups[0], _work_groups[1], _work_groups[2]);
|
|
|
- _gsg->pop_group_marker();
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case TS_do_extract_texture_data:
|
|
|
- nassertd(_gsg != nullptr && _texture != nullptr) break;
|
|
|
- _result = _gsg->extract_texture_data(_texture);
|
|
|
- break;
|
|
|
-
|
|
|
- case TS_do_extract_shader_buffer_data:
|
|
|
- nassertd(_gsg != nullptr && _texture != nullptr) break;
|
|
|
- _result = _gsg->extract_shader_buffer_data(_buffer, *_buffer_result);
|
|
|
- break;
|
|
|
-
|
|
|
- case TS_do_screenshot:
|
|
|
- nassertd(_region != nullptr) break;
|
|
|
- _texture = _region->get_screenshot();
|
|
|
+ case TS_callback:
|
|
|
+ nassertd(_callback != nullptr) break;
|
|
|
+ _callback(this);
|
|
|
break;
|
|
|
|
|
|
case TS_terminate:
|
|
|
@@ -2916,3 +2738,39 @@ thread_main() {
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Waits for this thread to become idle, then runs the given function on it.
|
|
|
+ */
|
|
|
+void GraphicsEngine::RenderThread::
|
|
|
+run_on_thread(Callback *callback, void *callback_data, void *return_data) {
|
|
|
+ MutexHolder cv_holder(_cv_mutex);
|
|
|
+
|
|
|
+ while (_thread_state != TS_wait) {
|
|
|
+ _cv_done.wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Temporarily set this so that it accesses data from the current thread.
|
|
|
+ int pipeline_stage = Thread::get_current_pipeline_stage();
|
|
|
+ int thread_pipeline_stage = get_pipeline_stage();
|
|
|
+ set_pipeline_stage(pipeline_stage);
|
|
|
+
|
|
|
+ // Now that the draw thread is idle, signal it to run the callback.
|
|
|
+ _callback = callback;
|
|
|
+ _callback_data = callback_data;
|
|
|
+ _return_data = return_data;
|
|
|
+ _thread_state = TS_callback;
|
|
|
+ _cv_mutex.release();
|
|
|
+ _cv_start.notify();
|
|
|
+ _cv_mutex.acquire();
|
|
|
+
|
|
|
+ // Wait for it to finish the job.
|
|
|
+ while (_thread_state != TS_wait) {
|
|
|
+ _cv_done.wait();
|
|
|
+ }
|
|
|
+
|
|
|
+ set_pipeline_stage(thread_pipeline_stage);
|
|
|
+ _callback = nullptr;
|
|
|
+ _callback_data = nullptr;
|
|
|
+ _return_data = nullptr;
|
|
|
+}
|