diff --git a/src/MiniFB_internal.c b/src/MiniFB_internal.c index 1cd1f41..9a721a7 100644 --- a/src/MiniFB_internal.c +++ b/src/MiniFB_internal.c @@ -5,7 +5,7 @@ #if defined(kUseBilinearInterpolation) //------------------------------------- -static uint32_t +static uint32_t interpolate(uint32_t *srcImage, uint32_t x, uint32_t y, uint32_t srcOffsetX, uint32_t srcOffsetY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch) { uint32_t incX = x + 1 < srcWidth ? 1 : 0; uint32_t incY = y + 1 < srcHeight ? srcPitch : 0; @@ -41,7 +41,7 @@ interpolate(uint32_t *srcImage, uint32_t x, uint32_t y, uint32_t srcOffsetX, uin // Only for 32 bits images //------------------------------------- -void +void stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidth, uint32_t srcHeight, uint32_t srcPitch, uint32_t *dstImage, uint32_t dstX, uint32_t dstY, uint32_t dstWidth, uint32_t dstHeight, uint32_t dstPitch) { @@ -79,7 +79,7 @@ stretch_image(uint32_t *srcImage, uint32_t srcX, uint32_t srcY, uint32_t srcWidt } //------------------------------------- -void +void calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height) { if (window_data->dst_width == 0) { window_data->dst_width = width; @@ -95,10 +95,19 @@ calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height) { } //------------------------------------- -void +void resize_dst(SWindowData *window_data, uint32_t width, uint32_t height) { window_data->dst_offset_x = (uint32_t) (width * window_data->factor_x); window_data->dst_offset_y = (uint32_t) (height * window_data->factor_y); window_data->dst_width = (uint32_t) (width * window_data->factor_width); window_data->dst_height = (uint32_t) (height * window_data->factor_height); } + +#if !defined(USE_OPENGL_API) + +//------------------------------------- +void +set_target_fps_aux() { +} + +#endif diff --git a/src/MiniFB_internal.h b/src/MiniFB_internal.h index b2d9185..3d73fe4 100755 --- a/src/MiniFB_internal.h +++ b/src/MiniFB_internal.h @@ -20,6 +20,7 @@ extern "C" { void calc_dst_factor(SWindowData *window_data, uint32_t width, uint32_t height); void resize_dst(SWindowData *window_data, uint32_t width, uint32_t height); + void set_target_fps_aux(); #if defined(__cplusplus) } diff --git a/src/MiniFB_timer.c b/src/MiniFB_timer.c index f032b28..e349970 100644 --- a/src/MiniFB_timer.c +++ b/src/MiniFB_timer.c @@ -6,6 +6,7 @@ double g_timer_frequency; double g_timer_resolution; double g_time_for_frame = 1.0 / 60.0; +bool g_use_hardware_sync = false; //------------------------------------- extern uint64_t mfb_timer_tick(void); @@ -20,6 +21,7 @@ mfb_set_target_fps(uint32_t fps) { else { g_time_for_frame = 1.0 / fps; } + set_target_fps_aux(); } //------------------------------------- @@ -50,7 +52,7 @@ mfb_timer_destroy(struct mfb_timer *tmr) { //------------------------------------- void mfb_timer_reset(struct mfb_timer *tmr) { - if(tmr == 0x0) + if(tmr == 0x0) return; tmr->start_time = mfb_timer_tick(); @@ -63,7 +65,7 @@ double mfb_timer_now(struct mfb_timer *tmr) { uint64_t counter; - if(tmr == 0x0) + if(tmr == 0x0) return 0.0; counter = mfb_timer_tick(); @@ -79,7 +81,7 @@ mfb_timer_delta(struct mfb_timer *tmr) { int64_t counter; uint64_t delta; - if(tmr == 0x0) + if(tmr == 0x0) return 0.0; counter = mfb_timer_tick(); diff --git a/src/gl/MiniFB_GL.c b/src/gl/MiniFB_GL.c index b743244..287b266 100644 --- a/src/gl/MiniFB_GL.c +++ b/src/gl/MiniFB_GL.c @@ -1,6 +1,7 @@ #if defined(USE_OPENGL_API) #include "MiniFB_GL.h" +#include "MiniFB_internal.h" #if defined(_WIN32) || defined(WIN32) #include #include @@ -19,6 +20,10 @@ #define UseCleanUp(x) #endif +extern double g_time_for_frame; +extern bool g_use_hardware_sync; + + //------------------------------------- #if defined(_WIN32) || defined(WIN32) bool @@ -59,20 +64,63 @@ setup_pixel_format(HDC hDC) { return true; } + +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC)(int); +typedef int (WINAPI * PFNWGLGETSWAPINTERVALEXTPROC)(void); +PFNWGLSWAPINTERVALEXTPROC SwapIntervalEXT = 0x0; +PFNWGLGETSWAPINTERVALEXTPROC GetSwapIntervalEXT = 0x0; + +#elif defined(linux) + +bool +setup_pixel_format(SWindowData_X11 *window_data_x11) { + GLint glxAttribs[] = { + GLX_RGBA, + GLX_DOUBLEBUFFER, + GLX_DEPTH_SIZE, 24, + GLX_STENCIL_SIZE, 8, + GLX_RED_SIZE, 8, + GLX_GREEN_SIZE, 8, + GLX_BLUE_SIZE, 8, + GLX_DEPTH_SIZE, 24, + GLX_STENCIL_SIZE, 8, + GLX_SAMPLE_BUFFERS, 0, + GLX_SAMPLES, 0, + None + }; + + XVisualInfo* visualInfo = glXChooseVisual(window_data_x11->display, window_data_x11->screen, glxAttribs); + if (visualInfo == 0) { + fprintf(stderr, "Could not create correct visual window.\n"); + XCloseDisplay(window_data_x11->display); + return false; + } + + return true; +} + +typedef void (*PFNGLXSWAPINTERVALEXTPROC)(Display*,GLXDrawable,int); +PFNGLXSWAPINTERVALEXTPROC SwapIntervalEXT = 0x0; + #endif //------------------------------------- -bool +bool create_GL_context(SWindowData *window_data) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; - if(setup_pixel_format(window_data_win->hdc) == false) + if (setup_pixel_format(window_data_win->hdc) == false) return false; + window_data_win->hGLRC = wglCreateContext(window_data_win->hdc); wglMakeCurrent(window_data_win->hdc, window_data_win->hGLRC); init_GL(window_data); + SwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC) wglGetProcAddress("wglSwapIntervalEXT"); + GetSwapIntervalEXT = (PFNWGLGETSWAPINTERVALEXTPROC) wglGetProcAddress("wglGetSwapIntervalEXT"); + set_target_fps_aux(); + return true; #elif defined(linux) @@ -89,26 +137,8 @@ create_GL_context(SWindowData *window_data) { //fprintf(stdout, "GLX version: %d.%d\n", majorGLX, minorGLX); } - GLint glxAttribs[] = { - GLX_RGBA, - GLX_DOUBLEBUFFER, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - GLX_RED_SIZE, 8, - GLX_GREEN_SIZE, 8, - GLX_BLUE_SIZE, 8, - GLX_DEPTH_SIZE, 24, - GLX_STENCIL_SIZE, 8, - GLX_SAMPLE_BUFFERS, 0, - GLX_SAMPLES, 0, - None - }; - XVisualInfo* visualInfo = glXChooseVisual(window_data_x11->display, window_data_x11->screen, glxAttribs); - if (visualInfo == 0) { - fprintf(stderr, "Could not create correct visual window.\n"); - XCloseDisplay(window_data_x11->display); + if (setup_pixel_format(window_data_x11) == false) return false; - } window_data_x11->context = glXCreateContext(window_data_x11->display, visualInfo, NULL, GL_TRUE); glXMakeCurrent(window_data_x11->display, window_data_x11->window, window_data_x11->context); @@ -120,12 +150,15 @@ create_GL_context(SWindowData *window_data) { init_GL(window_data); + SwapIntervalEXT = (PFNGLXSWAPINTERVALEXTPROC) getProcAddressGLX("glXSwapIntervalEXT"); + set_target_fps_aux(); + return true; #endif } //------------------------------------- -void +void destroy_GL_context(SWindowData *window_data) { #if defined(_WIN32) || defined(WIN32) @@ -150,13 +183,13 @@ destroy_GL_context(SWindowData *window_data) { #endif #define TEXTURE0 0x84C0 // [ Core in gl 1.3, gles1 1.0, gles2 2.0, glsc2 2.0, Provided by GL_ARB_multitexture (gl) ] -#define RGB 0x1907 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ] +#define RGB 0x1907 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ] #define RGBA 0x1908 // [ Core in gl 1.0, gles1 1.0, gles2 2.0, glsc2 2.0 ] #define BGR 0x80E0 // [ Core in gl 1.2 ] #define BGRA 0x80E1 // [ Core in gl 1.2, Provided by GL_ARB_vertex_array_bgra (gl|glcore) ] //------------------------------------- -void +void init_GL(SWindowData *window_data) { #if defined(_WIN32) || defined(WIN32) @@ -200,9 +233,9 @@ init_GL(SWindowData *window_data) { } //------------------------------------- -void +void resize_GL(SWindowData *window_data) { - if(window_data->is_initialized) { + if (window_data->is_initialized) { #if defined(_WIN32) || defined(WIN32) SWindowData_Win *window_data_ex = (SWindowData_Win *) window_data->specific; @@ -226,7 +259,7 @@ resize_GL(SWindowData *window_data) { } //------------------------------------- -void +void redraw_GL(SWindowData *window_data, const void *pixels) { #if defined(_WIN32) || defined(WIN32) @@ -253,11 +286,11 @@ redraw_GL(SWindowData *window_data, const void *pixels) { float vertices[] = { x, y, - 0, 0, + 0, 0, w, y, 1, 0, - + x, h, 0, 1, @@ -289,4 +322,47 @@ redraw_GL(SWindowData *window_data, const void *pixels) { #endif } -#endif \ No newline at end of file +//------------------------------------- +void +set_target_fps_aux() { + // Assuming the monitor refresh rate is 60 hz + int interval = (int) ((60.0 * g_time_for_frame) + 0.5); + +#if defined(_WIN32) || defined(WIN32) + + if (SwapIntervalEXT != 0x0) { + bool success = SwapIntervalEXT(interval); + if (GetSwapIntervalEXT != 0x0) { + int currentInterval = GetSwapIntervalEXT(); + if (interval != currentInterval) { + fprintf(stderr, "Cannot set target swap interval. Current swap interval is %d\n", currentInterval); + } + } + else if (success == false) { + fprintf(stderr, "Cannot set target swap interval.\n"); + } + g_use_hardware_sync = true; + } + +#elif defined(linux) + #define kGLX_SWAP_INTERVAL_EXT 0x20F1 + #define kGLX_MAX_SWAP_INTERVAL_EXT 0x20F2 + + if (SwapIntervalEXT != 0x0) { + Display *dpy = glXGetCurrentDisplay(); + GLXDrawable drawable = glXGetCurrentDrawable(); + unsigned int currentInterval, maxInterval; + + SwapIntervalEXT(dpy, drawable, interval); + glXQueryDrawable(dpy, drawable, kGLX_SWAP_INTERVAL_EXT, ¤tInterval); + if (interval != currentInterval) { + glXQueryDrawable(dpy, drawable, kGLX_MAX_SWAP_INTERVAL_EXT, &maxInterval); + fprintf(stderr, "Cannot set target swap interval. Current swap interval is %d (max: %d)\n", currentInterval, maxInterval); + } + g_use_hardware_sync = true; + } + +#endif +} + +#endif diff --git a/src/windows/WinMiniFB.c b/src/windows/WinMiniFB.c index 6be9dc2..933785f 100644 --- a/src/windows/WinMiniFB.c +++ b/src/windows/WinMiniFB.c @@ -192,7 +192,7 @@ WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { if(mfb_EnableNonClientDpiScaling) mfb_EnableNonClientDpiScaling(hWnd); - return DefWindowProc(hWnd, message, wParam, lParam);; + return DefWindowProc(hWnd, message, wParam, lParam); } // TODO @@ -647,11 +647,10 @@ mfb_update_events(struct mfb_window *window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// extern double g_time_for_frame; +extern bool g_use_hardware_sync; bool mfb_wait_sync(struct mfb_window *window) { - MSG msg; - if (window == 0x0) { return false; } @@ -662,9 +661,14 @@ mfb_wait_sync(struct mfb_window *window) { return false; } + if(g_use_hardware_sync) { + return true; + } + + MSG msg; SWindowData_Win *window_data_win = (SWindowData_Win *) window_data->specific; - double current; - uint32_t millis = 1; + double current; + uint32_t millis = 1; while (1) { current = mfb_timer_now(window_data_win->timer); if (current >= g_time_for_frame * 0.96) { diff --git a/src/x11/X11MiniFB.c b/src/x11/X11MiniFB.c index 5bae00a..446eb5e 100644 --- a/src/x11/X11MiniFB.c +++ b/src/x11/X11MiniFB.c @@ -433,6 +433,7 @@ mfb_update_events(struct mfb_window *window) { /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// extern double g_time_for_frame; +extern bool g_use_hardware_sync; bool mfb_wait_sync(struct mfb_window *window) { @@ -446,6 +447,10 @@ mfb_wait_sync(struct mfb_window *window) { return false; } + if(g_use_hardware_sync) { + return true; + } + SWindowData_X11 *window_data_x11 = (SWindowData_X11 *) window_data->specific; XFlush(window_data_x11->display); XEvent event;