diff --git a/src/include/glad/glad.h b/src/include/glad/glad.h index 32034bc8b..f8a96f376 100644 --- a/src/include/glad/glad.h +++ b/src/include/glad/glad.h @@ -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 } diff --git a/src/win/glad.c b/src/win/glad.c index 5594f75c6..7bab35d06 100644 --- a/src/win/glad.c +++ b/src/win/glad.c @@ -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 @@ -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; } diff --git a/src/win/win_opengl.c b/src/win/win_opengl.c index 7230bd303..9c7753151 100644 --- a/src/win/win_opengl.c +++ b/src/win/win_opengl.c @@ -44,6 +44,14 @@ #include #include +#if !defined(_MSC_VER) || defined(__clang__) +#include +#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 }; - - 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); - } - } + WaitForSingleObject(sync_objects.closing, INFINITE); + + _endthread(); } +/* +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++) { diff --git a/src/win/win_opengl_glslp.c b/src/win/win_opengl_glslp.c index 49b48d7ec..fc1d296e5 100644 --- a/src/win/win_opengl_glslp.c +++ b/src/win/win_opengl_glslp.c @@ -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);