Update for more modern GL approach.

This commit is contained in:
Themaister 2010-11-08 23:38:32 +01:00
parent af7819e5cc
commit c5f433f399
4 changed files with 89 additions and 78 deletions

View File

@ -3,7 +3,7 @@ include config.mk
TARGET = ssnes TARGET = ssnes
OBJ = ssnes.o OBJ = ssnes.o
LIBS = -lsamplerate -lsnes LIBS = -lsamplerate libsnes.a
ifeq ($(BUILD_RSOUND), 1) ifeq ($(BUILD_RSOUND), 1)
OBJ += rsound.o OBJ += rsound.o
@ -42,7 +42,7 @@ CFLAGS = -Wall -O3 -march=native -std=gnu99
all: $(TARGET) all: $(TARGET)
ssnes: $(OBJ) ssnes: $(OBJ)
@$(CC) -o $@ $(OBJ) $(LIBS) @$(CXX) -o $@ $(OBJ) $(LIBS)
@echo "LD $@" @echo "LD $@"
%.o: %.c config.h config.mk %.o: %.c config.h config.mk

View File

@ -67,7 +67,7 @@ typedef struct video_driver
{ {
void* (*init)(video_info_t *video, const input_driver_t **input); void* (*init)(video_info_t *video, const input_driver_t **input);
// Should the video driver act as an input driver as well? :) // Should the video driver act as an input driver as well? :)
bool (*frame)(void* data, const uint16_t* frame, int width, int height); bool (*frame)(void* data, const uint16_t* frame, int width, int height, int pitch);
void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding. void (*set_nonblock_state)(void* data, bool toggle); // Should we care about syncing to vblank? Fast forwarding.
void (*free)(void* data); void (*free)(void* data);
} video_driver_t; } video_driver_t;

148
gl.c
View File

