Merge pull request #1413 from ts-korhonen/opengl

Use persistent buffer for pixel transfer in OpenGL Core renderer
This commit is contained in:
Miran Grča
2021-04-29 19:38:17 +02:00
committed by GitHub
4 changed files with 297 additions and 134 deletions

View File

@@ -1,22 +1,23 @@
/*
OpenGL loader generated by glad 0.1.34 on Fri Apr 9 15:21:10 2021.
OpenGL loader generated by glad 0.1.34 on Tue Apr 27 15:16:07 2021.
Language/Generator: C/C++
Specification: gl
APIs: gl=3.3
Profile: core
Extensions:
GL_ARB_buffer_storage,
GL_ARB_debug_output
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --extensions=""
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_debug_output"
Online:
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_debug_output
*/
@@ -2121,6 +2122,58 @@ typedef void (APIENTRYP PFNGLSECONDARYCOLORP3UIVPROC)(GLenum type, const GLuint
GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
#endif
#define GL_MAP_PERSISTENT_BIT 0x0040
#define GL_MAP_COHERENT_BIT 0x0080
#define GL_DYNAMIC_STORAGE_BIT 0x0100
#define GL_CLIENT_STORAGE_BIT 0x0200
#define GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT 0x00004000
#define GL_BUFFER_IMMUTABLE_STORAGE 0x821F
#define GL_BUFFER_STORAGE_FLAGS 0x8220
#define GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242
#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243
#define GL_DEBUG_CALLBACK_FUNCTION_ARB 0x8244
#define GL_DEBUG_CALLBACK_USER_PARAM_ARB 0x8245
#define GL_DEBUG_SOURCE_API_ARB 0x8246
#define GL_DEBUG_SOURCE_WINDOW_SYSTEM_ARB 0x8247
#define GL_DEBUG_SOURCE_SHADER_COMPILER_ARB 0x8248
#define GL_DEBUG_SOURCE_THIRD_PARTY_ARB 0x8249
#define GL_DEBUG_SOURCE_APPLICATION_ARB 0x824A
#define GL_DEBUG_SOURCE_OTHER_ARB 0x824B
#define GL_DEBUG_TYPE_ERROR_ARB 0x824C
#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB 0x824D
#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB 0x824E
#define GL_DEBUG_TYPE_PORTABILITY_ARB 0x824F
#define GL_DEBUG_TYPE_PERFORMANCE_ARB 0x8250
#define GL_DEBUG_TYPE_OTHER_ARB 0x8251
#define GL_MAX_DEBUG_MESSAGE_LENGTH_ARB 0x9143
#define GL_MAX_DEBUG_LOGGED_MESSAGES_ARB 0x9144
#define GL_DEBUG_LOGGED_MESSAGES_ARB 0x9145
#define GL_DEBUG_SEVERITY_HIGH_ARB 0x9146
#define GL_DEBUG_SEVERITY_MEDIUM_ARB 0x9147
#define GL_DEBUG_SEVERITY_LOW_ARB 0x9148
#ifndef GL_ARB_buffer_storage
#define GL_ARB_buffer_storage 1
GLAPI int GLAD_GL_ARB_buffer_storage;
typedef void (APIENTRYP PFNGLBUFFERSTORAGEPROC)(GLenum target, GLsizeiptr size, const void *data, GLbitfield flags);
GLAPI PFNGLBUFFERSTORAGEPROC glad_glBufferStorage;
#define glBufferStorage glad_glBufferStorage
#endif
#ifndef GL_ARB_debug_output
#define GL_ARB_debug_output 1
GLAPI int GLAD_GL_ARB_debug_output;
typedef void (APIENTRYP PFNGLDEBUGMESSAGECONTROLARBPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint *ids, GLboolean enabled);
GLAPI PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB;
#define glDebugMessageControlARB glad_glDebugMessageControlARB
typedef void (APIENTRYP PFNGLDEBUGMESSAGEINSERTARBPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *buf);
GLAPI PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB;
#define glDebugMessageInsertARB glad_glDebugMessageInsertARB
typedef void (APIENTRYP PFNGLDEBUGMESSAGECALLBACKARBPROC)(GLDEBUGPROCARB callback, const void *userParam);
GLAPI PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB;
#define glDebugMessageCallbackARB glad_glDebugMessageCallbackARB
typedef GLuint (APIENTRYP PFNGLGETDEBUGMESSAGELOGARBPROC)(GLuint count, GLsizei bufSize, GLenum *sources, GLenum *types, GLuint *ids, GLenum *severities, GLsizei *lengths, GLchar *messageLog);
GLAPI PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB;
#define glGetDebugMessageLogARB glad_glGetDebugMessageLogARB
#endif
#ifdef __cplusplus
}

