Skip to content

Commit 4efb26e

Browse files
committed
deko3d: add native video driver for Switch HW render path
1 parent 86128a2 commit 4efb26e

20 files changed

Lines changed: 4640 additions & 4 deletions

Makefile.common

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1278,6 +1278,18 @@ ifeq ($(TARGET), retroarch_switch)
12781278
ifeq ($(HAVE_OPENGL), 1)
12791279
OBJ += gfx/drivers_context/switch_ctx.o
12801280
endif
1281+
ifeq ($(HAVE_DEKO3D), 1)
1282+
OBJ += gfx/drivers/deko3d.o
1283+
DEFINES += -DHAVE_DEKO3D
1284+
# Menu shaders for gfx_display_ctx_deko3d. GLSL -> DKSH (uam) ->
1285+
# .o (objcopy raw binary embed with stable symbol names:
1286+
# <basename>_dksh[], <basename>_dksh_end[], <basename>_dksh_size).
1287+
UAM ?= $(DEVKITPRO)/tools/bin/uam
1288+
OBJ += gfx/drivers/deko3d_menu_vsh_dksh.o \
1289+
gfx/drivers/deko3d_menu_fsh_dksh.o \
1290+
gfx/drivers/deko3d_blit_vsh_dksh.o \
1291+
gfx/drivers/deko3d_blit_fsh_dksh.o
1292+
endif
12811293
endif
12821294
OBJ += audio/drivers/switch_audio.o \
12831295
audio/drivers/switch_thread_audio.o \
@@ -2960,3 +2972,22 @@ endif
29602972
endif
29612973

29622974
##################################
2975+
2976+
#---------------------------------------------------------------------------------
2977+
# deko3d menu shaders: GLSL -> DKSH (uam) -> .o (objcopy raw binary embed).
2978+
# Pattern rules are scoped to gfx/drivers/ to avoid accidentally matching
2979+
# elsewhere. They only fire when the corresponding _dksh.o targets are in
2980+
# OBJ (added inside the HAVE_DEKO3D Switch block above).
2981+
#---------------------------------------------------------------------------------
2982+
gfx/drivers/%_vsh.dksh: gfx/drivers/%_vsh.glsl
2983+
@echo "==> uam vert $<"
2984+
@$(UAM) -s vert -o $@ $<
2985+
2986+
gfx/drivers/%_fsh.dksh: gfx/drivers/%_fsh.glsl
2987+
@echo "==> uam frag $<"
2988+
@$(UAM) -s frag -o $@ $<
2989+
2990+
gfx/drivers/%_dksh.o: gfx/drivers/%.dksh
2991+
@echo "==> objcopy $<"
2992+
@cd $$(dirname $<) && $(PREFIX)objcopy -I binary -O elf64-littleaarch64 -B aarch64 \
2993+
$$(basename $<) $$(basename $*)_dksh.o

Makefile.libnx

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ HAVE_FREETYPE = 0
6767
HAVE_SWITCH = 1
6868
HAVE_LIBNX = 1
6969
HAVE_OPENGL = 1
70+
HAVE_DEKO3D = 1
7071
HAVE_LANGEXTRA = 1
7172
HAVE_GFX_WIDGETS = 1
7273

@@ -156,6 +157,12 @@ ifeq ($(HAVE_OPENGL), 1)
156157
LIBS := -lEGL -lglapi -ldrm_nouveau $(LIBS)
157158
endif
158159

160+
ifeq ($(HAVE_DEKO3D), 1)
161+
CFLAGS += -DHAVE_DEKO3D
162+
CXXFLAGS += -DHAVE_DEKO3D
163+
LIBS := -ldeko3d $(LIBS)
164+
endif
165+
159166
#---------------------------------------------------------------------------------
160167
# list of directories containing libraries, this must be the top level containing
161168
# include and lib

