mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-04 10:54:24 -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
|
// Function: GraphicsEngine::flip_frame
|
||||||
// Access: Published
|
// 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
|
// Function: GraphicsEngine::do_sync_frame
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -1597,6 +1643,36 @@ do_sync_frame(Thread *current_thread) {
|
|||||||
_flip_state = FS_sync;
|
_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
|
// Function: GraphicsEngine::do_flip_frame
|
||||||
// Access: Private
|
// Access: Private
|
||||||
@ -2444,6 +2520,20 @@ do_flip(GraphicsEngine *engine, Thread *current_thread) {
|
|||||||
engine->flip_windows(_draw, 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
|
// Function: GraphicsEngine::WindowRenderer::do_close
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -101,6 +101,7 @@ PUBLISHED:
|
|||||||
BLOCKING void render_frame();
|
BLOCKING void render_frame();
|
||||||
BLOCKING void open_windows();
|
BLOCKING void open_windows();
|
||||||
BLOCKING void sync_frame();
|
BLOCKING void sync_frame();
|
||||||
|
BLOCKING void ready_flip();
|
||||||
BLOCKING void flip_frame();
|
BLOCKING void flip_frame();
|
||||||
|
|
||||||
bool extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg);
|
bool extract_texture_data(Texture *tex, GraphicsStateGuardian *gsg);
|
||||||
@ -144,8 +145,10 @@ private:
|
|||||||
void make_contexts(const Windows &wlist, Thread *current_thread);
|
void make_contexts(const Windows &wlist, Thread *current_thread);
|
||||||
|
|
||||||
void process_events(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 flip_windows(const Windows &wlist, Thread *current_thread);
|
||||||
void do_sync_frame(Thread *current_thread);
|
void do_sync_frame(Thread *current_thread);
|
||||||
|
void do_ready_flip(Thread *current_thread);
|
||||||
void do_flip_frame(Thread *current_thread);
|
void do_flip_frame(Thread *current_thread);
|
||||||
INLINE void close_gsg(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
|
INLINE void close_gsg(GraphicsPipe *pipe, GraphicsStateGuardian *gsg);
|
||||||
|
|
||||||
@ -261,6 +264,7 @@ private:
|
|||||||
void resort_windows();
|
void resort_windows();
|
||||||
void do_frame(GraphicsEngine *engine, Thread *current_thread);
|
void do_frame(GraphicsEngine *engine, Thread *current_thread);
|
||||||
void do_windows(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_flip(GraphicsEngine *engine, Thread *current_thread);
|
||||||
void do_release(GraphicsEngine *engine, Thread *current_thread);
|
void do_release(GraphicsEngine *engine, Thread *current_thread);
|
||||||
void do_close(GraphicsEngine *engine, Thread *current_thread);
|
void do_close(GraphicsEngine *engine, Thread *current_thread);
|
||||||
|
@ -1256,6 +1256,21 @@ void GraphicsOutput::
|
|||||||
begin_flip() {
|
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
|
// Function: GraphicsOutput::end_flip
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
@ -212,6 +212,7 @@ public:
|
|||||||
|
|
||||||
// These methods will be called within the app (main) thread.
|
// These methods will be called within the app (main) thread.
|
||||||
virtual void begin_flip();
|
virtual void begin_flip();
|
||||||
|
virtual void ready_flip();
|
||||||
virtual void end_flip();
|
virtual void end_flip();
|
||||||
|
|
||||||
// It is an error to call any of the following methods from any
|
// 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
|
// Function: GraphicsStateGuardian::clear
|
||||||
// Access: Public
|
// Access: Public
|
||||||
|
@ -276,7 +276,7 @@ public:
|
|||||||
|
|
||||||
void bind_fbo(GLuint fbo);
|
void bind_fbo(GLuint fbo);
|
||||||
virtual bool get_supports_cg_profile(const string &name) const;
|
virtual bool get_supports_cg_profile(const string &name) const;
|
||||||
|
void finish();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void do_issue_transform();
|
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
|
// Function: wglGraphicsWindow::close_window
|
||||||
// Access: Protected, Virtual
|
// Access: Protected, Virtual
|
||||||
|
@ -38,6 +38,7 @@ public:
|
|||||||
virtual void end_frame(FrameMode mode, Thread *current_thread);
|
virtual void end_frame(FrameMode mode, Thread *current_thread);
|
||||||
|
|
||||||
virtual void begin_flip();
|
virtual void begin_flip();
|
||||||
|
virtual void ready_flip();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual void close_window();
|
virtual void close_window();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user