View File

@@ -1,22 +1,23 @@
/*
OpenGL loader generated by glad 0.1.34 on Fri Apr 9 15:21:10 2021.
OpenGL loader generated by glad 0.1.34 on Tue Apr 27 15:16:07 2021.
Language/Generator: C/C++
Specification: gl
APIs: gl=3.3
Profile: core
Extensions:
GL_ARB_buffer_storage,
GL_ARB_debug_output
Loader: True
Local files: False
Omit khrplatform: False
Reproducible: False
Commandline:
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --extensions=""
--profile="core" --api="gl=3.3" --generator="c" --spec="gl" --extensions="GL_ARB_buffer_storage,GL_ARB_debug_output"
Online:
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3
https://glad.dav1d.de/#profile=core&language=c&specification=gl&loader=on&api=gl%3D3.3&extensions=GL_ARB_buffer_storage&extensions=GL_ARB_debug_output
*/
#include <stdio.h>
@@ -641,6 +642,13 @@ PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
PFNGLVIEWPORTPROC glad_glViewport = NULL;
PFNGLWAITSYNCPROC glad_glWaitSync = NULL;
int GLAD_GL_ARB_buffer_storage = 0;
int GLAD_GL_ARB_debug_output = 0;
PFNGLBUFFERSTORAGEPROC glad_glBufferStorage = NULL;
PFNGLDEBUGMESSAGECONTROLARBPROC glad_glDebugMessageControlARB = NULL;
PFNGLDEBUGMESSAGEINSERTARBPROC glad_glDebugMessageInsertARB = NULL;
PFNGLDEBUGMESSAGECALLBACKARBPROC glad_glDebugMessageCallbackARB = NULL;
PFNGLGETDEBUGMESSAGELOGARBPROC glad_glGetDebugMessageLogARB = NULL;
static void load_GL_VERSION_1_0(GLADloadproc load) {
if(!GLAD_GL_VERSION_1_0) return;
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
@@ -1054,9 +1062,21 @@ static void load_GL_VERSION_3_3(GLADloadproc load) {
glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
}
static void load_GL_ARB_buffer_storage(GLADloadproc load) {
if(!GLAD_GL_ARB_buffer_storage) return;
glad_glBufferStorage = (PFNGLBUFFERSTORAGEPROC)load("glBufferStorage");
}
static void load_GL_ARB_debug_output(GLADloadproc load) {
if(!GLAD_GL_ARB_debug_output) return;
glad_glDebugMessageControlARB = (PFNGLDEBUGMESSAGECONTROLARBPROC)load("glDebugMessageControlARB");
glad_glDebugMessageInsertARB = (PFNGLDEBUGMESSAGEINSERTARBPROC)load("glDebugMessageInsertARB");
glad_glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC)load("glDebugMessageCallbackARB");
glad_glGetDebugMessageLogARB = (PFNGLGETDEBUGMESSAGELOGARBPROC)load("glGetDebugMessageLogARB");
}
static int find_extensionsGL(void) {
if (!get_exts()) return 0;
(void)&has_ext;
GLAD_GL_ARB_buffer_storage = has_ext("GL_ARB_buffer_storage");
GLAD_GL_ARB_debug_output = has_ext("GL_ARB_debug_output");
free_exts();
return 1;
}
@@ -1135,6 +1155,8 @@ int gladLoadGLLoader(GLADloadproc load) {
load_GL_VERSION_3_3(load);
if (!find_extensionsGL()) return 0;
load_GL_ARB_buffer_storage(load);
load_GL_ARB_debug_output(load);
return GLVersion.major != 0 || GLVersion.minor != 0;
}

View File

