Add some documentation to win_opengl.c
This commit is contained in:
@@ -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);
|
||||||
|
Reference in New Issue
Block a user