@ -15,6 +15,7 @@
* If not, see <http://www.gnu.org/licenses/>. * If not, see <http://www.gnu.org/licenses/>.
*/ */
#define GL_GLEXT_PROTOTYPES
#include "driver.h" #include "driver.h"
#include <GL/glfw.h> #include <GL/glfw.h>
@ -23,8 +24,8 @@
#include <stdio.h> #include <stdio.h>
#include <sys/time.h> #include <sys/time.h>
static GLuint texture; static GLuint texture, pbo, vbo;
static uint8_t *gl_buffer; static uint8_t *gl_buffer, *vertex_buf;
static bool keep_aspect = true; static bool keep_aspect = true;
static GLuint tex_filter; static GLuint tex_filter;
@ -70,7 +71,6 @@ static int init_joypads(int max_pads)
static int16_t glfw_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id) static int16_t glfw_input_state(void *data, const struct snes_keybind **binds, bool port, unsigned device, unsigned index, unsigned id)
{ {
if ( device != SNES_DEVICE_JOYPAD ) if ( device != SNES_DEVICE_JOYPAD )
return 0; return 0;
@ -139,29 +139,29 @@ static void GLFWCALL resize(int width, int height)
if ( keep_aspect ) if ( keep_aspect )
{ {
//float desired_aspect = 256.0/224.0; float desired_aspect = 4.0/3;
float desired_aspect = 296.0/224.0; float device_aspect = (float)width / height;
float in_aspect = (float)width / height;
if ( (int)(in_aspect*100) > (int)(desired_aspect*100) ) // If the aspect ratios of screen and desired aspect ratio are sufficiently equal (floating point stuff),
// assume they are actually equal.
if ( (int)(device_aspect*1000) > (int)(desired_aspect*1000) )
{ {
float delta = (in_aspect / desired_aspect - 1.0) / 2.0 + 0.5; float delta = (desired_aspect / device_aspect - 1.0) / 2.0 + 0.5;
glOrtho(0.5 - delta, 0.5 + delta, 0, 1, -1, 1); glViewport(width * (0.5 - delta), 0, 2.0 * width * delta, height);
} }
else if ( (int)(in_aspect*100) < (int)(desired_aspect*100) ) else if ( (int)(device_aspect*1000) < (int)(desired_aspect*1000) )
{ {
float delta = (desired_aspect / in_aspect - 1.0) / 2.0 + 0.5; float delta = (device_aspect / desired_aspect - 1.0) / 2.0 + 0.5;
glOrtho(0, 1, 0.5 - delta, 0.5 + delta, -1, 1); glViewport(0, height * (0.5 - delta), width, 2.0 * height * delta);
} }
else else
glOrtho(0, 1, 0, 1, -1, 1); glViewport(0, 0, width, height);
} }
else else
glOrtho(0, 1, 0, 1, -1, 1); glViewport(0, 0, width, height);
glViewport(0, 0, width, height); glOrtho(0, 1, 0, 1, -1, 1);
glMatrixMode(GL_MODELVIEW); glMatrixMode(GL_MODELVIEW);
glLoadIdentity(); glLoadIdentity();
} }
@ -172,53 +172,9 @@ static float tv_to_fps(const struct timeval *tv, const struct timeval *new_tv, i
return frames/time; return frames/time;
} }
static bool gl_frame(void *data, const uint16_t* frame, int width, int height) static void show_fps(void)
{ {
gl_t *gl = data; // Shows FPS in taskbar.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, frame);
glLoadIdentity();
glColor4f(1, 1, 1, 1);
float h = 224.0/256.0;
GLfloat vertexes[] = {
0, 0, 0,
0, 1, 0,
1, 1, 0,
1, 0, 0
};
GLfloat tex_coords[] = {
0, h*height/gl->real_y,
0, 0,
(float)width/gl->real_x, 0,
(float)width/gl->real_x, h*height/gl->real_y
};
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), vertexes);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), tex_coords);
glDrawArrays(GL_QUADS, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
// Shows FPS in taskbar.
static int frames = 0; static int frames = 0;
static struct timeval tv; static struct timeval tv;
struct timeval new_tv; struct timeval new_tv;
@ -242,7 +198,28 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
glfwSetWindowTitle(tmpstr); glfwSetWindowTitle(tmpstr);
} }
frames++; frames++;
}
static bool gl_frame(void *data, const uint16_t* frame, int width, int height, int pitch)
{
gl_t *gl = data;
glClear(GL_COLOR_BUFFER_BIT);
GLfloat tex_coords[] = {
0, (float)height/gl->real_y,
0, 0,
(float)width/gl->real_x, 0,
(float)width/gl->real_x, (float)height/gl->real_y
};
glPixelStorei(GL_UNPACK_ROW_LENGTH, pitch >> 1);
glBufferSubData(GL_ARRAY_BUFFER, 128, sizeof(tex_coords), tex_coords);
glBufferSubData(GL_PIXEL_UNPACK_BUFFER, 0, height * pitch, frame);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_BGRA, GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
glDrawArrays(GL_QUADS, 0, 4);
show_fps();
glfwSwapBuffers(); glfwSwapBuffers();
return true; return true;
@ -250,9 +227,14 @@ static bool gl_frame(void *data, const uint16_t* frame, int width, int height)
static void gl_free(void *data) static void gl_free(void *data)
{ {
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDeleteTextures(1, &texture); glDeleteTextures(1, &texture);
glDeleteBuffers(1, &pbo);
glDeleteBuffers(1, &vbo);
glfwTerminate(); glfwTerminate();
free(gl_buffer); free(gl_buffer);
free(vertex_buf);
} }
static void gl_set_nonblock_state(void *data, bool state) static void gl_set_nonblock_state(void *data, bool state)
@ -284,7 +266,7 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
int res; int res;
res = glfwOpenWindow(video->width, video->height, 0, 0, 0, 0, 0, 0, (video->fullscreen) ? GLFW_FULLSCREEN : GLFW_WINDOW); res = glfwOpenWindow(video->width, video->height, 0, 0, 0, 0, 0, 0, (video->fullscreen) ? GLFW_FULLSCREEN : GLFW_WINDOW);
if ( !res ) if (!res)
{ {
glfwTerminate(); glfwTerminate();
return NULL; return NULL;
@ -298,19 +280,22 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
glfwSwapInterval(0); glfwSwapInterval(0);
gl->vsync = video->vsync; gl->vsync = video->vsync;
gl_buffer = malloc(256 * 256 * 2 * video->input_scale * video->input_scale); gl_buffer = calloc(1, 256 * 256 * 2 * video->input_scale * video->input_scale);
if ( !gl_buffer ) vertex_buf = calloc(1, 256);
if ( !gl_buffer || !vertex_buf )
{ {
fprintf(stderr, "Couldn't allocate memory :<\n"); fprintf(stderr, "Couldn't allocate memory :<\n");
exit(1); exit(1);
} }
gl->real_x = video->input_scale * 256; gl->real_x = video->input_scale * 256;
gl->real_y = video->input_scale * 224; gl->real_y = video->input_scale * 256;
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glEnable(GL_DITHER); glEnable(GL_DITHER);
glEnable(GL_DEPTH_TEST); glDisable(GL_DEPTH_TEST);
glColor3f(1, 1, 1);
glClearColor(0, 0, 0, 0);
glfwSetWindowTitle("SSNES"); glfwSetWindowTitle("SSNES");
@ -318,11 +303,36 @@ static void* gl_init(video_info_t *video, const input_driver_t **input)
glLoadIdentity(); glLoadIdentity();
glGenTextures(1, &texture); glGenTextures(1, &texture);
glGenBuffers(1, &pbo);
glGenBuffers(1, &vbo);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo);
glBufferData(GL_PIXEL_UNPACK_BUFFER, 256 * 256 * 2 * video->input_scale * video->input_scale, gl_buffer, GL_STREAM_DRAW);
glBindTexture(GL_TEXTURE_2D, texture); glBindTexture(GL_TEXTURE_2D, texture);
//glPixelStorei(GL_UNPACK_ROW_LENGTH, 256 * video->input_scale);
glTexImage2D(GL_TEXTURE_2D, glTexImage2D(GL_TEXTURE_2D,
0, GL_RGB, 256 * video->input_scale, 256 * video->input_scale, 0, GL_BGRA, 0, GL_RGB, 256 * video->input_scale, 256 * video->input_scale, 0, GL_BGRA,
GL_UNSIGNED_SHORT_1_5_5_5_REV, gl_buffer); GL_UNSIGNED_SHORT_1_5_5_5_REV, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, tex_filter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, tex_filter);
GLfloat vertexes[] = {
0, 0, 0,
0, 1, 0,
1, 1, 0,
1, 0, 0
};
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, 256, vertex_buf, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertexes), vertexes);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, 3 * sizeof(GLfloat), NULL);
glTexCoordPointer(2, GL_FLOAT, 2 * sizeof(GLfloat), (void*)128);
*input = &input_glfw; *input = &input_glfw;
return gl; return gl;