@@ -44,6 +44,14 @@
#include <stdint.h>
#include <string.h>
#if !defined(_MSC_VER) || defined(__clang__)
#include <stdatomic.h>
#else
typedef LONG atomic_flag;
#define atomic_flag_clear(OBJ) InterlockedExchange(OBJ, 0)
#define atomic_flag_test_and_set(OBJ) InterlockedExchange(OBJ, 1)
#endif
#include <86box/86box.h>
#include <86box/plat.h>
#include <86box/video.h>
@@ -53,6 +61,9 @@
static const int INIT_WIDTH = 640;
static const int INIT_HEIGHT = 400;
static const int BUFFERPIXELS = 4460544; /* Same size as render_buffer, pow(2048+64,2). */
static const int BUFFERBYTES = 17842176; /* Pixel is 4 bytes. */
static const int BUFFERCOUNT = 3; /* How many buffers to use for pixel transfer (2-3 is commonly recommended). */
/**
* @brief A dedicated OpenGL thread.
@@ -90,18 +101,26 @@ static union
HANDLE asArray[4];
} sync_objects = { 0 };
/**
* @brief Signal from OpenGL thread that it's done with video buffer.
*/
static HANDLE blit_done = NULL;
/**
* @brief Blit event parameters.
*/
static volatile struct
typedef struct
{
int x, y, y1, y2, w, h, resized;
} blit_info = { 0 };
int y1, y2, w, h;
void* buffer; /* Buffer for pixel transfer, allocated by gpu driver. */
volatile atomic_flag in_use; /* Is buffer currently in use. */
GLsync sync; /* Fence sync object used by opengl thread to track pixel transfer completion. */
} blit_info_t;
/**
* @brief Array of blit_infos, one for each buffer.
*/
static blit_info_t* blit_info = NULL;
/**
* @brief Buffer index of next write operation.
*/
static int write_pos = 0;
/**
* @brief Resize event parameters.
@@ -132,6 +151,7 @@ typedef struct
GLuint vertexArrayID;
GLuint vertexBufferID;
GLuint textureID;
GLuint unpackBufferID;
GLuint shader_progID;
/* Uniforms */
@@ -308,7 +328,7 @@ static void apply_shaders(gl_identifiers* gl)
* @brief Initialize OpenGL context
* @return Identifiers
*/
static gl_identifiers initialize_glcontext()
static int initialize_glcontext(gl_identifiers* gl)
{
/* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */
static const GLfloat surface[] = {
@@ -318,18 +338,16 @@ static gl_identifiers initialize_glcontext()
1.f, -1.f, 1.f, 1.f, 1.f, 1.f, 1.f, 1.f
};
gl_identifiers gl = { 0 };
glGenVertexArrays(1, &gl->vertexArrayID);
glGenVertexArrays(1, &gl.vertexArrayID);
glBindVertexArray(gl->vertexArrayID);
glBindVertexArray(gl.vertexArrayID);
glGenBuffers(1, &gl.vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, gl.vertexBufferID);
glGenBuffers(1, &gl->vertexBufferID);
glBindBuffer(GL_ARRAY_BUFFER, gl->vertexBufferID);
glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW);
glGenTextures(1, &gl.textureID);
glBindTexture(GL_TEXTURE_2D, gl.textureID);
glGenTextures(1, &gl->textureID);
glBindTexture(GL_TEXTURE_2D, gl->textureID);
static const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
@@ -338,32 +356,52 @@ static gl_identifiers initialize_glcontext()
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 0, 0, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, INIT_WIDTH, INIT_HEIGHT, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glGenBuffers(1, &gl->unpackBufferID);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl->unpackBufferID);
/* Create persistent buffer for pixel transfer. */
glBufferStorage(GL_PIXEL_UNPACK_BUFFER, BUFFERBYTES * BUFFERCOUNT, NULL, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
void* buf_ptr = glMapBufferRange(GL_PIXEL_UNPACK_BUFFER, 0, BUFFERBYTES * BUFFERCOUNT, GL_MAP_WRITE_BIT | GL_MAP_PERSISTENT_BIT | GL_MAP_COHERENT_BIT);
if (buf_ptr == NULL)
return 0;
/* Split the buffer area for each blit_info and set them available for use. */
for (int i = 0; i < BUFFERCOUNT; i++)
{
blit_info[i].buffer = (byte*)buf_ptr + BUFFERBYTES * i;
atomic_flag_clear(&blit_info[i].in_use);
}
glClearColor(0.f, 0.f, 0.f, 1.f);
apply_shaders(&gl);
apply_shaders(gl);
return gl;
return 1;
}
/**
* @brief Clean up OpenGL context
* @param gl Identifiers from initialize
*/
static void finalize_glcontext(gl_identifiers gl)
static void finalize_glcontext(gl_identifiers* gl)
{
glDeleteProgram(gl.shader_progID);
glDeleteTextures(1, &gl.textureID);
glDeleteBuffers(1, &gl.vertexBufferID);
glDeleteVertexArrays(1, &gl.vertexArrayID);
glDeleteProgram(gl->shader_progID);
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
glDeleteBuffers(1, &gl->unpackBufferID);
glDeleteTextures(1, &gl->textureID);
glDeleteBuffers(1, &gl->vertexBufferID);
glDeleteVertexArrays(1, &gl->vertexArrayID);
}
/**
* @brief Renders a frame and swaps the buffer
* @param gl Identifiers from initialize
*/
static void render_and_swap(gl_identifiers gl)
static void render_and_swap(gl_identifiers* gl)
{
static int frame_counter = 0;
@@ -372,13 +410,13 @@ static void render_and_swap(gl_identifiers gl)
SDL_GL_SwapWindow(window);
if (gl.frame_count != -1)
glUniform1i(gl.frame_count, frame_counter = (frame_counter + 1) & 1023);
if (gl->frame_count != -1)
glUniform1i(gl->frame_count, frame_counter = (frame_counter + 1) & 1023);
}
/**
* @brief Handle failure in OpenGL thread.
* Acts like a renderer until closing.
* Keeps the thread sleeping until closing.
*/
static void opengl_fail()
{
@@ -390,20 +428,21 @@ static void opengl_fail()
/* TODO: Notify user. */
HANDLE handles[] = { sync_objects.closing, sync_objects.blit_waiting };
WaitForSingleObject(sync_objects.closing, INFINITE);
while (1)
{
switch (WaitForMultipleObjects(2, handles, FALSE, INFINITE))
{
case WAIT_OBJECT_0: /* Close requested. End thread. */
_endthread();
case WAIT_OBJECT_0 + 1: /* Blitter is waiting, signal it to continue. */
SetEvent(blit_done);
}
}
}
/*
static void __stdcall opengl_debugmsg_callback(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar* message, const void* userParam)
{
OutputDebugStringA("OpenGL: ");
OutputDebugStringA(message);
OutputDebugStringA("\n");
}
#endif
*/
/**
* @brief Main OpenGL thread proc.
*
@@ -412,8 +451,16 @@ static void opengl_fail()
*/
static void opengl_main(void* param)
{
SDL_InitSubSystem(SDL_INIT_VIDEO);
SDL_SetHint(SDL_HINT_MOUSE_FOCUS_CLICKTHROUGH, "1"); /* Is this actually doing anything...? */
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
//SDL_GL_SetAttribute(SDL_GL_CONTEXT_FLAGS, SDL_GL_CONTEXT_DEBUG_FLAG | SDL_GL_CONTEXT_FORWARD_COMPATIBLE_FLAG);
window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
if (window == NULL)
@@ -444,13 +491,29 @@ static void opengl_main(void* param)
SDL_GL_SetSwapInterval(options.vsync);
if (!gladLoadGLLoader(SDL_GL_GetProcAddress))
if (!gladLoadGLLoader(SDL_GL_GetProcAddress) || !GLAD_GL_ARB_buffer_storage)
{
SDL_GL_DeleteContext(context);
opengl_fail();
}
gl_identifiers gl = initialize_glcontext();
/*
if (GLAD_GL_ARB_debug_output)
{
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
glDebugMessageControlARB(GL_DONT_CARE, GL_DEBUG_TYPE_PERFORMANCE_ARB, GL_DONT_CARE, 0, 0, GL_FALSE);
glDebugMessageCallbackARB(opengl_debugmsg_callback, NULL);
}
*/
gl_identifiers gl = { 0 };
if (!initialize_glcontext(&gl))
{
finalize_glcontext(&gl);
SDL_GL_DeleteContext(context);
opengl_fail();
}
if (gl.frame_count != -1)
glUniform1i(gl.frame_count, 0);
@@ -459,13 +522,15 @@ static void opengl_main(void* param)
uint32_t last_swap = plat_get_micro_ticks() - frametime;
int read_pos = 0; /* Buffer index of next read operation. */
/* Render loop */
int closing = 0;
while (!closing)
{
/* Rendering is done right after handling an event. */
if (frametime < 0)
render_and_swap(gl);
render_and_swap(&gl);
DWORD wait_result = WAIT_TIMEOUT;
@@ -488,11 +553,22 @@ static void opengl_main(void* param)
elapsed = ticks - last_swap;
}
render_and_swap(gl);
render_and_swap(&gl);
last_swap = ticks;
}
}
/* Check if commands that use buffers have been completed. */
for (int i = 0; i < BUFFERCOUNT; i++)
{
if (blit_info[i].sync != NULL && glClientWaitSync(blit_info[i].sync, GL_SYNC_FLUSH_COMMANDS_BIT, 0) != GL_TIMEOUT_EXPIRED)
{
glDeleteSync(blit_info[i].sync);
blit_info[i].sync = NULL;
atomic_flag_clear(&blit_info[i].in_use);
}
}
/* Handle window messages */
MSG msg;
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
@@ -516,23 +592,30 @@ static void opengl_main(void* param)
}
else if (sync_event == sync_objects.blit_waiting)
{
/* Resize the texture */
if (blit_info.resized)
{
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, blit_info.w, blit_info.h, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
blit_info_t* info = &blit_info[read_pos];
video_width = blit_info.w;
video_height = blit_info.h;
if (video_width != info->w || video_height != info->h)
{
video_width = info->w;
video_height = info->h;
/* Resize the texture */
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, video_width, video_height, 0, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, gl.unpackBufferID);
if (fullscreen)
SetEvent(sync_objects.resize);
}
/* Transfer video buffer to texture */
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, blit_info.y1, blit_info.w, blit_info.y2 - blit_info.y1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &(render_buffer->dat)[blit_info.y1 * blit_info.w]);
/* Update texture from pixel buffer. */
glPixelStorei(GL_UNPACK_SKIP_PIXELS, BUFFERPIXELS * read_pos);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, info->y1, info->w, info->y2 - info->y1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, NULL);
/* Signal that we're done with the video buffer */
SetEvent(blit_done);
/* Add fence to track when above gl commands are complete. */
info->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
read_pos = (read_pos + 1) % BUFFERCOUNT;
/* Update uniforms */
if (gl.input_size != -1)
@@ -656,7 +739,13 @@ static void opengl_main(void* param)
SDL_ShowCursor(show_cursor);
}
finalize_glcontext(gl);
for (int i = 0; i < BUFFERCOUNT; i++)
{
if (blit_info[i].sync != NULL)
glDeleteSync(blit_info[i].sync);
}
finalize_glcontext(&gl);
SDL_GL_DeleteContext(context);
@@ -669,23 +758,25 @@ static void opengl_main(void* param)
static void opengl_blit(int x, int y, int y1, int y2, int w, int h)
{
if (y1 == y2 || h <= 0 || render_buffer == NULL || thread == NULL)
if (y1 == y2 || h <= 0 || render_buffer == NULL || thread == NULL ||
atomic_flag_test_and_set(&blit_info[write_pos].in_use))
{
video_blit_complete();
return;
}
blit_info.resized = (w != blit_info.w || h != blit_info.h);
blit_info.x = x;
blit_info.y = y;
blit_info.y1 = y1;
blit_info.y2 = y2;
blit_info.w = w;
blit_info.h = h;
SignalObjectAndWait(sync_objects.blit_waiting, blit_done, INFINITE, FALSE);
memcpy(blit_info[write_pos].buffer, &(render_buffer->dat)[y1 * w], w * (y2 - y1) * 4);
video_blit_complete();
blit_info[write_pos].y1 = y1;
blit_info[write_pos].y2 = y2;
blit_info[write_pos].w = w;
blit_info[write_pos].h = h;
write_pos = (write_pos + 1) % BUFFERCOUNT;
ReleaseSemaphore(sync_objects.blit_waiting, 1, NULL);
}
static int framerate_to_frametime(int framerate)
@@ -704,7 +795,10 @@ int opengl_init(HWND hwnd)
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
sync_objects.asArray[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
blit_done = CreateEvent(NULL, FALSE, FALSE, NULL);
sync_objects.closing = CreateEvent(NULL, FALSE, FALSE, NULL);
sync_objects.resize = CreateEvent(NULL, FALSE, FALSE, NULL);
sync_objects.reload = CreateEvent(NULL, FALSE, FALSE, NULL);
sync_objects.blit_waiting = CreateSemaphore(NULL, 0, BUFFERCOUNT * 2, NULL);
parent = hwnd;
@@ -723,6 +817,15 @@ int opengl_init(HWND hwnd)
strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader);
options.mutex = thread_create_mutex();
blit_info = (blit_info_t*)malloc(BUFFERCOUNT * sizeof(blit_info_t));
memset(blit_info, 0, BUFFERCOUNT * sizeof(blit_info_t));
/* Buffers are not yet allocated, set them as in use. */
for (int i = 0; i < BUFFERCOUNT; i++)
atomic_flag_test_and_set(&blit_info[i].in_use);
write_pos = 0;
thread = thread_create(opengl_main, (void*)NULL);
atexit(opengl_close);
@@ -746,16 +849,12 @@ void opengl_close(void)
thread_wait(thread, -1);
memset((void*)&blit_info, 0, sizeof(blit_info));
thread_close_mutex(resize_info.mutex);
thread_close_mutex(options.mutex);
SetEvent(blit_done);
thread = NULL;
CloseHandle(blit_done);
free(blit_info);
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
{

View File

@@ -58,8 +58,9 @@ void main(){\n\
static const GLchar* fragment_shader = "#version 330 core\n\
in vec2 tex;\n\
uniform sampler2D texsampler;\n\
out vec4 color;\n\
void main() {\n\
gl_FragColor = texture(texsampler, tex);\n\
color = texture(texsampler, tex);\n\
}\n";
/**
@@ -97,65 +98,66 @@ static char* read_file_to_string(const char* path)
return NULL;
}
static int check_status(GLuint id, int is_shader)
{
GLint status = GL_FALSE;
if (is_shader)
glGetShaderiv(id, GL_COMPILE_STATUS, &status);
else
glGetProgramiv(id, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
int info_log_length;
if (is_shader)
glGetShaderiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
else
glGetProgramiv(id, GL_INFO_LOG_LENGTH, &info_log_length);
GLchar* info_log_text = (GLchar*)malloc(sizeof(GLchar) * info_log_length);
if (is_shader)
glGetShaderInfoLog(id, info_log_length, NULL, info_log_text);
else
glGetProgramInfoLog(id, info_log_length, NULL, info_log_text);
/* TODO: error logging */
free(info_log_text);
return 0;
}
return 1;
}
/**
* @brief Compile custom shaders into a program.
* @return Shader program identifier.
*/
GLuint load_custom_shaders(const char* path)
{
GLint status = GL_FALSE;
int info_log_length;
/* TODO: get path from config */
char* shader = read_file_to_string(path);
if (shader != NULL)
{
int success = 1;
const char* vertex_sources[2] = { "#define VERTEX\n", shader };
const char* fragment_sources[2] = { "#define FRAGMENT\n", shader };
const char* vertex_sources[2] = { "#version 330 core\n#define VERTEX\n", shader };
const char* fragment_sources[2] = { "#version 330 core\n#define FRAGMENT\n", shader };
GLuint vertex_id = glCreateShader(GL_VERTEX_SHADER);
GLuint fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(vertex_id, 2, vertex_sources, NULL);
glCompileShader(vertex_id);
glGetShaderiv(vertex_id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
glGetShaderiv(vertex_id, GL_INFO_LOG_LENGTH, &info_log_length);
GLchar* info_log_text = (GLchar*)malloc(sizeof(GLchar) * info_log_length);
glGetShaderInfoLog(vertex_id, info_log_length, NULL, info_log_text);
/* TODO: error logging */
free(info_log_text);
success = 0;
}
success *= check_status(vertex_id, 1);
glShaderSource(fragment_id, 2, fragment_sources, NULL);
glCompileShader(fragment_id);
glGetShaderiv(fragment_id, GL_COMPILE_STATUS, &status);
if (status == GL_FALSE)
{
glGetShaderiv(fragment_id, GL_INFO_LOG_LENGTH, &info_log_length);
GLchar* info_log_text = (GLchar*)malloc(sizeof(GLchar) * info_log_length);
glGetShaderInfoLog(fragment_id, info_log_length, NULL, info_log_text);
/* TODO: error logging */
free(info_log_text);
success = 0;
}
success *= check_status(fragment_id, 1);
free(shader);
@@ -168,20 +170,7 @@ GLuint load_custom_shaders(const char* path)
glAttachShader(prog_id, vertex_id);
glAttachShader(prog_id, fragment_id);
glLinkProgram(prog_id);
glGetProgramiv(prog_id, GL_LINK_STATUS, &status);
if (status == GL_FALSE)
{
glGetProgramiv(prog_id, GL_INFO_LOG_LENGTH, &info_log_length);
GLchar* info_log_text = (GLchar*)malloc(sizeof(GLchar) * info_log_length);
glGetProgramInfoLog(prog_id, info_log_length, NULL, info_log_text);
/* TODO: error logging */
free(info_log_text);
}
check_status(prog_id, 0);
glDetachShader(prog_id, vertex_id);
glDetachShader(prog_id, fragment_id);