configuration.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3586,7 +3586,8 @@ static bool check_menu_driver_compatibility(settings_t *settings)
35863586
|| (memcmp(video_driver, "d3d9_cg", 7) == 0 && video_driver[7] == '\0')
35873587
|| (memcmp(video_driver, "d3d10", 5) == 0 && video_driver[5] == '\0')
35883588
|| (memcmp(video_driver, "d3d11", 5) == 0 && video_driver[5] == '\0')
3589-
|| (memcmp(video_driver, "d3d12", 5) == 0 && video_driver[5] == '\0');
3589+
|| (memcmp(video_driver, "d3d12", 5) == 0 && video_driver[5] == '\0')
3590+
|| (memcmp(video_driver, "deko3d", 6) == 0 && video_driver[6] == '\0');
35903591
case 'g':
35913592
if (video_driver[1] == 'l')
35923593
return (memcmp(video_driver, "gl", 2) == 0 && video_driver[2] == '\0')

gfx/common/deko3d_common.h

Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
/* RetroArch - A frontend for libretro.
2+
*
3+
* RetroArch is free software: you can redistribute it and/or modify it under the terms
4+
* of the GNU General Public License as published by the Free Software Found-
5+
* ation, either version 3 of the License, or (at your option) any later version.
6+
*
7+
* RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
8+
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
9+
* PURPOSE. See the GNU General Public License for more details.
10+
*
11+
* You should have received a copy of the GNU General Public License along with RetroArch.
12+
* If not, see <http://www.gnu.org/licenses/>.
13+
*/
14+
15+
16+
#ifndef RA_DEKO3D_COMMON_H
17+
#define RA_DEKO3D_COMMON_H
18+
19+
#include <stdint.h>
20+
#include <stdbool.h>
21+
#include <deko3d.h>
22+
#include <switch.h>
23+
24+
#include <gfx/math/matrix_4x4.h>
25+
26+
#include <libretro_deko3d.h>
27+
28+
#include "../video_driver.h"
29+
30+
#ifdef __cplusplus
31+
extern "C" {
32+
#endif
33+
34+
/* Compile-time maxima for fixed-size arrays inside dk3d_t. Runtime
35+
* counts (dk3d->num_swapchain_images, dk3d->num_frames_in_flight) are
36+
* populated from settings at init and may be smaller than these caps. */
37+
#define DK3D_MAX_SWAPCHAIN_IMAGES 8
38+
#define DK3D_MAX_FRAMES_IN_FLIGHT 8
39+
#define DK3D_CMDBUF_SIZE (256 * 1024)
40+
#define DK3D_STAGING_SIZE (8 * 1024 * 1024)
41+
#define DK3D_MENU_STAGING_SIZE (4 * 1024 * 1024)
42+
#define DK3D_MENU_VBO_SIZE (256 * 1024)
43+
#define DK3D_MENU_UBO_SIZE (64 * 1024)
44+
#define DK3D_MENU_IMAGE_DESCS 256 /* per-frame image descriptor heap slots */
45+
46+
/* Per-frame resources: command buffer + memblock storage + fence the queue
47+
* signals when this frame's GPU work has completed. The set is rotated
48+
* round-robin every frame to avoid CPU waits on the GPU. */
49+
typedef struct dk3d_frame
50+
{
51+
DkCmdBuf cmdbuf;
52+
DkMemBlock cmd_memblock;
53+
DkFence done_fence;
54+
bool done_fence_valid;
55+
56+
/* Per-frame menu vertex buffer ring. Bump-allocated per draw; reset at
57+
* frame start. Holds interleaved (pos,uv,color) tuples. */
58+
DkMemBlock menu_vbo_mem;
59+
void *menu_vbo_ptr;
60+
DkGpuAddr menu_vbo_gpu;
61+
uint32_t menu_vbo_off;
62+
uint32_t menu_vbo_cap;
63+
64+
/* Per-frame menu uniform buffer ring. Each draw allocates one slice for
65+
* its mvp matrix (or pipeline-supplied UBO data). Bump-allocator. */
66+
DkMemBlock menu_ubo_mem;
67+
void *menu_ubo_ptr;
68+
DkGpuAddr menu_ubo_gpu;
69+
uint32_t menu_ubo_off;
70+
uint32_t menu_ubo_cap;
71+
72+
/* Per-frame image-descriptor heap. CPU writes new dk::ImageDescriptor
73+
* entries during draws; GPU reads via the cmdbuf-bound heap. Reset per
74+
* frame so unfenced-frame reuse cannot corrupt in-flight reads. */
75+
DkMemBlock menu_img_desc_mem;
76+
void *menu_img_desc_ptr;
77+
DkGpuAddr menu_img_desc_gpu;
78+
uint32_t menu_img_desc_next;
79+
} dk3d_frame_t;
80+
81+
/* Image tracked alongside its backing memory so we can free both. */
82+
typedef struct dk3d_image
83+
{
84+
DkImage image; /* opaque: must outlive the queue work referencing it */
85+
DkMemBlock memblock;
86+
uint32_t width;
87+
uint32_t height;
88+
DkImageFormat format;
89+
} dk3d_image_t;
90+
91+
/* Linear staging buffer pair: a CPU-visible DkMemBlock that the CPU writes
92+
* pixel data into, and a tile-mode DkImage that the GPU samples from after
93+
* a CopyBufferToImage. We keep both sized to the maximum content the driver
94+
* can be asked to display (1080p RGBA8 for SW frames; ~512x512 for menu). */
95+
typedef struct dk3d_stage
96+
{
97+
DkMemBlock cpu_memblock; /* CpuUncached | GpuCached */
98+
void *cpu_ptr; /* mapped pointer into cpu_memblock */
99+
uint32_t cpu_capacity; /* bytes */
100+
101+
dk3d_image_t image; /* tile-mode DkImage: dst of upload, src of blit */
102+
uint32_t used_width;
103+
uint32_t used_height;
104+
DkImageFormat used_format;
105+
bool valid;
106+
/* Set by the CPU-side writer when it has fresh pixels in cpu_memblock.
107+
* Cleared by dk3d_stage_upload_record() after the GPU copy command is
108+
* placed into the current frame's cmdbuf. Lets writers (e.g.
109+
* set_texture_frame) be called from a different point in the frame
110+
* lifecycle than dkCmdBufClear without losing the upload. */
111+
bool needs_gpu_upload;
112+
} dk3d_stage_t;
113+
114+
/* Resources backing the gfx_display_ctx_deko3d implementation. Shared
115+
* across frame slots; per-frame VBO storage lives on dk3d_frame_t. */
116+
typedef struct dk3d_menu_pipeline
117+
{
118+
DkShader vsh;
119+
DkShader fsh;
120+
DkMemBlock shader_mem;
121+
122+
/* Immutable single-entry sampler heap (linear, clamp-to-edge). Shared
123+
* across frames — never modified during rendering, so no per-frame copy. */
124+
DkMemBlock sampler_desc_mem;
125+
DkGpuAddr sampler_desc_gpu;
126+
127+
/* 1x1 white fallback texture, sampled when draw->texture == 0. */
128+
dk3d_image_t blank_tex;
129+
130+
/* ortho(0,1,1,0,-1,1): RA menu coords normalized [0,1] top-left origin. */
131+
math_matrix_4x4 mvp_no_rot;
132+
133+
/* Sticky state from blend/scissor ctx callbacks; consumed by draw(). */
134+
bool blend_on;
135+
bool scissor_on;
136+
int32_t scissor_x, scissor_y;
137+
uint32_t scissor_w, scissor_h;
138+
} dk3d_menu_pipeline_t;
139+
140+
/* The driver-private state. Mirrors switch_video_t in spirit but holds
141+
* deko3d objects instead of a CPU framebuffer. */
142+
typedef struct dk3d
143+
{
144+
/* Window / viewport */
145+
NWindow *win;
146+
unsigned surface_width;
147+
unsigned surface_height;
148+
struct video_viewport vp;
149+
bool keep_aspect;
150+
bool smooth; /* bilinear vs point */
151+
bool rgb32;
152+
bool vsync;
153+
bool hard_sync; /* settings->bools.video_hard_sync */
154+
unsigned hard_sync_frames; /* settings->uints.video_hard_sync_frames, 0..3 */
155+
unsigned swap_interval; /* dkSwapchainSetSwapInterval value when vsync on */
156+
unsigned num_swapchain_images; /* effective count, <= DK3D_MAX_SWAPCHAIN_IMAGES */
157+
unsigned num_frames_in_flight; /* effective ring depth, <= DK3D_MAX_FRAMES_IN_FLIGHT */
158+
bool is_threaded;
159+
bool should_resize;
160+
unsigned rotation;
161+
unsigned last_width;
162+
unsigned last_height;
163+
/* AppletOperationMode at last init/resize. dk3d_check_resize() recreates
164+
* the swapchain when this changes (dock <-> handheld). */
165+
int applet_op_mode;
166+
167+
/* Core deko3d objects */
168+
DkDevice device;
169+
DkQueue queue;
170+
171+
/* Per-image swapchain backing.
172+
* dk_images[i] outlives sc; sc references their addresses. */
173+
dk3d_image_t sc_images[DK3D_MAX_SWAPCHAIN_IMAGES];
174+
const DkImage *sc_image_ptrs[DK3D_MAX_SWAPCHAIN_IMAGES];
175+
DkSwapchain swapchain;
176+
int acquired_slot;
177+
178+
/* Frame ring */
179+
dk3d_frame_t frames[DK3D_MAX_FRAMES_IN_FLIGHT];
180+
uint32_t current_frame; /* index into frames[] */
181+
uint32_t frame_count; /* monotonic */
182+
183+
/* SW path (frame() with non-NULL frame and no HW set_image) */
184+
dk3d_stage_t sw_stage;
185+
186+
/* Menu texture (set_texture_frame) */
187+
dk3d_stage_t menu_stage;
188+
bool menu_enable;
189+
bool menu_full_screen;
190+
float menu_alpha;
191+
192+
/* gfx_display ctx state — proper menu driver (Ozone/XMB/MaterialUI). */
193+
dk3d_menu_pipeline_t menu_pipe;
194+
195+
/* HW render path: set_image hands us this. Pointers must stay valid
196+
* for the duration of the corresponding video_refresh call. */
197+
const DkImage *hw_image;
198+
unsigned hw_image_width;
199+
unsigned hw_image_height;
200+
unsigned hw_src_x;
201+
unsigned hw_src_y;
202+
unsigned hw_image_full_w;
203+
unsigned hw_image_full_h;
204+
float hw_aspect;
205+
DkFence *hw_acquire_fence;
206+
DkFence *hw_release_fence;
207+
bool hw_enable;
208+
209+
struct retro_hw_render_interface_deko3d hw_iface;
210+
211+
/* 3D-engine blit pipeline (replaces 2D dkCmdBufBlitImage for HW path).
212+
* Vertex shader uses gl_VertexIndex (no VBO). Sampler is bilinear
213+
* clamp-to-edge, matching the menu pipeline's default. */
214+
DkShader blit_vsh;
215+
DkShader blit_fsh;
216+
DkMemBlock blit_shader_mem;
217+
DkMemBlock blit_sampler_desc_mem;
218+
DkGpuAddr blit_sampler_desc_gpu;
219+
} dk3d_t;
220+
221+
/* Helpers (dk3d_init.c-style: implemented in deko3d.c for now). */
222+
bool dk3d_create_image_2d(DkDevice device,
223+
uint32_t width, uint32_t height, DkImageFormat fmt,
224+
uint32_t flags, dk3d_image_t *out);
225+
void dk3d_destroy_image(dk3d_image_t *img);
226+
227+
bool dk3d_stage_create(DkDevice device, uint32_t cpu_capacity,
228+
uint32_t max_width, uint32_t max_height, DkImageFormat fmt,
229+
dk3d_stage_t *out);
230+
void dk3d_stage_destroy(dk3d_stage_t *stage);
231+
232+
#ifdef __cplusplus
233+
}
234+
#endif
235+
236+
#endif

0 commit comments

Comments
 (0)