13
ssnes.c
View File

@ -212,6 +212,7 @@ static void uninit_video_input(void)
driver.input->free(driver.input_data); driver.input->free(driver.input_data);
} }
#if VIDEO_FILTER != FILTER_NONE
static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height) static inline void process_frame (uint16_t * restrict out, const uint16_t * restrict in, unsigned width, unsigned height)
{ {
int pitch = 1024; int pitch = 1024;
@ -226,6 +227,7 @@ static inline void process_frame (uint16_t * restrict out, const uint16_t * rest
memcpy(dst, src, width * sizeof(uint16_t)); memcpy(dst, src, width * sizeof(uint16_t));
} }
} }
#endif
// libsnes: 0.065 // libsnes: 0.065
// Format received is 16-bit 0RRRRRGGGGGBBBBB // Format received is 16-bit 0RRRRRGGGGGBBBBB
@ -241,14 +243,13 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
#elif VIDEO_FILTER == FILTER_NTSC #elif VIDEO_FILTER == FILTER_NTSC
uint16_t output_ntsc[SNES_NTSC_OUT_WIDTH(width) * height]; uint16_t output_ntsc[SNES_NTSC_OUT_WIDTH(width) * height];
#endif #endif
#if VIDEO_FILTER != FILTER_NONE
uint16_t output[width * height]; uint16_t output[width * height];
process_frame(output, data, width, height); process_frame(output, data, width, height);
#endif
#if VIDEO_FILTER == FILTER_NONE #if VIDEO_FILTER == FILTER_HQ2X
if ( !driver.video->frame(driver.video_data, output, width, height) )
video_active = false;
#elif VIDEO_FILTER == FILTER_HQ2X
ProcessHQ2x(output, outputHQ2x); ProcessHQ2x(output, outputHQ2x);
if ( !driver.video->frame(driver.video_data, outputHQ2x, width * 2, height * 2) ) if ( !driver.video->frame(driver.video_data, outputHQ2x, width * 2, height * 2) )
video_active = false; video_active = false;
@ -269,7 +270,7 @@ static void video_frame(const uint16_t *data, unsigned width, unsigned height)
if ( !driver.video->frame(driver.video_data, output_ntsc, SNES_NTSC_OUT_WIDTH(width), height) ) if ( !driver.video->frame(driver.video_data, output_ntsc, SNES_NTSC_OUT_WIDTH(width), height) )
video_active = false; video_active = false;
#else #else
if ( !driver.video->frame(driver.video_data, output, width, height) ) if ( !driver.video->frame(driver.video_data, data, width, height, (height == 448 || height == 478) ? 1024 : 2048) )
video_active = false; video_active = false;
#endif #endif