gl: refactor wsi into their own class.Allow dynamic vk<->gl switch

This commit is contained in:
Flyinghead 2019-10-18 21:57:08 +02:00
parent ac310114fe
commit 6611e9bf5e
38 changed files with 1387 additions and 1170 deletions

View File

@ -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/

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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;

View File

@ -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

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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;
}

View File

@ -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:

View File

@ -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;

View File

@ -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();
}

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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();

View File

@ -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; }

30
core/wsi/context.h Normal file
View File

@ -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();

234
core/wsi/egl.cpp Normal file
View File

@ -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

58
core/wsi/egl.h Normal file
View File

@ -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;

View File

@ -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>

View File

@ -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

29
core/wsi/gl4funcs.cpp Normal file
View File

@ -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

52
core/wsi/gl_context.h Normal file
View File

@ -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

35
core/wsi/osx.cpp Normal file
View File

@ -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

37
core/wsi/osx.h Normal file
View File

@ -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;

96
core/wsi/sdl.cpp Normal file
View File

@ -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

39
core/wsi/sdl.h Normal file
View File

@ -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;

49
core/wsi/swicher.cpp Normal file
View File

@ -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();
}

131
core/wsi/wgl.cpp Normal file
View File

@ -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

78
core/wsi/wgl.h Normal file
View File

@ -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;

175
core/wsi/xgl.cpp Normal file
View File

@ -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

45
core/wsi/xgl.h Normal file
View File

@ -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;

View File

@ -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();
}

View File

@ -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() {
}

View File

@ -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();