2018-11-16 00:42:29 +01:00
|
|
|
/*****************************************************************************\
|
|
|
|
Snes9x - Portable Super Nintendo Entertainment System (TM) emulator.
|
|
|
|
This file is licensed under the Snes9x License.
|
|
|
|
For further information, consult the LICENSE file in the root directory.
|
|
|
|
\*****************************************************************************/
|
|
|
|
|
2023-06-01 01:11:01 +02:00
|
|
|
#include <cstdlib>
|
2018-10-27 01:22:51 +02:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
2020-07-05 00:53:38 +02:00
|
|
|
#include <unistd.h>
|
2018-10-27 01:22:51 +02:00
|
|
|
|
2023-06-01 01:11:01 +02:00
|
|
|
#include "glx_context.hpp"
|
2018-10-27 01:22:51 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
GTKGLXContext::GTKGLXContext()
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
display = NULL;
|
|
|
|
context = NULL;
|
|
|
|
|
|
|
|
version_major = -1;
|
|
|
|
version_minor = -1;
|
2023-06-01 01:11:01 +02:00
|
|
|
|
|
|
|
gladLoaderLoadGLX(nullptr, 0);
|
2018-10-27 01:22:51 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
GTKGLXContext::~GTKGLXContext()
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
|
|
|
if (context)
|
2020-07-05 00:53:38 +02:00
|
|
|
glXDestroyContext(display, context);
|
2018-10-27 01:22:51 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
bool GTKGLXContext::attach(Display *dpy, Window xid)
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
|
|
|
GLXFBConfig *fbconfigs;
|
2020-07-05 00:53:38 +02:00
|
|
|
int num_fbconfigs;
|
2018-10-27 01:22:51 +02:00
|
|
|
|
|
|
|
int attribs[] = {
|
|
|
|
GLX_DOUBLEBUFFER, True,
|
|
|
|
GLX_X_RENDERABLE, True,
|
2020-07-05 00:53:38 +02:00
|
|
|
GLX_RED_SIZE, 8,
|
|
|
|
GLX_GREEN_SIZE, 8,
|
|
|
|
GLX_BLUE_SIZE, 8,
|
2018-10-27 01:22:51 +02:00
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
this->xid = xid;
|
|
|
|
display = dpy;
|
2018-10-27 01:22:51 +02:00
|
|
|
|
2020-11-04 20:11:28 +01:00
|
|
|
XWindowAttributes wa{};
|
|
|
|
XGetWindowAttributes(display, xid, &wa);
|
|
|
|
screen = XScreenNumberOfScreen(wa.screen);
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
glXQueryVersion(display, &version_major, &version_minor);
|
2018-10-27 22:12:21 +02:00
|
|
|
if (version_major < 2 && version_minor < 3)
|
|
|
|
return false;
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
fbconfigs = glXChooseFBConfig(display, screen, attribs, &num_fbconfigs);
|
2020-11-04 20:11:28 +01:00
|
|
|
|
2018-10-27 01:22:51 +02:00
|
|
|
if (!fbconfigs || num_fbconfigs < 1)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
printf("Couldn't match a GLX framebuffer config.\n");
|
2018-10-27 01:22:51 +02:00
|
|
|
return false;
|
|
|
|
}
|
2020-11-04 20:11:28 +01:00
|
|
|
|
2018-10-27 01:22:51 +02:00
|
|
|
fbconfig = fbconfigs[0];
|
2023-02-08 19:06:47 +01:00
|
|
|
free(fbconfigs);
|
2018-10-27 01:22:51 +02:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
bool GTKGLXContext::create_context()
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
|
|
|
int context_attribs[] = {
|
2018-10-28 01:13:51 +02:00
|
|
|
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
|
|
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
|
|
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
|
2018-10-27 01:22:51 +02:00
|
|
|
None
|
|
|
|
};
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
const char *extensions = glXQueryExtensionsString(display, screen);
|
2018-10-27 22:12:21 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
XSetErrorHandler([](Display *dpy, XErrorEvent *event) -> int {
|
|
|
|
printf("XError: type: %d code: %d\n", event->type, event->error_code);
|
|
|
|
return X_OK;
|
|
|
|
});
|
|
|
|
if (strstr(extensions, "GLX_ARB_create_context"))
|
|
|
|
context = glXCreateContextAttribsARB(display, fbconfig, NULL, True, context_attribs);
|
2018-10-27 22:12:21 +02:00
|
|
|
if (!context)
|
2020-07-05 00:53:38 +02:00
|
|
|
context = glXCreateNewContext(display, fbconfig, GLX_RGBA_TYPE, NULL, True);
|
|
|
|
XSetErrorHandler(nullptr);
|
2018-10-27 01:22:51 +02:00
|
|
|
|
|
|
|
if (!context)
|
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
printf("Couldn't create GLX context.\n");
|
2018-10-27 01:22:51 +02:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void GTKGLXContext::resize()
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
while (!ready())
|
|
|
|
usleep(100);
|
2018-10-27 01:22:51 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
unsigned int width;
|
|
|
|
unsigned int height;
|
|
|
|
glXQueryDrawable(display, xid, GLX_WIDTH, &width);
|
|
|
|
glXQueryDrawable(display, xid, GLX_HEIGHT, &height);
|
2018-10-27 01:22:51 +02:00
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
this->width = width;
|
|
|
|
this->height = height;
|
|
|
|
make_current();
|
2018-10-27 01:22:51 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void GTKGLXContext::swap_buffers()
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
glXSwapBuffers(display, xid);
|
2018-10-27 01:22:51 +02:00
|
|
|
}
|
|
|
|
|
2019-03-02 22:25:59 +01:00
|
|
|
bool GTKGLXContext::ready()
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void GTKGLXContext::make_current()
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
2020-07-05 00:53:38 +02:00
|
|
|
glXMakeCurrent(display, xid, context);
|
2018-10-27 01:22:51 +02:00
|
|
|
}
|
|
|
|
|
2020-07-05 00:53:38 +02:00
|
|
|
void GTKGLXContext::swap_interval(int frames)
|
2018-10-27 01:22:51 +02:00
|
|
|
{
|
2023-06-01 01:11:01 +02:00
|
|
|
if (GLAD_GLX_EXT_swap_control)
|
2020-07-05 00:53:38 +02:00
|
|
|
glXSwapIntervalEXT(display, xid, frames);
|
2023-06-01 01:11:01 +02:00
|
|
|
else if (GLAD_GLX_SGI_swap_control)
|
2020-07-05 00:53:38 +02:00
|
|
|
glXSwapIntervalSGI(frames);
|
2018-12-04 21:57:20 +01:00
|
|
|
#ifdef GLX_MESA_swap_control
|
2023-06-01 01:11:01 +02:00
|
|
|
else if (GLAD_GLX_MESA_swap_control)
|
2020-07-05 00:53:38 +02:00
|
|
|
glXSwapIntervalMESA(frames);
|
2018-12-04 21:57:20 +01:00
|
|
|
#endif
|
2018-10-27 01:22:51 +02:00
|
|
|
}
|