mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-02 09:52:27 -04:00
Added a windows OpenGL implementation of finish frame and begin finish. This allows for frame flip syncronization across multiple machines. This is a change made by WDI to aid cave rendering
This commit is contained in:
parent
1edd26540b
commit
626cb5966a
@ -949,6 +949,31 @@ sync_frame() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::ready_flip
|
||||
// Access: Published
|
||||
// Description: Waits for all the threads that started drawing their
|
||||
// last frame to finish drawing. Returns when all threads have
|
||||
// actually finished drawing, as opposed to 'sync_frame'
|
||||
// we seems to return once all draw calls have been submitted.
|
||||
// Calling 'flip_frame' after this function should immediately
|
||||
// cause a buffer flip. This function will only work in
|
||||
// opengl right now, for all other graphics pipelines it will
|
||||
// simply return immediately. In opengl it's a bit of a hack:
|
||||
// it will attempt to read a single pixel from the frame buffer to
|
||||
// force the graphics card to finish drawing before it returns
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
ready_flip() {
|
||||
Thread *current_thread = Thread::get_current_thread();
|
||||
LightReMutexHolder holder(_lock, current_thread);
|
||||
|
||||
if (_flip_state == FS_draw) {
|
||||
do_ready_flip(current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::flip_frame
|
||||
// Access: Published
|
||||
@ -1570,6 +1595,27 @@ flip_windows(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::ready_flip_windows
|
||||
// Access: Private
|
||||
// Description: This is called by the RenderThread object to flip the
|
||||
// buffers for all of the non-single-buffered windows in
|
||||
// the given list. This is run in the draw thread.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
ready_flip_windows(const GraphicsEngine::Windows &wlist, Thread *current_thread) {
|
||||
Windows::const_iterator wi;
|
||||
for (wi = wlist.begin(); wi != wlist.end(); ++wi) {
|
||||
GraphicsOutput *win = (*wi);
|
||||
if (win->flip_ready()) {
|
||||
PStatTimer timer(GraphicsEngine::_flip_begin_pcollector, current_thread);
|
||||
win->ready_flip();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::do_sync_frame
|
||||
// Access: Private
|
||||
@ -1597,6 +1643,36 @@ do_sync_frame(Thread *current_thread) {
|
||||
_flip_state = FS_sync;
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::do_ready_flip
|
||||
// Access: Private
|
||||
// Description: Wait until all draw calls have finished drawing and
|
||||
// the frame is ready to flip
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::
|
||||
do_ready_flip(Thread *current_thread) {
|
||||
nassertv(_lock.debug_is_locked());
|
||||
|
||||
// Statistics
|
||||
PStatTimer timer(_sync_pcollector, current_thread);
|
||||
|
||||
nassertv(_flip_state == FS_draw);
|
||||
|
||||
// Wait for all the threads to finish their current frame. Grabbing
|
||||
// and releasing the mutex should achieve that.
|
||||
Threads::const_iterator ti;
|
||||
for (ti = _threads.begin(); ti != _threads.end(); ++ti) {
|
||||
RenderThread *thread = (*ti).second;
|
||||
thread->_cv_mutex.acquire();
|
||||
thread->_cv_mutex.release();
|
||||
}
|
||||
_app.do_ready_flip(this,current_thread);
|
||||
_flip_state = FS_sync;
|
||||
|
||||
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::do_flip_frame
|
||||
// Access: Private
|
||||
@ -2444,6 +2520,20 @@ do_flip(GraphicsEngine *engine, Thread *current_thread) {
|
||||
engine->flip_windows(_draw, current_thread);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::WindowRenderer::do_ready_flip
|
||||
// Access: Public
|
||||
// Description: Prepares windows for flipping by waiting until all draw
|
||||
// calls are finished
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsEngine::WindowRenderer::
|
||||
do_ready_flip(GraphicsEngine *engine, Thread *current_thread) {
|
||||
LightReMutexHolder holder(_wl_lock);
|
||||
engine->ready_flip_windows(_cdraw, current_thread);
|
||||
engine->ready_flip_windows(_draw, current_thread);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsEngine::WindowRenderer::do_close
|
||||
// Access: Public
|
||||
|
@ -101,6 +101,7 @@ PUBLISHED:
|
||||
BLOCKING void render_frame();
|
||||
BLOCKING void open_windows();
|
||||
BLOCKING void sync_frame();
|
||||
BLOCKING void ready_flip();
|
||||
BLOCKING void flip_frame();
|
||||
|
||||
bool extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg);
|
||||
@ -144,8 +145,10 @@ private:
|
||||
void make_contexts(const Windows &wlist, Thread *current_thread);
|
||||
|
||||
void process_events(const Windows &wlist, Thread *current_thread);
|
||||
void ready_flip_windows(const Windows &wlist, Thread *current_thread);
|
||||
void flip_windows(const Windows &wlist, Thread *current_thread);
|
||||
void do_sync_frame(Thread *current_thread);
|
||||
void do_ready_flip(Thread *current_thread);
|
||||
void do_flip_frame(Thread *current_thread);
|
||||
INLINE void close_gsg(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
|
||||
|
||||
@ -261,6 +264,7 @@ private:
|
||||
void resort_windows();
|
||||
void do_frame(GraphicsEngine *engine, Thread *current_thread);
|
||||
void do_windows(GraphicsEngine *engine, Thread *current_thread);
|
||||
void do_ready_flip(GraphicsEngine *engine, Thread *current_thread);
|
||||
void do_flip(GraphicsEngine *engine, Thread *current_thread);
|
||||
void do_release(GraphicsEngine *engine, Thread *current_thread);
|
||||
void do_close(GraphicsEngine *engine, Thread *current_thread);
|
||||
|
@ -1256,6 +1256,21 @@ void GraphicsOutput::
|
||||
begin_flip() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsOutput::ready_flip
|
||||
// Access: Public, Virtual
|
||||
// Description: This function will be called within the draw thread
|
||||
// after end_frame() has been called on all windows, to
|
||||
// initiate the exchange of the front and back buffers.
|
||||
//
|
||||
// This should instruct the window to prepare for the
|
||||
// flip when it is command but not actually flip
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GraphicsOutput::
|
||||
ready_flip() {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsOutput::end_flip
|
||||
// Access: Public, Virtual
|
||||
|
@ -212,6 +212,7 @@ public:
|
||||
|
||||
// These methods will be called within the app (main) thread.
|
||||
virtual void begin_flip();
|
||||
virtual void ready_flip();
|
||||
virtual void end_flip();
|
||||
|
||||
// It is an error to call any of the following methods from any
|
||||
|
@ -1707,6 +1707,28 @@ reset() {
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GLGraphicsStateGuardian::finish
|
||||
// Access: Public, Virtual
|
||||
// Description: Force the graphics card to finish drawing before
|
||||
// returning. !!!!!HACK WARNING!!!!
|
||||
// glfinish does not actually wait for the graphics card to finish drawing
|
||||
// only for draw calls to finish. Thus flip may not happene
|
||||
// immediately. Instead we read a single pixel from
|
||||
// the framebuffer. This forces the graphics card to
|
||||
// finish drawing the frame before returning.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void CLP(GraphicsStateGuardian)::
|
||||
finish() {
|
||||
// Rather than call glfinish which returns immediately if
|
||||
// draw commands have been submitted, we will read a single pixel
|
||||
// from the frame. That will force the graphics card to finish
|
||||
// drawing before it is called
|
||||
char data[4];
|
||||
GLP(ReadPixels)(0,0,1,1,GL_RGBA,GL_UNSIGNED_BYTE,&data);
|
||||
//GLP(Finish);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GraphicsStateGuardian::clear
|
||||
// Access: Public
|
||||
|
@ -276,7 +276,7 @@ public:
|
||||
|
||||
void bind_fbo(GLuint fbo);
|
||||
virtual bool get_supports_cg_profile(const string &name) const;
|
||||
|
||||
void finish();
|
||||
|
||||
protected:
|
||||
void do_issue_transform();
|
||||
|
@ -144,6 +144,37 @@ begin_flip() {
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: wglGraphicsWindow::ready_flip
|
||||
// Access: Public, Virtual
|
||||
// Description: This function will be called within the draw thread
|
||||
// after end_frame() has been called on all windows, to
|
||||
// initiate the exchange of the front and back buffers.
|
||||
//
|
||||
// This should instruct the window to prepare for the
|
||||
// flip when command, but will not actually flip
|
||||
//
|
||||
// We have the two separate functions, begin_flip() and
|
||||
// end_flip(), to make it easier to flip all of the
|
||||
// windows at the same time.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void wglGraphicsWindow::
|
||||
ready_flip() {
|
||||
if (_hdc) {
|
||||
// The documentation on SwapBuffers() is not at all clear on
|
||||
// whether the GL context needs to be current before it can be
|
||||
// called. Empirically, it appears that it is not necessary in
|
||||
// many cases, but it definitely is necessary at least in the case
|
||||
// of Mesa on Windows.
|
||||
wglGraphicsStateGuardian *wglgsg;
|
||||
DCAST_INTO_V(wglgsg, _gsg);
|
||||
HGLRC context = wglgsg->get_context(_hdc);
|
||||
nassertv(context);
|
||||
wglGraphicsPipe::wgl_make_current(_hdc, context, &_make_current_pcollector);
|
||||
wglgsg->finish();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: wglGraphicsWindow::close_window
|
||||
// Access: Protected, Virtual
|
||||
|
@ -38,6 +38,7 @@ public:
|
||||
virtual void end_frame(FrameMode mode, Thread *current_thread);
|
||||
|
||||
virtual void begin_flip();
|
||||
virtual void ready_flip();
|
||||
|
||||
protected:
|
||||
virtual void close_window();
|
||||
|
Loading…
x
Reference in New Issue
Block a user