Merge pull request #1413 from ts-korhonen/opengl
Use persistent buffer for pixel transfer in OpenGL Core renderer
This commit is contained in:
@@ -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++
|
Language/Generator: C/C++
|
||||||
Specification: gl
|
Specification: gl
|
||||||
APIs: gl=3.3
|
APIs: gl=3.3
|
||||||
Profile: core
|
Profile: core
|
||||||
Extensions:
|
Extensions:
|
||||||
|
GL_ARB_buffer_storage,
|
||||||
|
GL_ARB_debug_output
|
||||||
Loader: True
|
Loader: True
|
||||||
Local files: False
|
Local files: False
|
||||||
Omit khrplatform: False
|
Omit khrplatform: False
|
||||||
Reproducible: False
|
Reproducible: False
|
||||||
|
|
||||||
Commandline:
|
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:
|
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;
|
GLAPI PFNGLSECONDARYCOLORP3UIVPROC glad_glSecondaryColorP3uiv;
|
||||||
#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
|
#define glSecondaryColorP3uiv glad_glSecondaryColorP3uiv
|
||||||
#endif
|
#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
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
@@ -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++
|
Language/Generator: C/C++
|
||||||
Specification: gl
|
Specification: gl
|
||||||
APIs: gl=3.3
|
APIs: gl=3.3
|
||||||
Profile: core
|
Profile: core
|
||||||
Extensions:
|
Extensions:
|
||||||
|
GL_ARB_buffer_storage,
|
||||||
|
GL_ARB_debug_output
|
||||||
Loader: True
|
Loader: True
|
||||||
Local files: False
|
Local files: False
|
||||||
Omit khrplatform: False
|
Omit khrplatform: False
|
||||||
Reproducible: False
|
Reproducible: False
|
||||||
|
|
||||||
Commandline:
|
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:
|
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>
|
#include <stdio.h>
|
||||||
@@ -641,6 +642,13 @@ PFNGLVERTEXP4UIPROC glad_glVertexP4ui = NULL;
|
|||||||
PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
|
PFNGLVERTEXP4UIVPROC glad_glVertexP4uiv = NULL;
|
||||||
PFNGLVIEWPORTPROC glad_glViewport = NULL;
|
PFNGLVIEWPORTPROC glad_glViewport = NULL;
|
||||||
PFNGLWAITSYNCPROC glad_glWaitSync = 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) {
|
static void load_GL_VERSION_1_0(GLADloadproc load) {
|
||||||
if(!GLAD_GL_VERSION_1_0) return;
|
if(!GLAD_GL_VERSION_1_0) return;
|
||||||
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
|
glad_glCullFace = (PFNGLCULLFACEPROC)load("glCullFace");
|
||||||
@@ -1054,9 +1062,21 @@ static void load_GL_VERSION_3_3(GLADloadproc load) {
|
|||||||
glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
|
glad_glSecondaryColorP3ui = (PFNGLSECONDARYCOLORP3UIPROC)load("glSecondaryColorP3ui");
|
||||||
glad_glSecondaryColorP3uiv = (PFNGLSECONDARYCOLORP3UIVPROC)load("glSecondaryColorP3uiv");
|
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) {
|
static int find_extensionsGL(void) {
|
||||||
if (!get_exts()) return 0;
|
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();
|
free_exts();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@@ -1135,6 +1155,8 @@ int gladLoadGLLoader(GLADloadproc load) {
|
|||||||
load_GL_VERSION_3_3(load);
|
load_GL_VERSION_3_3(load);
|
||||||
|
|
||||||
if (!find_extensionsGL()) return 0;
|
if (!find_extensionsGL()) return 0;
|
||||||
|
load_GL_ARB_buffer_storage(load);
|
||||||
|
load_GL_ARB_debug_output(load);
|
||||||
return GLVersion.major != 0 || GLVersion.minor != 0;
|
return GLVersion.major != 0 || GLVersion.minor != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -44,6 +44,14 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <string.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/86box.h>
|
||||||
#include <86box/plat.h>
|
#include <86box/plat.h>
|
||||||
#include <86box/video.h>
|
#include <86box/video.h>
|
||||||
@@ -53,6 +61,9 @@
|
|||||||
|
|
||||||
static const int INIT_WIDTH = 640;
|
static const int INIT_WIDTH = 640;
|
||||||
static const int INIT_HEIGHT = 400;
|
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.
|
* @brief A dedicated OpenGL thread.
|
||||||
@@ -90,18 +101,26 @@ static union
|
|||||||
HANDLE asArray[4];
|
HANDLE asArray[4];
|
||||||
} sync_objects = { 0 };
|
} sync_objects = { 0 };
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Signal from OpenGL thread that it's done with video buffer.
|
|
||||||
*/
|
|
||||||
static HANDLE blit_done = NULL;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Blit event parameters.
|
* @brief Blit event parameters.
|
||||||
*/
|
*/
|
||||||
static volatile struct
|
typedef struct
|
||||||
{
|
{
|
||||||
int x, y, y1, y2, w, h, resized;
|
int y1, y2, w, h;
|
||||||
} blit_info = { 0 };
|
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.
|
* @brief Resize event parameters.
|
||||||
@@ -132,6 +151,7 @@ typedef struct
|
|||||||
GLuint vertexArrayID;
|
GLuint vertexArrayID;
|
||||||
GLuint vertexBufferID;
|
GLuint vertexBufferID;
|
||||||
GLuint textureID;
|
GLuint textureID;
|
||||||
|
GLuint unpackBufferID;
|
||||||
GLuint shader_progID;
|
GLuint shader_progID;
|
||||||
|
|
||||||
/* Uniforms */
|
/* Uniforms */
|
||||||
@@ -308,7 +328,7 @@ static void apply_shaders(gl_identifiers* gl)
|
|||||||
* @brief Initialize OpenGL context
|
* @brief Initialize OpenGL context
|
||||||
* @return Identifiers
|
* @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 */
|
/* Vertex, texture 2d coordinates and color (white) making a quad as triangle strip */
|
||||||
static const GLfloat surface[] = {
|
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
|
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);
|
glBufferData(GL_ARRAY_BUFFER, sizeof(surface), surface, GL_STATIC_DRAW);
|
||||||
|
|
||||||
glGenTextures(1, &gl.textureID);
|
glGenTextures(1, &gl->textureID);
|
||||||
glBindTexture(GL_TEXTURE_2D, gl.textureID);
|
glBindTexture(GL_TEXTURE_2D, gl->textureID);
|
||||||
|
|
||||||
static const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f };
|
static const GLfloat border_color[] = { 0.f, 0.f, 0.f, 1.f };
|
||||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color);
|
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_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
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);
|
glClearColor(0.f, 0.f, 0.f, 1.f);
|
||||||
|
|
||||||
apply_shaders(&gl);
|
apply_shaders(gl);
|
||||||
|
|
||||||
return gl;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clean up OpenGL context
|
* @brief Clean up OpenGL context
|
||||||
* @param gl Identifiers from initialize
|
* @param gl Identifiers from initialize
|
||||||
*/
|
*/
|
||||||
static void finalize_glcontext(gl_identifiers gl)
|
static void finalize_glcontext(gl_identifiers* gl)
|
||||||
{
|
{
|
||||||
glDeleteProgram(gl.shader_progID);
|
glDeleteProgram(gl->shader_progID);
|
||||||
glDeleteTextures(1, &gl.textureID);
|
glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER);
|
||||||
glDeleteBuffers(1, &gl.vertexBufferID);
|
glDeleteBuffers(1, &gl->unpackBufferID);
|
||||||
glDeleteVertexArrays(1, &gl.vertexArrayID);
|
glDeleteTextures(1, &gl->textureID);
|
||||||
|
glDeleteBuffers(1, &gl->vertexBufferID);
|
||||||
|
glDeleteVertexArrays(1, &gl->vertexArrayID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Renders a frame and swaps the buffer
|
* @brief Renders a frame and swaps the buffer
|
||||||
* @param gl Identifiers from initialize
|
* @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;
|
static int frame_counter = 0;
|
||||||
|
|
||||||
@@ -372,13 +410,13 @@ static void render_and_swap(gl_identifiers gl)
|
|||||||
|
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
|
|
||||||
if (gl.frame_count != -1)
|
if (gl->frame_count != -1)
|
||||||
glUniform1i(gl.frame_count, frame_counter = (frame_counter + 1) & 1023);
|
glUniform1i(gl->frame_count, frame_counter = (frame_counter + 1) & 1023);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handle failure in OpenGL thread.
|
* @brief Handle failure in OpenGL thread.
|
||||||
* Acts like a renderer until closing.
|
* Keeps the thread sleeping until closing.
|
||||||
*/
|
*/
|
||||||
static void opengl_fail()
|
static void opengl_fail()
|
||||||
{
|
{
|
||||||
@@ -390,20 +428,21 @@ static void opengl_fail()
|
|||||||
|
|
||||||
/* TODO: Notify user. */
|
/* TODO: Notify user. */
|
||||||
|
|
||||||
HANDLE handles[] = { sync_objects.closing, sync_objects.blit_waiting };
|
WaitForSingleObject(sync_objects.closing, INFINITE);
|
||||||
|
|
||||||
while (1)
|
_endthread();
|
||||||
{
|
|
||||||
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.
|
* @brief Main OpenGL thread proc.
|
||||||
*
|
*
|
||||||
@@ -412,8 +451,16 @@ static void opengl_fail()
|
|||||||
*/
|
*/
|
||||||
static void opengl_main(void* param)
|
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_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);
|
window = SDL_CreateWindow("86Box OpenGL Renderer", 0, 0, resize_info.width, resize_info.height, SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS);
|
||||||
|
|
||||||
if (window == NULL)
|
if (window == NULL)
|
||||||
@@ -444,13 +491,29 @@ static void opengl_main(void* param)
|
|||||||
|
|
||||||
SDL_GL_SetSwapInterval(options.vsync);
|
SDL_GL_SetSwapInterval(options.vsync);
|
||||||
|
|
||||||
if (!gladLoadGLLoader(SDL_GL_GetProcAddress))
|
if (!gladLoadGLLoader(SDL_GL_GetProcAddress) || !GLAD_GL_ARB_buffer_storage)
|
||||||
{
|
{
|
||||||
SDL_GL_DeleteContext(context);
|
SDL_GL_DeleteContext(context);
|
||||||
opengl_fail();
|
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)
|
if (gl.frame_count != -1)
|
||||||
glUniform1i(gl.frame_count, 0);
|
glUniform1i(gl.frame_count, 0);
|
||||||
@@ -459,13 +522,15 @@ static void opengl_main(void* param)
|
|||||||
|
|
||||||
uint32_t last_swap = plat_get_micro_ticks() - frametime;
|
uint32_t last_swap = plat_get_micro_ticks() - frametime;
|
||||||
|
|
||||||
|
int read_pos = 0; /* Buffer index of next read operation. */
|
||||||
|
|
||||||
/* Render loop */
|
/* Render loop */
|
||||||
int closing = 0;
|
int closing = 0;
|
||||||
while (!closing)
|
while (!closing)
|
||||||
{
|
{
|
||||||
/* Rendering is done right after handling an event. */
|
/* Rendering is done right after handling an event. */
|
||||||
if (frametime < 0)
|
if (frametime < 0)
|
||||||
render_and_swap(gl);
|
render_and_swap(&gl);
|
||||||
|
|
||||||
DWORD wait_result = WAIT_TIMEOUT;
|
DWORD wait_result = WAIT_TIMEOUT;
|
||||||
|
|
||||||
@@ -488,11 +553,22 @@ static void opengl_main(void* param)
|
|||||||
elapsed = ticks - last_swap;
|
elapsed = ticks - last_swap;
|
||||||
}
|
}
|
||||||
|
|
||||||
render_and_swap(gl);
|
render_and_swap(&gl);
|
||||||
last_swap = ticks;
|
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 */
|
/* Handle window messages */
|
||||||
MSG msg;
|
MSG msg;
|
||||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
|
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)
|
else if (sync_event == sync_objects.blit_waiting)
|
||||||
{
|
{
|
||||||
/* Resize the texture */
|
blit_info_t* info = &blit_info[read_pos];
|
||||||
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);
|
|
||||||
|
|
||||||
video_width = blit_info.w;
|
if (video_width != info->w || video_height != info->h)
|
||||||
video_height = blit_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)
|
if (fullscreen)
|
||||||
SetEvent(sync_objects.resize);
|
SetEvent(sync_objects.resize);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Transfer video buffer to texture */
|
/* Update texture from pixel buffer. */
|
||||||
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]);
|
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 */
|
/* Add fence to track when above gl commands are complete. */
|
||||||
SetEvent(blit_done);
|
info->sync = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||||
|
|
||||||
|
read_pos = (read_pos + 1) % BUFFERCOUNT;
|
||||||
|
|
||||||
/* Update uniforms */
|
/* Update uniforms */
|
||||||
if (gl.input_size != -1)
|
if (gl.input_size != -1)
|
||||||
@@ -656,7 +739,13 @@ static void opengl_main(void* param)
|
|||||||
SDL_ShowCursor(show_cursor);
|
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);
|
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)
|
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();
|
video_blit_complete();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
blit_info.resized = (w != blit_info.w || h != blit_info.h);
|
memcpy(blit_info[write_pos].buffer, &(render_buffer->dat)[y1 * w], w * (y2 - y1) * 4);
|
||||||
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);
|
|
||||||
|
|
||||||
video_blit_complete();
|
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)
|
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++)
|
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
|
||||||
sync_objects.asArray[i] = CreateEvent(NULL, FALSE, FALSE, NULL);
|
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;
|
parent = hwnd;
|
||||||
|
|
||||||
@@ -723,6 +817,15 @@ int opengl_init(HWND hwnd)
|
|||||||
strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader);
|
strcpy_s(options.shaderfile, sizeof(options.shaderfile), video_shader);
|
||||||
options.mutex = thread_create_mutex();
|
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);
|
thread = thread_create(opengl_main, (void*)NULL);
|
||||||
|
|
||||||
atexit(opengl_close);
|
atexit(opengl_close);
|
||||||
@@ -746,16 +849,12 @@ void opengl_close(void)
|
|||||||
|
|
||||||
thread_wait(thread, -1);
|
thread_wait(thread, -1);
|
||||||
|
|
||||||
memset((void*)&blit_info, 0, sizeof(blit_info));
|
|
||||||
|
|
||||||
thread_close_mutex(resize_info.mutex);
|
thread_close_mutex(resize_info.mutex);
|
||||||
thread_close_mutex(options.mutex);
|
thread_close_mutex(options.mutex);
|
||||||
|
|
||||||
SetEvent(blit_done);
|
|
||||||
|
|
||||||
thread = NULL;
|
thread = NULL;
|
||||||
|
|
||||||
CloseHandle(blit_done);
|
free(blit_info);
|
||||||
|
|
||||||
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
|
for (int i = 0; i < sizeof(sync_objects) / sizeof(HANDLE); i++)
|
||||||
{
|
{
|
||||||
|
@@ -58,8 +58,9 @@ void main(){\n\
|
|||||||
static const GLchar* fragment_shader = "#version 330 core\n\
|
static const GLchar* fragment_shader = "#version 330 core\n\
|
||||||
in vec2 tex;\n\
|
in vec2 tex;\n\
|
||||||
uniform sampler2D texsampler;\n\
|
uniform sampler2D texsampler;\n\
|
||||||
|
out vec4 color;\n\
|
||||||
void main() {\n\
|
void main() {\n\
|
||||||
gl_FragColor = texture(texsampler, tex);\n\
|
color = texture(texsampler, tex);\n\
|
||||||
}\n";
|
}\n";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,65 +98,66 @@ static char* read_file_to_string(const char* path)
|
|||||||
return NULL;
|
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.
|
* @brief Compile custom shaders into a program.
|
||||||
* @return Shader program identifier.
|
* @return Shader program identifier.
|
||||||
*/
|
*/
|
||||||
GLuint load_custom_shaders(const char* path)
|
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);
|
char* shader = read_file_to_string(path);
|
||||||
|
|
||||||
if (shader != NULL)
|
if (shader != NULL)
|
||||||
{
|
{
|
||||||
int success = 1;
|
int success = 1;
|
||||||
|
|
||||||
const char* vertex_sources[2] = { "#define VERTEX\n", shader };
|
const char* vertex_sources[2] = { "#version 330 core\n#define VERTEX\n", shader };
|
||||||
const char* fragment_sources[2] = { "#define FRAGMENT\n", shader };
|
const char* fragment_sources[2] = { "#version 330 core\n#define FRAGMENT\n", shader };
|
||||||
|
|
||||||
GLuint vertex_id = glCreateShader(GL_VERTEX_SHADER);
|
GLuint vertex_id = glCreateShader(GL_VERTEX_SHADER);
|
||||||
GLuint fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
|
GLuint fragment_id = glCreateShader(GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
glShaderSource(vertex_id, 2, vertex_sources, NULL);
|
glShaderSource(vertex_id, 2, vertex_sources, NULL);
|
||||||
glCompileShader(vertex_id);
|
glCompileShader(vertex_id);
|
||||||
glGetShaderiv(vertex_id, GL_COMPILE_STATUS, &status);
|
success *= check_status(vertex_id, 1);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
glShaderSource(fragment_id, 2, fragment_sources, NULL);
|
glShaderSource(fragment_id, 2, fragment_sources, NULL);
|
||||||
glCompileShader(fragment_id);
|
glCompileShader(fragment_id);
|
||||||
glGetShaderiv(fragment_id, GL_COMPILE_STATUS, &status);
|
success *= check_status(fragment_id, 1);
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
free(shader);
|
free(shader);
|
||||||
|
|
||||||
@@ -168,20 +170,7 @@ GLuint load_custom_shaders(const char* path)
|
|||||||
glAttachShader(prog_id, vertex_id);
|
glAttachShader(prog_id, vertex_id);
|
||||||
glAttachShader(prog_id, fragment_id);
|
glAttachShader(prog_id, fragment_id);
|
||||||
glLinkProgram(prog_id);
|
glLinkProgram(prog_id);
|
||||||
glGetProgramiv(prog_id, GL_LINK_STATUS, &status);
|
check_status(prog_id, 0);
|
||||||
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
glDetachShader(prog_id, vertex_id);
|
glDetachShader(prog_id, vertex_id);
|
||||||
glDetachShader(prog_id, fragment_id);
|
glDetachShader(prog_id, fragment_id);
|
||||||
|
Reference in New Issue
Block a user