|
@@ -153,7 +153,6 @@ GraphicsEngine(Pipeline *pipeline) :
|
|
|
|
|
|
|
|
_windows_sorted = true;
|
|
_windows_sorted = true;
|
|
|
_window_sort_index = 0;
|
|
_window_sort_index = 0;
|
|
|
- _needs_open_windows = false;
|
|
|
|
|
|
|
|
|
|
set_threading_model(GraphicsThreadingModel(threading_model));
|
|
set_threading_model(GraphicsThreadingModel(threading_model));
|
|
|
if (!_threading_model.is_default()) {
|
|
if (!_threading_model.is_default()) {
|
|
@@ -326,13 +325,10 @@ make_output(GraphicsPipe *pipe,
|
|
|
|
|
|
|
|
// Sanity check everything.
|
|
// Sanity check everything.
|
|
|
|
|
|
|
|
- GraphicsThreadingModel threading_model = get_threading_model();
|
|
|
|
|
nassertr(pipe != (GraphicsPipe *)NULL, NULL);
|
|
nassertr(pipe != (GraphicsPipe *)NULL, NULL);
|
|
|
if (gsg != (GraphicsStateGuardian *)NULL) {
|
|
if (gsg != (GraphicsStateGuardian *)NULL) {
|
|
|
nassertr(pipe == gsg->get_pipe(), NULL);
|
|
nassertr(pipe == gsg->get_pipe(), NULL);
|
|
|
nassertr(this == gsg->get_engine(), NULL);
|
|
nassertr(this == gsg->get_engine(), NULL);
|
|
|
- nassertr(threading_model.get_draw_name() ==
|
|
|
|
|
- gsg->get_threading_model().get_draw_name(), NULL);
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// Are we really asking for a callback window?
|
|
// Are we really asking for a callback window?
|
|
@@ -346,8 +342,8 @@ make_output(GraphicsPipe *pipe,
|
|
|
if (this_gsg != (GraphicsStateGuardian *)NULL) {
|
|
if (this_gsg != (GraphicsStateGuardian *)NULL) {
|
|
|
CallbackGraphicsWindow *window = new CallbackGraphicsWindow(this, pipe, name, fb_prop, win_prop, flags, this_gsg);
|
|
CallbackGraphicsWindow *window = new CallbackGraphicsWindow(this, pipe, name, fb_prop, win_prop, flags, this_gsg);
|
|
|
window->_sort = sort;
|
|
window->_sort = sort;
|
|
|
- do_add_window(window, threading_model);
|
|
|
|
|
- do_add_gsg(window->get_gsg(), pipe, threading_model);
|
|
|
|
|
|
|
+ do_add_window(window);
|
|
|
|
|
+ do_add_gsg(window->get_gsg(), pipe);
|
|
|
display_cat.info() << "Created output of type CallbackGraphicsWindow\n";
|
|
display_cat.info() << "Created output of type CallbackGraphicsWindow\n";
|
|
|
return window;
|
|
return window;
|
|
|
}
|
|
}
|
|
@@ -386,8 +382,8 @@ make_output(GraphicsPipe *pipe,
|
|
|
(host->get_fb_properties().subsumes(fb_prop))) {
|
|
(host->get_fb_properties().subsumes(fb_prop))) {
|
|
|
ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
|
|
ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
|
|
|
buffer->_sort = sort;
|
|
buffer->_sort = sort;
|
|
|
- do_add_window(buffer, threading_model);
|
|
|
|
|
- do_add_gsg(host->get_gsg(), pipe, threading_model);
|
|
|
|
|
|
|
+ do_add_window(buffer);
|
|
|
|
|
+ do_add_gsg(host->get_gsg(), pipe);
|
|
|
display_cat.info() << "Created output of type ParasiteBuffer\n";
|
|
display_cat.info() << "Created output of type ParasiteBuffer\n";
|
|
|
return buffer;
|
|
return buffer;
|
|
|
}
|
|
}
|
|
@@ -398,8 +394,8 @@ make_output(GraphicsPipe *pipe,
|
|
|
if (force_parasite_buffer && can_use_parasite) {
|
|
if (force_parasite_buffer && can_use_parasite) {
|
|
|
ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
|
|
ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
|
|
|
buffer->_sort = sort;
|
|
buffer->_sort = sort;
|
|
|
- do_add_window(buffer, threading_model);
|
|
|
|
|
- do_add_gsg(host->get_gsg(), pipe, threading_model);
|
|
|
|
|
|
|
+ do_add_window(buffer);
|
|
|
|
|
+ do_add_gsg(host->get_gsg(), pipe);
|
|
|
display_cat.info() << "Created output of type ParasiteBuffer\n";
|
|
display_cat.info() << "Created output of type ParasiteBuffer\n";
|
|
|
return buffer;
|
|
return buffer;
|
|
|
}
|
|
}
|
|
@@ -412,17 +408,15 @@ make_output(GraphicsPipe *pipe,
|
|
|
pipe->make_output(name, fb_prop, win_prop, flags, this, gsg, host, retry, precertify);
|
|
pipe->make_output(name, fb_prop, win_prop, flags, this, gsg, host, retry, precertify);
|
|
|
if (window != (GraphicsOutput *)NULL) {
|
|
if (window != (GraphicsOutput *)NULL) {
|
|
|
window->_sort = sort;
|
|
window->_sort = sort;
|
|
|
- if ((precertify) && (gsg != 0) && (window->get_gsg()==gsg)) {
|
|
|
|
|
- do_add_window(window, threading_model);
|
|
|
|
|
- do_add_gsg(window->get_gsg(), pipe, threading_model);
|
|
|
|
|
|
|
+ if (precertify && gsg != nullptr && window->get_gsg() == gsg) {
|
|
|
|
|
+ do_add_window(window);
|
|
|
display_cat.info()
|
|
display_cat.info()
|
|
|
<< "Created output of type " << window->get_type() << "\n";
|
|
<< "Created output of type " << window->get_type() << "\n";
|
|
|
return window;
|
|
return window;
|
|
|
}
|
|
}
|
|
|
- do_add_window(window, threading_model);
|
|
|
|
|
|
|
+ do_add_window(window);
|
|
|
open_windows();
|
|
open_windows();
|
|
|
if (window->is_valid()) {
|
|
if (window->is_valid()) {
|
|
|
- do_add_gsg(window->get_gsg(), pipe, threading_model);
|
|
|
|
|
display_cat.info()
|
|
display_cat.info()
|
|
|
<< "Created output of type " << window->get_type() << "\n";
|
|
<< "Created output of type " << window->get_type() << "\n";
|
|
|
|
|
|
|
@@ -462,8 +456,8 @@ make_output(GraphicsPipe *pipe,
|
|
|
if (can_use_parasite) {
|
|
if (can_use_parasite) {
|
|
|
ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
|
|
ParasiteBuffer *buffer = new ParasiteBuffer(host, name, x_size, y_size, flags);
|
|
|
buffer->_sort = sort;
|
|
buffer->_sort = sort;
|
|
|
- do_add_window(buffer, threading_model);
|
|
|
|
|
- do_add_gsg(host->get_gsg(), pipe, threading_model);
|
|
|
|
|
|
|
+ do_add_window(buffer);
|
|
|
|
|
+ do_add_gsg(host->get_gsg(), pipe);
|
|
|
display_cat.info() << "Created output of type ParasiteBuffer\n";
|
|
display_cat.info() << "Created output of type ParasiteBuffer\n";
|
|
|
return buffer;
|
|
return buffer;
|
|
|
}
|
|
}
|
|
@@ -479,30 +473,24 @@ make_output(GraphicsPipe *pipe,
|
|
|
* shouldn't be called by user code as make_output normally does this under
|
|
* shouldn't be called by user code as make_output normally does this under
|
|
|
* the hood; it may be useful in esoteric cases in which a custom window
|
|
* the hood; it may be useful in esoteric cases in which a custom window
|
|
|
* object is used.
|
|
* object is used.
|
|
|
|
|
+ *
|
|
|
|
|
+ * This can be called during the rendering loop, unlike make_output(); the
|
|
|
|
|
+ * window will be opened before the next frame begins rendering. Because it
|
|
|
|
|
+ * doesn't call open_windows(), however, it's not guaranteed that the window
|
|
|
|
|
+ * will succeed opening even if it returns true.
|
|
|
*/
|
|
*/
|
|
|
bool GraphicsEngine::
|
|
bool GraphicsEngine::
|
|
|
add_window(GraphicsOutput *window, int sort) {
|
|
add_window(GraphicsOutput *window, int sort) {
|
|
|
- nassertr(window != NULL, false);
|
|
|
|
|
-
|
|
|
|
|
- GraphicsThreadingModel threading_model = get_threading_model();
|
|
|
|
|
|
|
+ nassertr(window != nullptr, false);
|
|
|
nassertr(this == window->get_engine(), false);
|
|
nassertr(this == window->get_engine(), false);
|
|
|
|
|
|
|
|
window->_sort = sort;
|
|
window->_sort = sort;
|
|
|
- do_add_window(window, threading_model);
|
|
|
|
|
-
|
|
|
|
|
- open_windows();
|
|
|
|
|
- if (window->is_valid()) {
|
|
|
|
|
- do_add_gsg(window->get_gsg(), window->get_pipe(), threading_model);
|
|
|
|
|
-
|
|
|
|
|
- display_cat.info()
|
|
|
|
|
- << "Added output of type " << window->get_type() << "\n";
|
|
|
|
|
|
|
+ do_add_window(window);
|
|
|
|
|
|
|
|
- return true;
|
|
|
|
|
|
|
+ display_cat.info()
|
|
|
|
|
+ << "Added output of type " << window->get_type() << "\n";
|
|
|
|
|
|
|
|
- } else {
|
|
|
|
|
- remove_window(window);
|
|
|
|
|
- return false;
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -537,6 +525,13 @@ remove_window(GraphicsOutput *window) {
|
|
|
}
|
|
}
|
|
|
count = _windows.erase(ptwin);
|
|
count = _windows.erase(ptwin);
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ // Also check whether it is in _new_windows.
|
|
|
|
|
+ {
|
|
|
|
|
+ MutexHolder new_windows_holder(_new_windows_lock, current_thread);
|
|
|
|
|
+ _new_windows.erase(std::remove(_new_windows.begin(), _new_windows.end(), ptwin));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
if (count == 0) {
|
|
if (count == 0) {
|
|
|
// Never heard of this window. Do nothing.
|
|
// Never heard of this window. Do nothing.
|
|
|
return false;
|
|
return false;
|
|
@@ -601,6 +596,11 @@ remove_all_windows() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ {
|
|
|
|
|
+ MutexHolder new_windows_holder(_new_windows_lock, current_thread);
|
|
|
|
|
+ _new_windows.clear();
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
_app.do_close(this, current_thread);
|
|
_app.do_close(this, current_thread);
|
|
|
_app.do_pending(this, current_thread);
|
|
_app.do_pending(this, current_thread);
|
|
|
terminate_threads(current_thread);
|
|
terminate_threads(current_thread);
|
|
@@ -694,14 +694,12 @@ render_frame() {
|
|
|
}
|
|
}
|
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
- if (_needs_open_windows) {
|
|
|
|
|
- // Make sure our buffers and windows are fully realized before we render a
|
|
|
|
|
- // frame. We do this particularly to realize our offscreen buffers, so
|
|
|
|
|
- // that we don't render a frame before the offscreen buffers are ready
|
|
|
|
|
- // (which might result in a frame going by without some textures having
|
|
|
|
|
- // been rendered).
|
|
|
|
|
- open_windows();
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // Make sure our buffers and windows are fully realized before we render a
|
|
|
|
|
+ // frame. We do this particularly to realize our offscreen buffers, so
|
|
|
|
|
+ // that we don't render a frame before the offscreen buffers are ready
|
|
|
|
|
+ // (which might result in a frame going by without some textures having
|
|
|
|
|
+ // been rendered).
|
|
|
|
|
+ open_windows();
|
|
|
|
|
|
|
|
ClockObject *global_clock = ClockObject::get_global_clock();
|
|
ClockObject *global_clock = ClockObject::get_global_clock();
|
|
|
|
|
|
|
@@ -945,10 +943,58 @@ open_windows() {
|
|
|
|
|
|
|
|
ReMutexHolder holder(_lock, current_thread);
|
|
ReMutexHolder holder(_lock, current_thread);
|
|
|
|
|
|
|
|
- if (!_windows_sorted) {
|
|
|
|
|
- do_resort_windows();
|
|
|
|
|
|
|
+ pvector<PT(GraphicsOutput)> new_windows;
|
|
|
|
|
+ {
|
|
|
|
|
+ MutexHolder new_windows_holder(_new_windows_lock, current_thread);
|
|
|
|
|
+ if (_new_windows.empty()) {
|
|
|
|
|
+ return;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ for (auto it = _new_windows.begin(); it != _new_windows.end(); ++it) {
|
|
|
|
|
+ GraphicsOutput *window = *it;
|
|
|
|
|
+
|
|
|
|
|
+ WindowRenderer *cull =
|
|
|
|
|
+ get_window_renderer(_threading_model.get_cull_name(),
|
|
|
|
|
+ _threading_model.get_cull_stage());
|
|
|
|
|
+ WindowRenderer *draw =
|
|
|
|
|
+ get_window_renderer(_threading_model.get_draw_name(),
|
|
|
|
|
+ _threading_model.get_draw_stage());
|
|
|
|
|
+
|
|
|
|
|
+ if (_threading_model.get_cull_sorting()) {
|
|
|
|
|
+ cull->add_window(cull->_cull, window);
|
|
|
|
|
+ draw->add_window(draw->_draw, window);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ cull->add_window(cull->_cdraw, window);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Ask the pipe which thread it prefers to run its windowing commands in
|
|
|
|
|
+ // (the "window thread"). This is the thread that handles the commands
|
|
|
|
|
+ // to open, resize, etc. the window. X requires this to be done in the
|
|
|
|
|
+ // app thread (along with all the other windows, since X is strictly
|
|
|
|
|
+ // single-threaded), but Windows requires this to be done in draw
|
|
|
|
|
+ // (because once an OpenGL context has been bound in a given thread, it
|
|
|
|
|
+ // cannot subsequently be bound in any other thread, and we have to bind
|
|
|
|
|
+ // a context in open_window()).
|
|
|
|
|
+
|
|
|
|
|
+ switch (window->get_pipe()->get_preferred_window_thread()) {
|
|
|
|
|
+ case GraphicsPipe::PWT_app:
|
|
|
|
|
+ _app.add_window(_app._window, window);
|
|
|
|
|
+ break;
|
|
|
|
|
+
|
|
|
|
|
+ case GraphicsPipe::PWT_draw:
|
|
|
|
|
+ draw->add_window(draw->_window, window);
|
|
|
|
|
+ break;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ _windows.push_back(window);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // Steal the list, since remove_window() may remove from _new_windows.
|
|
|
|
|
+ new_windows.swap(_new_windows);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ do_resort_windows();
|
|
|
|
|
+
|
|
|
// We do it twice, to allow both cull and draw to process the window.
|
|
// We do it twice, to allow both cull and draw to process the window.
|
|
|
for (int i = 0; i < 2; ++i) {
|
|
for (int i = 0; i < 2; ++i) {
|
|
|
_app.do_windows(this, current_thread);
|
|
_app.do_windows(this, current_thread);
|
|
@@ -970,7 +1016,15 @@ open_windows() {
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- _needs_open_windows = false;
|
|
|
|
|
|
|
+ // Now go through the list again to check whether they opened successfully.
|
|
|
|
|
+ for (auto it = new_windows.begin(); it != new_windows.end(); ++it) {
|
|
|
|
|
+ GraphicsOutput *window = *it;
|
|
|
|
|
+ if (window->is_valid()) {
|
|
|
|
|
+ do_add_gsg(window->get_gsg(), window->get_pipe());
|
|
|
|
|
+ } else {
|
|
|
|
|
+ remove_window(window);
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1927,10 +1981,10 @@ do_draw(GraphicsOutput *win, GraphicsStateGuardian *gsg, DisplayRegion *dr, Thre
|
|
|
* list of windows, and to request that the window be opened.
|
|
* list of windows, and to request that the window be opened.
|
|
|
*/
|
|
*/
|
|
|
void GraphicsEngine::
|
|
void GraphicsEngine::
|
|
|
-do_add_window(GraphicsOutput *window,
|
|
|
|
|
- const GraphicsThreadingModel &threading_model) {
|
|
|
|
|
- nassertv(window != NULL);
|
|
|
|
|
- ReMutexHolder holder(_lock);
|
|
|
|
|
|
|
+do_add_window(GraphicsOutput *window) {
|
|
|
|
|
+ nassertv(window != nullptr);
|
|
|
|
|
+
|
|
|
|
|
+ MutexHolder holder(_new_windows_lock);
|
|
|
nassertv(window->get_engine() == this);
|
|
nassertv(window->get_engine() == this);
|
|
|
|
|
|
|
|
// We have a special counter that is unique per window that allows us to
|
|
// We have a special counter that is unique per window that allows us to
|
|
@@ -1938,50 +1992,13 @@ do_add_window(GraphicsOutput *window,
|
|
|
window->_internal_sort_index = _window_sort_index;
|
|
window->_internal_sort_index = _window_sort_index;
|
|
|
++_window_sort_index;
|
|
++_window_sort_index;
|
|
|
|
|
|
|
|
- _windows_sorted = false;
|
|
|
|
|
- _windows.push_back(window);
|
|
|
|
|
-
|
|
|
|
|
- WindowRenderer *cull =
|
|
|
|
|
- get_window_renderer(threading_model.get_cull_name(),
|
|
|
|
|
- threading_model.get_cull_stage());
|
|
|
|
|
- WindowRenderer *draw =
|
|
|
|
|
- get_window_renderer(threading_model.get_draw_name(),
|
|
|
|
|
- threading_model.get_draw_stage());
|
|
|
|
|
-
|
|
|
|
|
- if (threading_model.get_cull_sorting()) {
|
|
|
|
|
- cull->add_window(cull->_cull, window);
|
|
|
|
|
- draw->add_window(draw->_draw, window);
|
|
|
|
|
- } else {
|
|
|
|
|
- cull->add_window(cull->_cdraw, window);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
-/*
|
|
|
|
|
- * Ask the pipe which thread it prefers to run its windowing commands in (the
|
|
|
|
|
- * "window thread"). This is the thread that handles the commands to open,
|
|
|
|
|
- * resize, etc. the window. X requires this to be done in the app thread
|
|
|
|
|
- * (along with all the other windows, since X is strictly single-threaded),
|
|
|
|
|
- * but Windows requires this to be done in draw (because once an OpenGL
|
|
|
|
|
- * context has been bound in a given thread, it cannot subsequently be bound
|
|
|
|
|
- * in any other thread, and we have to bind a context in open_window()).
|
|
|
|
|
- */
|
|
|
|
|
-
|
|
|
|
|
- switch (window->get_pipe()->get_preferred_window_thread()) {
|
|
|
|
|
- case GraphicsPipe::PWT_app:
|
|
|
|
|
- _app.add_window(_app._window, window);
|
|
|
|
|
- break;
|
|
|
|
|
-
|
|
|
|
|
- case GraphicsPipe::PWT_draw:
|
|
|
|
|
- draw->add_window(draw->_window, window);
|
|
|
|
|
- break;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
if (display_cat.is_debug()) {
|
|
if (display_cat.is_debug()) {
|
|
|
display_cat.debug()
|
|
display_cat.debug()
|
|
|
<< "Created " << window->get_type() << " " << (void *)window << "\n";
|
|
<< "Created " << window->get_type() << " " << (void *)window << "\n";
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
window->request_open();
|
|
window->request_open();
|
|
|
- _needs_open_windows = true;
|
|
|
|
|
|
|
+ _new_windows.push_back(window);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
/**
|
|
@@ -1990,13 +2007,12 @@ do_add_window(GraphicsOutput *window,
|
|
|
* variables based on the gsg's capabilities.
|
|
* variables based on the gsg's capabilities.
|
|
|
*/
|
|
*/
|
|
|
void GraphicsEngine::
|
|
void GraphicsEngine::
|
|
|
-do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
|
|
|
|
|
- const GraphicsThreadingModel &threading_model) {
|
|
|
|
|
|
|
+do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe) {
|
|
|
nassertv(gsg != NULL);
|
|
nassertv(gsg != NULL);
|
|
|
|
|
|
|
|
ReMutexHolder holder(_lock);
|
|
ReMutexHolder holder(_lock);
|
|
|
nassertv(gsg->get_pipe() == pipe && gsg->get_engine() == this);
|
|
nassertv(gsg->get_pipe() == pipe && gsg->get_engine() == this);
|
|
|
- gsg->_threading_model = threading_model;
|
|
|
|
|
|
|
+ gsg->_threading_model = _threading_model;
|
|
|
if (!_default_loader.is_null()) {
|
|
if (!_default_loader.is_null()) {
|
|
|
gsg->set_loader(_default_loader);
|
|
gsg->set_loader(_default_loader);
|
|
|
}
|
|
}
|
|
@@ -2004,8 +2020,8 @@ do_add_gsg(GraphicsStateGuardian *gsg, GraphicsPipe *pipe,
|
|
|
auto_adjust_capabilities(gsg);
|
|
auto_adjust_capabilities(gsg);
|
|
|
|
|
|
|
|
WindowRenderer *draw =
|
|
WindowRenderer *draw =
|
|
|
- get_window_renderer(threading_model.get_draw_name(),
|
|
|
|
|
- threading_model.get_draw_stage());
|
|
|
|
|
|
|
+ get_window_renderer(_threading_model.get_draw_name(),
|
|
|
|
|
+ _threading_model.get_draw_stage());
|
|
|
|
|
|
|
|
draw->add_gsg(gsg);
|
|
draw->add_gsg(gsg);
|
|
|
}
|
|
}
|