Add some documentation to win_opengl.c

This commit is contained in:
ts-korhonen
2021-04-10 17:41:51 +03:00
parent f315145c7d
commit 39268e88ef

View File

@@ -11,6 +11,14 @@
* NOTE: This is very much still a work-in-progress. * NOTE: This is very much still a work-in-progress.
* Expect missing functionality, hangs and bugs. * Expect missing functionality, hangs and bugs.
* *
* TODO: Input events routing
* Full screen mode
* Loader for glsl files.
* libretro has a sizeable library that could
* be a good target for compatibility.
* (UI) options
* ...
*
* Authors: Teemu Korhonen * Authors: Teemu Korhonen
* *
* Copyright 2021 Teemu Korhonen * Copyright 2021 Teemu Korhonen
@@ -42,14 +50,35 @@
#include <86box/video.h> #include <86box/video.h>
#include <86box/win_opengl.h> #include <86box/win_opengl.h>
/**
* @brief A dedicated OpenGL thread.
* OpenGL context's don't handle multiple threads well.
*/
static thread_t* thread = NULL; static thread_t* thread = NULL;
/**
* @brief A window usable with an OpenGL context
*/
static SDL_Window* window = NULL; static SDL_Window* window = NULL;
/**
* @brief Window info to modify window style.
*/
static SDL_SysWMinfo wmi = {}; static SDL_SysWMinfo wmi = {};
/**
* @brief Parent window (hwndRender from win_ui)
*/
static HWND parent = NULL; static HWND parent = NULL;
/**
* @brief Keeps track of parent window size.
*/
static RECT last_rect = {}; static RECT last_rect = {};
/**
* @brief Events listened in OpenGL thread.
*/
static union static union
{ {
struct struct
@@ -61,13 +90,22 @@ static union
HANDLE asArray[3]; HANDLE asArray[3];
} sync_objects = {}; } sync_objects = {};
/**
* @brief Signal from OpenGL thread that it's done with video buffer.
*/
static HANDLE blit_done = NULL; static HANDLE blit_done = NULL;
/**
* @brief Blit event parameters.
*/
static volatile struct static volatile struct
{ {
int x, y, y1, y2, w, h, resized; int x, y, y1, y2, w, h, resized;
} blit_info = {}; } blit_info = {};
/**
* @brief Identifiers to OpenGL object used.
*/
typedef struct typedef struct
{ {
GLuint vertexArrayID; GLuint vertexArrayID;
@@ -76,6 +114,9 @@ typedef struct
GLuint shader_progID; GLuint shader_progID;
} gl_objects; } gl_objects;
/**
* @brief Default vertex shader.
*/
static const GLchar* v_shader = "#version 330 core\n\ static const GLchar* v_shader = "#version 330 core\n\
layout(location = 0) in vec2 pos;\n\ layout(location = 0) in vec2 pos;\n\
layout(location = 1) in vec2 tex_in;\n\ layout(location = 1) in vec2 tex_in;\n\
@@ -85,6 +126,11 @@ void main(){\n\
tex = tex_in;\n\ tex = tex_in;\n\
}\n"; }\n";
/**
* @brief Default fragment shader.
*
* Note: Last two lines in main make it a very simple 50% scanline filter.
*/
static const GLchar* f_shader = "#version 330 core\n\ static const GLchar* f_shader = "#version 330 core\n\
in vec2 tex;\n\ in vec2 tex;\n\
out vec4 color;\n\ out vec4 color;\n\
@@ -95,6 +141,10 @@ void main() {\n\
color = color * vec4(0.5,0.5,0.5,1.0);\n\ color = color * vec4(0.5,0.5,0.5,1.0);\n\
}\n"; }\n";
/**
* @brief Load and compile default shaders into a program.
* @return Shader program identifier.
*/
static GLuint LoadShaders() static GLuint LoadShaders()
{ {
GLuint vs_id = glCreateShader(GL_VERTEX_SHADER); GLuint vs_id = glCreateShader(GL_VERTEX_SHADER);
@@ -136,6 +186,11 @@ static GLuint LoadShaders()
return prog_id; return prog_id;
} }
/**
* @brief Set or unset OpenGL context window as a child window.
*
* Modifies the window style and sets the parent window.
*/
static void SetParentBinding(int enable) static void SetParentBinding(int enable)
{ {
if (wmi.subsystem != SDL_SYSWM_WINDOWS) if (wmi.subsystem != SDL_SYSWM_WINDOWS)
@@ -153,8 +208,13 @@ static void SetParentBinding(int enable)
SetParent(wmi.info.win.window, enable ? parent : NULL); SetParent(wmi.info.win.window, enable ? parent : NULL);
} }
/**
* @brief Initialize OpenGL context
* @return Object identifiers
*/
static gl_objects initialize_glcontext() static gl_objects initialize_glcontext()
{ {
/* Vertex and texture 2d coordinates making a quad as triangle strip */
static const GLfloat surface[] = { static const GLfloat surface[] = {
-1.f, 1.f, 0.f, 0.f, -1.f, 1.f, 0.f, 0.f,
1.f, 1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 0.f,
@@ -176,7 +236,7 @@ static gl_objects initialize_glcontext()
glBindTexture(GL_TEXTURE_2D, obj.textureID); glBindTexture(GL_TEXTURE_2D, obj.textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
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);
@@ -197,6 +257,10 @@ static gl_objects initialize_glcontext()
return obj; return obj;
} }
/**
* @brief Clean up OpenGL context *
* @param Object identifiers from initialize
*/
static void finalize_glcontext(gl_objects obj) static void finalize_glcontext(gl_objects obj)
{ {
glDeleteProgram(obj.shader_progID); glDeleteProgram(obj.shader_progID);
@@ -205,6 +269,12 @@ static void finalize_glcontext(gl_objects obj)
glDeleteVertexArrays(1, &obj.vertexArrayID); glDeleteVertexArrays(1, &obj.vertexArrayID);
} }
/**
* @brief Main OpenGL thread proc.
*
* OpenGL context should be accessed only from this single thread.
* Events are used to synchronize communication.
*/
static void opengl_main() static void opengl_main()
{ {
RECT rect; RECT rect;
@@ -238,18 +308,21 @@ static void opengl_main()
do do
{ {
/* SDL_Window event handlers */
SDL_Event event; SDL_Event event;
/* Handle SDL_Window events */
while (SDL_PollEvent(&event)) while (SDL_PollEvent(&event))
{ {
/* Main window should be active to receive input */
if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED) if (event.type == SDL_WINDOWEVENT && event.window.event == SDL_WINDOWEVENT_FOCUS_GAINED)
SetForegroundWindow(GetParent(parent)); SetForegroundWindow(GetParent(parent));
/* Start mouse capture on button down */
else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT) else if (event.type == SDL_MOUSEBUTTONUP && event.button.button == SDL_BUTTON_LEFT)
plat_mouse_capture(1); plat_mouse_capture(1);
} }
/* Wait for sync events */ /* Wait for synchronized events for 1ms before going back to window events */
wait_result = WaitForMultipleObjects(sizeof(sync_objects) / sizeof(HANDLE), sync_objects.asArray, FALSE, 1); wait_result = WaitForMultipleObjects(sizeof(sync_objects) / sizeof(HANDLE), sync_objects.asArray, FALSE, 1);
} while (wait_result == WAIT_TIMEOUT); } while (wait_result == WAIT_TIMEOUT);
@@ -262,15 +335,19 @@ static void opengl_main()
} }
else if (sync_event == sync_objects.blit_waiting) else if (sync_event == sync_objects.blit_waiting)
{ {
/* Resize the texture if */
if (blit_info.resized) 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); 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);
/* 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]); 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]);
/* Signal that we're done with the video buffer */
SetEvent(blit_done); SetEvent(blit_done);
} }
else if (sync_event == sync_objects.resize) else if (sync_event == sync_objects.resize)
{ {
/* Detach from parent while resizing */
SetParentBinding(0); SetParentBinding(0);
GetWindowRect(parent, &rect); GetWindowRect(parent, &rect);
@@ -369,6 +446,7 @@ void opengl_set_fs(int fs)
{ {
if (window != NULL) if (window != NULL)
{ {
/* Can't full screen as child window */
SetParentBinding(fs ? 0 : 1); SetParentBinding(fs ? 0 : 1);
SDL_SetWindowFullscreen(window, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0); SDL_SetWindowFullscreen(window, fs ? SDL_WINDOW_FULLSCREEN_DESKTOP : 0);
@@ -383,6 +461,8 @@ void opengl_enable(int enable)
RECT rect; RECT rect;
GetWindowRect(parent, &rect); GetWindowRect(parent, &rect);
/* Resizing window is a common cause for enable */
/* TODO: route the resizing event explicitly form win_ui. */
if (!EqualRect(&rect, &last_rect)) if (!EqualRect(&rect, &last_rect))
{ {
CopyRect(&last_rect, &rect); CopyRect(&last_rect, &rect);