From 6611e9bf5e2cf030d3281e26ec8437ebe35cf465 Mon Sep 17 00:00:00 2001 From: Flyinghead Date: Fri, 18 Oct 2019 21:57:08 +0200 Subject: [PATCH] gl: refactor wsi into their own class.Allow dynamic vk<->gl switch --- core/core.mk | 2 +- core/hw/pvr/Renderer_if.cpp | 23 +- core/hw/pvr/Renderer_if.h | 6 +- core/linux-dist/dispmanx.cpp | 6 +- core/linux-dist/main.cpp | 21 - core/linux-dist/main.h | 3 - core/linux-dist/x11.cpp | 284 +++------- core/rend/gl4/gles.cpp | 32 +- core/rend/gles/gles.cpp | 534 +----------------- core/rend/gles/gles.h | 47 +- core/rend/gui.cpp | 13 +- core/rend/vulkan/allocator.h | 4 +- core/rend/vulkan/vulkan.h | 24 +- core/rend/vulkan/vulkan_context.cpp | 93 ++- core/sdl/sdl.cpp | 172 ++---- core/sdl/sdl.h | 1 + core/serialize.cpp | 1 - core/types.h | 1 - core/windows/winmain.cpp | 53 +- core/wsi/context.h | 30 + core/wsi/egl.cpp | 234 ++++++++ core/wsi/egl.h | 58 ++ core/{rend/gles => wsi}/gl32funcs.c | 18 + core/{rend/gles => wsi}/gl32funcs.h | 18 + core/wsi/gl4funcs.cpp | 29 + core/wsi/gl_context.h | 52 ++ core/wsi/osx.cpp | 35 ++ core/wsi/osx.h | 37 ++ core/wsi/sdl.cpp | 96 ++++ core/wsi/sdl.h | 39 ++ core/wsi/swicher.cpp | 49 ++ core/wsi/wgl.cpp | 131 +++++ core/wsi/wgl.h | 78 +++ core/wsi/xgl.cpp | 175 ++++++ core/wsi/xgl.h | 45 ++ .../reicast/src/main/jni/src/Android.cpp | 76 +-- shell/apple/emulator-ios/emulator/ios_main.mm | 21 - .../emulator-osx/emulator-osx/osx-main.mm | 16 - 38 files changed, 1387 insertions(+), 1170 deletions(-) create mode 100644 core/wsi/context.h create mode 100644 core/wsi/egl.cpp create mode 100644 core/wsi/egl.h rename core/{rend/gles => wsi}/gl32funcs.c (97%) rename core/{rend/gles => wsi}/gl32funcs.h (99%) create mode 100644 core/wsi/gl4funcs.cpp create mode 100644 core/wsi/gl_context.h create mode 100644 core/wsi/osx.cpp create mode 100644 core/wsi/osx.h create mode 100644 core/wsi/sdl.cpp create mode 100644 core/wsi/sdl.h create mode 100644 core/wsi/swicher.cpp create mode 100644 core/wsi/wgl.cpp create mode 100644 core/wsi/wgl.h create mode 100644 core/wsi/xgl.cpp create mode 100644 core/wsi/xgl.h diff --git a/core/core.mk b/core/core.mk index 588fe71ba..d9bd537fb 100755 --- a/core/core.mk +++ b/core/core.mk @@ -11,7 +11,7 @@ RZDCY_MODULES := cfg/ hw/arm7/ hw/aica/ hw/holly/ hw/ hw/gdrom/ hw/maple/ \ hw/mem/ hw/pvr/ hw/sh4/ hw/sh4/interpr/ hw/sh4/modules/ plugins/ profiler/ oslib/ \ hw/extdev/ hw/arm/ hw/naomi/ imgread/ ./ deps/coreio/ deps/zlib/ deps/chdr/ deps/crypto/ \ deps/libelf/ deps/chdpsr/ arm_emitter/ rend/ reios/ deps/libpng/ deps/xbrz/ \ - deps/libzip/ deps/imgui/ archive/ input/ log/ + deps/libzip/ deps/imgui/ archive/ input/ log/ wsi/ ifndef NOT_ARM RZDCY_MODULES += rec-ARM/ diff --git a/core/hw/pvr/Renderer_if.cpp b/core/hw/pvr/Renderer_if.cpp index bd001f59e..eff8b565b 100644 --- a/core/hw/pvr/Renderer_if.cpp +++ b/core/hw/pvr/Renderer_if.cpp @@ -5,6 +5,7 @@ #include "rend/gui.h" #include "hw/mem/_vmem.h" #include "cheats.h" +#include "wsi/context.h" #include @@ -80,9 +81,9 @@ u32 FrameCount=1; Renderer* renderer; static Renderer* fallback_renderer; -volatile bool renderer_enabled = true; // Signals the renderer thread to exit -volatile bool renderer_changed = false; // Signals the renderer thread to switch renderer -volatile bool renderer_reinit_requested = false; // Signals the renderer thread to reinit the renderer +bool renderer_enabled = true; // Signals the renderer thread to exit +int renderer_changed = -1; // Signals the renderer thread to switch renderer +bool renderer_reinit_requested = false; // Signals the renderer thread to reinit the renderer #if !defined(TARGET_NO_THREADS) cResetEvent rs, re; @@ -276,10 +277,11 @@ bool rend_frame(TA_context* ctx, bool draw_osd) { bool rend_single_frame() { - if (renderer_changed) + if (renderer_changed != settings.pvr.rend) { - renderer_changed = false; rend_term_renderer(); + settings.pvr.rend = renderer_changed; + SwitchRenderApi(); rend_create_renderer(); rend_init_renderer(); } @@ -375,6 +377,7 @@ static void rend_create_renderer() #endif } #endif + renderer_changed = settings.pvr.rend; } void rend_init_renderer() @@ -428,15 +431,7 @@ void* rend_thread(void* p) swap_pending = false; } } - if (renderer_changed) - { - renderer_changed = false; - renderer_reinit_requested = false; - rend_term_renderer(); - rend_create_renderer(); - rend_init_renderer(); - } - else if (renderer_reinit_requested) + if (renderer_reinit_requested) { renderer_reinit_requested = false; rend_init_renderer(); diff --git a/core/hw/pvr/Renderer_if.h b/core/hw/pvr/Renderer_if.h index 4981e97b3..c2313e06e 100644 --- a/core/hw/pvr/Renderer_if.h +++ b/core/hw/pvr/Renderer_if.h @@ -45,9 +45,9 @@ struct Renderer }; extern Renderer* renderer; -extern volatile bool renderer_enabled; // Signals the renderer thread to exit -extern volatile bool renderer_changed; // Signals the renderer thread to switch renderer -extern volatile bool renderer_reinit_requested; // Signals the renderer thread to reinit the renderer +extern bool renderer_enabled; // Signals the renderer thread to exit +extern int renderer_changed; // Signals the renderer thread to switch renderer when different from settings.pvr.rend +extern bool renderer_reinit_requested; // Signals the renderer thread to reinit the renderer Renderer* rend_GLES2(); #if !defined(GLES) && HOST_OS != OS_DARWIN diff --git a/core/linux-dist/dispmanx.cpp b/core/linux-dist/dispmanx.cpp index e75bcd8af..f4f5452b8 100644 --- a/core/linux-dist/dispmanx.cpp +++ b/core/linux-dist/dispmanx.cpp @@ -1,6 +1,7 @@ #if defined(SUPPORT_DISPMANX) #include "dispmanx.h" #include "main.h" +#include "wsi/context.h" #include #include @@ -75,7 +76,8 @@ void dispmanx_window_create() native_window.height = window_height; vc_dispmanx_update_submit_sync( dispman_update ); - x11_disp = (void*)dispman_display; - x11_win = (void*)&native_window; + theGLContext.SetNativeWindow((EGLNativeWindowType)&native_window); + theGLContext.SetNativeDisplay((EGLNativeDisplayType)dispman_display); + SwitchRenderApi(); } #endif diff --git a/core/linux-dist/main.cpp b/core/linux-dist/main.cpp index 5cbaaba9d..020748177 100644 --- a/core/linux-dist/main.cpp +++ b/core/linux-dist/main.cpp @@ -48,19 +48,6 @@ #include "profiler/profiler.h" #endif -void* x11_win = 0; -void* x11_disp = 0; - -void* libPvr_GetRenderTarget() -{ - return x11_win; -} - -void* libPvr_GetRenderSurface() -{ - return x11_disp; -} - u16 kcode[4] = {0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF}; u8 rt[4] = {0, 0, 0, 0}; u8 lt[4] = {0, 0, 0, 0}; @@ -155,8 +142,6 @@ void dc_term(); void* rend_thread(void* p); #ifdef TARGET_PANDORA - void gl_term(); - void clean_exit(int sig_num) { void* array[10]; @@ -171,12 +156,6 @@ void* rend_thread(void* p); } } - // Close EGL context ??? - if (sig_num!=0) - { - gl_term(); - } - x11_window_destroy(): // finish cleaning diff --git a/core/linux-dist/main.h b/core/linux-dist/main.h index 9bda87aec..f08edfc8c 100644 --- a/core/linux-dist/main.h +++ b/core/linux-dist/main.h @@ -4,6 +4,3 @@ extern u16 kcode[4]; extern u8 rt[4], lt[4]; extern s8 joyx[4], joyy[4]; - -extern void* x11_win; -extern void* x11_disp; diff --git a/core/linux-dist/x11.cpp b/core/linux-dist/x11.cpp index 59c4edfda..da0830af7 100644 --- a/core/linux-dist/x11.cpp +++ b/core/linux-dist/x11.cpp @@ -3,11 +3,6 @@ #include #include -#if !defined(GLES) - #include - #include -#endif - #include "types.h" #include "cfg/cfg.h" #include "x11.h" @@ -15,15 +10,12 @@ #include "rend/gui.h" #include "input/gamepad.h" #include "icon.h" +#include "wsi/context.h" #if FEAT_HAS_NIXPROF #include "profiler/profiler.h" #endif #include "x11_keyboard.h" -#ifdef USE_VULKAN -#include "rend/vulkan/vulkan.h" -static VulkanContext *vulkanContext; -#endif #if defined(TARGET_PANDORA) #define DEFAULT_FULLSCREEN true @@ -34,6 +26,8 @@ static VulkanContext *vulkanContext; #endif #define DEFAULT_WINDOW_HEIGHT 480 +static Window x11_win; +Display *x11_disp; class MouseInputMapping : public InputMapping { @@ -71,7 +65,7 @@ public: } }; -int x11_keyboard_input = 0; +static int x11_keyboard_input = 0; static std::shared_ptr x11_keyboard; static std::shared_ptr kb_gamepad; static std::shared_ptr mouse_gamepad; @@ -79,12 +73,8 @@ static std::shared_ptr mouse_gamepad; int x11_width; int x11_height; -int ndcid = 0; -void* x11_glc = NULL; -bool x11_fullscreen = false; -Atom wmDeleteMessage; - -void* x11_vis; +static bool x11_fullscreen = false; +static Atom wmDeleteMessage; extern bool dump_frame_switch; @@ -97,30 +87,30 @@ enum _NET_WM_STATE_TOGGLE =2 }; -void x11_window_set_fullscreen(bool fullscreen) +static void x11_window_set_fullscreen(bool fullscreen) { XEvent xev; xev.xclient.type = ClientMessage; - xev.xclient.window = (Window)x11_win; - xev.xclient.message_type = XInternAtom((Display*)x11_disp, "_NET_WM_STATE", False); + xev.xclient.window = x11_win; + xev.xclient.message_type = XInternAtom(x11_disp, "_NET_WM_STATE", False); xev.xclient.format = 32; xev.xclient.data.l[0] = 2; // _NET_WM_STATE_TOGGLE - xev.xclient.data.l[1] = XInternAtom((Display*)x11_disp, "_NET_WM_STATE_FULLSCREEN", True); + xev.xclient.data.l[1] = XInternAtom(x11_disp, "_NET_WM_STATE_FULLSCREEN", True); xev.xclient.data.l[2] = 0; // no second property to toggle xev.xclient.data.l[3] = 1; xev.xclient.data.l[4] = 0; INFO_LOG(RENDERER, "x11: setting fullscreen to %d", fullscreen); - XSendEvent((Display*)x11_disp, DefaultRootWindow((Display*)x11_disp), False, SubstructureNotifyMask, &xev); + XSendEvent(x11_disp, DefaultRootWindow(x11_disp), False, SubstructureNotifyMask, &xev); } void event_x11_handle() { XEvent event; - while(XPending((Display *)x11_disp)) + while(XPending(x11_disp)) { - XNextEvent((Display *)x11_disp, &event); + XNextEvent(x11_disp, &event); if (event.type == ClientMessage && event.xclient.data.l[0] == wmDeleteMessage) @@ -147,18 +137,17 @@ static Cursor create_empty_cursor() { if (empty_cursor == None) { - Display *display = (Display*)x11_disp; char data[] = { 0 }; XColor color; color.red = color.green = color.blue = 0; - Pixmap pixmap = XCreateBitmapFromData(display, DefaultRootWindow(display), + Pixmap pixmap = XCreateBitmapFromData(x11_disp, DefaultRootWindow(x11_disp), data, 1, 1); if (pixmap) { - empty_cursor = XCreatePixmapCursor(display, pixmap, pixmap, &color, &color, 0, 0); - XFreePixmap(display, pixmap); + empty_cursor = XCreatePixmapCursor(x11_disp, pixmap, pixmap, &color, &color, 0, 0); + XFreePixmap(x11_disp, pixmap); } } return empty_cursor; @@ -168,7 +157,7 @@ static void destroy_empty_cursor() { if (empty_cursor != None) { - XFreeCursor((Display*)x11_disp, empty_cursor); + XFreeCursor(x11_disp, empty_cursor); empty_cursor = None; } } @@ -178,10 +167,8 @@ static void x11_capture_mouse() x11_window_set_text("Flycast - mouse capture"); capturing_mouse = true; Cursor cursor = create_empty_cursor(); - Display *display = (Display*)x11_disp; - Window window = (Window)x11_win; - XDefineCursor(display, window, cursor); - XGrabPointer(display, window, False, + XDefineCursor(x11_disp, x11_win, cursor); + XGrabPointer(x11_disp, x11_win, False, ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask, GrabModeAsync, GrabModeAsync, None, None, CurrentTime); } @@ -190,10 +177,8 @@ static void x11_uncapture_mouse() { x11_window_set_text("Flycast"); capturing_mouse = false; - Display *display = (Display*)x11_disp; - Window window = (Window)x11_win; - XUndefineCursor(display, window); - XUngrabPointer(display, CurrentTime); + XUndefineCursor(x11_disp, x11_win); + XUngrabPointer(x11_disp, CurrentTime); } void input_x11_handle() @@ -204,9 +189,7 @@ void input_x11_handle() bool mouse_moved = false; XEvent e; - Display *display = (Display*)x11_disp; - - while (XCheckWindowEvent(display, (Window)x11_win, + while (XCheckWindowEvent(x11_disp, x11_win, KeyPressMask | KeyReleaseMask | ButtonPressMask | ButtonReleaseMask | PointerMotionMask | FocusChangeMask, &e)) @@ -224,10 +207,10 @@ void input_x11_handle() /* no break */ case KeyRelease: { - if (e.type == KeyRelease && XEventsQueued(display, QueuedAfterReading)) + if (e.type == KeyRelease && XEventsQueued(x11_disp, QueuedAfterReading)) { XEvent nev; - XPeekEvent(display, &nev); + XPeekEvent(x11_disp, &nev); if (nev.type == KeyPress && nev.xkey.time == e.xkey.time && nev.xkey.keycode == e.xkey.keycode) @@ -345,9 +328,9 @@ void input_x11_handle() { prev_x = x11_width / 2; prev_y = x11_height / 2; - XWarpPointer(display, None, (Window)x11_win, 0, 0, 0, 0, + XWarpPointer(x11_disp, None, x11_win, 0, 0, 0, 0, prev_x, prev_y); - XSync(display, true); + XSync(x11_disp, true); } } @@ -364,116 +347,54 @@ void input_x11_init() INFO_LOG(INPUT, "X11 Keyboard input disabled by config."); } -static int x11_error_handler(Display *, XErrorEvent *) -{ - return 0; -} - void x11_window_create() { if (cfgLoadInt("pvr", "nox11", 0) == 0) { XInitThreads(); - // X11 variables - Window x11Window = 0; - Display* x11Display = 0; - long x11Screen = 0; - XVisualInfo* x11Visual = 0; - Colormap x11Colormap = 0; - - /* - Step 0 - Create a NativeWindowType that we can use it for OpenGL ES output - */ - Window sRootWindow; - XSetWindowAttributes sWA; - unsigned int ui32Mask; - int i32Depth; // Initializes the display and screen - x11Display = XOpenDisplay(NULL); - if (!x11Display && !(x11Display = XOpenDisplay(":0"))) + x11_disp = XOpenDisplay(NULL); + if (x11_disp == nullptr && (x11_disp = XOpenDisplay(":0")) == nullptr) { ERROR_LOG(RENDERER, "Error: Unable to open X display"); return; } - x11Screen = XDefaultScreen(x11Display); - float xdpi = (float)DisplayWidth(x11Display, x11Screen) / DisplayWidthMM(x11Display, x11Screen) * 25.4; - float ydpi = (float)DisplayHeight(x11Display, x11Screen) / DisplayHeightMM(x11Display, x11Screen) * 25.4; + int x11Screen = XDefaultScreen(x11_disp); + float xdpi = (float)DisplayWidth(x11_disp, x11Screen) / DisplayWidthMM(x11_disp, x11Screen) * 25.4; + float ydpi = (float)DisplayHeight(x11_disp, x11Screen) / DisplayHeightMM(x11_disp, x11Screen) * 25.4; screen_dpi = max(xdpi, ydpi); // Gets the window parameters - sRootWindow = RootWindow(x11Display, x11Screen); + Window sRootWindow = RootWindow(x11_disp, x11Screen); int depth = CopyFromParent; + XVisualInfo* x11Visual = nullptr; + Colormap x11Colormap = 0; #if !defined(GLES) - // Get a matching FB config - static int visual_attribs[] = - { - GLX_X_RENDERABLE , True, - GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, - GLX_RENDER_TYPE , GLX_RGBA_BIT, - GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, - GLX_RED_SIZE , 8, - GLX_GREEN_SIZE , 8, - GLX_BLUE_SIZE , 8, - GLX_ALPHA_SIZE , 8, - GLX_DEPTH_SIZE , 24, - GLX_STENCIL_SIZE , 8, - GLX_DOUBLEBUFFER , True, - //GLX_SAMPLE_BUFFERS , 1, - //GLX_SAMPLES , 4, - None - }; - int glx_major, glx_minor; - - // FBConfigs were added in GLX version 1.3. - if (!glXQueryVersion(x11Display, &glx_major, &glx_minor) || - ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) - { - ERROR_LOG(RENDERER, "Invalid GLX version"); + if (!theGLContext.ChooseVisual(x11_disp, &x11Visual, &depth)) exit(1); - } - - int fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(x11Display, x11Screen, visual_attribs, &fbcount); - if (!fbc) - { - ERROR_LOG(RENDERER, "Failed to retrieve a framebuffer config"); - exit(1); - } - INFO_LOG(RENDERER, "Found %d matching FB configs.", fbcount); - - GLXFBConfig bestFbc = fbc[0]; - XFree(fbc); - - // Get a visual - XVisualInfo *vi = glXGetVisualFromFBConfig(x11Display, bestFbc); - INFO_LOG(RENDERER, "Chosen visual ID = 0x%lx", vi->visualid); - - - depth = vi->depth; - x11Visual = vi; - - x11Colormap = XCreateColormap(x11Display, RootWindow(x11Display, x11Screen), vi->visual, AllocNone); + x11Colormap = XCreateColormap(x11_disp, RootWindow(x11_disp, x11Screen), x11Visual->visual, AllocNone); #else - i32Depth = DefaultDepth(x11Display, x11Screen); + int i32Depth = DefaultDepth(x11_disp, x11Screen); x11Visual = new XVisualInfo; - XMatchVisualInfo(x11Display, x11Screen, i32Depth, TrueColor, x11Visual); - if (!x11Visual) + if (!XMatchVisualInfo(x11_disp, x11Screen, i32Depth, TrueColor, x11Visual)) { ERROR_LOG(RENDERER, "Error: Unable to acquire visual"); + delete x11Visual; return; } - x11Colormap = XCreateColormap(x11Display, sRootWindow, x11Visual->visual, AllocNone); + x11Colormap = XCreateColormap(x11_disp, sRootWindow, x11Visual->visual, AllocNone); #endif + XSetWindowAttributes sWA; sWA.colormap = x11Colormap; // Add to these for handling other events sWA.event_mask = StructureNotifyMask | ExposureMask | ButtonPressMask | ButtonReleaseMask | KeyPressMask | KeyReleaseMask; sWA.event_mask |= PointerMotionMask | FocusChangeMask; - ui32Mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap; + unsigned long ui32Mask = CWBackPixel | CWBorderPixel | CWEventMask | CWColormap; x11_width = cfgLoadInt("x11", "width", DEFAULT_WINDOW_WIDTH); x11_height = cfgLoadInt("x11", "height", DEFAULT_WINDOW_HEIGHT); @@ -481,101 +402,44 @@ void x11_window_create() if (x11_width < 0 || x11_height < 0) { - x11_width = XDisplayWidth(x11Display, x11Screen); - x11_height = XDisplayHeight(x11Display, x11Screen); + x11_width = XDisplayWidth(x11_disp, x11Screen); + x11_height = XDisplayHeight(x11_disp, x11Screen); } // Creates the X11 window - x11Window = XCreateWindow(x11Display, RootWindow(x11Display, x11Screen), (ndcid%3)*640, (ndcid/3)*480, x11_width, x11_height, + x11_win = XCreateWindow(x11_disp, RootWindow(x11_disp, x11Screen), 0, 0, x11_width, x11_height, 0, depth, InputOutput, x11Visual->visual, ui32Mask, &sWA); - XSetWindowBackground(x11Display, x11Window, 0); + XSetWindowBackground(x11_disp, x11_win, 0); - Atom net_wm_icon = XInternAtom(x11Display, "_NET_WM_ICON", False); - Atom cardinal = XInternAtom(x11Display, "CARDINAL", False); - XChangeProperty(x11Display, x11Window, net_wm_icon, cardinal, 32, PropModeReplace, + Atom net_wm_icon = XInternAtom(x11_disp, "_NET_WM_ICON", False); + Atom cardinal = XInternAtom(x11_disp, "CARDINAL", False); + XChangeProperty(x11_disp, x11_win, net_wm_icon, cardinal, 32, PropModeReplace, (const unsigned char*)reicast_icon, sizeof(reicast_icon) / sizeof(*reicast_icon)); // Capture the close window event - wmDeleteMessage = XInternAtom(x11Display, "WM_DELETE_WINDOW", False); - XSetWMProtocols(x11Display, x11Window, &wmDeleteMessage, 1); + wmDeleteMessage = XInternAtom(x11_disp, "WM_DELETE_WINDOW", False); + XSetWMProtocols(x11_disp, x11_win, &wmDeleteMessage, 1); - if(x11_fullscreen) + if (x11_fullscreen) { + Atom wmState = XInternAtom(x11_disp, "_NET_WM_STATE", False); + Atom wmFullscreen = XInternAtom(x11_disp, "_NET_WM_STATE_FULLSCREEN", False); + XChangeProperty(x11_disp, x11_win, wmState, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wmFullscreen, 1); - // fullscreen - Atom wmState = XInternAtom(x11Display, "_NET_WM_STATE", False); - Atom wmFullscreen = XInternAtom(x11Display, "_NET_WM_STATE_FULLSCREEN", False); - XChangeProperty(x11Display, x11Window, wmState, XA_ATOM, 32, PropModeReplace, (unsigned char *)&wmFullscreen, 1); - - XMapRaised(x11Display, x11Window); + XMapRaised(x11_disp, x11_win); } else { - XMapWindow(x11Display, x11Window); - } - - if (settings.pvr.IsOpenGL()) - { -#if !defined(GLES) -#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 -#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 - typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); - - glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; - glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); - verify(glXCreateContextAttribsARB != 0); - int context_attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 4, - GLX_CONTEXT_MINOR_VERSION_ARB, 3, -#ifndef RELEASE - GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, -#endif - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, - None - }; - int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&x11_error_handler); - - x11_glc = glXCreateContextAttribsARB(x11Display, bestFbc, 0, True, context_attribs); - if (!x11_glc) - { - INFO_LOG(RENDERER, "Open GL 4.3 not supported"); - // Try GL 3.0 - context_attribs[1] = 3; - context_attribs[3] = 0; - x11_glc = glXCreateContextAttribsARB(x11Display, bestFbc, 0, True, context_attribs); - if (!x11_glc) - { - die("Open GL 3.0 not supported\n"); - } - } - XSetErrorHandler(old_handler); - XSync(x11Display, False); - -#endif + XMapWindow(x11_disp, x11_win); } + theGLContext.SetDisplayAndWindow(x11_disp, x11_win); #ifdef USE_VULKAN - else - { - vulkanContext = new VulkanContext(); - const char * extensions[] = { VK_KHR_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME }; - vulkanContext->InitInstance(extensions, ARRAY_SIZE(extensions)); - vulkanContext->SetWindowSize(x11_width, x11_height); - VkXlibSurfaceCreateInfoKHR createInfo = { VK_STRUCTURE_TYPE_XLIB_SURFACE_CREATE_INFO_KHR, nullptr, 0, x11Display, x11Window }; - VkSurfaceKHR surface; - vkCreateXlibSurfaceKHR(vulkanContext->GetInstance(), &createInfo, nullptr, &surface); - vulkanContext->SetSurface(surface); - vulkanContext->InitDevice(); - } + theVulkanContext.SetWindow((void *)x11_win, (void *)x11_disp); #endif + SwitchRenderApi(); - XFlush(x11Display); - - //(EGLNativeDisplayType)x11Display; - x11_disp = (void*)x11Display; - x11_win = (void*)x11Window; - x11_vis = (void*)x11Visual->visual; + XFlush(x11_disp); x11_window_set_text("Flycast"); } @@ -589,22 +453,18 @@ void x11_window_set_text(const char* text) { if (x11_win) { - XStoreName((Display*)x11_disp, (Window)x11_win, text); - XSetIconName((Display*)x11_disp, (Window)x11_win, text); + XStoreName(x11_disp, x11_win, text); + XSetIconName(x11_disp, x11_win, text); XClassHint hint = { (char *)"WM_CLASS", (char *)text }; - XSetClassHint((Display*)x11_disp, (Window)x11_win, &hint); + XSetClassHint(x11_disp, x11_win, &hint); } } void x11_window_destroy() { destroy_empty_cursor(); - -#ifdef USE_VULKAN - if (vulkanContext != nullptr) - delete vulkanContext; -#endif + TermRenderApi(); // close XWindow if (x11_win) @@ -615,21 +475,13 @@ void x11_window_destroy() cfgSaveInt("x11", "height", x11_height); } cfgSaveBool("x11", "fullscreen", x11_fullscreen); - XDestroyWindow((Display*)x11_disp, (Window)x11_win); + XDestroyWindow(x11_disp, x11_win); x11_win = NULL; } if (x11_disp) { -#if !defined(GLES) - if (x11_glc) - { - glXMakeCurrent((Display*)x11_disp, None, NULL); - glXDestroyContext((Display*)x11_disp, (GLXContext)x11_glc); - x11_glc = NULL; - } -#endif - XCloseDisplay((Display*)x11_disp); - x11_disp = NULL; + XCloseDisplay(x11_disp); + x11_disp = nullptr; } } #endif diff --git a/core/rend/gl4/gles.cpp b/core/rend/gl4/gles.cpp index 47cd78f75..2e9d23ed6 100644 --- a/core/rend/gl4/gles.cpp +++ b/core/rend/gl4/gles.cpp @@ -1,6 +1,7 @@ #include #include "gl4.h" #include "rend/gles/glcache.h" +#include "wsi/gl_context.h" #include "rend/TexCache.h" #include "cfg/cfg.h" @@ -482,8 +483,6 @@ bool gl4CompilePipelineShader( gl4PipelineShader* s, bool rotate_90, const char return glIsProgram(s->program)==GL_TRUE; } -void gl_term(); - void gl4_delete_shaders() { for (auto it : gl4.shaders) @@ -507,8 +506,6 @@ static void gles_term(void) gl4_delete_shaders(); glDeleteVertexArrays(1, &gl4.vbo.main_vao); glDeleteVertexArrays(1, &gl4.vbo.modvol_vao); - - gl_term(); } static void create_modvol_shader() @@ -568,11 +565,6 @@ extern void gl4CreateTextures(int width, int height); static bool gles_init() { - - if (!gl_init((void*)libPvr_GetRenderTarget(), - (void*)libPvr_GetRenderSurface())) - return false; - int major = 0; int minor = 0; glGetIntegerv(GL_MAJOR_VERSION, &major); @@ -598,7 +590,7 @@ static bool gles_init() //clean up the buffer glcache.ClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - gl_swap(); + theGLContext.Swap(); initABuffer(); @@ -845,7 +837,7 @@ static bool RenderFrame() } else { - if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) + if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) { output_fbo = init_output_framebuffer(rendering_width, rendering_height); } @@ -971,7 +963,7 @@ static bool RenderFrame() if (is_rtt) ReadRTTBuffer(); - else if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) + else if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) gl4_render_output_framebuffer(); return !is_rtt; @@ -981,14 +973,14 @@ void termABuffer(); struct gl4rend : Renderer { - bool Init() { return gles_init(); } - void Resize(int w, int h) + bool Init() override { return gles_init(); } + void Resize(int w, int h) override { screen_width=w; screen_height=h; resize(lroundf(w * settings.rend.ScreenScaling / 100.f), lroundf(h * settings.rend.ScreenScaling / 100.f)); } - void Term() + void Term() override { termABuffer(); if (stencilTexId != 0) @@ -1020,13 +1012,13 @@ struct gl4rend : Renderer gles_term(); } - bool Process(TA_context* ctx) { return ProcessFrame(ctx); } - bool Render() { return RenderFrame(); } - bool RenderLastFrame() { return gl.swap_buffer_not_preserved ? gl4_render_output_framebuffer() : false; } + bool Process(TA_context* ctx) override { return ProcessFrame(ctx); } + bool Render() override { return RenderFrame(); } + bool RenderLastFrame() override { return !theGLContext.IsSwapBufferPreserved() ? gl4_render_output_framebuffer() : false; } - void Present() { gl_swap(); } + void Present() override { theGLContext.Swap(); } - void DrawOSD(bool clear_screen) + void DrawOSD(bool clear_screen) override { glBindVertexArray(gl4.vbo.main_vao); glBindBuffer(GL_ARRAY_BUFFER, gl4.vbo.geometry); glCheck(); diff --git a/core/rend/gles/gles.cpp b/core/rend/gles/gles.cpp index 332c67435..971bb1bc2 100644 --- a/core/rend/gles/gles.cpp +++ b/core/rend/gles/gles.cpp @@ -1,28 +1,11 @@ #include #include "glcache.h" #include "rend/TexCache.h" -#include "cfg/cfg.h" #include "rend/gui.h" +#include "wsi/gl_context.h" +#include "cfg/cfg.h" -#ifdef TARGET_PANDORA -#include -#include -#include -#include - -#ifndef FBIO_WAITFORVSYNC - #define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) -#endif -int fbdev = -1; -#endif - -#ifndef GLES -#if HOST_OS != OS_DARWIN -#undef ARRAY_SIZE // macros are evil -#include -#pragma comment(lib,"Opengl32.lib") -#endif -#else +#ifdef GLES #ifndef GL_RED #define GL_RED 0x1903 #endif @@ -30,43 +13,8 @@ int fbdev = -1; #define GL_MAJOR_VERSION 0x821B #endif #endif -#ifdef __ANDROID__ -#include // requires ndk r5 or newer -#endif #include -/* -GL|ES 2 -Slower, smaller subset of gl2 - -*Optimisation notes* -Keep stuff in packed ints -Keep data as small as possible -Keep vertex programs as small as possible -The drivers more or less suck. Don't depend on dynamic allocation, or any 'complex' feature -as it is likely to be problematic/slow -Do we really want to enable striping joins? - -*Design notes* -Follow same architecture as the d3d renderer for now -Render to texture, keep track of textures in GL memory -Direct flip to screen (no vlbank/fb emulation) -Do we really need a combining shader? it is needlessly expensive for openGL | ES -Render contexts -Free over time? we actually care about ram usage here? -Limit max resource size? for psp 48k verts worked just fine - -FB: -Pixel clip, mapping - -SPG/VO: -mapping - -TA: -Tile clip - -*/ - #include "oslib/oslib.h" #include "rend/rend.h" #include "input/gamepad.h" @@ -489,7 +437,7 @@ static void dump_screenshot(u8 *buffer, u32 width, u32 height) } -static void do_swap_automation() +void do_swap_automation() { static FILE* video_file = fopen(cfgLoadStr("record", "rawvid","").c_str(), "wb"); extern bool do_screenshot; @@ -520,432 +468,6 @@ static void do_swap_automation() #endif -#ifdef USE_EGL - - extern "C" void load_gles_symbols(); - static bool created_context; - - bool egl_makecurrent() - { - if (gl.setup.surface == EGL_NO_SURFACE || gl.setup.context == EGL_NO_CONTEXT) - return false; - return eglMakeCurrent(gl.setup.display, gl.setup.surface, gl.setup.surface, gl.setup.context); - } - - // Create a basic GLES context - bool gl_init(void* wind, void* disp) - { - gl.setup.native_wind=(EGLNativeWindowType)wind; - gl.setup.native_disp=(EGLNativeDisplayType)disp; - - //try to get a display - gl.setup.display = eglGetDisplay(gl.setup.native_disp); - - //if failed, get the default display (this will not happen in win32) - if(gl.setup.display == EGL_NO_DISPLAY) - gl.setup.display = eglGetDisplay((EGLNativeDisplayType) EGL_DEFAULT_DISPLAY); - - - // Initialise EGL - EGLint maj, min; - if (!eglInitialize(gl.setup.display, &maj, &min)) - { - ERROR_LOG(RENDERER, "EGL Error: eglInitialize failed"); - return false; - } - - if (gl.setup.surface == 0) - { - EGLint pi32ConfigAttribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_DEPTH_SIZE, 24, - EGL_STENCIL_SIZE, 8, - EGL_NONE - }; - - int num_config; - - EGLConfig config; - if (!eglChooseConfig(gl.setup.display, pi32ConfigAttribs, &config, 1, &num_config) || (num_config != 1)) - { - // Fall back to non preserved swap buffers - EGLint pi32ConfigFallbackAttribs[] = { - EGL_SURFACE_TYPE, EGL_WINDOW_BIT, - EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, - EGL_DEPTH_SIZE, 24, - EGL_STENCIL_SIZE, 8, - EGL_NONE - }; - if (!eglChooseConfig(gl.setup.display, pi32ConfigFallbackAttribs, &config, 1, &num_config) || (num_config != 1)) - { - ERROR_LOG(RENDERER, "EGL Error: eglChooseConfig failed"); - return false; - } - } -#ifdef __ANDROID__ - EGLint format; - if (!eglGetConfigAttrib(gl.setup.display, config, EGL_NATIVE_VISUAL_ID, &format)) - { - ERROR_LOG(RENDERER, "eglGetConfigAttrib() returned error %x", eglGetError()); - return false; - } - ANativeWindow_setBuffersGeometry((ANativeWindow *)wind, 0, 0, format); -#endif - gl.setup.surface = eglCreateWindowSurface(gl.setup.display, config, (EGLNativeWindowType)wind, NULL); - - if (gl.setup.surface == EGL_NO_SURFACE) - { - ERROR_LOG(RENDERER, "EGL Error: eglCreateWindowSurface failed: %x", eglGetError()); - return false; - } - -#ifndef GLES - bool try_full_gl = true; - if (!eglBindAPI(EGL_OPENGL_API)) - { - INFO_LOG(RENDERER, "eglBindAPI(EGL_OPENGL_API) failed: %x", eglGetError()); - try_full_gl = false; - } - if (try_full_gl) - { - EGLint contextAttrs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, - EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, - EGL_NONE }; - gl.setup.context = eglCreateContext(gl.setup.display, config, NULL, contextAttrs); - if (gl.setup.context != EGL_NO_CONTEXT) - { - egl_makecurrent(); - if (gl3wInit()) - ERROR_LOG(RENDERER, "gl3wInit() failed"); - } - } -#endif - if (gl.setup.context == EGL_NO_CONTEXT) - { - if (!eglBindAPI(EGL_OPENGL_ES_API)) - { - ERROR_LOG(RENDERER, "eglBindAPI() failed: %x", eglGetError()); - return false; - } - EGLint contextAttrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2 , EGL_NONE }; - - gl.setup.context = eglCreateContext(gl.setup.display, config, NULL, contextAttrs); - - if (gl.setup.context == EGL_NO_CONTEXT) - { - ERROR_LOG(RENDERER, "eglCreateContext() failed: %x", eglGetError()); - return false; - } -#ifdef GLES -// EGL only supports runtime loading with android? TDB - load_gles_symbols(); -#else - egl_makecurrent(); - if (gl3wInit()) - INFO_LOG(RENDERER, "gl3wInit() failed"); -#endif - } - created_context = true; - } - else if (glGetError == NULL) - { - // Needed when the context is not created here (Android, iOS) - load_gles_symbols(); - } - - if (!egl_makecurrent()) - { - ERROR_LOG(RENDERER, "eglMakeCurrent() failed: %x", eglGetError()); - return false; - } - - EGLint w,h; - eglQuerySurface(gl.setup.display, gl.setup.surface, EGL_WIDTH, &w); - eglQuerySurface(gl.setup.display, gl.setup.surface, EGL_HEIGHT, &h); - - screen_width=w; - screen_height=h; - - // Required when doing partial redraws - if (!eglSurfaceAttrib(gl.setup.display, gl.setup.surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) - { - INFO_LOG(RENDERER, "Swap buffers are not preserved. Last frame copy enabled"); - gl.swap_buffer_not_preserved = true; - } - - INFO_LOG(RENDERER, "EGL config: %p, %p, %p %dx%d", gl.setup.context, gl.setup.display, gl.setup.surface, w, h); - return true; - } - - void egl_stealcntx() - { - gl.setup.context = eglGetCurrentContext(); - gl.setup.display = eglGetCurrentDisplay(); - gl.setup.surface = eglGetCurrentSurface(EGL_DRAW); - } - - //swap buffers - void gl_swap() - { -#ifdef TEST_AUTOMATION - do_swap_automation(); -#endif -#ifdef TARGET_PANDORA0 - if (fbdev >= 0) - { - int arg = 0; - ioctl(fbdev,FBIO_WAITFORVSYNC,&arg); - } -#endif - eglSwapBuffers(gl.setup.display, gl.setup.surface); - } - - void gl_term() - { - if (!created_context) - return; - created_context = false; - eglMakeCurrent(gl.setup.display, NULL, NULL, EGL_NO_CONTEXT); -#ifdef _WIN32 - ReleaseDC((HWND)gl.setup.native_wind,(HDC)gl.setup.native_disp); -#else - if (gl.setup.context != NULL) - eglDestroyContext(gl.setup.display, gl.setup.context); - if (gl.setup.surface != NULL) - eglDestroySurface(gl.setup.display, gl.setup.surface); -#ifdef TARGET_PANDORA - if (gl.setup.display) - eglTerminate(gl.setup.display); - if (fbdev>=0) - close( fbdev ); - fbdev=-1; -#endif -#endif // !_WIN32 - gl.setup.context = EGL_NO_CONTEXT; - gl.setup.surface = EGL_NO_SURFACE; - gl.setup.display = EGL_NO_DISPLAY; - } - -#elif defined(_WIN32) && !defined(USE_SDL) - #define WGL_DRAW_TO_WINDOW_ARB 0x2001 - #define WGL_ACCELERATION_ARB 0x2003 - #define WGL_SWAP_METHOD_ARB 0x2007 - #define WGL_SUPPORT_OPENGL_ARB 0x2010 - #define WGL_DOUBLE_BUFFER_ARB 0x2011 - #define WGL_PIXEL_TYPE_ARB 0x2013 - #define WGL_COLOR_BITS_ARB 0x2014 - #define WGL_DEPTH_BITS_ARB 0x2022 - #define WGL_STENCIL_BITS_ARB 0x2023 - #define WGL_FULL_ACCELERATION_ARB 0x2027 - #define WGL_SWAP_EXCHANGE_ARB 0x2028 - #define WGL_TYPE_RGBA_ARB 0x202B - #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 - #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 - #define WGL_CONTEXT_FLAGS_ARB 0x2094 - - #define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 - #define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 - #define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 - #define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 - #define WGL_CONTEXT_FLAGS_ARB 0x2094 - #define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 - #define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 - #define ERROR_INVALID_VERSION_ARB 0x2095 - #define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 - - typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, - int *piFormats, UINT *nNumFormats); - typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); - typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); - - PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; - PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; - PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; - - - HDC ourWindowHandleToDeviceContext; - bool gl_init(void* hwnd, void* hdc) - { - if (ourWindowHandleToDeviceContext) - // Already initialized - return true; - - PIXELFORMATDESCRIPTOR pfd = - { - sizeof(PIXELFORMATDESCRIPTOR), - 1, - PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags - PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette. - 32, //Colordepth of the framebuffer. - 0, 0, 0, 0, 0, 0, - 0, - 0, - 0, - 0, 0, 0, 0, - 24, //Number of bits for the depthbuffer - 8, //Number of bits for the stencilbuffer - 0, //Number of Aux buffers in the framebuffer. - PFD_MAIN_PLANE, - 0, - 0, 0, 0 - }; - - /*HDC*/ ourWindowHandleToDeviceContext = (HDC)hdc;//GetDC((HWND)hwnd); - - int letWindowsChooseThisPixelFormat; - letWindowsChooseThisPixelFormat = ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); - SetPixelFormat(ourWindowHandleToDeviceContext,letWindowsChooseThisPixelFormat, &pfd); - - HGLRC ourOpenGLRenderingContext = wglCreateContext(ourWindowHandleToDeviceContext); - wglMakeCurrent (ourWindowHandleToDeviceContext, ourOpenGLRenderingContext); - - bool rv = true; - - if (rv) { - - wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - if(!wglChoosePixelFormatARB) - { - return false; - } - - wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); - if(!wglCreateContextAttribsARB) - { - return false; - } - - wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); - if(!wglSwapIntervalEXT) - { - return false; - } - - int attribs[] = - { - WGL_CONTEXT_MAJOR_VERSION_ARB, 4, - WGL_CONTEXT_MINOR_VERSION_ARB, 3, - WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, - 0 - }; - - HGLRC m_hrc = wglCreateContextAttribsARB(ourWindowHandleToDeviceContext,0, attribs); - - if (!m_hrc) - { - INFO_LOG(RENDERER, "Open GL 4.3 not supported"); - // Try Gl 3.1 - attribs[1] = 3; - attribs[3] = 1; - m_hrc = wglCreateContextAttribsARB(ourWindowHandleToDeviceContext,0, attribs); - } - - if (m_hrc) - wglMakeCurrent(ourWindowHandleToDeviceContext,m_hrc); - else - rv = false; - - wglDeleteContext(ourOpenGLRenderingContext); - } - - if (rv) { - rv = gl3wInit() != -1 && gl3wIsSupported(3, 1); - } - - RECT r; - GetClientRect((HWND)hwnd, &r); - screen_width = r.right - r.left; - screen_height = r.bottom - r.top; - - return rv; - } - #include - void gl_swap() - { -#ifdef TEST_AUTOMATION - do_swap_automation(); -#endif - wglSwapLayerBuffers(ourWindowHandleToDeviceContext,WGL_SWAP_MAIN_PLANE); - //SwapBuffers(ourWindowHandleToDeviceContext); - } - - void gl_term() - { - } -#elif defined(SUPPORT_X11) && !defined(USE_SDL) - //! windows && X11 - //let's assume glx for now - - #include - #include - #include - #include - - - bool gl_init(void* wind, void* disp) - { - extern void* x11_glc; - - glXMakeCurrent((Display*)libPvr_GetRenderSurface(), - (GLXDrawable)libPvr_GetRenderTarget(), - (GLXContext)x11_glc); - - screen_width = 640; - screen_height = 480; - return gl3wInit() != -1 && gl3wIsSupported(3, 1); - } - - void gl_swap() - { -#ifdef TEST_AUTOMATION - do_swap_automation(); -#endif - glXSwapBuffers((Display*)libPvr_GetRenderSurface(), (GLXDrawable)libPvr_GetRenderTarget()); - - Window win; - int temp; - unsigned int tempu, new_w, new_h; - XGetGeometry((Display*)libPvr_GetRenderSurface(), (GLXDrawable)libPvr_GetRenderTarget(), - &win, &temp, &temp, &new_w, &new_h,&tempu,&tempu); - - //if resized, clear up the draw buffers, to avoid out-of-draw-area junk data - if (new_w != screen_width || new_h != screen_height) { - screen_width = new_w; - screen_height = new_h; - } - - #if 0 - //handy to debug really stupid render-not-working issues ... - - glcache.ClearColor( 0, 0.5, 1, 1 ); - glClear( GL_COLOR_BUFFER_BIT ); - glXSwapBuffers((Display*)libPvr_GetRenderSurface(), (GLXDrawable)libPvr_GetRenderTarget()); - - - glcache.ClearColor ( 1, 0.5, 0, 1 ); - glClear ( GL_COLOR_BUFFER_BIT ); - glXSwapBuffers((Display*)libPvr_GetRenderSurface(), (GLXDrawable)libPvr_GetRenderTarget()); - #endif - } - - void gl_term() - { - } - -#else -extern void gl_term(); -#if HOST_OS == OS_DARWIN -void gl_swap() -{ -#ifdef TEST_AUTOMATION - do_swap_automation(); -#endif -} -#endif -#endif - static void gl_delete_shaders() { for (auto it : gl.shaders) @@ -973,7 +495,6 @@ static void gles_term() free_output_framebuffer(); gl_delete_shaders(); - gl_term(); } void findGLVersion() @@ -1314,9 +835,6 @@ bool gl_create_resources() return true; } -//swap buffers -void gl_swap(); - GLuint gl_CompileShader(const char* shader,GLuint type); bool gl_create_resources(); @@ -1326,23 +844,11 @@ bool gl_create_resources(); bool gles_init() { - if (!gl_init((void*)libPvr_GetRenderTarget(), - (void*)libPvr_GetRenderSurface())) - return false; - glcache.EnableCache(); if (!gl_create_resources()) return false; -#ifdef USE_EGL - #ifdef TARGET_PANDORA - fbdev=open("/dev/fb0", O_RDONLY); - #else - eglSwapInterval(gl.setup.display,1); - #endif -#endif - // glEnable(GL_DEBUG_OUTPUT); // glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS); // glDebugMessageCallback(gl_DebugOutput, NULL); @@ -1351,7 +857,7 @@ bool gles_init() //clean up the buffer glcache.ClearColor(0.f, 0.f, 0.f, 0.f); glClear(GL_COLOR_BUFFER_BIT); - gl_swap(); + theGLContext.Swap(); #ifdef GL_GENERATE_MIPMAP_HINT if (gl.is_gles) @@ -1929,7 +1435,7 @@ bool RenderFrame() } else { - if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) + if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) { init_output_framebuffer((int)lroundf(screen_width * screen_scaling), (int)lroundf(screen_height * screen_scaling)); } @@ -2061,7 +1567,7 @@ bool RenderFrame() if (is_rtt) ReadRTTBuffer(); - else if (settings.rend.ScreenScaling != 100 || gl.swap_buffer_not_preserved) + else if (settings.rend.ScreenScaling != 100 || !theGLContext.IsSwapBufferPreserved()) render_output_framebuffer(); return !is_rtt; @@ -2075,20 +1581,20 @@ void rend_set_fb_scale(float x,float y) struct glesrend : Renderer { - bool Init() { return gles_init(); } - void Resize(int w, int h) { screen_width=w; screen_height=h; } - void Term() + bool Init() override { return gles_init(); } + void Resize(int w, int h) override { screen_width=w; screen_height=h; } + void Term() override { killtex(); gles_term(); } - bool Process(TA_context* ctx) { return ProcessFrame(ctx); } - bool Render() { return RenderFrame(); } - bool RenderLastFrame() { return gl.swap_buffer_not_preserved ? render_output_framebuffer() : false; } - void Present() { gl_swap(); glViewport(0, 0, screen_width, screen_height); } + bool Process(TA_context* ctx) override { return ProcessFrame(ctx); } + bool Render() override { return RenderFrame(); } + bool RenderLastFrame() override { return !theGLContext.IsSwapBufferPreserved() ? render_output_framebuffer() : false; } + void Present() override { theGLContext.Swap(); glViewport(0, 0, screen_width, screen_height); } - void DrawOSD(bool clear_screen) + void DrawOSD(bool clear_screen) override { #ifndef GLES2 if (gl.gl_major >= 3) @@ -2119,7 +1625,8 @@ FILE* pngfile; void png_cstd_read(png_structp png_ptr, png_bytep data, png_size_t length) { - fread(data,1, length,pngfile); + if (fread(data, 1, length, pngfile) != length) + png_error(png_ptr, "Truncated read error"); } u8* loadPNGData(const string& fname, int &width, int &height) @@ -2138,7 +1645,12 @@ u8* loadPNGData(const string& fname, int &width, int &height) png_byte header[8]; //read the header - fread(header,1,8,file); + if (fread(header, 1, 8, file) != 8) + { + fclose(file); + WARN_LOG(RENDERER, "Not a PNG file : %s", filename); + return NULL; + } //test if png int is_png = !png_sig_cmp(header, 0, 8); diff --git a/core/rend/gles/gles.h b/core/rend/gles/gles.h index a6818a84f..cece2af63 100755 --- a/core/rend/gles/gles.h +++ b/core/rend/gles/gles.h @@ -3,38 +3,7 @@ #include #include "rend/rend.h" #include "rend/TexCache.h" - -#if (defined(GLES) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(__ANDROID__) -#define USE_EGL -#include -#include -#endif - -#ifdef GLES -#if defined(TARGET_IPHONE) //apple-specific ogles2 headers -//#include -#include -#include -#endif -#include -#include -#ifndef GLES2 -#include "gl32funcs.h" -#endif - -#ifndef GL_NV_draw_path -//IMGTEC GLES emulation -#pragma comment(lib,"libEGL.lib") -#pragma comment(lib,"libGLESv2.lib") -#else /* NV gles emulation*/ -#pragma comment(lib,"libGLES20.lib") -#endif - -#elif HOST_OS == OS_DARWIN - #include -#else - #include -#endif +#include "wsi/gl_context.h" #define glCheck() do { if (unlikely(settings.validate.OpenGlChecks)) { verify(glGetError()==GL_NO_ERROR); } } while(0) #define eglCheck() false @@ -77,17 +46,6 @@ struct PipelineShader struct gl_ctx { -#ifdef USE_EGL - struct - { - EGLNativeWindowType native_wind; - EGLNativeDisplayType native_disp; - EGLDisplay display; - EGLSurface surface; - EGLContext context; - } setup; -#endif - struct { GLuint program; @@ -137,7 +95,6 @@ struct gl_ctx bool is_gles; GLuint fog_image_format; GLenum index_type; - bool swap_buffer_not_preserved; bool GL_OES_packed_depth_stencil_supported; bool GL_OES_depth24_supported; @@ -157,10 +114,8 @@ struct text_info { }; enum ModifierVolumeMode { Xor, Or, Inclusion, Exclusion, ModeCount }; -bool gl_init(void* wind, void* disp); void gl_load_osd_resources(); void gl_free_osd_resources(); -void gl_swap(); bool ProcessFrame(TA_context* ctx); void UpdateFogTexture(u8 *fog_table, GLenum texture_slot, GLint fog_image_format); void findGLVersion(); diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index 6d1d122bc..ceb0ede9e 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -645,7 +645,7 @@ static void gui_display_settings() ImGui::NewFrame(); int dynarec_enabled = settings.dynarec.Enable; - u32 renderer = settings.pvr.rend; + int renderer = settings.pvr.rend; bool vulkan = renderer == 4; if (!settings_opening && settings.pvr.IsOpenGL()) @@ -957,7 +957,7 @@ static void gui_display_settings() ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, normal_padding); int renderer = settings.pvr.rend == 3 ? 2 : settings.rend.PerStripSorting ? 1 : 0; #if HOST_OS != OS_DARWIN - bool has_per_pixel = !gl.is_gles && gl.gl_major >= 4; + bool has_per_pixel = !gl.is_gles && gl.gl_major >= 4 && !vulkan; #else bool has_per_pixel = false; #endif @@ -1351,13 +1351,8 @@ static void gui_display_settings() ImGui_impl_RenderDrawData(ImGui::GetDrawData(), false); if (vulkan ^ (settings.pvr.rend == 4)) - { - settings.pvr.rend = vulkan ? 4 : 0; - dc_term(); - exit(0); - } - if (renderer != settings.pvr.rend) - renderer_changed = true; + renderer = settings.pvr.rend == 4 ? 0 : 4; + renderer_changed = renderer; settings.dynarec.Enable = (bool)dynarec_enabled; } diff --git a/core/rend/vulkan/allocator.h b/core/rend/vulkan/allocator.h index b9a11c10e..29129053d 100644 --- a/core/rend/vulkan/allocator.h +++ b/core/rend/vulkan/allocator.h @@ -34,7 +34,7 @@ public: { verify(size >= SmallestBlockSize); freeBlocks.push_back(std::make_pair(0, PowerOf2(size))); - INFO_LOG(RENDERER, "Allocated memory chunk of size %zd", PowerOf2(size)); + INFO_LOG(RENDERER, "Allocated memory chunk of size %llu", (unsigned long long)PowerOf2(size)); } Chunk(const Chunk& other) = delete; Chunk(Chunk&& other) = default; @@ -46,7 +46,7 @@ public: verify(usedBlocks.empty()); verify(freeBlocks.size() <= 1); if (!freeBlocks.empty()) - INFO_LOG(RENDERER, "Freeing memory chunk of size %zd", freeBlocks.front().second); + INFO_LOG(RENDERER, "Freeing memory chunk of size %llu", (unsigned long long)freeBlocks.front().second); } private: diff --git a/core/rend/vulkan/vulkan.h b/core/rend/vulkan/vulkan.h index b272b4c8d..7bb3d154e 100644 --- a/core/rend/vulkan/vulkan.h +++ b/core/rend/vulkan/vulkan.h @@ -34,16 +34,17 @@ class VulkanContext { public: VulkanContext() { verify(contextInstance == nullptr); contextInstance = this; } - ~VulkanContext(); + ~VulkanContext() { Term(); verify(contextInstance == this); contextInstance = nullptr; } + bool Init(); bool InitInstance(const char** extensions, uint32_t extensions_count); bool InitDevice(); void CreateSwapChain(); + void Term(); + void SetWindow(void *window, void *display) { this->window = window; this->display = display; } VkInstance GetInstance() const { return static_cast(instance.get()); } u32 GetGraphicsQueueFamilyIndex() const { return graphicsQueueIndex; } - VkSurfaceKHR GetSurface() { return (VkSurfaceKHR)this->surface; } - void SetSurface(VkSurfaceKHR surface) { this->surface = vk::SurfaceKHR(surface); } void SetWindowSize(u32 width, u32 height) { this->width = screen_width = width; this->height = screen_height = height; } void NewFrame(); void BeginRenderPass(); @@ -87,10 +88,17 @@ public: private: vk::Format InitDepthBuffer(); void InitImgui(); + vk::SurfaceKHR GetSurface() { +#ifdef USE_SDL + return surface; +#else + return *surface; +#endif + } bool HasSurfaceDimensionChanged() { - vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface); + vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(GetSurface()); VkExtent2D swapchainExtent; if (surfaceCapabilities.currentExtent.width == std::numeric_limits::max()) { @@ -112,6 +120,8 @@ private: return true; } + void *window = nullptr; + void *display = nullptr; bool rendering = false; bool renderDone = false; u32 width = 0; @@ -127,7 +137,11 @@ private: bool optimalTilingSupported4444 = false; vk::UniqueDevice device; +#ifdef USE_SDL vk::SurfaceKHR surface; +#else + vk::UniqueSurfaceKHR surface; +#endif vk::UniqueSwapchainKHR swapChain; std::vector imageViews; @@ -142,7 +156,7 @@ private: vk::UniqueImage depthImage; vk::UniqueImageView depthView; vk::UniqueDeviceMemory depthMemory; - vk::Format depthFormat; + vk::Format depthFormat = vk::Format::eUndefined; std::vector commandPools; std::vector commandBuffers; diff --git a/core/rend/vulkan/vulkan_context.cpp b/core/rend/vulkan/vulkan_context.cpp index 4eea5ce37..5e59f8cbd 100644 --- a/core/rend/vulkan/vulkan_context.cpp +++ b/core/rend/vulkan/vulkan_context.cpp @@ -23,6 +23,10 @@ #include "imgui_impl_vulkan.h" #include "../gui.h" #include "hw/pvr/Renderer_if.h" +#ifdef USE_SDL +#include +#include +#endif VulkanContext *VulkanContext::contextInstance; @@ -318,13 +322,13 @@ bool VulkanContext::InitDevice() // determine a queueFamilyIndex that supports present // first check if the graphicsQueueFamilyIndex is good enough - presentQueueIndex = physicalDevice.getSurfaceSupportKHR(graphicsQueueIndex, surface) ? graphicsQueueIndex : queueFamilyProperties.size(); + presentQueueIndex = physicalDevice.getSurfaceSupportKHR(graphicsQueueIndex, GetSurface()) ? graphicsQueueIndex : queueFamilyProperties.size(); if (presentQueueIndex == queueFamilyProperties.size()) { // the graphicsQueueFamilyIndex doesn't support present -> look for an other family index that supports both graphics and present for (size_t i = 0; i < queueFamilyProperties.size(); i++) { - if ((queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eGraphics) && physicalDevice.getSurfaceSupportKHR((u32)i, surface)) + if ((queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eGraphics) && physicalDevice.getSurfaceSupportKHR((u32)i, GetSurface())) { graphicsQueueIndex = (u32)i; presentQueueIndex = (u32)i; @@ -337,7 +341,7 @@ bool VulkanContext::InitDevice() DEBUG_LOG(RENDERER, "Using separate Graphics and Present queue families"); for (size_t i = 0; i < queueFamilyProperties.size(); i++) { - if (physicalDevice.getSurfaceSupportKHR((u32)i, surface)) + if (physicalDevice.getSurfaceSupportKHR((u32)i, GetSurface())) { presentQueueIndex = (u32)i; break; @@ -352,11 +356,21 @@ bool VulkanContext::InitDevice() else DEBUG_LOG(RENDERER, "Using distinct Graphics and Present queue families"); + // Enable VK_KHR_dedicated_allocation if available + std::vector deviceExtensions = { VK_KHR_SWAPCHAIN_EXTENSION_NAME }; + for (const auto& property : physicalDevice.enumerateDeviceExtensionProperties()) + { + if (!strcmp(property.extensionName, VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME)) + deviceExtensions.push_back(VK_KHR_GET_MEMORY_REQUIREMENTS_2_EXTENSION_NAME); + else if (!strcmp(property.extensionName, VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME)) + deviceExtensions.push_back(VK_KHR_DEDICATED_ALLOCATION_EXTENSION_NAME); + } + // create a UniqueDevice float queuePriority = 1.0f; - const char *dev_extensions[] = { "VK_KHR_swapchain" }; vk::DeviceQueueCreateInfo deviceQueueCreateInfo(vk::DeviceQueueCreateFlags(), graphicsQueueIndex, 1, &queuePriority); - device = physicalDevice.createDeviceUnique(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, 0, nullptr, 1, dev_extensions)); + device = physicalDevice.createDeviceUnique(vk::DeviceCreateInfo(vk::DeviceCreateFlags(), 1, &deviceQueueCreateInfo, + 0, nullptr, deviceExtensions.size(), &deviceExtensions[0])); // This links entry points directly from the driver and isn't absolutely necessary volkLoadDevice(static_cast(*device)); @@ -431,7 +445,7 @@ void VulkanContext::CreateSwapChain() imageViews.clear(); // get the supported VkFormats - std::vector formats = physicalDevice.getSurfaceFormatsKHR(surface); + std::vector formats = physicalDevice.getSurfaceFormatsKHR(GetSurface()); assert(!formats.empty()); vk::Format colorFormat = vk::Format::eUndefined; for (const auto& f : formats) @@ -449,7 +463,7 @@ void VulkanContext::CreateSwapChain() colorFormat = (formats[0].format == vk::Format::eUndefined) ? vk::Format::eB8G8R8A8Unorm : formats[0].format; } - vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(surface); + vk::SurfaceCapabilitiesKHR surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(GetSurface()); DEBUG_LOG(RENDERER, "Surface capabilities: %d x %d, %s, image count: %d - %d", surfaceCapabilities.currentExtent.width, surfaceCapabilities.currentExtent.height, vk::to_string(surfaceCapabilities.currentTransform).c_str(), surfaceCapabilities.minImageCount, surfaceCapabilities.maxImageCount); VkExtent2D swapchainExtent; @@ -470,7 +484,7 @@ void VulkanContext::CreateSwapChain() vk::PresentModeKHR swapchainPresentMode = vk::PresentModeKHR::eFifo; // Use FIFO on mobile, prefer Mailbox on desktop #if HOST_CPU != CPU_ARM && HOST_CPU != CPU_ARM64 && !defined(__ANDROID__) - for (auto& presentMode : physicalDevice.getSurfacePresentModesKHR(surface)) + for (auto& presentMode : physicalDevice.getSurfacePresentModesKHR(GetSurface())) { if (presentMode == vk::PresentModeKHR::eMailbox) { @@ -490,7 +504,7 @@ void VulkanContext::CreateSwapChain() u32 imageCount = std::max(3u, surfaceCapabilities.minImageCount); if (surfaceCapabilities.maxImageCount != 0) imageCount = std::min(imageCount, surfaceCapabilities.maxImageCount); - vk::SwapchainCreateInfoKHR swapChainCreateInfo(vk::SwapchainCreateFlagsKHR(), surface, imageCount, colorFormat, vk::ColorSpaceKHR::eSrgbNonlinear, + vk::SwapchainCreateInfoKHR swapChainCreateInfo(vk::SwapchainCreateFlagsKHR(), GetSurface(), imageCount, colorFormat, vk::ColorSpaceKHR::eSrgbNonlinear, swapchainExtent, 1, vk::ImageUsageFlagBits::eColorAttachment, vk::SharingMode::eExclusive, 0, nullptr, preTransform, compositeAlpha, swapchainPresentMode, true, nullptr); u32 queueFamilyIndices[2] = { graphicsQueueIndex, presentQueueIndex }; @@ -575,31 +589,40 @@ void VulkanContext::CreateSwapChain() bool VulkanContext::Init() { std::vector extensions; - extensions.push_back("VK_KHR_surface"); + extensions.push_back(VK_KHR_SURFACE_EXTENSION_NAME); #if defined(_WIN32) - extensions.push_back("VK_KHR_win32_surface"); + extensions.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); #elif defined(__MACH__) - extensions.push_back("VK_MVK_macos_surface"); + extensions.push_back(VK_MVK_MACOS_SURFACE_EXTENSION_NAME); #elif defined(SUPPORT_X11) - extensions.push_back("VK_KHR_xlib_surface"); + extensions.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); +#elif defined(__ANDROID__) + extensions.push_back(VK_KHR_ANDROID_SURFACE_EXTENSION_NAME); +#elif defined(USE_SDL) + sdl_recreate_window(SDL_WINDOW_VULKAN); + uint32_t extensionsCount = 0; + SDL_Vulkan_GetInstanceExtensions((SDL_Window *)window, &extensionsCount, NULL); + extensions.resize(extensionsCount + 1); + SDL_Vulkan_GetInstanceExtensions((SDL_Window *)window, &extensionsCount, &extensions[1]); #endif if (!InitInstance(&extensions[0], extensions.size())) return false; - VkSurfaceKHR surface = VK_NULL_HANDLE; #if defined(_WIN32) - VkWin32SurfaceCreateInfoKHR createInfo = {}; - createInfo.sType = VK_STRUCTURE_TYPE_WIN32_SURFACE_CREATE_INFO_KHR; - createInfo.hinstance = GetModuleHandle(NULL); - createInfo.hwnd = (HWND)libPvr_GetRenderTarget(); - if (vkCreateWin32SurfaceKHR(*instance, &createInfo, nullptr, &surface) != VK_SUCCESS) - { - ERROR_LOG(RENDERER, "Windows surface creation failed"); - return false; - } + vk::Win32SurfaceCreateInfoKHR createInfo(vk::Win32SurfaceCreateFlagsKHR(), GetModuleHandle(NULL), (HWND)window); + surface = instance->createWin32SurfaceKHRUnique(createInfo); +#elif defined(SUPPORT_X11) + vk::XlibSurfaceCreateInfoKHR createInfo(vk::XlibSurfaceCreateFlagsKHR(), (Display*)display, (Window)window); + surface = instance->createXlibSurfaceKHRUnique(createInfo); +#elif defined(__ANDROID__) + vk::AndroidSurfaceCreateInfoKHR createInfo(vk::AndroidSurfaceCreateFlagsKHR(), (struct ANativeWindow*)window); + surface = instance->createAndroidSurfaceKHRUnique(createInfo); +#elif defined(USE_SDL) + VkSurfaceKHR surface; + if (SDL_Vulkan_CreateSurface((SDL_Window *)window, *instance, (VkSurfaceKHR *)&this->surface) == 0) + return false; #endif - SetSurface(surface); return InitDevice(); } @@ -656,10 +679,10 @@ void VulkanContext::Present() } } -VulkanContext::~VulkanContext() +void VulkanContext::Term() { ImGui_ImplVulkan_Shutdown(); - if (device) + if (device && pipelineCache) { std::vector cacheData = device->getPipelineCacheData(*pipelineCache); if (!cacheData.empty()) @@ -686,9 +709,17 @@ VulkanContext::~VulkanContext() imageAcquiredSemaphores.clear(); renderCompleteSemaphores.clear(); drawFences.clear(); - if (surface) - vkDestroySurfaceKHR((VkInstance)*instance, (VkSurfaceKHR)surface, nullptr); - - verify(contextInstance == this); - contextInstance = nullptr; +#ifndef USE_SDL + surface.reset(); +#endif + pipelineCache.reset(); + device.reset(); +#ifdef VK_DEBUG +#ifndef __ANDROID__ + debugUtilsMessenger.reset(); +#else + debugReportCallback.reset(); +#endif +#endif + instance.reset(); } diff --git a/core/sdl/sdl.cpp b/core/sdl/sdl.cpp index ca7d3e736..5ab48af4b 100644 --- a/core/sdl/sdl.cpp +++ b/core/sdl/sdl.cpp @@ -4,24 +4,17 @@ #include "cfg/cfg.h" #include "linux-dist/main.h" #include "sdl/sdl.h" -#include "rend/gui.h" -#ifndef GLES -#include "khronos/GL3/gl3w.h" -#endif #endif #include "hw/maple/maple_devs.h" #include "sdl_gamepad.h" #include "sdl_keyboard.h" +#include "wsi/context.h" #ifdef USE_VULKAN #include -#include "rend/vulkan/vulkan.h" - -VulkanContext *vulkanContext; #endif static SDL_Window* window = NULL; -static SDL_GLContext glcontext; #ifdef TARGET_PANDORA #define WINDOW_WIDTH 800 @@ -43,8 +36,6 @@ extern f32 mo_x_delta; extern f32 mo_y_delta; extern f32 mo_wheel_delta; -extern int screen_width, screen_height; - static void sdl_open_joystick(int index) { SDL_Joystick *pJoystick = SDL_JoystickOpen(index); @@ -210,148 +201,49 @@ void sdl_window_set_text(const char* text) } #if HOST_OS != OS_DARWIN +void sdl_recreate_window(u32 flags) +{ + int x = SDL_WINDOWPOS_UNDEFINED; + int y = SDL_WINDOWPOS_UNDEFINED; + int width = cfgLoadInt("x11", "width", WINDOW_WIDTH); + int height = cfgLoadInt("x11", "height", WINDOW_HEIGHT); + if (window != nullptr) + { + SDL_GetWindowPosition(window, &x, &y); + SDL_GetWindowSize(window, &width, &height); + SDL_DestroyWindow(window); + } +#ifdef TARGET_PANDORA + flags |= SDL_FULLSCREEN; +#else + flags |= SDL_SWSURFACE | SDL_WINDOW_RESIZABLE; +#endif + window = SDL_CreateWindow("Flycast", x, y, width, height, flags); + if (!window) + { + die("error creating SDL window"); + } +#ifdef USE_VULKAN + theVulkanContext.SetWindow(window, nullptr); +#endif + theGLContext.SetWindow(window); +} + void sdl_window_create() { if (SDL_WasInit(SDL_INIT_VIDEO) == 0) { - if(SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) + if (SDL_InitSubSystem(SDL_INIT_VIDEO) != 0) { die("error initializing SDL Joystick subsystem"); } } - - int window_width = cfgLoadInt("x11","width", WINDOW_WIDTH); - int window_height = cfgLoadInt("x11","height", WINDOW_HEIGHT); - -#ifdef USE_VULKAN - if (settings.pvr.IsOpenGL()) -#endif - { - int flags = SDL_WINDOW_OPENGL; -#ifdef TARGET_PANDORA - flags |= SDL_FULLSCREEN; -#else - flags |= SDL_SWSURFACE | SDL_WINDOW_RESIZABLE; -#endif - -#ifdef GLES - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); -#else - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); -#endif - - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); - SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - - window = SDL_CreateWindow("Flycast", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, flags); - if (!window) - { - die("error creating SDL window"); - } - - glcontext = SDL_GL_CreateContext(window); - if (!glcontext) - { - die("Error creating SDL GL context"); - } - SDL_GL_MakeCurrent(window, NULL); - - SDL_GL_GetDrawableSize(window, &screen_width, &screen_height); - - float ddpi, hdpi, vdpi; - if (!SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(window), &ddpi, &hdpi, &vdpi)) - screen_dpi = (int)roundf(max(hdpi, vdpi)); - - INFO_LOG(RENDERER, "Created SDL Window (%ix%i) and GL Context successfully", window_width, window_height); - } -#ifdef USE_VULKAN - else - { - int flags = SDL_WINDOW_VULKAN | SDL_WINDOW_RESIZABLE | SDL_WINDOW_ALLOW_HIGHDPI; - window = SDL_CreateWindow("Flycast", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, window_width, window_height, flags); - if (!window) - { - die("error creating SDL window"); - } - - // Setup Vulkan - vulkanContext = new VulkanContext(); - - uint32_t extensions_count = 0; - SDL_Vulkan_GetInstanceExtensions(window, &extensions_count, NULL); - const char** extensions = new const char*[extensions_count]; - SDL_Vulkan_GetInstanceExtensions(window, &extensions_count, extensions); - - vulkanContext->InitInstance(extensions, extensions_count); - - delete[] extensions; - - // Create Window Surface - VkSurfaceKHR surface; - VkResult err; - if (SDL_Vulkan_CreateSurface(window, vulkanContext->GetInstance(), &surface) == 0) - { - die("Failed to create Vulkan surface."); - } - vulkanContext->SetSurface(surface); - - // Initialize context - int w, h; - SDL_GetWindowSize(window, &w, &h); - vulkanContext->SetWindowSize(w, h); - - vulkanContext->InitDevice(); - } -#endif -} - -bool gl_init(void* wind, void* disp) -{ - SDL_GL_MakeCurrent(window, glcontext); - #ifdef GLES - return true; - #else - return gl3wInit() != -1 && gl3wIsSupported(3, 1); - #endif -} - -void gl_swap() -{ - SDL_GL_SwapWindow(window); - - /* Check if drawable has been resized */ - SDL_GL_GetDrawableSize(window, &screen_width, &screen_height); -} - -void gl_term() -{ - // FIXME This destroys the gl context and there's no way to recreate it (crash when switching renderer) - SDL_GL_DeleteContext(glcontext); + SwitchRenderApi(); } void sdl_window_destroy() { -#ifdef USE_VULKAN - if (settings.pvr.IsOpenGL()) -#endif - { - SDL_GL_DeleteContext(glcontext); - } -#ifdef USE_VULKAN - else - { - delete vulkanContext; - } -#endif + TermRenderApi(); SDL_DestroyWindow(window); } #endif diff --git a/core/sdl/sdl.h b/core/sdl/sdl.h index 7b6b1a014..f270e463c 100644 --- a/core/sdl/sdl.h +++ b/core/sdl/sdl.h @@ -7,3 +7,4 @@ extern void input_sdl_handle(u32 port); extern void sdl_window_create(); extern void sdl_window_set_text(const char* text); extern void sdl_window_destroy(); +extern void sdl_recreate_window(u32 flags); diff --git a/core/serialize.cpp b/core/serialize.cpp index fa7ef6132..e1c6468a7 100644 --- a/core/serialize.cpp +++ b/core/serialize.cpp @@ -21,7 +21,6 @@ #include "reios/gdrom_hle.h" #include #include -#include "rend/gles/gles.h" #include "hw/sh4/dyna/blockmanager.h" #include "hw/sh4/dyna/ngen.h" #include "hw/naomi/naomi_cart.h" diff --git a/core/types.h b/core/types.h index 68cfad704..d56f8dffe 100644 --- a/core/types.h +++ b/core/types.h @@ -588,7 +588,6 @@ void libPvr_Term(); void libPvr_LockedBlockWrite(vram_block* block,u32 addr); //set to 0 if not used void* libPvr_GetRenderTarget(); -void* libPvr_GetRenderSurface(); //AICA s32 libAICA_Init(); diff --git a/core/windows/winmain.cpp b/core/windows/winmain.cpp index ad80154f5..ae890026e 100644 --- a/core/windows/winmain.cpp +++ b/core/windows/winmain.cpp @@ -8,9 +8,7 @@ #include "win_keyboard.h" #include "hw/sh4/dyna/blockmanager.h" #include "log/LogManager.h" -#ifdef USE_VULKAN -#include "rend/vulkan/vulkan.h" -#endif +#include "wsi/context.h" #define _WIN32_WINNT 0x0500 #include @@ -369,7 +367,8 @@ LRESULT CALLBACK WndProc2(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) return DefWindowProc(hWnd, message, wParam, lParam); } -void* window_win; +static HWND hWnd; + void os_CreateWindow() { WNDCLASS sWC; @@ -398,28 +397,19 @@ void os_CreateWindow() SetRect(&sRect, 0, 0, screen_width, screen_height); AdjustWindowRectEx(&sRect, WS_OVERLAPPEDWINDOW, false, 0); - HWND hWnd = CreateWindow( WINDOW_CLASS, VER_FULLNAME, WS_VISIBLE | WS_OVERLAPPEDWINDOW | (window_maximized ? WS_MAXIMIZE : 0), + hWnd = CreateWindow( WINDOW_CLASS, VER_FULLNAME, WS_VISIBLE | WS_OVERLAPPEDWINDOW | (window_maximized ? WS_MAXIMIZE : 0), 0, 0, sRect.right-sRect.left, sRect.bottom-sRect.top, NULL, NULL, sWC.hInstance, NULL); - - window_win=hWnd; } void* libPvr_GetRenderTarget() { - return window_win; + return (void*)hWnd; } -void* libPvr_GetRenderSurface() -{ - return GetDC((HWND)window_win); -} - - void ToggleFullscreen() { static RECT rSaved; static bool fullscreen=false; - HWND hWnd = (HWND)window_win; fullscreen = !fullscreen; @@ -465,7 +455,7 @@ BOOL CtrlHandler( DWORD fdwCtrlType ) case CTRL_CLOSE_EVENT: // Handle the CTRL-C signal. case CTRL_C_EVENT: - SendMessageA((HWND)libPvr_GetRenderTarget(),WM_CLOSE,0,0); //FIXEM + SendMessageA(hWnd, WM_CLOSE, 0, 0); //FIXEM return( TRUE ); default: return FALSE; @@ -475,9 +465,9 @@ BOOL CtrlHandler( DWORD fdwCtrlType ) void os_SetWindowText(const char* text) { - if (GetWindowLong((HWND)libPvr_GetRenderTarget(),GWL_STYLE)&WS_BORDER) + if (GetWindowLong(hWnd, GWL_STYLE) & WS_BORDER) { - SetWindowText((HWND)libPvr_GetRenderTarget(), text); + SetWindowText(hWnd, text); } } @@ -692,7 +682,6 @@ int main(int argc, char **argv) #pragma comment(linker, "/subsystem:windows") int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShowCmd) - { int argc = 0; wchar* cmd_line = GetCommandLineA(); @@ -724,28 +713,15 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi setup_seh(); #endif #ifdef USE_VULKAN - VulkanContext *vulkanContext = nullptr; - if (settings.pvr.rend == 4) - { - vulkanContext = new VulkanContext(); - if (!vulkanContext->Init()) - { - settings.pvr.rend = 0; - delete vulkanContext; - vulkanContext = nullptr; - ERROR_LOG(RENDERER, "Vulkan initialization failed. Falling back to Open GL"); - } - } + theVulkanContext.SetWindow((void *)hWnd, (void *)GetDC((HWND)hWnd)); #endif + theGLContext.SetWindow(hWnd); + theGLContext.SetDeviceContext(GetDC(hWnd)); + SwitchRenderApi(); rend_thread(NULL); dc_term(); - -#ifdef USE_VULKAN - if (vulkanContext != nullptr) - delete vulkanContext; -#endif } #ifndef __GNUC__ __except( ExeptionHandler(GetExceptionInformation()) ) @@ -766,8 +742,8 @@ int CALLBACK WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLi -LARGE_INTEGER qpf; -double qpfd; +static LARGE_INTEGER qpf; +static double qpfd; //Helper functions double os_GetSeconds() { @@ -803,4 +779,3 @@ void os_DoEvents() } int get_mic_data(u8* buffer) { return 0; } -int push_vmu_screen(u8* buffer) { return 0; } diff --git a/core/wsi/context.h b/core/wsi/context.h new file mode 100644 index 000000000..627d653f7 --- /dev/null +++ b/core/wsi/context.h @@ -0,0 +1,30 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#pragma once +#include "gl_context.h" +#ifdef USE_VULKAN +#include "rend/vulkan/vulkan.h" + +extern VulkanContext theVulkanContext; +#endif +void SwitchRenderApi(); +void TermRenderApi(); + diff --git a/core/wsi/egl.cpp b/core/wsi/egl.cpp new file mode 100644 index 000000000..7599884e7 --- /dev/null +++ b/core/wsi/egl.cpp @@ -0,0 +1,234 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "gl_context.h" + +#ifdef USE_EGL +#include "types.h" + +#ifdef __ANDROID__ +#include // requires ndk r5 or newer +#endif +#ifdef TARGET_PANDORA +#include +#include +#include +#include + +#ifndef FBIO_WAITFORVSYNC +#define FBIO_WAITFORVSYNC _IOW('F', 0x20, __u32) +#endif +#endif + +extern "C" void load_gles_symbols(); + +EGLGraphicsContext theGLContext; + +bool EGLGraphicsContext::MakeCurrent() +{ + if (surface == EGL_NO_SURFACE || context == EGL_NO_CONTEXT) + return false; + return eglMakeCurrent(display, surface, surface, context); +} + +bool EGLGraphicsContext::Init() +{ + //try to get a display + display = eglGetDisplay(nativeDisplay); + + //if failed, get the default display (this will not happen in win32) + if (display == EGL_NO_DISPLAY) + display = eglGetDisplay(EGL_DEFAULT_DISPLAY); + + // Initialise EGL + EGLint maj, min; + if (!eglInitialize(display, &maj, &min)) + { + ERROR_LOG(RENDERER, "EGL Error: eglInitialize failed"); + return false; + } + + if (surface == EGL_NO_SURFACE) + { + EGLint pi32ConfigAttribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT | EGL_SWAP_BEHAVIOR_PRESERVED_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + + int num_config; + + EGLConfig config; + if (!eglChooseConfig(display, pi32ConfigAttribs, &config, 1, &num_config) || (num_config != 1)) + { + // Fall back to non preserved swap buffers + EGLint pi32ConfigFallbackAttribs[] = { + EGL_SURFACE_TYPE, EGL_WINDOW_BIT, + EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, + EGL_DEPTH_SIZE, 24, + EGL_STENCIL_SIZE, 8, + EGL_NONE + }; + if (!eglChooseConfig(display, pi32ConfigFallbackAttribs, &config, 1, &num_config) || (num_config != 1)) + { + ERROR_LOG(RENDERER, "EGL Error: eglChooseConfig failed"); + return false; + } + } +#ifdef __ANDROID__ + EGLint format; + if (!eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format)) + { + ERROR_LOG(RENDERER, "eglGetConfigAttrib() returned error %x", eglGetError()); + return false; + } + ANativeWindow_setBuffersGeometry((ANativeWindow *)nativeWindow, 0, 0, format); +#endif + surface = eglCreateWindowSurface(display, config, nativeWindow, NULL); + + if (surface == EGL_NO_SURFACE) + { + ERROR_LOG(RENDERER, "EGL Error: eglCreateWindowSurface failed: %x", eglGetError()); + return false; + } + +#ifndef GLES + bool try_full_gl = true; + if (!eglBindAPI(EGL_OPENGL_API)) + { + INFO_LOG(RENDERER, "eglBindAPI(EGL_OPENGL_API) failed: %x", eglGetError()); + try_full_gl = false; + } + if (try_full_gl) + { + EGLint contextAttrs[] = { EGL_CONTEXT_MAJOR_VERSION_KHR, 3, + EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR, EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR, + EGL_NONE }; + context = eglCreateContext(display, config, NULL, contextAttrs); + if (context != EGL_NO_CONTEXT) + { + MakeCurrent(); + if (gl3wInit()) + ERROR_LOG(RENDERER, "gl3wInit() failed"); + } + } +#endif + if (context == EGL_NO_CONTEXT) + { + if (!eglBindAPI(EGL_OPENGL_ES_API)) + { + ERROR_LOG(RENDERER, "eglBindAPI() failed: %x", eglGetError()); + return false; + } + + EGLint contextAttrs[] = { EGL_CONTEXT_CLIENT_VERSION, 2 , EGL_NONE }; + + context = eglCreateContext(display, config, NULL, contextAttrs); + + if (context == EGL_NO_CONTEXT) + { + ERROR_LOG(RENDERER, "eglCreateContext() failed: %x", eglGetError()); + return false; + } + +#ifdef GLES +// EGL only supports runtime loading with android? TDB + load_gles_symbols(); +#else + MakeCurrent(); + if (gl3wInit()) + INFO_LOG(RENDERER, "gl3wInit() failed"); +#endif + } + } + else if (glGetError == NULL) + { + // Needed when the context is not created here (Android java mode, iOS) + // Broken atm + load_gles_symbols(); + } + + if (!MakeCurrent()) + { + ERROR_LOG(RENDERER, "eglMakeCurrent() failed: %x", eglGetError()); + return false; + } + + EGLint w,h; + eglQuerySurface(display, surface, EGL_WIDTH, &w); + eglQuerySurface(display, surface, EGL_HEIGHT, &h); + + screen_width = w; + screen_height = h; + + // Required when doing partial redraws + swap_buffer_preserved = true; + if (!eglSurfaceAttrib(display, surface, EGL_SWAP_BEHAVIOR, EGL_BUFFER_PRESERVED)) + { + INFO_LOG(RENDERER, "Swap buffers are not preserved. Last frame copy enabled"); + swap_buffer_preserved = false; + } +#ifdef TARGET_PANDORA + fbdev = open("/dev/fb0", O_RDONLY); +#else + eglSwapInterval(display, 1); +#endif + + INFO_LOG(RENDERER, "EGL config: %p, %p, %p %dx%d", context, display, surface, w, h); + return true; +} + +void EGLGraphicsContext::Term() +{ + eglMakeCurrent(display, NULL, NULL, EGL_NO_CONTEXT); + if (context != EGL_NO_CONTEXT) + eglDestroyContext(display, context); + if (surface != EGL_NO_SURFACE) + eglDestroySurface(display, surface); +#ifdef TARGET_PANDORA + if (display != EGL_NO_DISPLAY) + eglTerminate(display); + if (fbdev >= 0) + close(fbdev); + fbdev = -1; +#endif + + context = EGL_NO_CONTEXT; + surface = EGL_NO_SURFACE; + display = EGL_NO_DISPLAY; +} + +void EGLGraphicsContext::Swap() +{ +#ifdef TEST_AUTOMATION + do_swap_automation(); +#endif +#if 0 && defined(TARGET_PANDORA) + if (fbdev >= 0) + { + int arg = 0; + ioctl(fbdev,FBIO_WAITFORVSYNC,&arg); + } +#endif + eglSwapBuffers(display, surface); +} +#endif // USE_EGL diff --git a/core/wsi/egl.h b/core/wsi/egl.h new file mode 100644 index 000000000..308ba3735 --- /dev/null +++ b/core/wsi/egl.h @@ -0,0 +1,58 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include +#include +#ifndef GLES2 +#include "gl32funcs.h" +#endif + +#define USE_EGL +#include +#include + +class EGLGraphicsContext +{ +public: + ~EGLGraphicsContext() { Term(); } + + bool Init(); + void Term(); + void Swap(); + bool MakeCurrent(); + bool IsSwapBufferPreserved() const { return swap_buffer_preserved; } + void SetNativeWindow(EGLNativeWindowType window) + { nativeWindow = window; } + void SetNativeDisplay(EGLNativeDisplayType display) + { nativeDisplay = display; } + +private: + EGLNativeDisplayType nativeDisplay = EGL_DEFAULT_DISPLAY; + EGLNativeWindowType nativeWindow = (EGLNativeWindowType)0; + EGLDisplay display = EGL_NO_DISPLAY; + EGLSurface surface = EGL_NO_SURFACE; + EGLContext context = EGL_NO_CONTEXT; + bool swap_buffer_preserved = true; +#ifdef TARGET_PANDORA + int fbdev = -1; +#endif +}; + +extern EGLGraphicsContext theGLContext; diff --git a/core/rend/gles/gl32funcs.c b/core/wsi/gl32funcs.c similarity index 97% rename from core/rend/gles/gl32funcs.c rename to core/wsi/gl32funcs.c index 05e54c41e..af5272e5c 100644 --- a/core/rend/gles/gl32funcs.c +++ b/core/wsi/gl32funcs.c @@ -1,3 +1,21 @@ +/* + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ #include #include #include diff --git a/core/rend/gles/gl32funcs.h b/core/wsi/gl32funcs.h similarity index 99% rename from core/rend/gles/gl32funcs.h rename to core/wsi/gl32funcs.h index 792dd40fa..6d40a61b4 100644 --- a/core/rend/gles/gl32funcs.h +++ b/core/wsi/gl32funcs.h @@ -1,3 +1,21 @@ +/* + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ #pragma once #ifdef __cplusplus diff --git a/core/wsi/gl4funcs.cpp b/core/wsi/gl4funcs.cpp new file mode 100644 index 000000000..6fd83e932 --- /dev/null +++ b/core/wsi/gl4funcs.cpp @@ -0,0 +1,29 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "types.h" + +#ifndef GLES +#if HOST_OS != OS_DARWIN +#undef ARRAY_SIZE // macros are evil +#include +#endif +#endif + diff --git a/core/wsi/gl_context.h b/core/wsi/gl_context.h new file mode 100644 index 000000000..fa6d03fc8 --- /dev/null +++ b/core/wsi/gl_context.h @@ -0,0 +1,52 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#pragma once +#include "types.h" + +void do_swap_automation(); +// FIXME +extern int screen_width, screen_height; + +#if HOST_OS == OS_DARWIN + +#include "osx.h" + +#elif defined(USE_SDL) + +#include "sdl.h" + +#elif defined(GLES) || defined(__ANDROID__) + +#include "egl.h" + +#elif defined(_WIN32) + +#include "wgl.h" + +#elif defined(SUPPORT_X11) + +#include "xgl.h" + +#else + +#error Unsupported window system + +#endif diff --git a/core/wsi/osx.cpp b/core/wsi/osx.cpp new file mode 100644 index 000000000..41161a34e --- /dev/null +++ b/core/wsi/osx.cpp @@ -0,0 +1,35 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "build.h" + +#if HOST_OS == OS_DARWIN +#include "gl_context.h" + +OSXGraphicsContext theGLContext; + +void OSXGraphicsContext::Swap() +{ +#ifdef TEST_AUTOMATION + do_swap_automation(); +#endif +} + +#endif diff --git a/core/wsi/osx.h b/core/wsi/osx.h new file mode 100644 index 000000000..e245db5e8 --- /dev/null +++ b/core/wsi/osx.h @@ -0,0 +1,37 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#if defined(TARGET_IPHONE) //apple-specific ogles2 headers +#include +#include +#else +#include +#endif + +class OSXGraphicsContext +{ +public: + bool Init() { return true; } + void Term() {} + void Swap(); + bool IsSwapBufferPreserved() const { return true; } +}; + +extern OSXGraphicsContext theGLContext; diff --git a/core/wsi/sdl.cpp b/core/wsi/sdl.cpp new file mode 100644 index 000000000..534d3ee52 --- /dev/null +++ b/core/wsi/sdl.cpp @@ -0,0 +1,96 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "build.h" +#if 1//defined(USE_SDL) && HOST_OS != OS_DARWIN +#include "gl_context.h" +#include "rend/gui.h" +#include "sdl/sdl.h" + +SDLGLGraphicsContext theGLContext; + +bool SDLGLGraphicsContext::Init() +{ +#ifdef GLES + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0); +#else + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); +#endif + + SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24); + SDL_GL_SetAttribute(SDL_GL_STENCIL_SIZE, 8); + SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); + + sdl_recreate_window(SDL_WINDOW_OPENGL); + + glcontext = SDL_GL_CreateContext(window); + if (!glcontext) + { + ERROR_LOG(RENDERER, "Error creating SDL GL context"); + SDL_DestroyWindow(window); + window = nullptr; + return false; + } + SDL_GL_MakeCurrent(window, NULL); + + SDL_GL_GetDrawableSize(window, &screen_width, &screen_height); + + float ddpi, hdpi, vdpi; + if (!SDL_GetDisplayDPI(SDL_GetWindowDisplayIndex(window), &ddpi, &hdpi, &vdpi)) + screen_dpi = (int)roundf(max(hdpi, vdpi)); + + INFO_LOG(RENDERER, "Created SDL Window and GL Context successfully"); + + SDL_GL_MakeCurrent(window, glcontext); + +#ifdef GLES + return true; +#else + return gl3wInit() != -1 && gl3wIsSupported(3, 1); +#endif +} + +void SDLGLGraphicsContext::Swap() +{ + SDL_GL_SwapWindow(window); + + /* Check if drawable has been resized */ + SDL_GL_GetDrawableSize(window, &screen_width, &screen_height); +} + +void SDLGLGraphicsContext::Term() +{ + if (glcontext != nullptr) + { + SDL_GL_DeleteContext(glcontext); + glcontext = nullptr; + } +} + +#endif + diff --git a/core/wsi/sdl.h b/core/wsi/sdl.h new file mode 100644 index 000000000..902828f65 --- /dev/null +++ b/core/wsi/sdl.h @@ -0,0 +1,39 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include +#include "types.h" +#include + +class SDLGLGraphicsContext +{ +public: + bool Init(); + void Term(); + void Swap(); + bool IsSwapBufferPreserved() const { return true; } + void SetWindow(SDL_Window *window) { this->window = window; } + +private: + SDL_Window* window = nullptr; + SDL_GLContext glcontext = nullptr; +}; + +extern SDLGLGraphicsContext theGLContext; diff --git a/core/wsi/swicher.cpp b/core/wsi/swicher.cpp new file mode 100644 index 000000000..67b783ae4 --- /dev/null +++ b/core/wsi/swicher.cpp @@ -0,0 +1,49 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "context.h" + +#ifdef USE_VULKAN +VulkanContext theVulkanContext; +#endif + +void SwitchRenderApi() +{ +#ifdef USE_VULKAN + if (settings.pvr.rend == 4) + { + theGLContext.Term(); + if (theVulkanContext.Init()) + return; + // Fall back to Open GL + } + theVulkanContext.Term(); +#endif + if (!theGLContext.Init()) + exit(1); +} + +void TermRenderApi() +{ +#ifdef USE_VULKAN + theVulkanContext.Term(); +#endif + theGLContext.Term(); +} diff --git a/core/wsi/wgl.cpp b/core/wsi/wgl.cpp new file mode 100644 index 000000000..57b8c38d6 --- /dev/null +++ b/core/wsi/wgl.cpp @@ -0,0 +1,131 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "gl_context.h" +#include "types.h" + +#if defined(_WIN32) && !defined(USE_SDL) + +WGLGraphicsContext theGLContext; + +bool WGLContext::Init() +{ + if (ourOpenGLRenderingContext != NULL) + // Already initialized + return true; + + PIXELFORMATDESCRIPTOR pfd = + { + sizeof(PIXELFORMATDESCRIPTOR), + 1, + PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER, //Flags + PFD_TYPE_RGBA, //The kind of framebuffer. RGBA or palette. + 32, //Colordepth of the framebuffer. + 0, 0, 0, 0, 0, 0, + 0, + 0, + 0, + 0, 0, 0, 0, + 24, //Number of bits for the depthbuffer + 8, //Number of bits for the stencilbuffer + 0, //Number of Aux buffers in the framebuffer. + PFD_MAIN_PLANE, + 0, + 0, 0, 0 + }; + + int letWindowsChooseThisPixelFormat; + letWindowsChooseThisPixelFormat = ChoosePixelFormat(ourWindowHandleToDeviceContext, &pfd); + SetPixelFormat(ourWindowHandleToDeviceContext,letWindowsChooseThisPixelFormat, &pfd); + + HGLRC tempOpenGLContext = wglCreateContext(ourWindowHandleToDeviceContext); + wglMakeCurrent(ourWindowHandleToDeviceContext, tempOpenGLContext); + + wglChoosePixelFormatARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); + if(!wglChoosePixelFormatARB) + return false; + + wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB"); + if(!wglCreateContextAttribsARB) + return false; + + wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT"); + if(!wglSwapIntervalEXT) + return false; + + int attribs[] = + { + WGL_CONTEXT_MAJOR_VERSION_ARB, 4, + WGL_CONTEXT_MINOR_VERSION_ARB, 3, + WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, + WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB, + 0 + }; + + ourOpenGLRenderingContext = wglCreateContextAttribsARB(ourWindowHandleToDeviceContext, 0, attribs); + + if (!ourOpenGLRenderingContext) + { + INFO_LOG(RENDERER, "Open GL 4.3 not supported"); + // Try Gl 3.1 + attribs[1] = 3; + attribs[3] = 1; + ourOpenGLRenderingContext = wglCreateContextAttribsARB(ourWindowHandleToDeviceContext, 0, attribs); + } + + bool rv = true; + + if (ourOpenGLRenderingContext) + wglMakeCurrent(ourWindowHandleToDeviceContext, ourOpenGLRenderingContext); + else + rv = false; + + wglDeleteContext(tempOpenGLContext); + + if (rv) { + rv = gl3wInit() != -1 && gl3wIsSupported(3, 1); + } + + RECT r; + GetClientRect(ourWindow, &r); + screen_width = r.right - r.left; + screen_height = r.bottom - r.top; + + return rv; +} + +void WGLContext::Swap() +{ +#ifdef TEST_AUTOMATION + do_swap_automation(); +#endif + wglSwapLayerBuffers(ourWindowHandleToDeviceContext, WGL_SWAP_MAIN_PLANE); +} + +void WGLContext::Term() +{ + if (ourOpenGLRenderingContext != NULL) + { + wglDeleteContext(ourOpenGLRenderingContext); + ourOpenGLRenderingContext = NULL; + } +} + +#endif diff --git a/core/wsi/wgl.h b/core/wsi/wgl.h new file mode 100644 index 000000000..78a1a837b --- /dev/null +++ b/core/wsi/wgl.h @@ -0,0 +1,78 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include +#include + +#define WGL_DRAW_TO_WINDOW_ARB 0x2001 +#define WGL_ACCELERATION_ARB 0x2003 +#define WGL_SWAP_METHOD_ARB 0x2007 +#define WGL_SUPPORT_OPENGL_ARB 0x2010 +#define WGL_DOUBLE_BUFFER_ARB 0x2011 +#define WGL_PIXEL_TYPE_ARB 0x2013 +#define WGL_COLOR_BITS_ARB 0x2014 +#define WGL_DEPTH_BITS_ARB 0x2022 +#define WGL_STENCIL_BITS_ARB 0x2023 +#define WGL_FULL_ACCELERATION_ARB 0x2027 +#define WGL_SWAP_EXCHANGE_ARB 0x2028 +#define WGL_TYPE_RGBA_ARB 0x202B +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 + +#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126 +#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092 +#define WGL_CONTEXT_LAYER_PLANE_ARB 0x2093 +#define WGL_CONTEXT_FLAGS_ARB 0x2094 +#define WGL_CONTEXT_DEBUG_BIT_ARB 0x0001 +#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x0002 +#define ERROR_INVALID_VERSION_ARB 0x2095 +#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001 + +typedef BOOL (WINAPI * PFNWGLCHOOSEPIXELFORMATARBPROC) (HDC hdc, const int *piAttribIList, const FLOAT *pfAttribFList, UINT nMaxFormats, + int *piFormats, UINT *nNumFormats); +typedef HGLRC (WINAPI * PFNWGLCREATECONTEXTATTRIBSARBPROC) (HDC hDC, HGLRC hShareContext, const int *attribList); +typedef BOOL (WINAPI * PFNWGLSWAPINTERVALEXTPROC) (int interval); + +PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormatARB; +PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB; +PFNWGLSWAPINTERVALEXTPROC wglSwapIntervalEXT; + + +class WGLGraphicsContext +{ +public: + ~WGLGraphicsContext() { Term(); } + + bool Init(); + void Term(); + void Swap(); + bool IsSwapBufferPreserved() const { return true; } + void SetWindow(HWND hwnd) { this->ourWindow = hwnd; } + void SetDeviceContext(HDC hdc) { this->ourWindowHandleToDeviceContext = hdc; } + +private: + HGLRC ourOpenGLRenderingContext = NULL; + HDC ourWindowHandleToDeviceContext = NULL; + HWND ourWindow = NULL; +}; + +extern WGLGraphicsContext theGLContext; diff --git a/core/wsi/xgl.cpp b/core/wsi/xgl.cpp new file mode 100644 index 000000000..5b4b68067 --- /dev/null +++ b/core/wsi/xgl.cpp @@ -0,0 +1,175 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include "types.h" +#if defined(SUPPORT_X11) && !defined(USE_SDL) +#include "gl_context.h" + +#ifndef GLX_CONTEXT_MAJOR_VERSION_ARB +#define GLX_CONTEXT_MAJOR_VERSION_ARB 0x2091 +#endif +#ifndef GLX_CONTEXT_MINOR_VERSION_ARB +#define GLX_CONTEXT_MINOR_VERSION_ARB 0x2092 +#endif + +XGLGraphicsContext theGLContext; + +static int x11_error_handler(Display *, XErrorEvent *) +{ + return 0; +} + +bool XGLGraphicsContext::Init() +{ + typedef GLXContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLXContext, Bool, const int*); + + glXCreateContextAttribsARBProc glXCreateContextAttribsARB = 0; + glXCreateContextAttribsARB = (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte*)"glXCreateContextAttribsARB"); + verify(glXCreateContextAttribsARB != 0); + int context_attribs[] = + { + GLX_CONTEXT_MAJOR_VERSION_ARB, 4, + GLX_CONTEXT_MINOR_VERSION_ARB, 3, +#ifndef RELEASE + GLX_CONTEXT_FLAGS_ARB, GLX_CONTEXT_DEBUG_BIT_ARB, +#endif + GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB, + None + }; + int (*old_handler)(Display *, XErrorEvent *) = XSetErrorHandler(&x11_error_handler); + + context = glXCreateContextAttribsARB(this->display, *framebufferConfigs, 0, True, context_attribs); + if (!context) + { + INFO_LOG(RENDERER, "Open GL 4.3 not supported"); + // Try GL 3.0 + context_attribs[1] = 3; + context_attribs[3] = 0; + context = glXCreateContextAttribsARB(this->display, *framebufferConfigs, 0, True, context_attribs); + if (!context) + { + ERROR_LOG(RENDERER, "Open GL 3.0 not supported\n"); + return false; + } + } + XSetErrorHandler(old_handler); + XSync(this->display, False); + + glXMakeCurrent(this->display, this->window, context); + + screen_width = 640; + screen_height = 480; + return gl3wInit() != -1 && gl3wIsSupported(3, 1); +} + +bool XGLGraphicsContext::ChooseVisual(Display* x11Display, XVisualInfo** visual, int* depth) +{ + // Get a matching FB config + static int visual_attribs[] = + { + GLX_X_RENDERABLE , True, + GLX_DRAWABLE_TYPE , GLX_WINDOW_BIT, + GLX_RENDER_TYPE , GLX_RGBA_BIT, + GLX_X_VISUAL_TYPE , GLX_TRUE_COLOR, + GLX_RED_SIZE , 8, + GLX_GREEN_SIZE , 8, + GLX_BLUE_SIZE , 8, + GLX_ALPHA_SIZE , 8, + GLX_DEPTH_SIZE , 24, + GLX_STENCIL_SIZE , 8, + GLX_DOUBLEBUFFER , True, + //GLX_SAMPLE_BUFFERS , 1, + //GLX_SAMPLES , 4, + None + }; + + int glx_major, glx_minor; + + // FBConfigs were added in GLX version 1.3. + if (!glXQueryVersion(x11Display, &glx_major, &glx_minor) || + ((glx_major == 1) && (glx_minor < 3)) || (glx_major < 1)) + { + ERROR_LOG(RENDERER, "Invalid GLX version"); + return false; + } + const long x11Screen = XDefaultScreen(x11Display); + + int fbcount; + framebufferConfigs = glXChooseFBConfig(x11Display, x11Screen, visual_attribs, &fbcount); + if (framebufferConfigs == nullptr) + { + ERROR_LOG(RENDERER, "Failed to retrieve a framebuffer config"); + return false; + } + INFO_LOG(RENDERER, "Found %d matching FB configs.", fbcount); + + // Get a visual + XVisualInfo *vi = glXGetVisualFromFBConfig(x11Display, *framebufferConfigs); + INFO_LOG(RENDERER, "Chosen visual ID = 0x%lx", vi->visualid); + + *depth = vi->depth; + *visual = vi; + + return true; +} + +void XGLGraphicsContext::Swap() +{ +#ifdef TEST_AUTOMATION + do_swap_automation(); +#endif + glXSwapBuffers(display, window); + + Window win; + int temp; + unsigned int tempu, new_w, new_h; + XGetGeometry(display, window, &win, &temp, &temp, &new_w, &new_h, &tempu, &tempu); + + //if resized, clear up the draw buffers, to avoid out-of-draw-area junk data + if (new_w != screen_width || new_h != screen_height) { + screen_width = new_w; + screen_height = new_h; + } + +#if 0 + //handy to debug really stupid render-not-working issues ... + + glcache.ClearColor(0, 0.5, 1, 1); + glClear(GL_COLOR_BUFFER_BIT); + glXSwapBuffers(display, window); + + + glcache.ClearColor(1, 0.5, 0, 1); + glClear(GL_COLOR_BUFFER_BIT); + glXSwapBuffers(display, window); +#endif +} + +void XGLGraphicsContext::Term() +{ + if (context) + { + glXMakeCurrent(display, None, NULL); + glXDestroyContext(display, context); + context = (GLXContext)0; + } +} + +#endif diff --git a/core/wsi/xgl.h b/core/wsi/xgl.h new file mode 100644 index 000000000..cc9e56dda --- /dev/null +++ b/core/wsi/xgl.h @@ -0,0 +1,45 @@ +/* + Created on: Oct 18, 2019 + + Copyright 2019 flyinghead + + This file is part of Flycast. + + Flycast is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 2 of the License, or + (at your option) any later version. + + Flycast is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Flycast. If not, see . +*/ +#include +#include +#include +#include + +class XGLGraphicsContext +{ +public: + ~XGLGraphicsContext() { Term(); XFree(framebufferConfigs); } + + bool Init(); + void Term(); + void Swap(); + bool IsSwapBufferPreserved() const { return true; } + bool ChooseVisual(Display* x11Display, XVisualInfo** visual, int* depth); + void SetDisplayAndWindow(Display *display, GLXDrawable window) { this->display = display; this->window = window; } + +private: + GLXDrawable window; + Display *display; + GLXContext context; + GLXFBConfig* framebufferConfigs = nullptr; +}; + +extern XGLGraphicsContext theGLContext; diff --git a/shell/android-studio/reicast/src/main/jni/src/Android.cpp b/shell/android-studio/reicast/src/main/jni/src/Android.cpp index d7b4f19aa..02aa472db 100644 --- a/shell/android-studio/reicast/src/main/jni/src/Android.cpp +++ b/shell/android-studio/reicast/src/main/jni/src/Android.cpp @@ -25,7 +25,7 @@ #include "rend/gui.h" #include "cfg/cfg.h" #include "log/LogManager.h" -#include "rend/vulkan/vulkan.h" +#include "wsi/context.h" JavaVM* g_jvm; @@ -178,16 +178,6 @@ void UpdateInputState(u32 Port) // @@@ Nothing here yet } -void *libPvr_GetRenderTarget() -{ - return g_window; // the surface to render to -} - -void *libPvr_GetRenderSurface() -{ - return NULL; // default display -} - void common_linux_setup(); void os_SetupInput() @@ -404,63 +394,13 @@ extern void egl_stealcntx(); static void *render_thread_func(void *) { #ifdef USE_VULKAN - VulkanContext *vulkanContext = nullptr; - if (settings.pvr.rend == 4) - { - // Vulkan init - INFO_LOG(RENDERER, "Initializing Vulkan"); - vulkanContext = new VulkanContext(); - std::vector extensions; - extensions.emplace_back("VK_KHR_surface"); - extensions.emplace_back("VK_KHR_android_surface"); - if (vulkanContext->InitInstance(&extensions[0], extensions.size())) - { - VkAndroidSurfaceCreateInfoKHR createInfo { - .sType = VK_STRUCTURE_TYPE_ANDROID_SURFACE_CREATE_INFO_KHR, - .pNext = nullptr, - .flags = 0, - .window = g_window - }; - VkSurfaceKHR surface; - if (vkCreateAndroidSurfaceKHR(vulkanContext->GetInstance(), &createInfo, nullptr, &surface) != VK_SUCCESS) - { - ERROR_LOG(RENDERER, "Vulkan surface creation failed"); - settings.pvr.rend = 0; - - } - else - { - vulkanContext->SetSurface(surface); - if (!vulkanContext->InitDevice()) - settings.pvr.rend = 0; - else - INFO_LOG(RENDERER, "Vulkan init done"); - } - } - else - { - settings.pvr.rend = 0; - } - } - if (settings.pvr.rend != 4) - { - // Clean up any aborted vulkan context in case it failed to initialize - // and fall back to Open GL - if (vulkanContext == nullptr) - { - delete vulkanContext; - vulkanContext = nullptr; - } - INFO_LOG(RENDERER, "Initializing OpenGL"); - } - + theVulkanContext.SetWindow((void *)g_window, nullptr); #endif + theGLContext.SetNativeWindow((EGLNativeWindowType)g_window); + SwitchRenderApi(); + rend_thread(NULL); -#ifdef USE_VULKAN - if (vulkanContext) - delete vulkanContext; -#endif ANativeWindow_release(g_window); g_window = NULL; @@ -492,19 +432,19 @@ JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendinitJava(JNIEnv * { screen_width = width; screen_height = height; - egl_stealcntx(); + // FIXME egl_stealcntx(); rend_init_renderer(); } JNIEXPORT jboolean JNICALL Java_com_reicast_emulator_emu_JNIdc_rendframeJava(JNIEnv *env,jobject obj) { - egl_stealcntx(); + // FIXME egl_stealcntx(); return (jboolean)rend_single_frame(); } JNIEXPORT void JNICALL Java_com_reicast_emulator_emu_JNIdc_rendtermJava(JNIEnv * env, jobject obj) { - egl_stealcntx(); + // FIXME egl_stealcntx(); rend_term_renderer(); } diff --git a/shell/apple/emulator-ios/emulator/ios_main.mm b/shell/apple/emulator-ios/emulator/ios_main.mm index 4411e6e86..e5d31b5bf 100644 --- a/shell/apple/emulator-ios/emulator/ios_main.mm +++ b/shell/apple/emulator-ios/emulator/ios_main.mm @@ -98,24 +98,3 @@ void UpdateInputState(u32 port) { void get_mic_data(u8* ) { } - -void* libPvr_GetRenderTarget() { - return 0; -} - -void* libPvr_GetRenderSurface() { - return 0; - -} - -bool gl_init(void*, void*) { - return true; -} - -void gl_term() { - -} - -void gl_swap() { - -} diff --git a/shell/apple/emulator-osx/emulator-osx/osx-main.mm b/shell/apple/emulator-osx/emulator-osx/osx-main.mm index 09bcddf62..712284f04 100644 --- a/shell/apple/emulator-osx/emulator-osx/osx-main.mm +++ b/shell/apple/emulator-osx/emulator-osx/osx-main.mm @@ -43,7 +43,6 @@ s8 joyx[4],joyy[4]; u8 rt[4],lt[4]; int get_mic_data(u8* buffer) { return 0; } -int push_vmu_screen(u8* buffer) { return 0; } void os_SetWindowText(const char * text) { puts(text); @@ -73,21 +72,6 @@ void os_SetupInput() GamepadDevice::Register(mouse_gamepad); } -void* libPvr_GetRenderTarget() { - return 0; -} - -void* libPvr_GetRenderSurface() { - return 0; -} - -bool gl_init(void*, void*) { - return true; -} - -void gl_term() { -} - void common_linux_setup(); int reicast_init(int argc, char* argv[]); void dc_exit();