gl: refactor wsi into their own class.Allow dynamic vk<->gl switch
This commit is contained in:
parent
ac310114fe
commit
6611e9bf5e
|
@ -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/
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include "rend/gui.h"
|
||||
#include "hw/mem/_vmem.h"
|
||||
#include "cheats.h"
|
||||
#include "wsi/context.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#if defined(SUPPORT_DISPMANX)
|
||||
#include "dispmanx.h"
|
||||
#include "main.h"
|
||||
#include "wsi/context.h"
|
||||
|
||||
#include <bcm_host.h>
|
||||
#include <EGL/egl.h>
|
||||
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -3,11 +3,6 @@
|
|||
#include <X11/Xatom.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
#if !defined(GLES)
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
#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<X11KeyboardDevice> x11_keyboard;
|
||||
static std::shared_ptr<X11KbGamepadDevice> kb_gamepad;
|
||||
static std::shared_ptr<X11MouseGamepadDevice> mouse_gamepad;
|
||||
|
@ -79,12 +73,8 @@ static std::shared_ptr<X11MouseGamepadDevice> 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
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include <cmath>
|
||||
#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();
|
||||
|
|
|
@ -1,28 +1,11 @@
|
|||
#include <cmath>
|
||||
#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 <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#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 <GL4/gl3w.c>
|
||||
#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 <android/native_window.h> // requires ndk r5 or newer
|
||||
#endif
|
||||
#include <png.h>
|
||||
|
||||
/*
|
||||
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 <wingdi.h>
|
||||
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 <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
|
||||
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);
|
||||
|
|
|
@ -3,38 +3,7 @@
|
|||
#include <atomic>
|
||||
#include "rend/rend.h"
|
||||
#include "rend/TexCache.h"
|
||||
|
||||
#if (defined(GLES) && HOST_OS != OS_DARWIN && !defined(USE_SDL)) || defined(__ANDROID__)
|
||||
#define USE_EGL
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
#endif
|
||||
|
||||
#ifdef GLES
|
||||
#if defined(TARGET_IPHONE) //apple-specific ogles2 headers
|
||||
//#include <APPLE/egl.h>
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#endif
|
||||
#include <GLES32/gl32.h>
|
||||
#include <GLES32/gl2ext.h>
|
||||
#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 <OpenGL/gl3.h>
|
||||
#else
|
||||
#include <GL4/gl3w.h>
|
||||
#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();
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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<VkInstance>(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<uint32_t>::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<vk::UniqueImageView> 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<vk::UniqueCommandPool> commandPools;
|
||||
std::vector<vk::UniqueCommandBuffer> commandBuffers;
|
||||
|
|
|
@ -23,6 +23,10 @@
|
|||
#include "imgui_impl_vulkan.h"
|
||||
#include "../gui.h"
|
||||
#include "hw/pvr/Renderer_if.h"
|
||||
#ifdef USE_SDL
|
||||
#include <sdl/sdl.h>
|
||||
#include <SDL2/SDL_vulkan.h>
|
||||
#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<const char *> 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<VkDevice>(*device));
|
||||
|
@ -431,7 +445,7 @@ void VulkanContext::CreateSwapChain()
|
|||
imageViews.clear();
|
||||
|
||||
// get the supported VkFormats
|
||||
std::vector<vk::SurfaceFormatKHR> formats = physicalDevice.getSurfaceFormatsKHR(surface);
|
||||
std::vector<vk::SurfaceFormatKHR> 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<const char *> 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<u8> 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();
|
||||
}
|
||||
|
|
172
core/sdl/sdl.cpp
172
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 <SDL2/SDL_vulkan.h>
|
||||
#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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "reios/gdrom_hle.h"
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include "rend/gles/gles.h"
|
||||
#include "hw/sh4/dyna/blockmanager.h"
|
||||
#include "hw/sh4/dyna/ngen.h"
|
||||
#include "hw/naomi/naomi_cart.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();
|
||||
|
|
|
@ -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 <windows.h>
|
||||
|
@ -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; }
|
||||
|
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
#include "gl_context.h"
|
||||
#ifdef USE_VULKAN
|
||||
#include "rend/vulkan/vulkan.h"
|
||||
|
||||
extern VulkanContext theVulkanContext;
|
||||
#endif
|
||||
void SwitchRenderApi();
|
||||
void TermRenderApi();
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "gl_context.h"
|
||||
|
||||
#ifdef USE_EGL
|
||||
#include "types.h"
|
||||
|
||||
#ifdef __ANDROID__
|
||||
#include <android/native_window.h> // requires ndk r5 or newer
|
||||
#endif
|
||||
#ifdef TARGET_PANDORA
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <linux/fb.h>
|
||||
|
||||
#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
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <GLES32/gl32.h>
|
||||
#include <GLES32/gl2ext.h>
|
||||
#ifndef GLES2
|
||||
#include "gl32funcs.h"
|
||||
#endif
|
||||
|
||||
#define USE_EGL
|
||||
#include <EGL/egl.h>
|
||||
#include <EGL/eglext.h>
|
||||
|
||||
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;
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <stddef.h>
|
||||
#include <GLES32/gl32.h>
|
||||
#include <EGL/egl.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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "types.h"
|
||||
|
||||
#ifndef GLES
|
||||
#if HOST_OS != OS_DARWIN
|
||||
#undef ARRAY_SIZE // macros are evil
|
||||
#include <GL4/gl3w.c>
|
||||
#endif
|
||||
#endif
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#if defined(TARGET_IPHONE) //apple-specific ogles2 headers
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#else
|
||||
#include <OpenGL/gl3.h>
|
||||
#endif
|
||||
|
||||
class OSXGraphicsContext
|
||||
{
|
||||
public:
|
||||
bool Init() { return true; }
|
||||
void Term() {}
|
||||
void Swap();
|
||||
bool IsSwapBufferPreserved() const { return true; }
|
||||
};
|
||||
|
||||
extern OSXGraphicsContext theGLContext;
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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
|
||||
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <SDL2/SDL.h>
|
||||
#include "types.h"
|
||||
#include <GL4/gl3w.h>
|
||||
|
||||
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;
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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();
|
||||
}
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <windows.h>
|
||||
#include <GL4/gl3w.h>
|
||||
|
||||
#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;
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#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
|
|
@ -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 <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include <GL4/gl3w.h>
|
||||
#include <X11/X.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <GL/glx.h>
|
||||
|
||||
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;
|
|
@ -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<const char*> 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();
|
||||
}
|
||||
|
||||
|
|
|
@ -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() {
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
Loading…
Reference in New Issue