diff --git a/api/boinc_api.C b/api/boinc_api.C index 4e99c5f812..87f7ac3277 100644 --- a/api/boinc_api.C +++ b/api/boinc_api.C @@ -30,6 +30,7 @@ #include #include #include +#include // for timing #endif #ifdef __APPLE_CC__ @@ -55,12 +56,18 @@ static APP_INIT_DATA aid; GRAPHICS_INFO gi; -static double timer_period = 0.1; +static double timer_period = 1.0/50.0; // 50 Hz timer static double time_until_checkpoint; +static double time_until_redraw; static double time_until_fraction_done_update; static double fraction_done; static bool ready_to_checkpoint = false; +static bool ready_to_redraw = false; static bool this_process_active; +int ok_to_draw = 0; +#ifdef _WIN32 +HANDLE hGlobalDrawEvent; +#endif // read the INIT_DATA and FD_INIT files // @@ -120,6 +127,7 @@ int boinc_init() { #endif time_until_checkpoint = aid.checkpoint_period; time_until_fraction_done_update = aid.fraction_done_update_period; + time_until_redraw = gi.refresh_period; this_process_active = true; set_timer(timer_period); @@ -161,6 +169,17 @@ int boinc_resolve_filename(char *virtual_name, char *physical_name, int len) { bool boinc_time_to_checkpoint() { + // Tell the graphics thread it's OK to draw now + if (ready_to_redraw) { + ok_to_draw = 1; + // And wait for the graphics thread to notify us that it's done drawing + ResetEvent(hGlobalDrawEvent); + WaitForSingleObject( hGlobalDrawEvent, INFINITE ); + // Reset the refresh counter + time_until_redraw = gi.refresh_period; + ready_to_redraw = false; + } + return ready_to_checkpoint; } @@ -248,7 +267,7 @@ double boinc_cpu_time() { } #ifdef _WIN32 -void CALLBACK on_timer(HWND hwnd, UINT uMsg, UINT idEvent, DWORD dwTime) { +void CALLBACK on_timer(UINT uTimerID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2) { #else void on_timer(int a) { #endif @@ -260,6 +279,13 @@ void on_timer(int a) { } } + if (!ready_to_redraw) { + time_until_redraw -= timer_period; + if (time_until_redraw <= 0) { + ready_to_redraw = true; + } + } + if (this_process_active) { time_until_fraction_done_update -= timer_period; if (time_until_fraction_done_update < 0) { @@ -275,7 +301,23 @@ void on_timer(int a) { int set_timer(double period) { int retval=0; #ifdef _WIN32 - retval = SetTimer(NULL, 0, (int)(period*1000), on_timer); + // Use Windows multimedia timer, since it is more accurate + // than SetTimer and doesn't require an associated event loop + retval = timeSetEvent( + (int)(period*1000), // uDelay + (int)(period*1000), // uResolution + on_timer, // lpTimeProc + NULL, // dwUser + TIME_PERIODIC // fuEvent + ); + + // Create the event object used to signal between the + // worker and event threads + hGlobalDrawEvent = CreateEvent( + NULL, // no security attributes + TRUE, // manual reset event + TRUE, // initial state is signaled + NULL); // object not named #endif #if HAVE_SIGNAL_H diff --git a/api/windows_opengl.cpp b/api/windows_opengl.cpp index 9fa864df2c..131344d50a 100755 --- a/api/windows_opengl.cpp +++ b/api/windows_opengl.cpp @@ -1,3 +1,22 @@ +// The contents of this file are subject to the Mozilla Public License +// Version 1.0 (the "License"); you may not use this file except in +// compliance with the License. You may obtain a copy of the License at +// http://www.mozilla.org/MPL/ +// +// Software distributed under the License is distributed on an "AS IS" +// basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the +// License for the specific language governing rights and limitations +// under the License. +// +// The Original Code is the Berkeley Open Infrastructure for Network Computing. +// +// The Initial Developer of the Original Code is the SETI@home project. +// Portions created by the SETI@home project are Copyright (C) 2002 +// University of California at Berkeley. All Rights Reserved. +// +// Contributor(s): +// + /* * This Code Was Created By Jeff Molofee 2000 * A HUGE Thanks To Fredric Echols For Cleaning Up @@ -12,7 +31,6 @@ #include // Header File For The GLu32 Library #include // Header File For The Glaux Library #include -#include #include "graphics_api.h" @@ -22,6 +40,7 @@ HWND hWnd=NULL; // Holds Our Window Handle HINSTANCE hInstance; // Holds The Instance Of The Application int mouse_thresh = 3; int initCursorPosx, initCursorPosy; +extern int ok_to_draw; GLuint base; // Base Display List For The Font Set GLfloat cnt1; // 1st Counter Used To Move Text & For Coloring @@ -30,8 +49,9 @@ GLfloat cnt2; // 2nd Counter Used To Move Text & For Coloring bool keys[256]; bool active=TRUE; // Window Active Flag Set To TRUE By Default bool fullscreen=TRUE; // Fullscreen Flag Set To Fullscreen Mode By Default -BOOL done=FALSE; // Bool Variable To Exit Loop +BOOL done=FALSE; // Bool Variable To Exit Loop int counter; +extern HANDLE hGlobalDrawEvent; int DrawGLScene(GLvoid); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc @@ -444,16 +464,12 @@ LRESULT CALLBACK WndProc( HWND hWnd, // Handle For This Window DWORD WINAPI win_graphics_event_loop( LPVOID gi ) { MSG msg; // Windows Message Structure - clock_t next_draw_time; - - next_draw_time = clock(); fullscreen=FALSE; // Windowed Mode // Create Our OpenGL Window if (!CreateGLWindow("BOINC Application Window",((GRAPHICS_INFO*)gi)->xsize, - ((GRAPHICS_INFO*)gi)->ysize,1,fullscreen)) - { + ((GRAPHICS_INFO*)gi)->ysize,1,fullscreen)) { return 0; // Quit If Window Was Not Created } @@ -473,13 +489,15 @@ DWORD WINAPI win_graphics_event_loop( LPVOID gi ) { { if (active) // Program Active? { - if (keys[VK_ESCAPE]) { // Was ESC Pressed? - done=TRUE; // ESC Signalled A Quit - } - else if (clock()>next_draw_time) { // Not Time To Quit, Update Screen - DrawGLScene(); // Draw The Scene - SwapBuffers(hDC); // Swap Buffers (Double Buffering). This is taking lots of CPU time - next_draw_time = clock()+(1000/60); + if (ok_to_draw) { // Not Time To Quit, Update Screen + // Draw The Scene + DrawGLScene(); + // Swap Buffers (Double Buffering). This seems to take lots of CPU time + SwapBuffers(hDC); + // TODO: Do we need a mutex for ok_to_draw? + ok_to_draw = 0; + // Signal the worker thread that we're done drawing + SetEvent(hGlobalDrawEvent); } }