102 Patches: Detours to the Rescue
C reference for DttR maintainers and modders.
Loading...
Searching...
No Matches
com_direct3ddevice7.c
Go to the documentation of this file.
1// Translates IDirect3DDevice7 calls to the SDL3 GPU backend
2// https://archive.org/details/dx7sdk-7001
3
5#include "graphics_private.h"
6#include <dttr_config.h>
7#include <dttr_log.h>
8#include <math.h>
9#include <stdlib.h>
10#include <string.h>
11
12#define MAX_VERTICES 4096
13#define DTTR_MAT4_ELEMS 16
14#define DTTR_MAT4_BYTES (sizeof(float) * DTTR_MAT4_ELEMS)
16
19 float *restrict out,
20 const float *restrict a,
21 const float *restrict b
22) {
23 float tmp[DTTR_MAT4_ELEMS];
24 for (int i = 0; i < 4; i++) {
25 for (int j = 0; j < 4; j++) {
26 tmp[i * 4 + j] = 0;
27 for (int k = 0; k < 4; k++) {
28 tmp[i * 4 + j] += a[i * 4 + k] * b[k * 4 + j];
29 }
30 }
31 }
32
33 memcpy(out, tmp, sizeof(tmp));
34}
35
37static bool d3d_device7_get_transform_state(DWORD type, float **out_matrix_f) {
39 switch (type) {
40 case D3DTRANSFORMSTATE_WORLD:
41 *out_matrix_f = state->model;
42 return true;
43 case D3DTRANSFORMSTATE_VIEW:
44 *out_matrix_f = state->view;
45 return true;
46 case D3DTRANSFORMSTATE_PROJECTION:
47 *out_matrix_f = state->proj;
48 return true;
49 default:
50 *out_matrix_f = NULL;
51 return false;
52 }
53}
54
56 switch (type) {
57 case D3DTRANSFORMSTATE_WORLD:
58 return "WORLD";
59
60 case D3DTRANSFORMSTATE_VIEW:
61 return "VIEW";
62
63 case D3DTRANSFORMSTATE_PROJECTION:
64 return "PROJECTION";
65
66 default:
67 return "UNKNOWN";
68 }
69}
70
71static void d3d_device7_set_transform_state(DWORD type, const float *m) {
72 float *matrix_f = NULL;
73
74 if (!m) {
75 return;
76 }
77
78 if (!d3d_device7_get_transform_state(type, &matrix_f)) {
79 return;
80 }
81
82 for (int i = 0; i < DTTR_MAT4_ELEMS; i++) {
83 if (!isfinite(m[i])) {
85 "SetTransform(%s) rejected non-finite matrix input",
87 );
88 return;
89 }
90 }
91
92 memcpy(matrix_f, m, DTTR_MAT4_BYTES);
93}
94
97 const DTTR_Vertex *restrict in,
98 uint32_t count,
99 DTTR_Vertex *restrict out
100) {
101 if (count < 3) {
102 return 0;
103 }
104
105 uint32_t n = 0;
106 for (uint32_t i = 0; i < count - 2; i++) {
107 if (i & 1) {
108 out[n++] = in[i + 1];
109 out[n++] = in[i];
110 out[n++] = in[i + 2];
111 } else {
112 out[n++] = in[i];
113 out[n++] = in[i + 1];
114 out[n++] = in[i + 2];
115 }
116 }
117
118 return n;
119}
120
123 const DTTR_Vertex *restrict in,
124 uint32_t count,
125 DTTR_Vertex *restrict out
126) {
127 if (count < 3) {
128 return 0;
129 }
130
131 uint32_t n = 0;
132 for (uint32_t i = 0; i < count - 2; i++) {
133 out[n++] = in[0];
134 out[n++] = in[i + 1];
135 out[n++] = in[i + 2];
136 }
137
138 return n;
139}
140
160
163 uint32_t flags,
164 uint32_t color,
165 float depth,
166 uint32_t stencil
167) {
169 if (!state->frame_active && dttr_graphics_is_gpu_thread()) {
171 }
172
173 if (!state->frame_active) {
174 return;
175 }
176
177 DTTR_BatchRecord clear_rec = {0};
178 clear_rec.type = DTTR_BATCH_CLEAR;
179 clear_rec.clear.flags = flags;
180 clear_rec.clear.depth = depth;
181
182 if (flags & DTTR_CLEAR_COLOR) {
183 clear_rec.clear.color.r = ((color >> 16) & 0xff) / 255.0f;
184 clear_rec.clear.color.g = ((color >> 8) & 0xff) / 255.0f;
185 clear_rec.clear.color.b = (color & 0xff) / 255.0f;
186 clear_rec.clear.color.a = ((color >> 24) & 0xff) / 255.0f;
187 state->clear_color = clear_rec.clear.color;
188 } else {
189 clear_rec.clear.color = state->clear_color;
190 }
191
192 kv_push(DTTR_BatchRecord, state->batch_records, clear_rec);
193}
194
196 switch (type) {
200 default:
201 return type;
202 }
203}
204
207 uint32_t count
208) {
209 switch (type) {
212 return count < 3 ? 0 : (count - 2) * 3;
213 default:
214 return count;
215 }
216}
217
220 const DTTR_Vertex *verts,
221 uint32_t count,
222 DTTR_Vertex *out
223) {
224 switch (*type) {
226 d3d_device7_expand_strip(verts, count, out);
228 break;
230 d3d_device7_expand_fan(verts, count, out);
232 break;
233 default:
234 memcpy(out, verts, count * DTTR_VERTEX_SIZE);
235 break;
236 }
237}
238
242 const DTTR_Vertex *verts,
243 uint32_t count,
244 bool transformed,
245 bool textured
246) {
248
249 if (!dttr_graphics_is_gpu_thread() || !verts || count == 0) {
250 return;
251 }
252
253 if (state->backend_type == DTTR_BACKEND_SDL_GPU && !state->cmd) {
254 return;
255 }
256
257 if (!state->device && state->backend_type == DTTR_BACKEND_SDL_GPU) {
258 DTTR_LOG_WARN("DrawPrimitive: missing device/buffers");
259 return;
260 }
261
264
266 const uint32_t upload_count = d3d_device7_expanded_primitive_count(type, count);
267 if (upload_count == 0) {
268 return;
269 }
270
271 const bool fill_mesh_seams = dttr_graphics_should_fill_mesh_seams(
272 upload_type,
273 transformed,
274 state->depth_test,
275 state->blend_enabled
276 );
277
278 if (!state->transfer_mapped)
279 return;
280 if (state->vertex_offset + upload_count > DTTR_MAX_FRAME_VERTICES) {
282 "DrawPrimitive: frame vertex limit reached (%u + %u > %u)",
283 state->vertex_offset,
284 upload_count,
286 );
287 return;
288 }
289
290 DTTR_Vertex *upload_verts = (DTTR_Vertex *)((uint8_t *)state->transfer_mapped
291 + state->vertex_offset
293 d3d_device7_copy_or_expand_primitive(&type, verts, count, upload_verts);
294
295 if (fill_mesh_seams) {
297 upload_verts,
298 upload_count,
299 state->logical_width,
300 state->logical_height,
301 state->width,
302 state->height
303 );
304 }
305
306 DTTR_BatchRecord draw_rec = {0};
307 draw_rec.type = DTTR_BATCH_DRAW;
308 draw_rec.draw.first_vertex = state->vertex_offset;
309 draw_rec.draw.vertex_count = upload_count;
310 draw_rec.draw.blend_mode = DTTR_BLEND_OFF;
311 if (state->blend_enabled) {
312 draw_rec.draw.blend_mode = (state->blend_dst == DTTR_BLEND_ONE)
315 }
316
317 draw_rec.draw.depth_test = state->depth_test;
318 draw_rec.draw.depth_write = state->depth_write;
319
320 {
321 float mv[DTTR_MAT4_ELEMS];
322 d3d_device7_mat4_multiply_f(mv, state->view, state->model);
324 }
325
326 draw_rec.draw.uniforms.screen_size[0] = (float)state->logical_width;
327 draw_rec.draw.uniforms.screen_size[1] = (float)state->logical_height;
328 draw_rec.draw.uniforms.is_2d = transformed ? (dttr_config.sprite_smooth ? 2.0f : 1.0f)
329 : 0.0f;
330 draw_rec.draw.uniforms.has_texture = textured ? 1.0f : 0.0f;
331 draw_rec.draw.uniforms.color_op = (float)state->stage_color_op;
332 draw_rec.draw.uniforms.color_arg1 = (float)state->stage_color_arg1;
333 draw_rec.draw.uniforms.color_arg2 = (float)state->stage_color_arg2;
334 draw_rec.draw.uniforms.alpha_op = (float)state->stage_alpha_op;
335 draw_rec.draw.uniforms.alpha_arg1 = (float)state->stage_alpha_arg1;
336 draw_rec.draw.uniforms.alpha_arg2 = (float)state->stage_alpha_arg2;
337
338 draw_rec.draw.texture = (textured && state->bound_texture) ? state->bound_texture
339 : state->dummy_texture;
340 const int cu = (state->addr_u == DTTR_TEXADDR_CLAMP) ? 1 : 0;
341 const int cv = (state->addr_v == DTTR_TEXADDR_CLAMP) ? 1 : 0;
342 draw_rec.draw.sampler = state->samplers[cu * 2 + cv];
343 draw_rec.draw.sampler_index = cu * 2 + cv;
344 draw_rec.draw.texture_index = (textured && state->bound_texture_handle)
345 ? (uint32_t)(state->bound_texture_handle - 1)
346 : UINT32_MAX;
347
348 state->vertex_offset += upload_count;
349
350 // Merge into previous record if state matches and vertices are contiguous
351 size_t n = kv_size(state->batch_records);
352 if (n > 0) {
353 DTTR_BatchRecord *prev = &kv_A(state->batch_records, n - 1);
354 if (prev->type == DTTR_BATCH_DRAW
355 && prev->draw.first_vertex + prev->draw.vertex_count
356 == draw_rec.draw.first_vertex
357 && prev->draw.blend_mode == draw_rec.draw.blend_mode
358 && prev->draw.depth_test == draw_rec.draw.depth_test
359 && prev->draw.depth_write == draw_rec.draw.depth_write
360 && prev->draw.texture == draw_rec.draw.texture
361 && prev->draw.sampler == draw_rec.draw.sampler
362 && prev->draw.texture_index == draw_rec.draw.texture_index
363 && prev->draw.sampler_index == draw_rec.draw.sampler_index
364 && memcmp(&prev->draw.uniforms, &draw_rec.draw.uniforms, sizeof(DTTR_Uniforms))
365 == 0) {
366 prev->draw.vertex_count += draw_rec.draw.vertex_count;
367 return;
368 }
369 }
370
371 kv_push(DTTR_BatchRecord, state->batch_records, draw_rec);
372}
373
375 state->bound_texture_handle = DTTR_INVALID_TEXTURE;
376 state->bound_texture = NULL;
377}
378
382 if (!tex) {
383 if (state->bound_texture_handle == DTTR_INVALID_TEXTURE
384 && !state->bound_texture) {
385 return;
386 }
387
389 return;
390 }
391
392 if (state->bound_texture_handle == tex && state->bound_texture) {
393 return;
394 }
395
396 const int idx = (int)tex - 1;
397 if (idx < 0 || idx >= state->staged_texture_count) {
399 return;
400 }
401
402 if (!state->texture_mutex) {
404 return;
405 }
406
407 SDL_LockMutex(state->texture_mutex);
408 DTTR_StagedTexture *st = &state->staged_textures[idx];
411 }
412
413 state->bound_texture_handle = tex;
414 state->bound_texture = st->gpu_tex;
415 SDL_UnlockMutex(state->texture_mutex);
416}
417
423
426 dttr_backend.addr_u = addr;
427}
428
431 dttr_backend.addr_v = addr;
432}
433
435static void d3d_device7_set_viewport(int x, int y, int w, int h, float min_z, float max_z) {
437 if (w <= 0 || h <= 0)
438 return;
439
440 state->viewport_x = x;
441 state->viewport_y = y;
442 state->viewport_w = w;
443 state->viewport_h = h;
444 state->viewport_min_z = min_z;
445 state->viewport_max_z = max_z;
446}
447
448DTTR_COM_QI_SELF(d3ddevice7_queryinterface, DTTR_Graphics_COM_Direct3DDevice7)
449
451
453
455 d3ddevice7_getcaps,
457 void,
459)
460
461static HRESULT __stdcall d3ddevice7_enumtextureformats(
463 void *cb,
464 void *ctx
465) {
466
467 if (!cb) {
468 return S_OK;
469 }
470
471 const LPD3DENUMPIXELFORMATSCALLBACK callback = (LPD3DENUMPIXELFORMATSCALLBACK)cb;
472
473 // Report the ARGB4444 format required by the game.
474 DDPIXELFORMAT fmt_argb4444 = {
475 .dwSize = sizeof(DDPIXELFORMAT),
476 .dwFlags = DDPF_RGB | DDPF_ALPHAPIXELS,
477 .dwRGBBitCount = 16,
478 .dwRBitMask = 0x0F00,
479 .dwGBitMask = 0x00F0,
480 .dwBBitMask = 0x000F,
481 .dwRGBAlphaBitMask = 0xF000,
482 };
483
484 HRESULT hr = callback(&fmt_argb4444, ctx);
485
486 if (hr != 1) {
487 return S_OK;
488 }
489
490 // Report RGB565 as the fallback texture format.
491 DDPIXELFORMAT fmt_rgb565 = {
492 .dwSize = sizeof(DDPIXELFORMAT),
493 .dwFlags = DDPF_RGB,
494 .dwRGBBitCount = 16,
495 .dwRBitMask = 0xF800,
496 .dwGBitMask = 0x07E0,
497 .dwBBitMask = 0x001F,
498 .dwRGBAlphaBitMask = 0,
499 };
500
501 callback(&fmt_rgb565, ctx);
502
503 return S_OK;
504}
505
507
509
511 d3ddevice7_getdirect3d,
512 void *,
513 NULL,
515)
516
518 d3ddevice7_setrendertarget,
520 void *surface,
522)
523
525 d3ddevice7_getrendertarget,
526 void *,
527 NULL,
529)
530
531static HRESULT __stdcall d3ddevice7_clear(
534 void *rects,
537 float z,
539) {
540
541 uint32_t f = 0;
542 if (flags & D3DCLEAR_TARGET)
544 if (flags & D3DCLEAR_ZBUFFER)
546 if (flags & D3DCLEAR_STENCIL)
549 return S_OK;
550}
551
552static HRESULT __stdcall d3ddevice7_settransform(
554 DWORD type,
555 void *matrix
556) {
557 d3d_device7_set_transform_state(type, (const float *)matrix);
558 return S_OK;
559}
560
561static HRESULT __stdcall d3ddevice7_gettransform(
563 DWORD type,
564 void *matrix
565) {
566 if (!matrix)
567 return S_OK;
568
569 float *matrix_f = NULL;
570 if (!d3d_device7_get_transform_state(type, &matrix_f)) {
571 memset(matrix, 0, DTTR_MAT4_BYTES);
572 return S_OK;
573 }
574
575 memcpy(matrix, matrix_f, DTTR_MAT4_BYTES);
576 return S_OK;
577}
578
579static HRESULT __stdcall d3ddevice7_setviewport(
581 void *vp
582) {
583
584 if (!vp)
585 return S_OK;
586
587 const D3DVIEWPORT7 *v = (const D3DVIEWPORT7 *)vp;
589 (int)v->dwX,
590 (int)v->dwY,
591 (int)v->dwWidth,
592 (int)v->dwHeight,
593 v->dvMinZ,
594 v->dvMaxZ
595 );
596
597 return S_OK;
598}
599
600static HRESULT __stdcall d3ddevice7_multiplytransform(
602 DWORD type,
603 void *matrix
604) {
605 if (!matrix)
606 return S_OK;
607
608 float *matrix_f = NULL;
609 if (!d3d_device7_get_transform_state(type, &matrix_f))
610 return S_OK;
611
612 float result[DTTR_MAT4_ELEMS];
613 d3d_device7_mat4_multiply_f(result, matrix_f, (const float *)matrix);
614 memcpy(matrix_f, result, sizeof(result));
615 return S_OK;
616}
617
618static HRESULT __stdcall d3ddevice7_getviewport(
620 void *vp
621) {
622
623 if (!vp)
624 return S_OK;
625
626 D3DVIEWPORT7 *v = (D3DVIEWPORT7 *)vp;
628 v->dwX = (DWORD)state->viewport_x;
629 v->dwY = (DWORD)state->viewport_y;
630 v->dwWidth = (DWORD)state->viewport_w;
631 v->dwHeight = (DWORD)state->viewport_h;
632 v->dvMinZ = state->viewport_min_z;
633 v->dvMaxZ = state->viewport_max_z;
634 return S_OK;
635}
636
638 d3ddevice7_setmaterial,
640 void *mat
641)
642
644 d3ddevice7_getmaterial,
646 void,
648)
649
651 d3ddevice7_setlight,
653 DWORD idx,
654 void *light
655)
656
658 d3ddevice7_getlight,
660 void,
662 DWORD idx
663)
664
665static HRESULT __stdcall d3ddevice7_setrenderstate(
667 DWORD state,
668 DWORD value
669) {
670
671 switch (state) {
672 case D3DRENDERSTATE_ZENABLE:
673 dttr_backend.depth_test = value != 0;
674 break;
675 case D3DRENDERSTATE_ZWRITEENABLE:
676 dttr_backend.depth_write = value != 0;
677 break;
678 case D3DRENDERSTATE_ZFUNC:
679 break;
680 case D3DRENDERSTATE_ALPHABLENDENABLE:
681 dttr_backend.blend_enabled = value != 0;
682 break;
683 case D3DRENDERSTATE_SRCBLEND:
685 break;
686 case D3DRENDERSTATE_DESTBLEND:
688 break;
689 case D3DRENDERSTATE_CULLMODE:
690 break;
691 }
692
693 return S_OK;
694}
695
697 d3ddevice7_getrenderstate,
698 DWORD,
699 0,
702)
703
705
707 d3ddevice7_endstateblock,
709 1,
711)
712
714 d3ddevice7_preload,
716 void *tex
717)
718
719static HRESULT __stdcall d3ddevice7_drawprimitive(
723 void *vertices,
724 DWORD count,
726) {
727
728 if (!vertices || count == 0) {
729 return S_OK;
730 }
731
732 if (count > MAX_VERTICES) {
734 }
735
736 // Parse the flexible vertex format layout.
737 // https://learn.microsoft.com/en-us/windows/win32/direct3d9/d3dfvf
738 const DWORD pos_type = fvf & DTTR_D3DFVF_POSITION_MASK;
739 const bool has_rhw = (pos_type == DTTR_D3DFVF_XYZRHW);
740 const bool has_xyzw = (pos_type == DTTR_D3DFVF_XYZW);
741 const bool has_normal = (!has_rhw && !has_xyzw) && ((fvf & DTTR_D3DFVF_NORMAL) != 0);
742 const bool has_psize = (!has_rhw && !has_xyzw) && ((fvf & DTTR_D3DFVF_PSIZE) != 0);
743 const bool has_diffuse = (fvf & DTTR_D3DFVF_DIFFUSE) != 0;
744 const bool has_specular = (fvf & DTTR_D3DFVF_SPECULAR) != 0;
745 const int tex_count = (int)((fvf >> DTTR_D3DFVF_TEXCOUNT_SHIFT) & 0xF);
746 const bool has_tex = tex_count > 0;
747
748 const uint8_t *src = (const uint8_t *)vertices;
750 const float logical_w = (float)state->logical_width;
751 const float logical_h = (float)state->logical_height;
752 const float vp_x = (float)state->viewport_x;
753 const float vp_y = (float)state->viewport_y;
754 const float vp_w = (float)((state->viewport_w > 0) ? state->viewport_w : 1);
755 const float vp_h = (float)((state->viewport_h > 0) ? state->viewport_h : 1);
756 const float vp_min_z = state->viewport_min_z;
757 const float vp_max_z = state->viewport_max_z;
758 const float vp_z_span = vp_max_z - vp_min_z;
759
760 size_t pos_bytes = 3 * sizeof(float);
761 switch (pos_type) {
763 case DTTR_D3DFVF_XYZW:
765 pos_bytes = 4 * sizeof(float);
766 break;
768 pos_bytes = 5 * sizeof(float);
769 break;
771 pos_bytes = 6 * sizeof(float);
772 break;
774 pos_bytes = 7 * sizeof(float);
775 break;
777 pos_bytes = 8 * sizeof(float);
778 break;
779 default:
780 // D3DFVF_XYZ and unknown position types use the base XYZ width.
781 pos_bytes = 3 * sizeof(float);
782 break;
783 }
784
785 // LASTBETA flags replace the final beta float in blend-weight formats.
786 if ((pos_type >= DTTR_D3DFVF_XYZB1 && pos_type <= DTTR_D3DFVF_XYZB5)
789 && pos_bytes >= sizeof(float)) {
790 pos_bytes -= sizeof(float);
791 pos_bytes += sizeof(DWORD);
792 }
793
794 const size_t normal_bytes = has_normal ? (3 * sizeof(float)) : 0;
795 const size_t psize_bytes = has_psize ? sizeof(float) : 0;
797 const size_t diffuse_bytes = has_diffuse ? sizeof(DWORD) : 0;
799 const size_t specular_bytes = has_specular ? sizeof(DWORD) : 0;
801
802 size_t stride = tex_off;
803 for (int t = 0; t < tex_count; t++) {
804 // Dimension code maps 00=2D, 01=3D, 10=4D, 11=1D.
805 DWORD dim_code = (fvf >> (16 + t * 2)) & 0x3;
806 int dim = 2;
807 if (dim_code == 1) {
808 dim = 3;
809 } else if (dim_code == 2) {
810 dim = 4;
811 } else if (dim_code == 3) {
812 dim = 1;
813 }
814
815 stride += (size_t)dim * sizeof(float);
816 }
817
818 // Malformed FVF input still needs enough bytes for a position.
819 const size_t min_stride = has_rhw ? (4 * sizeof(float)) : (3 * sizeof(float));
822 }
823
824 for (DWORD i = 0; i < count; i++) {
825 const float *v = (const float *)(src + i * stride);
826 float out_x = v[0];
827 float out_y = v[1];
828 float out_z = v[2];
829
830 if (has_rhw) {
831 out_x = ((out_x - vp_x) * logical_w) / vp_w;
832 out_y = ((out_y - vp_y) * logical_h) / vp_h;
833 if (fabsf(vp_z_span) > 1.0e-8f) {
834 out_z = (out_z - vp_min_z) / vp_z_span;
835 }
836 }
837
838 d3d_device7_verts[i].x = out_x;
839 d3d_device7_verts[i].y = out_y;
840 d3d_device7_verts[i].z = out_z;
841 float rhw = has_rhw ? v[3] : 1.0f;
842 if (!isfinite(rhw) || rhw <= 0.0f)
843 rhw = 1.0f;
844 d3d_device7_verts[i].rhw = rhw;
845
846 if (has_diffuse) {
847 const DWORD c = *(const DWORD *)(src + i * stride + diffuse_off);
848 d3d_device7_verts[i].a = ((c >> 24) & 0xFF) / 255.0f;
849 d3d_device7_verts[i].r = ((c >> 16) & 0xFF) / 255.0f;
850 d3d_device7_verts[i].g = ((c >> 8) & 0xFF) / 255.0f;
851 d3d_device7_verts[i].b = (c & 0xFF) / 255.0f;
852 } else {
853 d3d_device7_verts[i].a = 1.0f;
854 d3d_device7_verts[i].r = 1.0f;
855 d3d_device7_verts[i].g = 1.0f;
856 d3d_device7_verts[i].b = 1.0f;
857 }
858
859 if (has_tex) {
860 const float *tc = (const float *)(src + i * stride + tex_off);
861 d3d_device7_verts[i].u = tc[0];
862 d3d_device7_verts[i].v = tc[1];
863 } else {
864 d3d_device7_verts[i].u = d3d_device7_verts[i].v = 0.0f;
865 }
866 }
867
868 if (has_rhw) {
869 float max_rhw = 0.0f;
870 for (DWORD i = 0; i < count; i++) {
871 if (d3d_device7_verts[i].rhw > max_rhw) {
872 max_rhw = d3d_device7_verts[i].rhw;
873 }
874 }
875
876 if (max_rhw > 0.0f) {
877 const float inv_max = 1.0f / max_rhw;
878 for (DWORD i = 0; i < count; i++) {
879 d3d_device7_verts[i].rhw *= inv_max;
880 }
881 }
882 }
883
886 return S_OK;
887}
888
890 d3ddevice7_drawindexedprimitive,
892 DWORD prim,
893 DWORD fvf,
894 void *v,
895 DWORD vn,
896 WORD *indices,
897 DWORD in,
899)
900
902 d3ddevice7_setclipstatus,
904 void *status
905)
906
908 d3ddevice7_getclipstatus,
910 void,
912)
913
915 d3ddevice7_drawprimitivestrided,
918 DWORD fvf,
919 void *d,
921 DWORD f
922)
923
925 d3ddevice7_drawindexedprimitivestrided,
927 DWORD prim,
928 DWORD fvf,
929 void *d,
930 DWORD vn,
931 WORD *i,
932 DWORD in,
933 DWORD f
934)
935
937 d3ddevice7_drawprimitivevb,
939 DWORD prim,
940 void *vb,
942 DWORD n,
943 DWORD f
944)
945
947 d3ddevice7_drawindexedprimitivevb,
949 DWORD prim,
950 void *vb,
951 DWORD st,
952 DWORD vn,
953 WORD *i,
954 DWORD in,
955 DWORD f
956)
957
959 d3ddevice7_computespherevisibility,
960 DWORD,
961 0,
963 void *c,
964 float *r,
965 DWORD n,
966 DWORD f
967)
968
970 d3ddevice7_gettexture,
971 void *,
972 NULL,
975)
976
977static HRESULT __stdcall d3ddevice7_settexture(
981) {
982
983 if (!texture) {
984 // Unbind texture
986
987 return S_OK;
988 }
989
993
994 return S_OK;
995}
996
997static HRESULT __stdcall d3ddevice7_gettexturestagestate(
999 DWORD stage,
1000 DWORD type,
1001 DWORD *out
1002) {
1003 if (!out)
1004 return S_OK;
1005
1006 if (stage != 0) {
1007 *out = 0;
1008 return S_OK;
1009 }
1010
1011 switch (type) {
1012 case D3DTSS_COLOROP:
1013 *out = dttr_backend.stage_color_op;
1014 break;
1015 case D3DTSS_COLORARG1:
1016 *out = dttr_backend.stage_color_arg1;
1017 break;
1018 case D3DTSS_COLORARG2:
1019 *out = dttr_backend.stage_color_arg2;
1020 break;
1021 case D3DTSS_ALPHAOP:
1022 *out = dttr_backend.stage_alpha_op;
1023 break;
1024 case D3DTSS_ALPHAARG1:
1025 *out = dttr_backend.stage_alpha_arg1;
1026 break;
1027 case D3DTSS_ALPHAARG2:
1028 *out = dttr_backend.stage_alpha_arg2;
1029 break;
1030 case D3DTSS_ADDRESSU:
1031 *out = (DWORD)dttr_backend.addr_u;
1032 break;
1033 case D3DTSS_ADDRESSV:
1034 *out = (DWORD)dttr_backend.addr_v;
1035 break;
1036 default:
1037 *out = 0;
1038 break;
1039 }
1040
1041 return S_OK;
1042}
1043
1044static HRESULT __stdcall d3ddevice7_settexturestagestate(
1046 DWORD stage,
1047 DWORD type,
1048 DWORD value
1049) {
1050 switch (type) {
1051 case D3DTSS_COLOROP:
1052 dttr_backend.stage_color_op = (DWORD)value;
1053 break;
1054 case D3DTSS_COLORARG1:
1055 dttr_backend.stage_color_arg1 = value;
1056 break;
1057 case D3DTSS_COLORARG2:
1058 dttr_backend.stage_color_arg2 = value;
1059 break;
1060 case D3DTSS_ALPHAOP:
1061 dttr_backend.stage_alpha_op = (DWORD)value;
1062 break;
1063 case D3DTSS_ALPHAARG1:
1064 dttr_backend.stage_alpha_arg1 = value;
1065 break;
1066 case D3DTSS_ALPHAARG2:
1067 dttr_backend.stage_alpha_arg2 = value;
1068 break;
1069 case D3DTSS_ADDRESS:
1070 // Legacy combined state sets both texture address axes.
1073 break;
1074 case D3DTSS_ADDRESSU:
1076 break;
1077 case D3DTSS_ADDRESSV:
1079 break;
1080 }
1081
1082 return S_OK;
1083}
1084
1086 d3ddevice7_validatedevice,
1087 DWORD,
1088 1,
1090)
1091
1093 d3ddevice7_applystateblock,
1095 DWORD block
1096)
1097
1099 d3ddevice7_capturestateblock,
1101 DWORD block
1102)
1103
1105 d3ddevice7_deletestateblock,
1107 DWORD block
1108)
1109
1111 d3ddevice7_createstateblock,
1112 DWORD,
1113 1,
1115 DWORD t
1116)
1117
1119 d3ddevice7_load,
1121 void *dst,
1122 void *dstPt,
1123 void *src,
1124 void *srcR,
1125 DWORD f
1126)
1127
1129 d3ddevice7_lightenable,
1131 DWORD idx,
1132 BOOL enable
1133)
1134
1136 d3ddevice7_getlightenable,
1140 DWORD idx
1141)
1142
1144 d3ddevice7_setclipplane,
1146 DWORD idx,
1147 float *plane
1148)
1149
1151 d3ddevice7_getclipplane,
1152 16,
1153 float,
1155 DWORD idx
1156)
1157
1158static HRESULT __stdcall d3ddevice7_getinfo(
1160 DWORD id,
1161 void *info,
1162 DWORD sz
1163) {
1164
1165 if (info && sz > 0)
1166 memset(info, 0, sz);
1167 return S_OK;
1168}
1169
1171 .QueryInterface = d3ddevice7_queryinterface,
1172 .AddRef = d3ddevice7_addref,
1173 .Release = d3ddevice7_release,
1174 .GetCaps = d3ddevice7_getcaps,
1175 .EnumTextureFormats = d3ddevice7_enumtextureformats,
1176 .BeginScene = d3ddevice7_beginscene,
1177 .EndScene = d3ddevice7_endscene,
1178 .GetDirect3D = d3ddevice7_getdirect3d,
1179 .SetRenderTarget = d3ddevice7_setrendertarget,
1180 .GetRenderTarget = d3ddevice7_getrendertarget,
1181 .Clear = d3ddevice7_clear,
1182 .SetTransform = d3ddevice7_settransform,
1183 .GetTransform = d3ddevice7_gettransform,
1184 .SetViewport = d3ddevice7_setviewport,
1185 .MultiplyTransform = d3ddevice7_multiplytransform,
1186 .GetViewport = d3ddevice7_getviewport,
1187 .SetMaterial = d3ddevice7_setmaterial,
1188 .GetMaterial = d3ddevice7_getmaterial,
1189 .SetLight = d3ddevice7_setlight,
1190 .GetLight = d3ddevice7_getlight,
1191 .SetRenderState = d3ddevice7_setrenderstate,
1192 .GetRenderState = d3ddevice7_getrenderstate,
1193 .BeginStateBlock = d3ddevice7_beginstateblock,
1194 .EndStateBlock = d3ddevice7_endstateblock,
1195 .PreLoad = d3ddevice7_preload,
1196 .DrawPrimitive = d3ddevice7_drawprimitive,
1197 .DrawIndexedPrimitive = d3ddevice7_drawindexedprimitive,
1198 .SetClipStatus = d3ddevice7_setclipstatus,
1199 .GetClipStatus = d3ddevice7_getclipstatus,
1200 .DrawPrimitiveStrided = d3ddevice7_drawprimitivestrided,
1201 .DrawIndexedPrimitiveStrided = d3ddevice7_drawindexedprimitivestrided,
1202 .DrawPrimitiveVB = d3ddevice7_drawprimitivevb,
1203 .DrawIndexedPrimitiveVB = d3ddevice7_drawindexedprimitivevb,
1204 .ComputeSphereVisibility = d3ddevice7_computespherevisibility,
1205 .GetTexture = d3ddevice7_gettexture,
1206 .SetTexture = d3ddevice7_settexture,
1207 .GetTextureStageState = d3ddevice7_gettexturestagestate,
1208 .SetTextureStageState = d3ddevice7_settexturestagestate,
1209 .ValidateDevice = d3ddevice7_validatedevice,
1210 .ApplyStateBlock = d3ddevice7_applystateblock,
1211 .CaptureStateBlock = d3ddevice7_capturestateblock,
1212 .DeleteStateBlock = d3ddevice7_deletestateblock,
1213 .CreateStateBlock = d3ddevice7_createstateblock,
1214 .Load = d3ddevice7_load,
1215 .LightEnable = d3ddevice7_lightenable,
1216 .GetLightEnable = d3ddevice7_getlightenable,
1217 .SetClipPlane = d3ddevice7_setclipplane,
1218 .GetClipPlane = d3ddevice7_getclipplane,
1219 .GetInfo = d3ddevice7_getinfo,
1220};
1221
1225 );
1226 if (dev) {
1227 dev->vtbl = &vtbl;
1228 }
1229
1230 return dev;
1231}
static DTTR_Graphics_COM_Direct3D7_VT vtbl
const size_t diffuse_off
void * cb
const size_t specular_off
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 * surface
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void * srcR
static HRESULT d3ddevice7_gettexturestagestate(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD stage, DWORD type, DWORD *out)
#define MAX_VERTICES
DTTR_Graphics_COM_Direct3DDevice7 * self
const bool has_xyzw
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD void DWORD st
static HRESULT d3ddevice7_gettransform(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD type, void *matrix)
return S_OK
const float logical_w
static DTTR_PrimitiveType d3d_device7_map_primitive_type(DWORD prim_type)
Maps a D3D primitive code to the internal primitive enum.
#define DTTR_MAT4_BYTES
static HRESULT d3ddevice7_settransform(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD type, void *matrix)
const float vp_y
static bool d3d_device7_get_transform_state(DWORD type, float **out_matrix_f)
Selects the backend transform matrix for a D3D transform state token.
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void * dstPt
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 float * r
const float vp_h
DTTR_Graphics_COM_Direct3DDevice7 *self DWORD DWORD fvf
const float vp_min_z
static void d3d_device7_mat4_multiply_f(float *restrict out, const float *restrict a, const float *restrict b)
Multiplies two row-major 4x4 float matrices into out.
const int tex_count
DTTR_Graphics_COM_Direct3DDevice7 * dttr_graphics_com_create_direct3ddevice7()
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f BOOL
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD count
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void * d
static void d3d_device7_record_draw(DTTR_PrimitiveType type, const DTTR_Vertex *verts, uint32_t count, bool transformed, bool textured)
Appends a draw record to the current frame batch.
const bool has_specular
size_t stride
const DTTR_BackendState * state
static uint32_t d3d_device7_expand_fan(const DTTR_Vertex *restrict in, uint32_t count, DTTR_Vertex *restrict out)
Expands a triangle fan into a triangle list.
static DTTR_PrimitiveType d3d_device7_uploaded_primitive_type(DTTR_PrimitiveType type)
static void d3d_device7_clear_bound_texture(DTTR_BackendState *state)
const bool has_diffuse
static DTTR_Vertex d3d_device7_verts[MAX_VERTICES]
DDPIXELFORMAT fmt_rgb565
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD void DWORD DWORD color
static void d3d_device7_set_texture_address_u(DTTR_TextureAddress addr)
Sets texture addressing mode for U coordinates.
const bool has_tex
static void d3d_device7_record_clear(uint32_t flags, uint32_t color, float depth, uint32_t stencil)
Appends a clear record to the current frame batch.
size_t pos_bytes
static HRESULT d3ddevice7_getviewport(DTTR_Graphics_COM_Direct3DDevice7 *self, void *vp)
void void * ctx
static uint32_t d3d_device7_expand_strip(const DTTR_Vertex *restrict in, uint32_t count, DTTR_Vertex *restrict out)
Expands a triangle strip into a triangle list.
static void d3d_device7_set_viewport(int x, int y, int w, int h, float min_z, float max_z)
Updates the viewport state used by transformed rendering paths.
static const char * d3d_device7_transform_label(DWORD type)
static void d3d_device7_set_transform_state(DWORD type, const float *m)
const size_t normal_bytes
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void void void void DWORD f FALSE
const bool has_psize
DTTR_Graphics_COM_Direct3DDevice7 *self DTTR_Graphics_COM_Direct3DDevice7 DWORD static idx HRESULT d3ddevice7_setrenderstate(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD state, DWORD value)
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 float DWORD DWORD f DWORD stage
HRESULT hr
const bool has_rhw
const float vp_z_span
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD void DWORD DWORD float DWORD stencil
static HRESULT d3ddevice7_setviewport(DTTR_Graphics_COM_Direct3DDevice7 *self, void *vp)
static void d3d_device7_set_texture_address_v(DTTR_TextureAddress addr)
Sets texture addressing mode for V coordinates.
DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 DWORD block DTTR_Graphics_COM_Direct3DDevice7 void * dst
const DTTR_PrimitiveType type
const float vp_x
static void d3d_device7_texture_bind(DTTR_Texture tex)
Binds an internal texture handle for subsequent draw records.
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 float DWORD DWORD f DWORD void * texture
const float logical_h
const size_t psize_bytes
static void d3d_device7_set_blend_func(DTTR_BlendFactor src, DTTR_BlendFactor dst)
Sets source and destination blend factors.
const size_t min_stride
static HRESULT d3ddevice7_multiplytransform(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD type, void *matrix)
DTTR_Graphics_COM_Direct3DDevice7 *self DWORD prim_type
DDPIXELFORMAT fmt_argb4444
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 DTTR_Graphics_COM_Direct3DDevice7 DWORD static idx HRESULT d3ddevice7_getinfo(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD id, void *info, DWORD sz)
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD DWORD f DTTR_Graphics_COM_Direct3DDevice7 DWORD void * vb
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD void * rects
DTTR_Graphics_COM_Direct3DDevice7 *self DWORD DWORD void * vertices
const float vp_max_z
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
const bool has_normal
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD void DWORD DWORD float z
static void d3d_device7_copy_or_expand_primitive(DTTR_PrimitiveType *type, const DTTR_Vertex *verts, uint32_t count, DTTR_Vertex *out)
const size_t diffuse_bytes
const uint8_t * src
static uint32_t d3d_device7_expanded_primitive_count(DTTR_PrimitiveType type, uint32_t count)
DTTR_Graphics_COM_Direct3DDevice7 void DWORD flags DWORD void DWORD flags
const float vp_w
const size_t tex_off
static HRESULT d3ddevice7_settexturestagestate(DTTR_Graphics_COM_Direct3DDevice7 *self, DWORD stage, DWORD type, DWORD value)
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD prim
#define DTTR_MAT4_ELEMS
const size_t specular_bytes
DTTR_Graphics_COM_Direct3DDevice7 void *status DTTR_Graphics_COM_Direct3DDevice7 DWORD DWORD void DWORD n
DTTR_Graphics_COM_DirectDraw7 *self DWORD DWORD h
DTTR_Graphics_COM_DirectDraw7 DWORD f
DTTR_Graphics_COM_DirectDraw7 *self DWORD w
DTTR_Graphics_COM_DirectDrawSurface7 DWORD x
DTTR_Graphics_COM_DirectDrawSurface7 DWORD DWORD y
DTTR_Graphics_COM_DirectDrawSurface7 DWORD flags void NULL
DTTR_Config dttr_config
Definition defaults.c:53
#define DTTR_LOG_WARN(...)
Definition dttr_log.h:30
void dttr_graphics_begin_frame()
Definition graphics.c:599
#define DTTR_D3DPT_POINTLIST
#define DTTR_D3DFVF_XYZB2
#define DTTR_D3DFVF_XYZB3
#define DTTR_D3DFVF_SPECULAR
#define DTTR_D3DFVF_XYZRHW
#define DTTR_COM_STUB_MEMSET(fn, size, buf_type,...)
#define DTTR_COM_STUB_SET(fn, out_type, val,...)
#define DTTR_D3DPT_LINELIST
#define DTTR_D3DPT_TRIANGLEFAN
#define DTTR_D3DFVF_TEXCOUNT_SHIFT
#define DTTR_COM_NOOP_HRESULT(fn,...)
#define DTTR_COM_ADDREF(fn, type)
#define DTTR_D3DFVF_POSITION_MASK
#define DTTR_D3DFVF_NORMAL
#define DTTR_D3DFVF_XYZB4
#define DTTR_D3DFVF_XYZB1
#define DTTR_D3DFVF_DIFFUSE
#define DTTR_COM_QI_SELF(fn, type)
#define DTTR_D3DPT_LINESTRIP
#define DTTR_D3DPT_TRIANGLESTRIP
#define DTTR_D3DFVF_XYZB5
#define DTTR_D3DFVF_LASTBETA_UBYTE4
#define DTTR_SIZEOF_D3DMATERIAL7
#define DTTR_COM_RELEASE(fn, type)
#define DTTR_D3DFVF_LASTBETA_D3DCOLOR
#define DTTR_D3DFVF_PSIZE
#define DTTR_SIZEOF_D3DCLIPSTATUS
#define DTTR_D3DFVF_XYZW
#define DTTR_D3DPT_TRIANGLELIST
#define DTTR_SIZEOF_D3DLIGHT7
#define DTTR_SIZEOF_D3DDEVICEDESC7
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
#define DTTR_MAX_FRAME_VERTICES
DTTR_BlendFactor
@ DTTR_BLEND_ONE
bool dttr_graphics_ensure_staged_texture(DTTR_BackendState *state, DTTR_StagedTexture *st)
Definition util.c:14
#define DTTR_BLEND_ALPHA
#define DTTR_CLEAR_COLOR
#define DTTR_BLEND_OFF
bool dttr_graphics_is_gpu_thread()
Definition util.c:182
#define DTTR_CLEAR_STENCIL
#define DTTR_VERTEX_SIZE
@ DTTR_BACKEND_SDL_GPU
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
uint32_t DTTR_Texture
#define DTTR_BLEND_ADDITIVE
#define DTTR_CLEAR_DEPTH
@ DTTR_BATCH_DRAW
@ DTTR_BATCH_CLEAR
DTTR_TextureAddress
@ DTTR_TEXADDR_CLAMP
DTTR_BackendState dttr_backend
Definition util.c:8
DTTR_PrimitiveType
@ DTTR_PRIM_POINTLIST
@ DTTR_PRIM_LINELIST
@ DTTR_PRIM_LINESTRIP
@ DTTR_PRIM_TRIANGLEFAN
@ DTTR_PRIM_TRIANGLELIST
@ DTTR_PRIM_TRIANGLESTRIP
#define DTTR_INVALID_TEXTURE
A recorded clear or draw command replayed during frame submission.
SDL_GPUSampler * sampler
struct DTTR_BatchRecord::@173304276063167267021134124022136033175102267147::@317066375077304207167347173122133172104242212006 clear
struct DTTR_BatchRecord::@173304276063167267021134124022136033175102267147::@107356260052026241174121242151011150024304321020 draw
SDL_GPUTexture * texture
DTTR_Uniforms uniforms
DTTR_BatchRecordType type
DTTR_Graphics_COM_Direct3DDevice7_VT * vtbl