102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
util.c
Go to the documentation of this file.
1#include "graphics_private.h"
2
3#include <dttr_config.h>
4#include <dttr_log.h>
5#include <math.h>
6#include <string.h>
7
9
10#define DTTR_MESH_SEAM_FILL_PHYSICAL_PX 0.5f
11#define DTTR_MESH_SEAM_MAX_VERTEX_NUDGE_PHYSICAL_PX 0.75f
12#define DTTR_MESH_SEAM_MIN_AREA_PX 1.0e-4f
13
15 if (!st || !state->device) {
16 return st && st->gpu_tex != NULL;
17 }
18
19 if (st->gpu_tex) {
20 return true;
21 }
22
23 const SDL_GPUTextureCreateInfo tex_info = {
24 .type = SDL_GPU_TEXTURETYPE_2D,
25 .format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM,
26 .usage = SDL_GPU_TEXTUREUSAGE_SAMPLER | SDL_GPU_TEXTUREUSAGE_COLOR_TARGET,
27 .width = st->width,
28 .height = st->height,
29 .layer_count_or_depth = 1,
30 .num_levels = dttr_graphics_calc_mip_levels(st->width, st->height),
31 };
32
33 st->gpu_tex = SDL_CreateGPUTexture(state->device, &tex_info);
34
35 if (!st->gpu_tex) {
37 "Failed to create GPU texture %dx%d: %s",
38 st->width,
39 st->height,
40 SDL_GetError()
41 );
42 return false;
43 }
44
45 return true;
46}
47
49 int dst_w,
50 int dst_h,
51 int src_w,
52 int src_h,
53 bool stretch,
54 bool integer_fit,
55 float fallback_scale
56) {
58 .x = 0,
59 .y = 0,
60 .w = dst_w,
61 .h = dst_h,
62 };
63
64 if (stretch || src_w <= 0 || src_h <= 0) {
65 return rect;
66 }
67
68 const float sx = (float)dst_w / (float)src_w;
69 const float sy = (float)dst_h / (float)src_h;
70 float scale = sx < sy ? sx : sy;
71
72 if (scale < 0.001f) {
73 scale = fallback_scale;
74 }
75
76 if (integer_fit && scale >= 1.0f) {
77 scale = floorf(scale);
78 }
79
80 rect.w = (int)((float)src_w * scale);
81 rect.h = (int)((float)src_h * scale);
82
83 if (rect.w < 1) {
84 rect.w = 1;
85 }
86
87 if (rect.h < 1) {
88 rect.h = 1;
89 }
90
91 if (rect.w > dst_w) {
92 rect.w = dst_w;
93 }
94
95 if (rect.h > dst_h) {
96 rect.h = dst_h;
97 }
98
99 rect.x = (dst_w - rect.w) / 2;
100 rect.y = (dst_h - rect.h) / 2;
101 return rect;
102}
103
105 int d = w > h ? w : h;
106 int levels = 1;
107
108 while (d > 1) {
109 d >>= 1;
110 levels++;
111 }
112
113 return levels;
114}
115
117 memset(m, 0, DTTR_MAT4_SIZE);
118 m[0] = m[5] = m[10] = m[15] = 1.0f;
119}
120
121const char *dttr_graphics_shader_format_name(SDL_GPUShaderFormat format) {
122 switch (format) {
123 case SDL_GPU_SHADERFORMAT_SPIRV:
124 return "SPIRV";
125 case SDL_GPU_SHADERFORMAT_DXIL:
126 return "DXIL";
127 case SDL_GPU_SHADERFORMAT_METALLIB:
128 return "METALLIB";
129 case SDL_GPU_SHADERFORMAT_PRIVATE:
130 return "PRIVATE";
131 default:
132 return "UNKNOWN";
133 }
134}
135
137 return SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL;
138}
139
140SDL_GPUShaderFormat dttr_graphics_select_shader_format(SDL_GPUShaderFormat formats) {
141 if (formats & SDL_GPU_SHADERFORMAT_DXIL) {
142 return SDL_GPU_SHADERFORMAT_DXIL;
143 }
144
145 if (formats & SDL_GPU_SHADERFORMAT_SPIRV) {
146 return SDL_GPU_SHADERFORMAT_SPIRV;
147 }
148
149 return SDL_GPU_SHADERFORMAT_INVALID;
150}
151
152SDL_GPUShaderFormat dttr_graphics_shader_format_for_driver(const char *driver) {
153 if (!driver || !driver[0]) {
154 return SDL_GPU_SHADERFORMAT_INVALID;
155 }
156
157 if (strcmp(driver, DTTR_DRIVER_DIRECT3D12) == 0) {
158 return SDL_GPU_SHADERFORMAT_DXIL;
159 }
160
161 if (strcmp(driver, DTTR_DRIVER_VULKAN) == 0) {
162 return SDL_GPU_SHADERFORMAT_SPIRV;
163 }
164
165 return SDL_GPU_SHADERFORMAT_INVALID;
166}
167
168// Selects a driver-preferred shader format, then falls back to generic selection.
170 const char *driver,
171 SDL_GPUShaderFormat formats
172) {
173 const SDL_GPUShaderFormat preferred = dttr_graphics_shader_format_for_driver(driver);
174
175 if ((preferred != SDL_GPU_SHADERFORMAT_INVALID) && (formats & preferred)) {
176 return preferred;
177 }
178
180}
181
184
185 if (!state->initialized) {
186 return false;
187 }
188
189 if (state->gpu_thread_id == 0) {
190 return true;
191 }
192
193 return SDL_GetCurrentThreadID() == state->gpu_thread_id;
194}
195
196// Restricts seam fill to the rendering mode and draw states that expose solid mesh
197// cracks.
200 bool transformed,
201 bool depth_test,
202 bool blend_enabled
203) {
204 return dttr_config.scaling_method == DTTR_SCALING_METHOD_LOGICAL
205 && dttr_config.vertex_precision == DTTR_VERTEX_PRECISION_SUBPIXEL
206 && type == DTTR_PRIM_TRIANGLELIST && transformed && depth_test
207 && !blend_enabled;
208}
209
210// Expands one triangle in physical-pixel space while preserving all non-position attrs.
212 DTTR_Vertex *tri,
213 float logical_to_px_x,
214 float logical_to_px_y,
215 float px_to_logical_x,
216 float px_to_logical_y
217) {
218 float x[3];
219 float y[3];
220 float nx[3];
221 float ny[3];
222 float c[3];
223
224 for (int i = 0; i < 3; i++) {
225 x[i] = tri[i].x * logical_to_px_x;
226 y[i] = tri[i].y * logical_to_px_y;
227 }
228
229 const float area_px = (x[1] - x[0]) * (y[2] - y[0]) - (y[1] - y[0]) * (x[2] - x[0]);
230 if (!isfinite(area_px) || fabsf(area_px) <= DTTR_MESH_SEAM_MIN_AREA_PX) {
231 return;
232 }
233
234 const float winding = area_px > 0.0f ? 1.0f : -1.0f;
235 for (int i = 0; i < 3; i++) {
236 const int j = (i + 1) % 3;
237 const float dx = x[j] - x[i];
238 const float dy = y[j] - y[i];
239 const float len = sqrtf(dx * dx + dy * dy);
240
241 if (!isfinite(len) || len <= 1.0e-6f) {
242 return;
243 }
244
245 nx[i] = winding * dy / len;
246 ny[i] = -winding * dx / len;
247 c[i] = nx[i] * x[i] + ny[i] * y[i] + DTTR_MESH_SEAM_FILL_PHYSICAL_PX;
248 }
249
250 for (int i = 0; i < 3; i++) {
251 const int prev = (i + 2) % 3;
252 const float det = nx[prev] * ny[i] - ny[prev] * nx[i];
253
254 if (!isfinite(det) || fabsf(det) <= 1.0e-6f) {
255 continue;
256 }
257
258 const float expanded_x = (c[prev] * ny[i] - ny[prev] * c[i]) / det;
259 const float expanded_y = (nx[prev] * c[i] - c[prev] * nx[i]) / det;
260
261 if (isfinite(expanded_x) && isfinite(expanded_y)) {
262 float dx = expanded_x - x[i];
263 float dy = expanded_y - y[i];
264 const float dist2 = dx * dx + dy * dy;
265 const float max_dist = DTTR_MESH_SEAM_MAX_VERTEX_NUDGE_PHYSICAL_PX;
266
267 if (isfinite(dist2) && dist2 > max_dist * max_dist) {
268 const float scale = max_dist / sqrtf(dist2);
269 dx *= scale;
270 dy *= scale;
271 }
272
273 tri[i].x = (x[i] + dx) * px_to_logical_x;
274 tri[i].y = (y[i] + dy) * px_to_logical_y;
275 }
276 }
277}
278
279// Applies conservative overlap to a triangle list in-place.
281 DTTR_Vertex *verts,
282 uint32_t count,
283 int logical_width,
284 int logical_height,
285 int render_width,
286 int render_height
287) {
288 if (!verts || count < 3 || logical_width <= 0 || logical_height <= 0
289 || render_width <= 0 || render_height <= 0) {
290 return;
291 }
292
293 const float logical_to_px_x = (float)render_width / (float)logical_width;
294 const float logical_to_px_y = (float)render_height / (float)logical_height;
295 const float px_to_logical_x = (float)logical_width / (float)render_width;
296 const float px_to_logical_y = (float)logical_height / (float)render_height;
297
298 for (uint32_t i = 0; i + 2 < count; i += 3) {
300 &verts[i],
301 logical_to_px_x,
302 logical_to_px_y,
303 px_to_logical_x,
304 px_to_logical_y
305 );
306 }
307}
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
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD count
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void * d
const DTTR_BackendState * state
const DTTR_PrimitiveType type
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD void DWORD DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 void * c
DTTR_Graphics_COM_DirectDraw7 *self DWORD DWORD h
DTTR_Graphics_COM_DirectDraw7 *self DWORD w
DTTR_Graphics_COM_DirectDrawSurface7 DWORD x
void * rect
DTTR_Graphics_COM_DirectDrawSurface7 DWORD DWORD y
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
@ DTTR_VERTEX_PRECISION_SUBPIXEL
Definition dttr_config.h:45
#define DTTR_DRIVER_VULKAN
Definition dttr_config.h:31
@ DTTR_SCALING_METHOD_LOGICAL
Definition dttr_config.h:22
#define DTTR_DRIVER_DIRECT3D12
Definition dttr_config.h:32
DTTR_Config dttr_config
Definition defaults.c:53
#define DTTR_LOG_WARN(...)
Definition dttr_log.h:30
DTTR_BackendState dttr_backend
Definition util.c:8
DTTR_PrimitiveType
@ DTTR_PRIM_TRIANGLELIST
#define DTTR_MAT4_SIZE
Game-image placement within the present target, in target pixels.
void dttr_graphics_fill_mesh_seams(DTTR_Vertex *verts, uint32_t count, int logical_width, int logical_height, int render_width, int render_height)
Expands triangle-list vertices by a tiny physical-pixel amount to hide mesh cracks.
Definition util.c:280
void dttr_graphics_mat4_identity(float *m)
Definition util.c:116
SDL_GPUShaderFormat dttr_graphics_select_shader_format_for_driver(const char *driver, SDL_GPUShaderFormat formats)
Definition util.c:169
bool dttr_graphics_ensure_staged_texture(DTTR_BackendState *state, DTTR_StagedTexture *st)
Definition util.c:14
bool dttr_graphics_is_gpu_thread()
Definition util.c:182
SDL_GPUShaderFormat dttr_graphics_requested_shader_formats()
Definition util.c:136
bool dttr_graphics_should_fill_mesh_seams(DTTR_PrimitiveType type, bool transformed, bool depth_test, bool blend_enabled)
Returns true when a draw call should receive subpixel logical-scaling seam fill.
Definition util.c:198
SDL_GPUShaderFormat dttr_graphics_select_shader_format(SDL_GPUShaderFormat formats)
Definition util.c:140
#define DTTR_MESH_SEAM_FILL_PHYSICAL_PX
Definition util.c:10
SDL_GPUShaderFormat dttr_graphics_shader_format_for_driver(const char *driver)
Definition util.c:152
static void fill_mesh_seam_triangle(DTTR_Vertex *tri, float logical_to_px_x, float logical_to_px_y, float px_to_logical_x, float px_to_logical_y)
Definition util.c:211
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)
Definition util.c:48
const char * dttr_graphics_shader_format_name(SDL_GPUShaderFormat format)
Definition util.c:121
#define DTTR_MESH_SEAM_MAX_VERTEX_NUDGE_PHYSICAL_PX
Definition util.c:11
int dttr_graphics_calc_mip_levels(int w, int h)
Definition util.c:104
#define DTTR_MESH_SEAM_MIN_AREA_PX
Definition util.c:12