|
| 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