2010-09-25 17:46:12 +02:00
|
|
|
#include <gtk/gtk.h>
|
2018-10-15 21:04:28 +02:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
2010-09-25 17:46:12 +02:00
|
|
|
#include <gdk/gdkx.h>
|
2018-10-15 21:04:28 +02:00
|
|
|
#include <X11/Xlib.h>
|
|
|
|
#endif
|
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
#include <gdk/gdkwayland.h>
|
|
|
|
#endif
|
2010-10-22 04:18:56 +02:00
|
|
|
#include <libxml/parser.h>
|
|
|
|
#include <libxml/tree.h>
|
2010-09-25 17:46:12 +02:00
|
|
|
#include <dlfcn.h>
|
2010-09-26 11:19:15 +02:00
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
2010-09-25 17:46:12 +02:00
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
#include "gtk_display.h"
|
|
|
|
#include "gtk_display_driver_opengl.h"
|
2018-05-24 19:18:59 +02:00
|
|
|
#include "gtk_shader_parameters.h"
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-05-11 22:56:58 +02:00
|
|
|
#include "shaders/shader_helpers.h"
|
2018-05-08 23:56:18 +02:00
|
|
|
|
2018-10-19 00:47:39 +02:00
|
|
|
static bool
|
|
|
|
on_wayland (void)
|
|
|
|
{
|
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
return (GDK_IS_WAYLAND_DISPLAY (gdk_display_get_default ()));
|
|
|
|
#endif
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2018-05-21 21:15:31 +02:00
|
|
|
static void S9xViewportCallback (int src_width, int src_height,
|
|
|
|
int viewport_x, int viewport_y,
|
|
|
|
int viewport_width, int viewport_height,
|
|
|
|
int *out_x, int *out_y,
|
|
|
|
int *out_width, int *out_height)
|
|
|
|
{
|
|
|
|
|
|
|
|
S9xApplyAspect (src_width, src_height, viewport_width, viewport_height);
|
|
|
|
*out_x = src_width + viewport_x;
|
|
|
|
*out_y = src_height + viewport_y;
|
|
|
|
*out_width = viewport_width;
|
|
|
|
*out_height = viewport_height;
|
2018-10-15 21:04:28 +02:00
|
|
|
|
2018-05-21 21:15:31 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
S9xOpenGLDisplayDriver::S9xOpenGLDisplayDriver (Snes9xWindow *window,
|
|
|
|
Snes9xConfig *config)
|
|
|
|
{
|
|
|
|
this->window = window;
|
|
|
|
this->config = config;
|
|
|
|
this->drawing_area = GTK_WIDGET (window->drawing_area);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2018-05-05 00:12:22 +02:00
|
|
|
S9xOpenGLDisplayDriver::update (int width, int height, int yoffset)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
uint8 *final_buffer = NULL;
|
|
|
|
int final_pitch;
|
|
|
|
void *pboMemory = NULL;
|
2010-09-26 11:19:15 +02:00
|
|
|
int x, y, w, h;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
GtkAllocation allocation;
|
|
|
|
gtk_widget_get_allocation (drawing_area, &allocation);
|
|
|
|
|
2018-05-05 21:14:06 +02:00
|
|
|
if (output_window_width != allocation.width ||
|
|
|
|
output_window_height != allocation.height)
|
|
|
|
{
|
|
|
|
resize_window (allocation.width, allocation.height);
|
|
|
|
}
|
|
|
|
|
2016-10-03 02:41:42 +02:00
|
|
|
#if GTK_CHECK_VERSION(3,10,0)
|
|
|
|
int gdk_scale_factor = gdk_window_get_scale_factor (gdk_window);
|
|
|
|
|
2018-10-19 00:47:39 +02:00
|
|
|
if (!on_wayland ())
|
|
|
|
{
|
|
|
|
allocation.width *= gdk_scale_factor;
|
|
|
|
allocation.height *= gdk_scale_factor;
|
|
|
|
}
|
2016-10-03 02:41:42 +02:00
|
|
|
#endif
|
|
|
|
|
2018-05-24 20:00:09 +02:00
|
|
|
if (using_glsl_shaders)
|
2018-05-08 23:56:18 +02:00
|
|
|
{
|
2018-05-12 22:07:07 +02:00
|
|
|
glBindTexture (GL_TEXTURE_2D, texmap);
|
2018-05-08 23:56:18 +02:00
|
|
|
}
|
|
|
|
|
2018-05-14 00:31:25 +02:00
|
|
|
GLint filter = Settings.BilinearFilter ? GL_LINEAR : GL_NEAREST;
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter);
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter);
|
2010-10-28 18:27:07 +02:00
|
|
|
GLint clamp = (using_shaders || !dyn_resizing) ? GL_CLAMP_TO_BORDER : GL_CLAMP_TO_EDGE;
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, clamp);
|
|
|
|
glTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, clamp);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
glClear (GL_COLOR_BUFFER_BIT);
|
2018-05-12 22:07:07 +02:00
|
|
|
glEnable (GL_TEXTURE_2D);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (config->scale_method > 0)
|
|
|
|
{
|
|
|
|
uint8 *src_buffer = (uint8 *) padded_buffer[0];
|
|
|
|
int src_pitch = image_width * image_bpp;
|
|
|
|
uint8 *dst_buffer;
|
|
|
|
int dst_pitch;
|
|
|
|
|
2018-05-05 00:12:22 +02:00
|
|
|
src_buffer += (src_pitch * yoffset);
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
dst_buffer = (uint8 *) padded_buffer[1];
|
|
|
|
dst_pitch = scaled_max_width * image_bpp;
|
|
|
|
final_buffer = (uint8 *) padded_buffer[1];
|
|
|
|
final_pitch = scaled_max_width * image_bpp;
|
|
|
|
|
|
|
|
S9xFilter (src_buffer,
|
|
|
|
src_pitch,
|
|
|
|
dst_buffer,
|
|
|
|
dst_pitch,
|
|
|
|
width,
|
|
|
|
height);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
final_buffer = (uint8 *) padded_buffer[0];
|
|
|
|
final_pitch = image_width * image_bpp;
|
2018-05-05 00:12:22 +02:00
|
|
|
final_buffer += (final_pitch * yoffset);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
x = width; y = height;
|
|
|
|
w = allocation.width; h = allocation.height;
|
|
|
|
S9xApplyAspect (x, y, w, h);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-11-18 13:42:55 +01:00
|
|
|
glViewport (x, allocation.height - y - h, w, h);
|
2010-09-26 11:19:15 +02:00
|
|
|
window->set_mouseable_area (x, y, w, h);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
update_texture_size (width, height);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
if (using_pbos)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2010-09-26 11:19:15 +02:00
|
|
|
if (config->pbo_format == PBO_FMT_16)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
|
|
|
|
glBufferData (GL_PIXEL_UNPACK_BUFFER,
|
|
|
|
width * height * 2,
|
|
|
|
NULL,
|
|
|
|
GL_STREAM_DRAW);
|
|
|
|
pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
for (int y = 0; y < height; y++)
|
|
|
|
{
|
|
|
|
memcpy ((uint8 *) pboMemory + (width * y * 2),
|
|
|
|
final_buffer + (y * final_pitch),
|
|
|
|
width * image_bpp);
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexSubImage2D (GL_TEXTURE_2D,
|
2010-09-26 11:19:15 +02:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB,
|
|
|
|
GL_UNSIGNED_SHORT_5_6_5,
|
2010-09-26 11:19:15 +02:00
|
|
|
BUFFER_OFFSET (0));
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
}
|
|
|
|
else if (config->pbo_format == PBO_FMT_24)
|
|
|
|
{
|
2018-05-04 21:28:50 +02:00
|
|
|
glPixelStorei (GL_UNPACK_ALIGNMENT, 1);
|
2010-09-26 11:19:15 +02:00
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
|
|
|
|
glBufferData (GL_PIXEL_UNPACK_BUFFER,
|
2018-05-04 21:28:50 +02:00
|
|
|
width * height * 3,
|
2010-09-26 11:19:15 +02:00
|
|
|
NULL,
|
|
|
|
GL_STREAM_DRAW);
|
|
|
|
pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
|
|
|
|
|
|
|
/* Pixel swizzling in software */
|
2018-05-04 21:28:50 +02:00
|
|
|
S9xSetEndianess (ENDIAN_SWAPPED);
|
2010-09-26 11:19:15 +02:00
|
|
|
S9xConvert (final_buffer,
|
|
|
|
pboMemory,
|
|
|
|
final_pitch,
|
2018-05-04 21:28:50 +02:00
|
|
|
width * 3,
|
2010-09-26 11:19:15 +02:00
|
|
|
width,
|
|
|
|
height,
|
|
|
|
24);
|
|
|
|
|
|
|
|
glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);
|
|
|
|
|
2018-05-04 21:28:50 +02:00
|
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexSubImage2D (GL_TEXTURE_2D,
|
2010-09-26 11:19:15 +02:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
GL_RGB,
|
|
|
|
GL_UNSIGNED_BYTE,
|
|
|
|
BUFFER_OFFSET (0));
|
|
|
|
|
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
}
|
|
|
|
else /* PBO_FMT_32 */
|
|
|
|
{
|
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
|
|
|
|
glBufferData (GL_PIXEL_UNPACK_BUFFER,
|
|
|
|
width * height * 4,
|
|
|
|
NULL,
|
|
|
|
GL_STREAM_DRAW);
|
|
|
|
pboMemory = glMapBuffer (GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY);
|
|
|
|
|
|
|
|
/* Pixel swizzling in software */
|
2018-05-04 21:28:50 +02:00
|
|
|
S9xSetEndianess (ENDIAN_NORMAL);
|
2010-09-26 11:19:15 +02:00
|
|
|
S9xConvert (final_buffer,
|
|
|
|
pboMemory,
|
|
|
|
final_pitch,
|
|
|
|
width * 4,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
32);
|
|
|
|
|
|
|
|
glUnmapBuffer (GL_PIXEL_UNPACK_BUFFER);
|
|
|
|
|
|
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, width);
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexSubImage2D (GL_TEXTURE_2D,
|
2010-09-25 17:46:12 +02:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
|
|
|
GL_BGRA,
|
2010-09-26 11:19:15 +02:00
|
|
|
PBO_BGRA_NATIVE_ORDER,
|
|
|
|
BUFFER_OFFSET (0));
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, final_pitch / image_bpp);
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexSubImage2D (GL_TEXTURE_2D,
|
2010-09-26 11:19:15 +02:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
width,
|
|
|
|
height,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB,
|
|
|
|
GL_UNSIGNED_SHORT_5_6_5,
|
2010-09-26 11:19:15 +02:00
|
|
|
final_buffer);
|
|
|
|
}
|
|
|
|
|
2018-05-12 22:07:07 +02:00
|
|
|
texcoords[1] = (float) (height) / texture_height;
|
|
|
|
texcoords[2] = (float) (width) / texture_width;
|
|
|
|
texcoords[3] = texcoords[1];
|
|
|
|
texcoords[4] = texcoords[2];
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-05-11 01:47:55 +02:00
|
|
|
if (using_shaders && using_glsl_shaders)
|
|
|
|
{
|
2018-05-21 21:15:31 +02:00
|
|
|
glsl_shader->render (texmap, width, height, x, allocation.height - y - h, w, h, S9xViewportCallback);
|
2018-05-13 01:07:23 +02:00
|
|
|
gl_swap ();
|
|
|
|
return;
|
2018-05-11 01:47:55 +02:00
|
|
|
}
|
2018-05-08 23:56:18 +02:00
|
|
|
else if (using_shaders)
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
GLint location;
|
2014-02-05 10:22:07 +01:00
|
|
|
float inputSize[2];
|
|
|
|
float outputSize[2];
|
|
|
|
float textureSize[2];
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2014-02-05 10:22:07 +01:00
|
|
|
inputSize[0] = width;
|
|
|
|
inputSize[1] = height;
|
2010-09-26 11:19:15 +02:00
|
|
|
location = glGetUniformLocation (program, "rubyInputSize");
|
|
|
|
glUniform2fv (location, 1, inputSize);
|
|
|
|
|
2014-02-05 10:22:07 +01:00
|
|
|
outputSize[0] = w;
|
|
|
|
outputSize[1] = h;
|
2010-09-26 11:19:15 +02:00
|
|
|
location = glGetUniformLocation (program, "rubyOutputSize");
|
|
|
|
glUniform2fv (location, 1, outputSize);
|
|
|
|
|
2014-02-05 10:22:07 +01:00
|
|
|
textureSize[0] = texture_width;
|
|
|
|
textureSize[1] = texture_height;
|
2010-09-26 11:19:15 +02:00
|
|
|
location = glGetUniformLocation (program, "rubyTextureSize");
|
|
|
|
glUniform2fv (location, 1, textureSize);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
glDrawArrays (GL_QUADS, 0, 4);
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
gl_swap ();
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-05-12 22:07:07 +02:00
|
|
|
void *
|
|
|
|
S9xOpenGLDisplayDriver::get_parameters(void)
|
|
|
|
{
|
|
|
|
if (using_glsl_shaders && glsl_shader)
|
|
|
|
{
|
|
|
|
return (void *) &glsl_shader->param;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2018-05-12 23:22:27 +02:00
|
|
|
void
|
2018-05-13 18:02:52 +02:00
|
|
|
S9xOpenGLDisplayDriver::save (const char *filename)
|
2018-05-12 23:22:27 +02:00
|
|
|
{
|
|
|
|
if (using_glsl_shaders && glsl_shader)
|
|
|
|
{
|
2018-05-13 18:02:52 +02:00
|
|
|
glsl_shader->save(filename);
|
2018-05-12 23:22:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::clear_buffers (void)
|
|
|
|
{
|
|
|
|
memset (buffer[0], 0, image_padded_size);
|
|
|
|
memset (buffer[1], 0, scaled_padded_size);
|
|
|
|
|
2018-05-05 00:12:22 +02:00
|
|
|
glPixelStorei (GL_UNPACK_ROW_LENGTH, scaled_max_width);
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexSubImage2D (GL_TEXTURE_2D,
|
2010-09-25 17:46:12 +02:00
|
|
|
0,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
scaled_max_width,
|
|
|
|
scaled_max_height,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB,
|
|
|
|
GL_UNSIGNED_SHORT_5_6_5,
|
2018-05-05 00:12:22 +02:00
|
|
|
buffer[1]);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::update_texture_size (int width, int height)
|
|
|
|
{
|
|
|
|
if (width != texture_width || height != texture_height)
|
|
|
|
{
|
|
|
|
if (dyn_resizing)
|
|
|
|
{
|
2018-05-12 22:07:07 +02:00
|
|
|
glBindTexture (GL_TEXTURE_2D, texmap);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
if (using_pbos)
|
|
|
|
{
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexImage2D (GL_TEXTURE_2D,
|
2010-09-25 17:46:12 +02:00
|
|
|
0,
|
2018-05-04 21:28:50 +02:00
|
|
|
config->pbo_format == PBO_FMT_16 ? GL_RGB565 : 4,
|
2010-09-25 17:46:12 +02:00
|
|
|
width,
|
|
|
|
height,
|
|
|
|
0,
|
2010-09-26 11:19:15 +02:00
|
|
|
PBO_GET_FORMAT (config->pbo_format),
|
|
|
|
PBO_GET_PACKING (config->pbo_format),
|
2010-09-25 17:46:12 +02:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-05-12 22:07:07 +02:00
|
|
|
glTexImage2D (GL_TEXTURE_2D,
|
2010-09-25 17:46:12 +02:00
|
|
|
0,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB565,
|
2010-09-25 17:46:12 +02:00
|
|
|
width,
|
|
|
|
height,
|
|
|
|
0,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB,
|
|
|
|
GL_UNSIGNED_SHORT_5_6_5,
|
2010-09-25 17:46:12 +02:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
texture_width = width;
|
|
|
|
texture_height = height;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2018-05-09 00:56:13 +02:00
|
|
|
S9xOpenGLDisplayDriver::pbos_available (void)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-05-11 22:56:58 +02:00
|
|
|
|
|
|
|
if (gl_version_at_least (2, 1))
|
|
|
|
return 1;
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
if (!extensions)
|
|
|
|
return 0;
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
if (strstr (extensions, "pixel_buffer_object"))
|
|
|
|
{
|
2010-09-26 11:19:15 +02:00
|
|
|
return 1;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2018-05-09 00:56:13 +02:00
|
|
|
S9xOpenGLDisplayDriver::shaders_available (void)
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
|
|
|
|
|
|
|
|
if (!extensions)
|
2010-09-25 17:46:12 +02:00
|
|
|
return 0;
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-05-11 22:56:58 +02:00
|
|
|
if (strstr (extensions, "fragment_program") ||
|
|
|
|
strstr (extensions, "fragment_shader"))
|
|
|
|
{
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int npot_available (void)
|
|
|
|
{
|
|
|
|
if (gl_version_at_least (2, 0))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
|
|
|
|
|
|
|
|
if (!extensions)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (strstr (extensions, "non_power_of_two") ||
|
|
|
|
strstr (extensions, "npot"))
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
2018-05-09 00:52:40 +02:00
|
|
|
return 1;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
return 0;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
int
|
2010-10-22 04:18:56 +02:00
|
|
|
S9xOpenGLDisplayDriver::load_shaders (const char *shader_file)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2010-10-22 04:18:56 +02:00
|
|
|
xmlDoc *xml_doc = NULL;
|
|
|
|
xmlNodePtr node = NULL;
|
|
|
|
char *fragment = NULL, *vertex = NULL;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-05-08 23:56:18 +02:00
|
|
|
int length = strlen (shader_file);
|
2018-05-11 01:47:55 +02:00
|
|
|
|
|
|
|
if ((length > 6 && !strcasecmp(shader_file + length - 6, ".glslp")) ||
|
|
|
|
(length > 5 && !strcasecmp(shader_file + length - 5, ".glsl")))
|
|
|
|
{
|
2018-05-11 22:56:58 +02:00
|
|
|
if (shaders_available() && npot_available())
|
2018-05-11 01:47:55 +02:00
|
|
|
{
|
|
|
|
glsl_shader = new GLSLShader;
|
|
|
|
if (glsl_shader->load_shader ((char *) shader_file))
|
|
|
|
{
|
|
|
|
using_glsl_shaders = 1;
|
2018-05-12 22:07:07 +02:00
|
|
|
dyn_resizing = TRUE;
|
2018-05-24 19:18:59 +02:00
|
|
|
|
|
|
|
if (glsl_shader->param.size () > 0)
|
|
|
|
window->enable_widget ("shader_parameters_item", TRUE);
|
|
|
|
|
2018-05-11 01:47:55 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
delete glsl_shader;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
printf ("Need shader extensions and non-power-of-two-textures for GLSL.\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 00:56:13 +02:00
|
|
|
if (!shaders_available ())
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
fprintf (stderr, _("Cannot load GLSL shader functions.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-10-22 04:18:56 +02:00
|
|
|
xml_doc = xmlReadFile (shader_file, NULL, 0);
|
|
|
|
|
|
|
|
if (!xml_doc)
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
2010-10-22 04:18:56 +02:00
|
|
|
fprintf (stderr, _("Cannot read shader file.\n"));
|
2010-09-26 11:19:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-10-22 04:18:56 +02:00
|
|
|
node = xmlDocGetRootElement (xml_doc);
|
|
|
|
|
|
|
|
if (xmlStrcasecmp (node->name, BAD_CAST "shader"))
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
2010-10-22 04:18:56 +02:00
|
|
|
fprintf (stderr, _("File %s is not a shader file.\n"), shader_file);
|
|
|
|
xmlFreeDoc (xml_doc);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (xmlNodePtr i = node->children; i; i = i->next)
|
|
|
|
{
|
|
|
|
if (!xmlStrcasecmp (i->name, BAD_CAST "vertex"))
|
|
|
|
{
|
|
|
|
if (i->children)
|
|
|
|
vertex = (char *) i->children->content;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!xmlStrcasecmp (i->name, BAD_CAST "fragment"))
|
|
|
|
{
|
|
|
|
if (i->children)
|
|
|
|
fragment = (char *) i->children->content;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-22 04:32:47 +02:00
|
|
|
if (!vertex && !fragment)
|
2010-10-22 04:18:56 +02:00
|
|
|
{
|
2010-10-22 04:32:47 +02:00
|
|
|
fprintf (stderr, _("Shader lacks any programs.\n"));
|
2010-10-22 04:18:56 +02:00
|
|
|
xmlFreeDoc (xml_doc);
|
2010-09-26 11:19:15 +02:00
|
|
|
return 0;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
program = glCreateProgram ();
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-10-22 04:32:47 +02:00
|
|
|
if (vertex)
|
|
|
|
{
|
|
|
|
vertex_shader = glCreateShader (GL_VERTEX_SHADER);
|
|
|
|
glShaderSource (vertex_shader, 1, (const GLchar **) &vertex, NULL);
|
|
|
|
glCompileShader (vertex_shader);
|
|
|
|
glAttachShader (program, vertex_shader);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (fragment)
|
|
|
|
{
|
|
|
|
fragment_shader = glCreateShader (GL_FRAGMENT_SHADER);
|
|
|
|
glShaderSource (fragment_shader, 1, (const GLchar **) &fragment, NULL);
|
|
|
|
glCompileShader (fragment_shader);
|
|
|
|
glAttachShader (program, fragment_shader);
|
|
|
|
}
|
|
|
|
|
|
|
|
glLinkProgram (program);
|
2010-09-26 11:19:15 +02:00
|
|
|
glUseProgram (program);
|
|
|
|
|
2010-10-22 04:18:56 +02:00
|
|
|
xmlFreeDoc (xml_doc);
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
return 1;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
int
|
|
|
|
S9xOpenGLDisplayDriver::opengl_defaults (void)
|
|
|
|
{
|
2018-05-12 22:07:07 +02:00
|
|
|
dyn_resizing = FALSE;
|
2010-09-25 17:46:12 +02:00
|
|
|
using_pbos = 0;
|
2018-05-12 22:07:07 +02:00
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
if (config->use_pbos)
|
|
|
|
{
|
2018-05-09 00:56:13 +02:00
|
|
|
if (!pbos_available ())
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
fprintf (stderr, _("pixel_buffer_object extension not supported.\n"));
|
|
|
|
|
|
|
|
config->use_pbos = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
using_pbos = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
using_shaders = 0;
|
2018-05-11 01:47:55 +02:00
|
|
|
using_glsl_shaders = 0;
|
|
|
|
glsl_shader = NULL;
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
if (config->use_shaders)
|
|
|
|
{
|
2010-10-22 04:18:56 +02:00
|
|
|
if (!load_shaders (config->fragment_shader))
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
config->use_shaders = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
using_shaders = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-09 00:56:13 +02:00
|
|
|
texture_width = 1024;
|
|
|
|
texture_height = 1024;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-05-12 22:07:07 +02:00
|
|
|
if (config->npot_textures)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-05-12 22:07:07 +02:00
|
|
|
if (npot_available ())
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
|
|
|
dyn_resizing = TRUE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-08 23:56:18 +02:00
|
|
|
glEnableClientState (GL_VERTEX_ARRAY);
|
|
|
|
glEnableClientState (GL_TEXTURE_COORD_ARRAY);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
vertices[0] = 0.0f;
|
|
|
|
vertices[1] = 0.0f;
|
|
|
|
vertices[2] = 1.0f;
|
|
|
|
vertices[3] = 0.0f;
|
|
|
|
vertices[4] = 1.0f;
|
|
|
|
vertices[5] = 1.0f;
|
|
|
|
vertices[6] = 0.0f;
|
|
|
|
vertices[7] = 1.0f;
|
|
|
|
|
|
|
|
glVertexPointer (2, GL_FLOAT, 0, vertices);
|
|
|
|
|
|
|
|
texcoords[0] = 0.0f;
|
|
|
|
texcoords[5] = 0.0f;
|
|
|
|
texcoords[6] = 0.0f;
|
|
|
|
texcoords[7] = 0.0f;
|
|
|
|
|
|
|
|
glTexCoordPointer (2, GL_FLOAT, 0, texcoords);
|
|
|
|
|
|
|
|
if (config->use_pbos)
|
|
|
|
{
|
|
|
|
glGenBuffers (1, &pbo);
|
|
|
|
glGenTextures (1, &texmap);
|
|
|
|
|
2018-05-12 22:07:07 +02:00
|
|
|
glBindTexture (GL_TEXTURE_2D, texmap);
|
|
|
|
glTexImage2D (GL_TEXTURE_2D,
|
2010-09-25 17:46:12 +02:00
|
|
|
0,
|
2018-05-04 21:28:50 +02:00
|
|
|
config->pbo_format == PBO_FMT_16 ? GL_RGB565 : 4,
|
2010-09-25 17:46:12 +02:00
|
|
|
texture_width,
|
|
|
|
texture_height,
|
|
|
|
0,
|
2010-09-26 11:19:15 +02:00
|
|
|
PBO_GET_FORMAT (config->pbo_format),
|
|
|
|
PBO_GET_PACKING (config->pbo_format),
|
2010-09-25 17:46:12 +02:00
|
|
|
NULL);
|
|
|
|
|
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, pbo);
|
|
|
|
glBufferData (GL_PIXEL_UNPACK_BUFFER,
|
|
|
|
texture_width * texture_height * 3,
|
|
|
|
NULL,
|
|
|
|
GL_STREAM_DRAW);
|
|
|
|
|
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glGenTextures (1, &texmap);
|
|
|
|
|
2018-05-12 22:07:07 +02:00
|
|
|
glBindTexture (GL_TEXTURE_2D, texmap);
|
|
|
|
glTexImage2D (GL_TEXTURE_2D,
|
2010-09-25 17:46:12 +02:00
|
|
|
0,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB565,
|
2010-09-25 17:46:12 +02:00
|
|
|
texture_width,
|
|
|
|
texture_height,
|
|
|
|
0,
|
2018-05-04 21:28:50 +02:00
|
|
|
GL_RGB,
|
|
|
|
GL_UNSIGNED_SHORT_5_6_5,
|
2010-09-25 17:46:12 +02:00
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
glEnable (GL_DITHER);
|
|
|
|
|
|
|
|
glDisable (GL_POLYGON_SMOOTH);
|
|
|
|
glShadeModel (GL_FLAT);
|
|
|
|
glPolygonMode (GL_FRONT, GL_FILL);
|
|
|
|
|
|
|
|
glEnable (GL_CULL_FACE);
|
|
|
|
glCullFace (GL_BACK);
|
|
|
|
|
|
|
|
glClearColor (0.0, 0.0, 0.0, 0.0);
|
|
|
|
glTexEnvf (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
|
|
|
|
|
|
|
glDisable (GL_BLEND);
|
|
|
|
glDisable (GL_DEPTH_TEST);
|
|
|
|
glDisable (GL_TEXTURE_2D);
|
|
|
|
|
|
|
|
glMatrixMode (GL_PROJECTION);
|
|
|
|
glLoadIdentity ();
|
|
|
|
glOrtho (0.0, 1.0, 0.0, 1.0, -1, 1);
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::refresh (int width, int height)
|
|
|
|
{
|
2010-09-25 17:46:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-26 11:19:15 +02:00
|
|
|
S9xOpenGLDisplayDriver::resize_window (int width, int height)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
|
|
|
|
if (!using_egl)
|
|
|
|
gdk_window_destroy (gdk_window);
|
|
|
|
|
2014-02-05 09:44:04 +01:00
|
|
|
create_window (width, height);
|
2018-10-15 21:04:28 +02:00
|
|
|
|
|
|
|
if (using_egl)
|
|
|
|
eglMakeCurrent (egl_display, egl_surface, egl_surface, egl_context);
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
else
|
|
|
|
glXMakeCurrent (display, xwindow, glx_context);
|
|
|
|
#endif
|
|
|
|
|
2018-08-06 00:03:36 +02:00
|
|
|
swap_control (config->sync_to_vblank);
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2018-10-19 00:47:39 +02:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
static void wl_global (void *data,
|
|
|
|
struct wl_registry *wl_registry,
|
|
|
|
uint32_t name,
|
|
|
|
const char *interface,
|
|
|
|
uint32_t version)
|
|
|
|
{
|
|
|
|
struct wl_collection *wl = (struct wl_collection *) data;
|
|
|
|
|
|
|
|
if (!strcmp (interface, "wl_compositor"))
|
|
|
|
wl->compositor = (struct wl_compositor *) wl_registry_bind (wl_registry, name, &wl_compositor_interface, 1);
|
|
|
|
else if (!strcmp (interface, "wl_subcompositor"))
|
|
|
|
wl->subcompositor = (struct wl_subcompositor *) wl_registry_bind (wl_registry, name, &wl_subcompositor_interface, 1);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void wl_global_remove (void *data,
|
|
|
|
struct wl_registry *wl_registry,
|
|
|
|
uint32_t name)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct wl_registry_listener wl_registry_listener = {
|
|
|
|
wl_global,
|
|
|
|
wl_global_remove
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::create_window (int width, int height)
|
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
if (using_egl)
|
|
|
|
{
|
|
|
|
egl_surface = NULL;
|
|
|
|
gdk_window = gtk_widget_get_window (drawing_area);
|
|
|
|
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
if (GDK_IS_X11_WINDOW (gdk_window))
|
|
|
|
{
|
|
|
|
xwindow = GDK_COMPAT_WINDOW_XID (gdk_window);
|
2018-10-19 00:47:39 +02:00
|
|
|
egl_surface = eglCreateWindowSurface (egl_display, egl_config, (EGLNativeWindowType) xwindow, NULL);
|
2018-10-15 21:04:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
if (GDK_IS_WAYLAND_WINDOW (gdk_window))
|
|
|
|
{
|
2018-10-19 00:47:39 +02:00
|
|
|
int x, y, w, h;
|
|
|
|
gdk_window_get_geometry (gdk_window, &x, &y, &w, &h);
|
|
|
|
|
|
|
|
/* Gets whole window surface */
|
|
|
|
wl.parent = gdk_wayland_window_get_wl_surface (gdk_window);
|
|
|
|
wl.display = gdk_wayland_display_get_wl_display (gdk_window_get_display (gdk_window));
|
|
|
|
wl.registry = wl_display_get_registry (wl.display);
|
|
|
|
wl.compositor = NULL;
|
|
|
|
wl.subcompositor = NULL;
|
|
|
|
wl_registry_add_listener (wl.registry, &wl_registry_listener, &wl);
|
|
|
|
wl_display_roundtrip (wl.display);
|
|
|
|
|
|
|
|
if (!wl.compositor || !wl.subcompositor)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (!wl.child)
|
2018-10-19 01:08:01 +02:00
|
|
|
{
|
2018-10-19 00:47:39 +02:00
|
|
|
wl.child = wl_compositor_create_surface (wl.compositor);
|
2018-10-19 01:08:01 +02:00
|
|
|
wl.region = wl_compositor_create_region (wl.compositor);
|
|
|
|
}
|
2018-10-19 00:47:39 +02:00
|
|
|
|
|
|
|
if (!wl.subsurface)
|
|
|
|
{
|
|
|
|
wl.subsurface = wl_subcompositor_get_subsurface (wl.subcompositor, wl.child, wl.parent);
|
|
|
|
}
|
|
|
|
|
2018-10-19 00:53:07 +02:00
|
|
|
wl_subsurface_set_desync (wl.subsurface);
|
|
|
|
wl_subsurface_set_position (wl.subsurface, x, y);
|
2018-10-19 01:08:01 +02:00
|
|
|
wl_surface_set_input_region (wl.child, wl.region);
|
2018-10-19 00:53:07 +02:00
|
|
|
|
2018-10-19 00:47:39 +02:00
|
|
|
if (wl.egl_window)
|
|
|
|
wl_egl_window_resize (wl.egl_window, w, h, 0, 0);
|
|
|
|
else
|
|
|
|
wl.egl_window = wl_egl_window_create (wl.child, w, h);
|
|
|
|
|
|
|
|
if (!egl_surface)
|
|
|
|
egl_surface = eglCreateWindowSurface (egl_display, egl_config, (EGLNativeWindowType) wl.egl_window, NULL);
|
2018-10-15 21:04:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GdkWindowAttr window_attr;
|
|
|
|
memset (&window_attr, 0, sizeof (GdkWindowAttr));
|
|
|
|
window_attr.event_mask = GDK_EXPOSURE_MASK | GDK_STRUCTURE_MASK;
|
|
|
|
window_attr.width = width;
|
|
|
|
window_attr.height = height;
|
|
|
|
window_attr.x = 0;
|
|
|
|
window_attr.y = 0;
|
|
|
|
window_attr.wclass = GDK_INPUT_OUTPUT;
|
|
|
|
window_attr.window_type = GDK_WINDOW_CHILD;
|
|
|
|
window_attr.visual = gdk_x11_screen_lookup_visual (gtk_widget_get_screen (drawing_area), vi->visualid);
|
|
|
|
|
|
|
|
gdk_window = gdk_window_new (gtk_widget_get_window (drawing_area),
|
|
|
|
&window_attr,
|
|
|
|
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL);
|
|
|
|
gdk_window_set_user_data (gdk_window, (gpointer) drawing_area);
|
|
|
|
|
|
|
|
gdk_window_show (gdk_window);
|
|
|
|
xwindow = GDK_COMPAT_WINDOW_XID (gdk_window);
|
|
|
|
}
|
|
|
|
#endif
|
2010-09-26 11:19:15 +02:00
|
|
|
|
|
|
|
output_window_width = width;
|
|
|
|
output_window_height = height;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
2018-10-15 21:04:28 +02:00
|
|
|
S9xOpenGLDisplayDriver::init_gl (void)
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
using_egl = 0;
|
|
|
|
if (epoxy_has_egl ())
|
|
|
|
{
|
|
|
|
printf ("Using EGL context\n");
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
using_egl = 1;
|
|
|
|
EGLint num_configs;
|
|
|
|
EGLint const egl_attribs[] = { EGL_COLOR_BUFFER_TYPE, EGL_RGB_BUFFER, EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT, EGL_NONE };
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
egl_display = NULL;
|
|
|
|
GdkDisplay *d = gdk_display_get_default ();
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
if (GDK_IS_X11_DISPLAY (d))
|
|
|
|
{
|
|
|
|
display = GDK_DISPLAY_XDISPLAY (d);
|
2018-10-19 00:47:39 +02:00
|
|
|
egl_display = eglGetDisplay ((EGLNativeDisplayType) display);
|
2018-10-15 21:04:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
if (GDK_IS_WAYLAND_DISPLAY (d))
|
|
|
|
{
|
|
|
|
struct wl_display *wl_d = gdk_wayland_display_get_wl_display (d);
|
2018-10-19 00:47:39 +02:00
|
|
|
egl_display = eglGetDisplay ((EGLNativeDisplayType) wl_d);
|
2018-10-15 21:04:28 +02:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
if (!egl_display)
|
|
|
|
return 0;
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
eglInitialize (egl_display, NULL, NULL);
|
|
|
|
eglChooseConfig (egl_display, egl_attribs, &egl_config, 1, &num_configs);
|
|
|
|
eglBindAPI (EGL_OPENGL_API);
|
2018-05-05 20:49:42 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (num_configs < 1)
|
|
|
|
{
|
|
|
|
fprintf (stderr, _("Couldn't find any appropriate EGL configs.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-19 00:47:39 +02:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
if (on_wayland ())
|
|
|
|
memset (&wl, 0, sizeof (wl));
|
|
|
|
#endif
|
2018-10-15 21:04:28 +02:00
|
|
|
create_window (1, 1);
|
|
|
|
if (!egl_surface)
|
|
|
|
{
|
|
|
|
fprintf (stderr, _("Couldn't create an EGL surface.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
egl_context = eglCreateContext (egl_display, egl_config, EGL_NO_CONTEXT, NULL);
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (!egl_context)
|
|
|
|
{
|
|
|
|
fprintf (stderr, _("Couldn't create an EGL context.\n"));
|
|
|
|
eglDestroySurface (egl_display, egl_surface);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (!eglMakeCurrent (egl_display, egl_surface, egl_surface, egl_context))
|
|
|
|
{
|
|
|
|
fprintf (stderr, _("Couldn't make current EGL context.\n"));
|
|
|
|
eglDestroyContext (egl_display, egl_context);
|
|
|
|
eglDestroySurface (egl_display, egl_surface);
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
}
|
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
else /* GLX */
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
printf ("Using GLX context\n");
|
2010-09-26 11:19:15 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
int glx_attribs[] = { GLX_RGBA, GLX_DOUBLEBUFFER, None };
|
|
|
|
|
|
|
|
display = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
|
|
|
|
|
|
|
vi = glXChooseVisual (display, DefaultScreen (display), glx_attribs);
|
|
|
|
|
|
|
|
if (!vi)
|
|
|
|
{
|
|
|
|
fprintf (stderr, _("Couldn't find an adequate OpenGL visual.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
xcolormap = XCreateColormap (display,
|
|
|
|
GDK_COMPAT_WINDOW_XID (gtk_widget_get_window (drawing_area)),
|
|
|
|
vi->visual,
|
|
|
|
AllocNone);
|
|
|
|
|
|
|
|
create_window (1, 1);
|
|
|
|
gdk_window_hide (gdk_window);
|
|
|
|
|
|
|
|
glx_context = glXCreateContext (display, vi, 0, 1);
|
|
|
|
|
|
|
|
if (!glx_context)
|
|
|
|
{
|
|
|
|
XFreeColormap (display, xcolormap);
|
|
|
|
gdk_window_destroy (gdk_window);
|
|
|
|
|
|
|
|
fprintf (stderr, _("Couldn't create an OpenGL context.\n"));
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!glXMakeCurrent (display, xwindow, glx_context))
|
|
|
|
{
|
|
|
|
XFreeColormap (display, xcolormap);
|
|
|
|
g_object_unref (gdk_window);
|
|
|
|
gdk_window_destroy (gdk_window);
|
|
|
|
|
|
|
|
fprintf (stderr, "glXMakeCurrent failed.\n");
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-26 11:19:15 +02:00
|
|
|
}
|
2018-10-15 21:04:28 +02:00
|
|
|
#endif
|
2010-09-26 11:19:15 +02:00
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
int
|
|
|
|
S9xOpenGLDisplayDriver::init (void)
|
|
|
|
{
|
2010-09-26 11:19:15 +02:00
|
|
|
initialized = 0;
|
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (!init_gl ())
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
if (!opengl_defaults ())
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
buffer[0] = malloc (image_padded_size);
|
|
|
|
buffer[1] = malloc (scaled_padded_size);
|
|
|
|
|
|
|
|
clear_buffers ();
|
|
|
|
|
2018-05-05 00:12:22 +02:00
|
|
|
padded_buffer[0] = (void *) (((uint8 *) buffer[0]) + image_padded_offset);
|
|
|
|
padded_buffer[1] = (void *) (((uint8 *) buffer[1]) + scaled_padded_offset);
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
GFX.Screen = (uint16 *) padded_buffer[0];
|
|
|
|
GFX.Pitch = image_width * image_bpp;
|
|
|
|
|
2010-09-26 11:19:15 +02:00
|
|
|
swap_control (config->sync_to_vblank);
|
|
|
|
|
|
|
|
initialized = 1;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::swap_control (int enable)
|
|
|
|
{
|
2011-01-09 10:32:38 +01:00
|
|
|
enable = enable ? 1 : 0;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (using_egl)
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
eglSwapInterval (egl_display, enable);
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
2018-10-15 21:04:28 +02:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
else
|
2010-09-25 17:46:12 +02:00
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
const char *extensions = (const char *) glGetString (GL_EXTENSIONS);
|
|
|
|
|
|
|
|
if (strstr (extensions, "EXT_swap_control"))
|
|
|
|
{
|
|
|
|
glXSwapIntervalEXT (display, xwindow, enable);
|
|
|
|
}
|
|
|
|
else if (strstr (extensions, "SGI_swap_control"))
|
|
|
|
{
|
|
|
|
glXSwapIntervalSGI (enable);
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|
2018-10-15 21:04:28 +02:00
|
|
|
#endif
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 *
|
|
|
|
S9xOpenGLDisplayDriver::get_next_buffer (void)
|
|
|
|
{
|
|
|
|
return (uint16 *) padded_buffer[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::push_buffer (uint16 *src)
|
|
|
|
{
|
|
|
|
memmove (padded_buffer[0], src, image_size);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint16 *
|
|
|
|
S9xOpenGLDisplayDriver::get_current_buffer (void)
|
|
|
|
{
|
|
|
|
return (uint16 *) padded_buffer[0];
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::gl_swap (void)
|
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
if (using_egl)
|
2018-10-19 00:47:39 +02:00
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
eglSwapBuffers (egl_display, egl_surface);
|
2018-10-19 00:47:39 +02:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
if (on_wayland ())
|
2018-10-19 01:00:27 +02:00
|
|
|
{
|
|
|
|
wl_display_flush (wl.display);
|
|
|
|
}
|
2018-10-19 00:47:39 +02:00
|
|
|
#endif
|
|
|
|
}
|
2018-10-15 21:04:28 +02:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
else
|
|
|
|
glXSwapBuffers (display, xwindow);
|
|
|
|
#endif
|
2010-09-26 11:19:15 +02:00
|
|
|
|
|
|
|
if (config->sync_every_frame)
|
|
|
|
{
|
2010-12-26 01:30:09 +01:00
|
|
|
usleep (0);
|
2010-09-26 11:19:15 +02:00
|
|
|
glFinish ();
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::deinit (void)
|
|
|
|
{
|
2010-09-26 11:19:15 +02:00
|
|
|
if (!initialized)
|
|
|
|
return;
|
|
|
|
|
2018-05-11 01:47:55 +02:00
|
|
|
if (using_shaders && using_glsl_shaders)
|
|
|
|
{
|
2018-05-24 19:18:59 +02:00
|
|
|
window->enable_widget ("shader_parameters_item", FALSE);
|
|
|
|
gtk_shader_parameters_dialog_close ();
|
2018-05-11 01:47:55 +02:00
|
|
|
glsl_shader->destroy();
|
|
|
|
delete glsl_shader;
|
|
|
|
}
|
2018-05-08 23:56:18 +02:00
|
|
|
else if (using_shaders)
|
2010-09-26 11:19:15 +02:00
|
|
|
{
|
|
|
|
glUseProgram (0);
|
|
|
|
glDetachShader (program, vertex_shader);
|
|
|
|
glDetachShader (program, fragment_shader);
|
|
|
|
glDeleteShader (vertex_shader);
|
|
|
|
glDeleteShader (fragment_shader);
|
|
|
|
glDeleteProgram (program);
|
|
|
|
using_shaders = 0;
|
|
|
|
}
|
2010-09-25 17:46:12 +02:00
|
|
|
|
|
|
|
GFX.Screen = NULL;
|
|
|
|
|
|
|
|
padded_buffer[0] = NULL;
|
|
|
|
padded_buffer[1] = NULL;
|
|
|
|
|
|
|
|
free (buffer[0]);
|
|
|
|
free (buffer[1]);
|
|
|
|
|
|
|
|
if (using_pbos)
|
|
|
|
{
|
|
|
|
glBindBuffer (GL_PIXEL_UNPACK_BUFFER, 0);
|
|
|
|
glDeleteBuffers (1, &pbo);
|
|
|
|
}
|
|
|
|
|
|
|
|
glDeleteTextures (1, &texmap);
|
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (using_egl)
|
|
|
|
{
|
|
|
|
eglDestroyContext (egl_display, egl_context);
|
|
|
|
eglDestroySurface (egl_display, egl_surface);
|
2018-10-19 00:47:39 +02:00
|
|
|
#ifdef GDK_WINDOWING_WAYLAND
|
|
|
|
if (on_wayland ())
|
|
|
|
{
|
|
|
|
if (wl.egl_window)
|
|
|
|
wl_egl_window_destroy (wl.egl_window);
|
|
|
|
if (wl.subsurface)
|
|
|
|
wl_subsurface_destroy (wl.subsurface);
|
|
|
|
if (wl.child)
|
2018-10-19 01:08:01 +02:00
|
|
|
{
|
|
|
|
wl_region_destroy (wl.region);
|
2018-10-19 00:47:39 +02:00
|
|
|
wl_surface_destroy (wl.child);
|
2018-10-19 01:08:01 +02:00
|
|
|
}
|
2018-10-19 00:47:39 +02:00
|
|
|
}
|
|
|
|
#endif
|
2018-10-15 21:04:28 +02:00
|
|
|
}
|
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
else
|
|
|
|
{
|
|
|
|
glXDestroyContext (display, glx_context);
|
|
|
|
gdk_window_destroy (gdk_window);
|
|
|
|
XFree (vi);
|
|
|
|
XFreeColormap (display, xcolormap);
|
|
|
|
}
|
|
|
|
#endif
|
2018-10-19 00:47:39 +02:00
|
|
|
|
2010-09-25 17:46:12 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
S9xOpenGLDisplayDriver::reconfigure (int width, int height)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
S9xOpenGLDisplayDriver::query_availability (void)
|
|
|
|
{
|
2018-10-15 21:04:28 +02:00
|
|
|
if (epoxy_has_egl ())
|
|
|
|
return 1;
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
#ifdef GDK_WINDOWING_X11
|
|
|
|
Display *dpy = GDK_DISPLAY_XDISPLAY (gdk_display_get_default ());
|
2018-07-12 17:15:07 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (epoxy_has_glx (dpy))
|
|
|
|
return 1;
|
|
|
|
#endif
|
2010-09-25 17:46:12 +02:00
|
|
|
|
2018-10-15 21:04:28 +02:00
|
|
|
if (gui_config->hw_accel == HWA_OPENGL)
|
|
|
|
gui_config->hw_accel = HWA_NONE;
|
|
|
|
|
|
|
|
return 0;
|
2010-09-25 17:46:12 +02:00
|
|
|
}
|