11#define DRIVER_DISPLAY_OPENGL "OpenGL 3.3"
13#ifdef DTTR_MODS_ENABLED
24#include "gen/opengl_shaders.h"
27 GLuint shader = glCreateShader(
type);
29 glCompileShader(shader);
32 glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
36 glGetShaderInfoLog(shader,
sizeof(info),
NULL, info);
38 "GL shader compile failed (%s): %s",
39 type == GL_VERTEX_SHADER ?
"vert" :
"frag",
42 glDeleteShader(shader);
50 GLuint vert =
compile_shader(GL_VERTEX_SHADER, OPENGL_BASIC_VERT_SOURCE);
56 GLuint frag =
compile_shader(GL_FRAGMENT_SHADER, OPENGL_BASIC_FRAG_SOURCE);
63 GLuint program = glCreateProgram();
64 glAttachShader(program, vert);
65 glAttachShader(program, frag);
66 glLinkProgram(program);
72 glGetProgramiv(program, GL_LINK_STATUS, &status);
76 glGetProgramInfoLog(program,
sizeof(info),
NULL, info);
78 glDeleteProgram(program);
86 glGenFramebuffers(1, &gl->
fbo);
87 glBindFramebuffer(GL_FRAMEBUFFER, gl->
fbo);
102 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
103 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
104 glFramebufferTexture2D(
106 GL_COLOR_ATTACHMENT0,
114 glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, width, height);
115 glFramebufferRenderbuffer(
122 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
123 glBindFramebuffer(GL_FRAMEBUFFER, 0);
125 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
137 glDeleteFramebuffers(1, &gl->
fbo);
155 const GLint min_filter =
dttr_config.generate_texture_mipmaps
156 ? GL_LINEAR_MIPMAP_LINEAR
159 for (
int cu = 0; cu < 2; cu++) {
160 for (
int cv = 0; cv < 2; cv++) {
162 GLint wrap_s = cu ? GL_CLAMP_TO_EDGE : GL_REPEAT;
163 GLint wrap_t = cv ? GL_CLAMP_TO_EDGE : GL_REPEAT;
164 glSamplerParameteri(s, GL_TEXTURE_WRAP_S, wrap_s);
165 glSamplerParameteri(s, GL_TEXTURE_WRAP_T, wrap_t);
166 glSamplerParameteri(s, GL_TEXTURE_MIN_FILTER, min_filter);
167 glSamplerParameteri(s, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
175 if (requested <= 1) {
179 GLint max_samples = 0;
180 glGetIntegerv(GL_MAX_SAMPLES, &max_samples);
182 if (max_samples <= 1) {
186 if (requested > max_samples) {
187 requested = max_samples;
194 glGenFramebuffers(1, &gl->
msaa_fbo);
195 glBindFramebuffer(GL_FRAMEBUFFER, gl->
msaa_fbo);
199 glRenderbufferStorageMultisample(GL_RENDERBUFFER,
samples, GL_RGBA8,
w,
h);
200 glFramebufferRenderbuffer(
202 GL_COLOR_ATTACHMENT0,
209 glRenderbufferStorageMultisample(GL_RENDERBUFFER,
samples, GL_DEPTH_COMPONENT24,
w,
h);
210 glFramebufferRenderbuffer(
217 GLenum fb_status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
218 glBindFramebuffer(GL_FRAMEBUFFER, 0);
220 if (fb_status != GL_FRAMEBUFFER_COMPLETE) {
221 DTTR_LOG_ERROR(
"GL MSAA framebuffer incomplete: 0x%x", fb_status);
231 glDeleteFramebuffers(1, &gl->
msaa_fbo);
252 if (!
state->texture_mutex) {
256 SDL_LockMutex(
state->texture_mutex);
266 SDL_UnlockMutex(
state->texture_mutex);
289 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
290 SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3);
291 SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
292 SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
293 SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
304 DTTR_LOG_ERROR(
"SDL_GL_CreateContext failed: %s", SDL_GetError());
316 SDL_GL_SetSwapInterval(0);
318 if (!gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress)) {
346 glGenVertexArrays(1, &gl->
vao);
347 glBindVertexArray(gl->
vao);
348 glGenBuffers(1, &gl->
vbo);
349 glBindBuffer(GL_ARRAY_BUFFER, gl->
vbo);
359 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE,
stride, (
void *)0);
360 glEnableVertexAttribArray(0);
361 glVertexAttribPointer(1, 1, GL_FLOAT, GL_FALSE,
stride, (
void *)(3 *
sizeof(
float)));
362 glEnableVertexAttribArray(1);
363 glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE,
stride, (
void *)(4 *
sizeof(
float)));
364 glEnableVertexAttribArray(2);
365 glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE,
stride, (
void *)(8 *
sizeof(
float)));
366 glEnableVertexAttribArray(3);
370 glDeleteVertexArrays(1, &gl->
vao);
371 glDeleteBuffers(1, &gl->
vbo);
384 DTTR_LOG_WARN(
"OpenGL MSAA %dx failed, falling back to no MSAA", msaa);
392 const uint32_t white = 0xFFFFFFFF;
393 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, &white);
399 DTTR_LOG_ERROR(
"Failed to allocate OpenGL vertex staging buffer");
405 state->backend_data = gl;
410 "OpenGL 3.3 backend initialized (vendor: %s, renderer: %s)",
411 glGetString(GL_VENDOR),
412 glGetString(GL_RENDERER)
432 DTTR_LOG_ERROR(
"Failed to recreate OpenGL FBO at %dx%d", width, height);
445 state->width = width;
446 state->height = height;
453 if (!
state->texture_mutex) {
457 SDL_LockMutex(
state->texture_mutex);
458 const size_t queued_count = kv_size(
state->pending_upload_indices);
462 for (
size_t q = 0; q < queued_count; q++) {
463 const int idx = kv_A(
state->pending_upload_indices, q);
465 if (idx < 0 || idx >=
state->staged_texture_count) {
472 st->pending_upload =
false;
476 st->pending_upload =
false;
478 bool new_texture =
false;
485 glBindTexture(GL_TEXTURE_2D, gl->
gl_textures[idx]);
488 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
489 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
512 state->pending_upload_indices.n = 0;
513 SDL_UnlockMutex(
state->texture_mutex);
517 glGenerateMipmap(GL_TEXTURE_2D);
525 const uint8_t *pixels,
548 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
549 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
557 if (!gl ||
state->frame_active) {
561 state->frame_index++;
566 state->batch_records.n = 0;
567 state->vertex_offset = 0;
569 state->frame_active =
true;
575 glBindFramebuffer(GL_FRAMEBUFFER, render_fbo);
579 glBindVertexArray(gl->
vao);
581 int last_blend_mode = -1;
582 bool last_depth_test =
false;
583 bool last_depth_write =
false;
584 GLuint last_texture = 0;
585 int last_sampler_index = -1;
587 for (
size_t i = 0; i < kv_size(
state->batch_records); i++) {
591 GLbitfield clear_mask = 0;
600 clear_mask |= GL_COLOR_BUFFER_BIT;
605 glDepthMask(GL_TRUE);
606 clear_mask |= GL_DEPTH_BUFFER_BIT;
607 last_depth_write =
true;
614 last_blend_mode = -1;
615 last_depth_test =
false;
617 last_sampler_index = -1;
626 glBlendEquation(GL_FUNC_ADD);
629 glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE);
633 GL_ONE_MINUS_SRC_ALPHA,
635 GL_ONE_MINUS_SRC_ALPHA
645 glEnable(GL_DEPTH_TEST);
646 glDepthFunc(GL_LEQUAL);
648 glDisable(GL_DEPTH_TEST);
685 if (tex_id != last_texture) {
686 glActiveTexture(GL_TEXTURE0);
687 glBindTexture(GL_TEXTURE_2D, tex_id);
689 last_texture = tex_id;
708 if (!gl || !
state->frame_active) {
712 state->frame_active =
false;
716 if (
state->vertex_offset > 0) {
717 glBindBuffer(GL_ARRAY_BUFFER, gl->
vbo);
726 if (kv_size(
state->batch_records) > 0) {
730#ifdef DTTR_MODS_ENABLED
736 glBindFramebuffer(GL_READ_FRAMEBUFFER, gl->
msaa_fbo);
737 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gl->
fbo);
752 int window_w = 0, window_h = 0;
753 SDL_GetWindowSizeInPixels(
state->window, &window_w, &window_h);
756 window_w =
state->width;
760 window_h =
state->height;
775 glBindFramebuffer(GL_READ_FRAMEBUFFER, gl->
fbo);
776 glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
778 glViewport(0, 0, window_w, window_h);
779 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
780 glClear(GL_COLOR_BUFFER_BIT);
782 const GLenum blit_filter = (
dttr_config.present_filter == SDL_GPU_FILTER_NEAREST)
792 present.
x + present.
w,
793 present.
y + present.
h,
798#ifdef DTTR_MODS_ENABLED
799 glBindFramebuffer(GL_FRAMEBUFFER, 0);
809 SDL_GL_SwapWindow(
state->window);
816 const uint8_t *pixels,
823 if (!gl || !pixels || width <= 0 || height <= 0) {
827 if (
state->frame_active) {
837 int window_w = 0, window_h = 0;
838 SDL_GetWindowSizeInPixels(
state->window, &window_w, &window_h);
840 if (window_w <= 0 || window_h <= 0) {
844 glBindFramebuffer(GL_FRAMEBUFFER, 0);
845 glViewport(0, 0, window_w, window_h);
846 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
847 glClear(GL_COLOR_BUFFER_BIT);
849 glDisable(GL_DEPTH_TEST);
853 glBindVertexArray(gl->
vao);
864 const float x0 = (
float)present.
x;
865 const float y0 = (
float)present.
y;
866 const float x1 = (
float)(present.
x + present.
w);
867 const float y1 = (
float)(present.
y + present.
h);
869 float neutral_mvp[16];
871 glUniformMatrix4fv(gl->
loc_mvp, 1, GL_FALSE, neutral_mvp);
882 glActiveTexture(GL_TEXTURE0);
888 {x0, y0, 0, 1, 1, 1, 1, 1, 0, 0},
889 {x1, y0, 0, 1, 1, 1, 1, 1, 1, 0},
890 {x0, y1, 0, 1, 1, 1, 1, 1, 0, 1},
891 {x0, y1, 0, 1, 1, 1, 1, 1, 0, 1},
892 {x1, y0, 0, 1, 1, 1, 1, 1, 1, 0},
893 {x1, y1, 0, 1, 1, 1, 1, 1, 1, 1},
896 glBindBuffer(GL_ARRAY_BUFFER, gl->
vbo);
897 glBufferSubData(GL_ARRAY_BUFFER, 0,
sizeof(verts), verts);
898 glDrawArrays(GL_TRIANGLES, 0, 6);
900 SDL_GL_SwapWindow(
state->window);
916 glDeleteVertexArrays(1, &gl->
vao);
920 glDeleteBuffers(1, &gl->
vbo);
static void replay_batch_records_gl(DTTR_BackendState *state, opengl_backend_data *gl)
static void upload_pending_textures_gl(DTTR_BackendState *state, opengl_backend_data *gl)
static void defer_texture_destroy(DTTR_BackendState *state, int texture_index)
static void upload_video_texture(opengl_backend_data *gl, const uint8_t *pixels, int width, int height)
bool dttr_graphics_opengl_init(DTTR_BackendState *state)
static GLuint create_program()
static void begin_frame(DTTR_BackendState *state)
static GLuint compile_shader(GLenum type, const char *source)
static bool create_msaa_fbo(opengl_backend_data *gl, int w, int h, int samples)
static int select_gl_msaa_samples()
static const char * get_driver_name(const DTTR_BackendState *state)
static void destroy_fbo(opengl_backend_data *gl)
static void create_samplers(opengl_backend_data *gl)
static void release_deferred_gl_destroys(DTTR_BackendState *state, opengl_backend_data *gl)
static void end_frame(DTTR_BackendState *state)
static bool resize_fbo(DTTR_BackendState *state, int width, int height)
static void cleanup(DTTR_BackendState *state)
static bool create_fbo(opengl_backend_data *gl, int width, int height)
static const DTTR_RendererVtbl renderer
#define DRIVER_DISPLAY_OPENGL
static void destroy_msaa_fbo(opengl_backend_data *gl)
static bool present_video_frame_bgra(DTTR_BackendState *state, const uint8_t *pixels, int width, int height, int stride)
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD idx float
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD void DWORD st
const DTTR_BackendState * state
const DTTR_PrimitiveType type
DTTR_Graphics_COM_DirectDraw7 *self DWORD DWORD h
DTTR_Graphics_COM_DirectDraw7 *self DWORD w
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
@ DTTR_SCALING_METHOD_LOGICAL
@ DTTR_SCALING_MODE_STRETCH
@ DTTR_SCALING_MODE_INTEGER
#define DTTR_LOG_WARN(...)
#define DTTR_LOG_INFO(...)
#define DTTR_LOG_ERROR(...)
static game_data_source source
void dttr_graphics_mod_present_rect_before(DTTR_BackendState *state, const DTTR_PresentRect *present)
void dttr_graphics_mod_present_rect_after(DTTR_BackendState *state, const DTTR_PresentRect *present, bool overlay_rendered)
#define DTTR_MAX_FRAME_VERTICES
void dttr_graphics_mat4_identity(float *m)
#define DTTR_SAMPLER_COUNT
#define DTTR_D3DTA_DIFFUSE
#define DTTR_D3DTOP_SELECTARG1
static void dttr_graphics_mod_before_game_frame(DTTR_BackendState *)
#define DTTR_BLEND_ADDITIVE
#define DTTR_D3DTA_TEXTURE
DTTR_PresentRect dttr_graphics_compute_present_rect(int dst_w, int dst_h, int src_w, int src_h, bool stretch, bool integer_fit, float fallback_scale)
#define DTTR_D3DTOP_MODULATE
static void dttr_graphics_mod_after_game_frame(DTTR_BackendState *)
static void dttr_graphics_mod_frame_begin(DTTR_BackendState *)
static void dttr_graphics_mod_frame_end(DTTR_BackendState *)
#define DTTR_MAX_STAGED_TEXTURES
void dttr_imgui_render_opengl(uint32_t game_x, uint32_t game_y, uint32_t game_w, uint32_t game_h)
void dttr_imgui_render_game_opengl()
static mss_sample samples[DTTR_MSS_DEFAULT_MIXER_CHANNELS]
A recorded clear or draw command replayed during frame submission.
struct DTTR_BatchRecord::@173304276063167267021134124022136033175102267147::@317066375077304207167347173122133172104242212006 clear
struct DTTR_BatchRecord::@173304276063167267021134124022136033175102267147::@107356260052026241174121242151011150024304321020 draw
DTTR_BatchRecordType type
Game-image placement within the present target, in target pixels.
Backend-specific operations dispatched through function pointers.
GLuint deferred_gl_destroys[DTTR_MAX_STAGED_TEXTURES]
GLuint pending_mipmap_textures[DTTR_MAX_STAGED_TEXTURES]
GLuint gl_samplers[DTTR_SAMPLER_COUNT]
int deferred_gl_destroy_count
GLuint gl_textures[DTTR_MAX_STAGED_TEXTURES]