SDL_render_gpu.c 62 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2025 Sam Lantinga <[email protected]>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "SDL_internal.h"
  19. #ifdef SDL_VIDEO_RENDER_GPU
  20. #include "../../video/SDL_pixels_c.h"
  21. #include "../SDL_d3dmath.h"
  22. #include "../SDL_sysrender.h"
  23. #include "SDL_gpu_util.h"
  24. #include "SDL_pipeline_gpu.h"
  25. #include "SDL_shaders_gpu.h"
  26. typedef struct GPU_VertexShaderUniformData
  27. {
  28. Float4X4 mvp;
  29. SDL_FColor color;
  30. } GPU_VertexShaderUniformData;
  31. typedef struct GPU_SimpleFragmentShaderUniformData
  32. {
  33. float color_scale;
  34. } GPU_SimpleFragmentShaderUniformData;
  35. typedef struct GPU_AdvancedFragmentShaderUniformData
  36. {
  37. float scRGB_output;
  38. float texture_type;
  39. float input_type;
  40. float color_scale;
  41. float texel_width;
  42. float texel_height;
  43. float texture_width;
  44. float texture_height;
  45. float tonemap_method;
  46. float tonemap_factor1;
  47. float tonemap_factor2;
  48. float sdr_white_point;
  49. float YCbCr_matrix[16];
  50. } GPU_AdvancedFragmentShaderUniformData;
  51. // These should mirror the definitions in shaders/texture_advanced.frag.hlsl
  52. static const float TONEMAP_NONE = 0;
  53. //static const float TONEMAP_LINEAR = 1;
  54. static const float TONEMAP_CHROME = 2;
  55. //static const float TEXTURETYPE_NONE = 0;
  56. static const float TEXTURETYPE_RGB = 1;
  57. static const float TEXTURETYPE_RGB_PIXELART = 2;
  58. static const float TEXTURETYPE_RGBA = 3;
  59. static const float TEXTURETYPE_RGBA_PIXELART = 4;
  60. static const float TEXTURETYPE_PALETTE_NEAREST = 5;
  61. static const float TEXTURETYPE_PALETTE_LINEAR = 6;
  62. static const float TEXTURETYPE_PALETTE_PIXELART = 7;
  63. static const float TEXTURETYPE_NV12 = 8;
  64. static const float TEXTURETYPE_NV21 = 9;
  65. static const float TEXTURETYPE_YUV = 10;
  66. static const float INPUTTYPE_UNSPECIFIED = 0;
  67. static const float INPUTTYPE_SRGB = 1;
  68. static const float INPUTTYPE_SCRGB = 2;
  69. static const float INPUTTYPE_HDR10 = 3;
  70. typedef struct GPU_RenderData
  71. {
  72. bool external_device;
  73. SDL_GPUDevice *device;
  74. GPU_Shaders shaders;
  75. GPU_PipelineCache pipeline_cache;
  76. struct
  77. {
  78. SDL_GPUTexture *texture;
  79. SDL_GPUTextureFormat format;
  80. Uint32 width;
  81. Uint32 height;
  82. } backbuffer;
  83. struct
  84. {
  85. SDL_GPUSwapchainComposition composition;
  86. SDL_GPUPresentMode present_mode;
  87. } swapchain;
  88. struct
  89. {
  90. SDL_GPUTransferBuffer *transfer_buf;
  91. SDL_GPUBuffer *buffer;
  92. Uint32 buffer_size;
  93. } vertices;
  94. struct
  95. {
  96. SDL_GPURenderPass *render_pass;
  97. SDL_Texture *render_target;
  98. SDL_GPUCommandBuffer *command_buffer;
  99. SDL_GPUColorTargetInfo color_attachment;
  100. SDL_GPUViewport viewport;
  101. SDL_Rect scissor;
  102. SDL_FColor draw_color;
  103. bool scissor_enabled;
  104. bool scissor_was_enabled;
  105. } state;
  106. SDL_GPUSampler *samplers[RENDER_SAMPLER_COUNT];
  107. } GPU_RenderData;
  108. typedef struct GPU_PaletteData
  109. {
  110. SDL_GPUTexture *texture;
  111. } GPU_PaletteData;
  112. typedef struct GPU_TextureData
  113. {
  114. SDL_GPUTexture *texture;
  115. SDL_GPUTextureFormat format;
  116. void *pixels;
  117. int pitch;
  118. SDL_Rect locked_rect;
  119. const float *YCbCr_matrix;
  120. #ifdef SDL_HAVE_YUV
  121. // YV12 texture support
  122. bool yuv;
  123. SDL_GPUTexture *textureU;
  124. SDL_GPUTexture *textureV;
  125. // NV12 texture support
  126. bool nv12;
  127. SDL_GPUTexture *textureNV;
  128. #endif
  129. } GPU_TextureData;
  130. static bool GPU_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
  131. {
  132. SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
  133. SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
  134. SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
  135. SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
  136. SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
  137. SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
  138. if (GPU_ConvertBlendFactor(srcColorFactor) == SDL_GPU_BLENDFACTOR_INVALID ||
  139. GPU_ConvertBlendFactor(srcAlphaFactor) == SDL_GPU_BLENDFACTOR_INVALID ||
  140. GPU_ConvertBlendOperation(colorOperation) == SDL_GPU_BLENDOP_INVALID ||
  141. GPU_ConvertBlendFactor(dstColorFactor) == SDL_GPU_BLENDFACTOR_INVALID ||
  142. GPU_ConvertBlendFactor(dstAlphaFactor) == SDL_GPU_BLENDFACTOR_INVALID ||
  143. GPU_ConvertBlendOperation(alphaOperation) == SDL_GPU_BLENDOP_INVALID) {
  144. return false;
  145. }
  146. return true;
  147. }
  148. static bool GPU_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
  149. {
  150. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  151. GPU_PaletteData *palettedata = (GPU_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
  152. if (!palettedata) {
  153. return false;
  154. }
  155. palette->internal = palettedata;
  156. SDL_GPUTextureCreateInfo tci;
  157. SDL_zero(tci);
  158. tci.format = SDL_GetGPUTextureFormatFromPixelFormat(SDL_PIXELFORMAT_RGBA32);
  159. tci.layer_count_or_depth = 1;
  160. tci.num_levels = 1;
  161. tci.usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
  162. tci.width = 256;
  163. tci.height = 1;
  164. tci.sample_count = SDL_GPU_SAMPLECOUNT_1;
  165. palettedata->texture = SDL_CreateGPUTexture(data->device, &tci);
  166. if (!palettedata->texture) {
  167. return false;
  168. }
  169. return true;
  170. }
  171. static bool GPU_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
  172. {
  173. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  174. GPU_PaletteData *palettedata = (GPU_PaletteData *)palette->internal;
  175. const Uint32 data_size = ncolors * sizeof(*colors);
  176. SDL_GPUTransferBufferCreateInfo tbci;
  177. SDL_zero(tbci);
  178. tbci.size = data_size;
  179. tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
  180. SDL_GPUTransferBuffer *tbuf = SDL_CreateGPUTransferBuffer(data->device, &tbci);
  181. if (tbuf == NULL) {
  182. return false;
  183. }
  184. Uint8 *output = SDL_MapGPUTransferBuffer(data->device, tbuf, false);
  185. SDL_memcpy(output, colors, data_size);
  186. SDL_UnmapGPUTransferBuffer(data->device, tbuf);
  187. SDL_GPUCommandBuffer *cbuf = data->state.command_buffer;
  188. SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf);
  189. SDL_GPUTextureTransferInfo tex_src;
  190. SDL_zero(tex_src);
  191. tex_src.transfer_buffer = tbuf;
  192. tex_src.rows_per_layer = 1;
  193. tex_src.pixels_per_row = ncolors;
  194. SDL_GPUTextureRegion tex_dst;
  195. SDL_zero(tex_dst);
  196. tex_dst.texture = palettedata->texture;
  197. tex_dst.x = 0;
  198. tex_dst.y = 0;
  199. tex_dst.w = ncolors;
  200. tex_dst.h = 1;
  201. tex_dst.d = 1;
  202. SDL_UploadToGPUTexture(cpass, &tex_src, &tex_dst, false);
  203. SDL_EndGPUCopyPass(cpass);
  204. SDL_ReleaseGPUTransferBuffer(data->device, tbuf);
  205. return true;
  206. }
  207. static void GPU_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
  208. {
  209. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  210. GPU_PaletteData *palettedata = (GPU_PaletteData *)palette->internal;
  211. if (palettedata) {
  212. SDL_ReleaseGPUTexture(data->device, palettedata->texture);
  213. SDL_free(palettedata);
  214. }
  215. }
  216. static bool GPU_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
  217. {
  218. GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
  219. GPU_TextureData *data;
  220. SDL_GPUTextureFormat format;
  221. SDL_GPUTextureUsageFlags usage = SDL_GPU_TEXTUREUSAGE_SAMPLER;
  222. switch (texture->format) {
  223. case SDL_PIXELFORMAT_INDEX8:
  224. case SDL_PIXELFORMAT_YV12:
  225. case SDL_PIXELFORMAT_IYUV:
  226. case SDL_PIXELFORMAT_NV12:
  227. case SDL_PIXELFORMAT_NV21:
  228. format = SDL_GPU_TEXTUREFORMAT_R8_UNORM;
  229. break;
  230. case SDL_PIXELFORMAT_P010:
  231. format = SDL_GPU_TEXTUREFORMAT_R16_UNORM;
  232. break;
  233. default:
  234. format = SDL_GetGPUTextureFormatFromPixelFormat(texture->format);
  235. break;
  236. }
  237. if (renderer->output_colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
  238. switch (format) {
  239. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM:
  240. format = SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB;
  241. break;
  242. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM:
  243. format = SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB;
  244. break;
  245. default:
  246. break;
  247. }
  248. }
  249. if (format == SDL_GPU_TEXTUREFORMAT_INVALID) {
  250. return SDL_SetError("Texture format %s not supported by SDL_GPU",
  251. SDL_GetPixelFormatName(texture->format));
  252. }
  253. data = (GPU_TextureData *)SDL_calloc(1, sizeof(*data));
  254. if (!data) {
  255. return false;
  256. }
  257. if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
  258. size_t size;
  259. data->pitch = texture->w * SDL_BYTESPERPIXEL(texture->format);
  260. size = (size_t)texture->h * data->pitch;
  261. if (texture->format == SDL_PIXELFORMAT_YV12 ||
  262. texture->format == SDL_PIXELFORMAT_IYUV) {
  263. // Need to add size for the U and V planes
  264. size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
  265. }
  266. if (texture->format == SDL_PIXELFORMAT_NV12 ||
  267. texture->format == SDL_PIXELFORMAT_NV21 ||
  268. texture->format == SDL_PIXELFORMAT_P010) {
  269. // Need to add size for the U/V plane
  270. size += 2 * ((texture->h + 1) / 2) * ((data->pitch + 1) / 2);
  271. }
  272. data->pixels = SDL_calloc(1, size);
  273. if (!data->pixels) {
  274. SDL_free(data);
  275. return false;
  276. }
  277. // TODO allocate a persistent transfer buffer
  278. }
  279. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  280. usage |= SDL_GPU_TEXTUREUSAGE_COLOR_TARGET;
  281. }
  282. texture->internal = data;
  283. SDL_GPUTextureCreateInfo tci;
  284. SDL_zero(tci);
  285. tci.format = format;
  286. tci.layer_count_or_depth = 1;
  287. tci.num_levels = 1;
  288. tci.usage = usage;
  289. tci.width = texture->w;
  290. tci.height = texture->h;
  291. tci.sample_count = SDL_GPU_SAMPLECOUNT_1;
  292. data->format = format;
  293. data->texture = SDL_CreateGPUTexture(renderdata->device, &tci);
  294. if (!data->texture) {
  295. return false;
  296. }
  297. SDL_PropertiesID props = SDL_GetTextureProperties(texture);
  298. SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_POINTER, data->texture);
  299. #ifdef SDL_HAVE_YUV
  300. if (texture->format == SDL_PIXELFORMAT_YV12 ||
  301. texture->format == SDL_PIXELFORMAT_IYUV) {
  302. data->yuv = true;
  303. tci.width = (tci.width + 1) / 2;
  304. tci.height = (tci.height + 1) / 2;
  305. data->textureU = SDL_CreateGPUTexture(renderdata->device, &tci);
  306. if (!data->textureU) {
  307. return false;
  308. }
  309. SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_U_POINTER, data->textureU);
  310. data->textureV = SDL_CreateGPUTexture(renderdata->device, &tci);
  311. if (!data->textureV) {
  312. return false;
  313. }
  314. SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_V_POINTER, data->textureU);
  315. data->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
  316. if (!data->YCbCr_matrix) {
  317. return SDL_SetError("Unsupported YUV colorspace");
  318. }
  319. }
  320. if (texture->format == SDL_PIXELFORMAT_NV12 ||
  321. texture->format == SDL_PIXELFORMAT_NV21 ||
  322. texture->format == SDL_PIXELFORMAT_P010) {
  323. int bits_per_pixel;
  324. data->nv12 = true;
  325. tci.width = ((tci.width + 1) / 2);
  326. tci.height = ((tci.height + 1) / 2);
  327. if (texture->format == SDL_PIXELFORMAT_P010) {
  328. tci.format = SDL_GPU_TEXTUREFORMAT_R16G16_UNORM;
  329. } else {
  330. tci.format = SDL_GPU_TEXTUREFORMAT_R8G8_UNORM;
  331. }
  332. data->textureNV = SDL_CreateGPUTexture(renderdata->device, &tci);
  333. if (!data->textureNV) {
  334. return false;
  335. }
  336. SDL_SetPointerProperty(props, SDL_PROP_TEXTURE_GPU_TEXTURE_UV_POINTER, data->textureNV);
  337. switch (texture->format) {
  338. case SDL_PIXELFORMAT_P010:
  339. bits_per_pixel = 10;
  340. break;
  341. default:
  342. bits_per_pixel = 8;
  343. break;
  344. }
  345. data->YCbCr_matrix = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, bits_per_pixel);
  346. if (!data->YCbCr_matrix) {
  347. return SDL_SetError("Unsupported YUV colorspace");
  348. }
  349. }
  350. #endif // SDL_HAVE_YUV
  351. return true;
  352. }
  353. static bool GPU_UpdateTextureInternal(GPU_RenderData *renderdata, SDL_GPUCopyPass *cpass, SDL_GPUTexture *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch)
  354. {
  355. size_t row_size, data_size;
  356. if (!SDL_size_mul_check_overflow(w, bpp, &row_size) ||
  357. !SDL_size_mul_check_overflow(h, row_size, &data_size)) {
  358. return SDL_SetError("update size overflow");
  359. }
  360. SDL_GPUTransferBufferCreateInfo tbci;
  361. SDL_zero(tbci);
  362. tbci.size = (Uint32)data_size;
  363. tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
  364. SDL_GPUTransferBuffer *tbuf = SDL_CreateGPUTransferBuffer(renderdata->device, &tbci);
  365. if (tbuf == NULL) {
  366. return false;
  367. }
  368. Uint8 *output = SDL_MapGPUTransferBuffer(renderdata->device, tbuf, false);
  369. if (!output) {
  370. return false;
  371. }
  372. if ((size_t)pitch == row_size) {
  373. SDL_memcpy(output, pixels, data_size);
  374. } else {
  375. const Uint8 *input = pixels;
  376. for (int i = 0; i < h; ++i) {
  377. SDL_memcpy(output, input, row_size);
  378. output += row_size;
  379. input += pitch;
  380. }
  381. }
  382. SDL_UnmapGPUTransferBuffer(renderdata->device, tbuf);
  383. SDL_GPUTextureTransferInfo tex_src;
  384. SDL_zero(tex_src);
  385. tex_src.transfer_buffer = tbuf;
  386. tex_src.rows_per_layer = h;
  387. tex_src.pixels_per_row = w;
  388. SDL_GPUTextureRegion tex_dst;
  389. SDL_zero(tex_dst);
  390. tex_dst.texture = texture;
  391. tex_dst.x = x;
  392. tex_dst.y = y;
  393. tex_dst.w = w;
  394. tex_dst.h = h;
  395. tex_dst.d = 1;
  396. SDL_UploadToGPUTexture(cpass, &tex_src, &tex_dst, false);
  397. SDL_ReleaseGPUTransferBuffer(renderdata->device, tbuf);
  398. return true;
  399. }
  400. #ifdef SDL_HAVE_YUV
  401. static bool GPU_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
  402. const SDL_Rect *rect,
  403. const Uint8 *Yplane, int Ypitch,
  404. const Uint8 *UVplane, int UVpitch);
  405. static bool GPU_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
  406. const SDL_Rect *rect,
  407. const Uint8 *Yplane, int Ypitch,
  408. const Uint8 *Uplane, int Upitch,
  409. const Uint8 *Vplane, int Vpitch);
  410. #endif
  411. static bool GPU_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
  412. {
  413. GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
  414. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  415. bool retval = true;
  416. SDL_GPUCommandBuffer *cbuf = renderdata->state.command_buffer;
  417. SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf);
  418. int bpp = SDL_BYTESPERPIXEL(texture->format);
  419. retval = GPU_UpdateTextureInternal(renderdata, cpass, data->texture, bpp, rect->x, rect->y, rect->w, rect->h, pixels, pitch);
  420. #ifdef SDL_HAVE_YUV
  421. if (data->nv12) {
  422. const Uint8 *Yplane = (const Uint8 *)pixels;
  423. const Uint8 *UVplane = Yplane + rect->h * pitch;
  424. int UVpitch;
  425. bpp *= 2;
  426. if (texture->format == SDL_PIXELFORMAT_P010) {
  427. UVpitch = (pitch + 3) & ~3;
  428. } else {
  429. bpp = 1;
  430. UVpitch = (pitch + 1) & ~1;
  431. }
  432. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureNV, bpp, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, UVplane, UVpitch);
  433. } else if (data->yuv) {
  434. int Ypitch = pitch;
  435. int UVpitch = ((Ypitch + 1) / 2);
  436. const Uint8 *Yplane = (const Uint8 *)pixels;
  437. const Uint8 *Uplane = Yplane + rect->h * Ypitch;
  438. const Uint8 *Vplane = Uplane + ((rect->h + 1) / 2) * UVpitch;
  439. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureU, bpp, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, UVpitch);
  440. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureV, bpp, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, UVpitch);
  441. }
  442. #endif
  443. SDL_EndGPUCopyPass(cpass);
  444. return retval;
  445. }
  446. #ifdef SDL_HAVE_YUV
  447. static bool GPU_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
  448. const SDL_Rect *rect,
  449. const Uint8 *Yplane, int Ypitch,
  450. const Uint8 *Uplane, int Upitch,
  451. const Uint8 *Vplane, int Vpitch)
  452. {
  453. GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
  454. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  455. int bpp = SDL_BYTESPERPIXEL(texture->format);
  456. bool retval = true;
  457. SDL_GPUCommandBuffer *cbuf = renderdata->state.command_buffer;
  458. SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf);
  459. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->texture, bpp, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch);
  460. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureU, bpp, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch);
  461. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureV, bpp, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch);
  462. SDL_EndGPUCopyPass(cpass);
  463. return retval;
  464. }
  465. static bool GPU_UpdateTextureNV(SDL_Renderer *renderer, SDL_Texture *texture,
  466. const SDL_Rect *rect,
  467. const Uint8 *Yplane, int Ypitch,
  468. const Uint8 *UVplane, int UVpitch)
  469. {
  470. GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
  471. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  472. int bpp = SDL_BYTESPERPIXEL(texture->format);
  473. bool retval = true;
  474. SDL_GPUCommandBuffer *cbuf = renderdata->state.command_buffer;
  475. SDL_GPUCopyPass *cpass = SDL_BeginGPUCopyPass(cbuf);
  476. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->texture, bpp, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch);
  477. bpp *= 2;
  478. retval &= GPU_UpdateTextureInternal(renderdata, cpass, data->textureNV, bpp, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, UVplane, UVpitch);
  479. SDL_EndGPUCopyPass(cpass);
  480. return retval;
  481. }
  482. #endif // SDL_HAVE_YUV
  483. static bool GPU_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
  484. const SDL_Rect *rect, void **pixels, int *pitch)
  485. {
  486. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  487. data->locked_rect = *rect;
  488. *pixels =
  489. (void *)((Uint8 *)data->pixels + rect->y * data->pitch +
  490. rect->x * SDL_BYTESPERPIXEL(texture->format));
  491. *pitch = data->pitch;
  492. return true;
  493. }
  494. static void GPU_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  495. {
  496. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  497. const SDL_Rect *rect;
  498. void *pixels;
  499. rect = &data->locked_rect;
  500. pixels =
  501. (void *)((Uint8 *)data->pixels + rect->y * data->pitch +
  502. rect->x * SDL_BYTESPERPIXEL(texture->format));
  503. GPU_UpdateTexture(renderer, texture, rect, pixels, data->pitch);
  504. }
  505. static bool GPU_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
  506. {
  507. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  508. data->state.render_target = texture;
  509. return true;
  510. }
  511. static bool GPU_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
  512. {
  513. return true; // nothing to do in this backend.
  514. }
  515. static SDL_FColor GetDrawCmdColor(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
  516. {
  517. SDL_FColor color = cmd->data.color.color;
  518. if (SDL_RenderingLinearSpace(renderer)) {
  519. SDL_ConvertToLinear(&color);
  520. }
  521. color.r *= cmd->data.color.color_scale;
  522. color.g *= cmd->data.color.color_scale;
  523. color.b *= cmd->data.color.color_scale;
  524. return color;
  525. }
  526. static bool GPU_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
  527. {
  528. float *verts = (float *)SDL_AllocateRenderVertices(renderer, count * 2 * sizeof(float), 0, &cmd->data.draw.first);
  529. if (!verts) {
  530. return false;
  531. }
  532. cmd->data.draw.count = count;
  533. for (int i = 0; i < count; i++) {
  534. *(verts++) = 0.5f + points[i].x;
  535. *(verts++) = 0.5f + points[i].y;
  536. }
  537. return true;
  538. }
  539. static bool GPU_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
  540. const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride,
  541. int num_vertices, const void *indices, int num_indices, int size_indices,
  542. float scale_x, float scale_y)
  543. {
  544. int i;
  545. int count = indices ? num_indices : num_vertices;
  546. float *verts;
  547. size_t sz = 2 * sizeof(float) + 4 * sizeof(float) + (texture ? 2 : 0) * sizeof(float);
  548. bool convert_color = SDL_RenderingLinearSpace(renderer);
  549. verts = (float *)SDL_AllocateRenderVertices(renderer, count * sz, 0, &cmd->data.draw.first);
  550. if (!verts) {
  551. return false;
  552. }
  553. cmd->data.draw.count = count;
  554. size_indices = indices ? size_indices : 0;
  555. for (i = 0; i < count; i++) {
  556. int j;
  557. float *xy_;
  558. SDL_FColor col_;
  559. if (size_indices == 4) {
  560. j = ((const Uint32 *)indices)[i];
  561. } else if (size_indices == 2) {
  562. j = ((const Uint16 *)indices)[i];
  563. } else if (size_indices == 1) {
  564. j = ((const Uint8 *)indices)[i];
  565. } else {
  566. j = i;
  567. }
  568. xy_ = (float *)((char *)xy + j * xy_stride);
  569. *(verts++) = xy_[0] * scale_x;
  570. *(verts++) = xy_[1] * scale_y;
  571. col_ = *(SDL_FColor *)((char *)color + j * color_stride);
  572. if (convert_color) {
  573. SDL_ConvertToLinear(&col_);
  574. }
  575. *(verts++) = col_.r;
  576. *(verts++) = col_.g;
  577. *(verts++) = col_.b;
  578. *(verts++) = col_.a;
  579. if (texture) {
  580. float *uv_ = (float *)((char *)uv + j * uv_stride);
  581. *(verts++) = uv_[0];
  582. *(verts++) = uv_[1];
  583. }
  584. }
  585. return true;
  586. }
  587. static void GPU_InvalidateCachedState(SDL_Renderer *renderer)
  588. {
  589. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  590. data->state.scissor_enabled = false;
  591. }
  592. static SDL_GPURenderPass *RestartRenderPass(GPU_RenderData *data)
  593. {
  594. if (data->state.render_pass) {
  595. SDL_EndGPURenderPass(data->state.render_pass);
  596. }
  597. data->state.render_pass = SDL_BeginGPURenderPass(
  598. data->state.command_buffer, &data->state.color_attachment, 1, NULL);
  599. // *** FIXME ***
  600. // This is busted. We should be able to know which load op to use.
  601. // LOAD is incorrect behavior most of the time, unless we had to break a render pass.
  602. // -cosmonaut
  603. data->state.color_attachment.load_op = SDL_GPU_LOADOP_LOAD;
  604. data->state.scissor_was_enabled = false;
  605. return data->state.render_pass;
  606. }
  607. static void PushVertexUniforms(GPU_RenderData *data, SDL_RenderCommand *cmd)
  608. {
  609. GPU_VertexShaderUniformData uniforms;
  610. SDL_zero(uniforms);
  611. uniforms.mvp.m[0][0] = 2.0f / data->state.viewport.w;
  612. uniforms.mvp.m[1][1] = -2.0f / data->state.viewport.h;
  613. uniforms.mvp.m[2][2] = 1.0f;
  614. uniforms.mvp.m[3][0] = -1.0f;
  615. uniforms.mvp.m[3][1] = 1.0f;
  616. uniforms.mvp.m[3][3] = 1.0f;
  617. uniforms.color = data->state.draw_color;
  618. SDL_PushGPUVertexUniformData(data->state.command_buffer, 0, &uniforms, sizeof(uniforms));
  619. }
  620. static void SetViewportAndScissor(GPU_RenderData *data)
  621. {
  622. SDL_SetGPUViewport(data->state.render_pass, &data->state.viewport);
  623. if (data->state.scissor_enabled) {
  624. SDL_SetGPUScissor(data->state.render_pass, &data->state.scissor);
  625. data->state.scissor_was_enabled = true;
  626. } else if (data->state.scissor_was_enabled) {
  627. SDL_Rect r;
  628. r.x = (int)data->state.viewport.x;
  629. r.y = (int)data->state.viewport.y;
  630. r.w = (int)data->state.viewport.w;
  631. r.h = (int)data->state.viewport.h;
  632. SDL_SetGPUScissor(data->state.render_pass, &r);
  633. data->state.scissor_was_enabled = false;
  634. }
  635. }
  636. static SDL_GPUSampler *GetSampler(GPU_RenderData *data, SDL_PixelFormat format, SDL_ScaleMode scale_mode, SDL_TextureAddressMode address_u, SDL_TextureAddressMode address_v)
  637. {
  638. Uint32 key = RENDER_SAMPLER_HASHKEY(scale_mode, address_u, address_v);
  639. SDL_assert(key < SDL_arraysize(data->samplers));
  640. if (!data->samplers[key]) {
  641. SDL_GPUSamplerCreateInfo sci;
  642. SDL_zero(sci);
  643. switch (scale_mode) {
  644. case SDL_SCALEMODE_NEAREST:
  645. sci.min_filter = SDL_GPU_FILTER_NEAREST;
  646. sci.mag_filter = SDL_GPU_FILTER_NEAREST;
  647. sci.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
  648. break;
  649. case SDL_SCALEMODE_PIXELART: // Uses linear sampling
  650. case SDL_SCALEMODE_LINEAR:
  651. if (format == SDL_PIXELFORMAT_INDEX8) {
  652. // We'll do linear sampling in the shader
  653. sci.min_filter = SDL_GPU_FILTER_NEAREST;
  654. sci.mag_filter = SDL_GPU_FILTER_NEAREST;
  655. sci.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_NEAREST;
  656. } else {
  657. sci.min_filter = SDL_GPU_FILTER_LINEAR;
  658. sci.mag_filter = SDL_GPU_FILTER_LINEAR;
  659. sci.mipmap_mode = SDL_GPU_SAMPLERMIPMAPMODE_LINEAR;
  660. }
  661. break;
  662. default:
  663. SDL_SetError("Unknown scale mode: %d", scale_mode);
  664. return NULL;
  665. }
  666. switch (address_u) {
  667. case SDL_TEXTURE_ADDRESS_CLAMP:
  668. sci.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
  669. break;
  670. case SDL_TEXTURE_ADDRESS_WRAP:
  671. sci.address_mode_u = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
  672. break;
  673. default:
  674. SDL_SetError("Unknown texture address mode: %d", address_u);
  675. return NULL;
  676. }
  677. switch (address_v) {
  678. case SDL_TEXTURE_ADDRESS_CLAMP:
  679. sci.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
  680. break;
  681. case SDL_TEXTURE_ADDRESS_WRAP:
  682. sci.address_mode_v = SDL_GPU_SAMPLERADDRESSMODE_REPEAT;
  683. break;
  684. default:
  685. SDL_SetError("Unknown texture address mode: %d", address_v);
  686. return NULL;
  687. }
  688. sci.address_mode_w = SDL_GPU_SAMPLERADDRESSMODE_CLAMP_TO_EDGE;
  689. data->samplers[key] = SDL_CreateGPUSampler(data->device, &sci);
  690. }
  691. return data->samplers[key];
  692. }
  693. static void CalculateAdvancedShaderConstants(SDL_Renderer *renderer, const SDL_RenderCommand *cmd, const SDL_Texture *texture, GPU_AdvancedFragmentShaderUniformData *constants)
  694. {
  695. float output_headroom;
  696. SDL_zerop(constants);
  697. constants->scRGB_output = (float)SDL_RenderingLinearSpace(renderer);
  698. constants->color_scale = cmd->data.draw.color_scale;
  699. switch (texture->format) {
  700. case SDL_PIXELFORMAT_INDEX8:
  701. switch (cmd->data.draw.texture_scale_mode) {
  702. case SDL_SCALEMODE_NEAREST:
  703. constants->texture_type = TEXTURETYPE_PALETTE_NEAREST;
  704. break;
  705. case SDL_SCALEMODE_LINEAR:
  706. constants->texture_type = TEXTURETYPE_PALETTE_LINEAR;
  707. break;
  708. case SDL_SCALEMODE_PIXELART:
  709. constants->texture_type = TEXTURETYPE_PALETTE_PIXELART;
  710. break;
  711. default:
  712. SDL_assert(!"Unknown scale mode");
  713. break;
  714. }
  715. break;
  716. case SDL_PIXELFORMAT_YV12:
  717. case SDL_PIXELFORMAT_IYUV:
  718. constants->texture_type = TEXTURETYPE_YUV;
  719. constants->input_type = INPUTTYPE_SRGB;
  720. break;
  721. case SDL_PIXELFORMAT_NV12:
  722. constants->texture_type = TEXTURETYPE_NV12;
  723. constants->input_type = INPUTTYPE_SRGB;
  724. break;
  725. case SDL_PIXELFORMAT_NV21:
  726. constants->texture_type = TEXTURETYPE_NV21;
  727. constants->input_type = INPUTTYPE_SRGB;
  728. break;
  729. case SDL_PIXELFORMAT_P010:
  730. constants->texture_type = TEXTURETYPE_NV12;
  731. constants->input_type = INPUTTYPE_HDR10;
  732. break;
  733. default:
  734. switch (texture->format) {
  735. case SDL_PIXELFORMAT_BGRX32:
  736. case SDL_PIXELFORMAT_RGBX32:
  737. if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) {
  738. constants->texture_type = TEXTURETYPE_RGB_PIXELART;
  739. } else {
  740. constants->texture_type = TEXTURETYPE_RGB;
  741. }
  742. break;
  743. default:
  744. if (cmd->data.draw.texture_scale_mode == SDL_SCALEMODE_PIXELART) {
  745. constants->texture_type = TEXTURETYPE_RGBA_PIXELART;
  746. } else {
  747. constants->texture_type = TEXTURETYPE_RGBA;
  748. }
  749. break;
  750. }
  751. if (texture->colorspace == SDL_COLORSPACE_SRGB_LINEAR) {
  752. constants->input_type = INPUTTYPE_SCRGB;
  753. } else if (texture->colorspace == SDL_COLORSPACE_HDR10) {
  754. constants->input_type = INPUTTYPE_HDR10;
  755. } else {
  756. // The sampler will convert from sRGB to linear on load if working in linear colorspace
  757. constants->input_type = INPUTTYPE_UNSPECIFIED;
  758. }
  759. break;
  760. }
  761. if (constants->texture_type == TEXTURETYPE_PALETTE_LINEAR ||
  762. constants->texture_type == TEXTURETYPE_PALETTE_PIXELART ||
  763. constants->texture_type == TEXTURETYPE_RGB_PIXELART ||
  764. constants->texture_type == TEXTURETYPE_RGBA_PIXELART) {
  765. constants->texture_width = texture->w;
  766. constants->texture_height = texture->h;
  767. constants->texel_width = 1.0f / constants->texture_width;
  768. constants->texel_height = 1.0f / constants->texture_height;
  769. }
  770. constants->sdr_white_point = texture->SDR_white_point;
  771. if (renderer->target) {
  772. output_headroom = renderer->target->HDR_headroom;
  773. } else {
  774. output_headroom = renderer->HDR_headroom;
  775. }
  776. if (texture->HDR_headroom > output_headroom) {
  777. constants->tonemap_method = TONEMAP_CHROME;
  778. constants->tonemap_factor1 = (output_headroom / (texture->HDR_headroom * texture->HDR_headroom));
  779. constants->tonemap_factor2 = (1.0f / output_headroom);
  780. }
  781. #ifdef SDL_HAVE_YUV
  782. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  783. if (data->yuv || data->nv12) {
  784. SDL_memcpy(constants->YCbCr_matrix, data->YCbCr_matrix, sizeof(constants->YCbCr_matrix));
  785. }
  786. #endif
  787. }
  788. static void Draw(
  789. GPU_RenderData *data, SDL_RenderCommand *cmd,
  790. Uint32 num_verts,
  791. Uint32 offset,
  792. SDL_GPUPrimitiveType prim)
  793. {
  794. if (!data->state.render_pass || data->state.color_attachment.load_op == SDL_GPU_LOADOP_CLEAR) {
  795. RestartRenderPass(data);
  796. }
  797. SDL_GPURenderPass *pass = data->state.render_pass;
  798. SDL_GPURenderState *custom_state = cmd->data.draw.gpu_render_state;
  799. SDL_GPUShader *custom_frag_shader = custom_state ? custom_state->fragment_shader : NULL;
  800. GPU_VertexShaderID v_shader;
  801. GPU_FragmentShaderID f_shader;
  802. GPU_SimpleFragmentShaderUniformData simple_constants = { cmd->data.draw.color_scale };
  803. GPU_AdvancedFragmentShaderUniformData advanced_constants;
  804. if (prim == SDL_GPU_PRIMITIVETYPE_TRIANGLELIST) {
  805. SDL_Texture *texture = cmd->data.draw.texture;
  806. if (texture) {
  807. v_shader = VERT_SHADER_TRI_TEXTURE;
  808. CalculateAdvancedShaderConstants(texture->renderer, cmd, texture, &advanced_constants);
  809. if ((advanced_constants.texture_type == TEXTURETYPE_RGB ||
  810. advanced_constants.texture_type == TEXTURETYPE_RGBA) &&
  811. advanced_constants.input_type == INPUTTYPE_UNSPECIFIED &&
  812. advanced_constants.tonemap_method == TONEMAP_NONE) {
  813. if (texture->format == SDL_PIXELFORMAT_RGBA32 || texture->format == SDL_PIXELFORMAT_BGRA32) {
  814. f_shader = FRAG_SHADER_TEXTURE_RGBA;
  815. } else {
  816. f_shader = FRAG_SHADER_TEXTURE_RGB;
  817. }
  818. } else {
  819. f_shader = FRAG_SHADER_TEXTURE_ADVANCED;
  820. }
  821. } else {
  822. v_shader = VERT_SHADER_TRI_COLOR;
  823. f_shader = FRAG_SHADER_COLOR;
  824. }
  825. } else {
  826. v_shader = VERT_SHADER_LINEPOINT;
  827. f_shader = FRAG_SHADER_COLOR;
  828. }
  829. if (custom_frag_shader) {
  830. f_shader = FRAG_SHADER_TEXTURE_CUSTOM;
  831. data->shaders.frag_shaders[FRAG_SHADER_TEXTURE_CUSTOM] = custom_frag_shader;
  832. }
  833. GPU_PipelineParameters pipe_params;
  834. SDL_zero(pipe_params);
  835. pipe_params.blend_mode = cmd->data.draw.blend;
  836. pipe_params.vert_shader = v_shader;
  837. pipe_params.frag_shader = f_shader;
  838. pipe_params.primitive_type = prim;
  839. pipe_params.custom_frag_shader = custom_frag_shader;
  840. if (data->state.render_target) {
  841. pipe_params.attachment_format = ((GPU_TextureData *)data->state.render_target->internal)->format;
  842. } else {
  843. pipe_params.attachment_format = data->backbuffer.format;
  844. }
  845. SDL_GPUGraphicsPipeline *pipe = GPU_GetPipeline(&data->pipeline_cache, &data->shaders, data->device, &pipe_params);
  846. if (!pipe) {
  847. return;
  848. }
  849. SDL_BindGPUGraphicsPipeline(pass, pipe);
  850. Uint32 sampler_slot = 0;
  851. if (cmd->data.draw.texture) {
  852. SDL_Texture *texture = cmd->data.draw.texture;
  853. GPU_TextureData *tdata = (GPU_TextureData *)texture->internal;
  854. SDL_GPUTextureSamplerBinding sampler_bind;
  855. SDL_zero(sampler_bind);
  856. sampler_bind.sampler = GetSampler(data, texture->format, cmd->data.draw.texture_scale_mode, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v);
  857. sampler_bind.texture = tdata->texture;
  858. SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
  859. if (f_shader == FRAG_SHADER_TEXTURE_ADVANCED) {
  860. if (texture->palette) {
  861. GPU_PaletteData *palette = (GPU_PaletteData *)texture->palette->internal;
  862. sampler_bind.sampler = GetSampler(data, SDL_PIXELFORMAT_UNKNOWN, SDL_SCALEMODE_NEAREST, SDL_TEXTURE_ADDRESS_CLAMP, SDL_TEXTURE_ADDRESS_CLAMP);
  863. sampler_bind.texture = palette->texture;
  864. SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
  865. #ifdef SDL_HAVE_YUV
  866. } else if (tdata->yuv) {
  867. sampler_bind.texture = tdata->textureU;
  868. SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
  869. sampler_bind.texture = tdata->textureV;
  870. SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
  871. } else if (tdata->nv12) {
  872. sampler_bind.texture = tdata->textureNV;
  873. SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
  874. #endif
  875. }
  876. // We need to fill 3 sampler slots for the advanced shader
  877. while (sampler_slot < 3) {
  878. SDL_BindGPUFragmentSamplers(pass, sampler_slot++, &sampler_bind, 1);
  879. }
  880. }
  881. }
  882. if (custom_state) {
  883. if (custom_state->num_sampler_bindings > 0) {
  884. SDL_BindGPUFragmentSamplers(pass, sampler_slot, custom_state->sampler_bindings, custom_state->num_sampler_bindings);
  885. }
  886. if (custom_state->num_storage_textures > 0) {
  887. SDL_BindGPUFragmentStorageTextures(pass, 0, custom_state->storage_textures, custom_state->num_storage_textures);
  888. }
  889. if (custom_state->num_storage_buffers > 0) {
  890. SDL_BindGPUFragmentStorageBuffers(pass, 0, custom_state->storage_buffers, custom_state->num_storage_buffers);
  891. }
  892. if (custom_state->num_uniform_buffers > 0) {
  893. for (int i = 0; i < custom_state->num_uniform_buffers; i++) {
  894. SDL_GPURenderStateUniformBuffer *ub = &custom_state->uniform_buffers[i];
  895. SDL_PushGPUFragmentUniformData(data->state.command_buffer, ub->slot_index, ub->data, ub->length);
  896. }
  897. }
  898. } else {
  899. if (f_shader == FRAG_SHADER_TEXTURE_ADVANCED) {
  900. SDL_PushGPUFragmentUniformData(data->state.command_buffer, 0, &advanced_constants, sizeof(advanced_constants));
  901. } else {
  902. SDL_PushGPUFragmentUniformData(data->state.command_buffer, 0, &simple_constants, sizeof(simple_constants));
  903. }
  904. }
  905. SDL_GPUBufferBinding buffer_bind;
  906. SDL_zero(buffer_bind);
  907. buffer_bind.buffer = data->vertices.buffer;
  908. buffer_bind.offset = offset;
  909. SDL_BindGPUVertexBuffers(pass, 0, &buffer_bind, 1);
  910. PushVertexUniforms(data, cmd);
  911. SetViewportAndScissor(data);
  912. SDL_DrawGPUPrimitives(pass, num_verts, 1, 0, 0);
  913. }
  914. static void ReleaseVertexBuffer(GPU_RenderData *data)
  915. {
  916. if (data->vertices.buffer) {
  917. SDL_ReleaseGPUBuffer(data->device, data->vertices.buffer);
  918. }
  919. if (data->vertices.transfer_buf) {
  920. SDL_ReleaseGPUTransferBuffer(data->device, data->vertices.transfer_buf);
  921. }
  922. data->vertices.buffer_size = 0;
  923. }
  924. static bool InitVertexBuffer(GPU_RenderData *data, Uint32 size)
  925. {
  926. SDL_GPUBufferCreateInfo bci;
  927. SDL_zero(bci);
  928. bci.size = size;
  929. bci.usage = SDL_GPU_BUFFERUSAGE_VERTEX;
  930. data->vertices.buffer = SDL_CreateGPUBuffer(data->device, &bci);
  931. if (!data->vertices.buffer) {
  932. return false;
  933. }
  934. SDL_GPUTransferBufferCreateInfo tbci;
  935. SDL_zero(tbci);
  936. tbci.size = size;
  937. tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_UPLOAD;
  938. data->vertices.transfer_buf = SDL_CreateGPUTransferBuffer(data->device, &tbci);
  939. if (!data->vertices.transfer_buf) {
  940. return false;
  941. }
  942. data->vertices.buffer_size = size;
  943. return true;
  944. }
  945. static bool UploadVertices(GPU_RenderData *data, void *vertices, size_t vertsize)
  946. {
  947. if (vertsize == 0) {
  948. return true;
  949. }
  950. if (vertsize > data->vertices.buffer_size) {
  951. ReleaseVertexBuffer(data);
  952. if (!InitVertexBuffer(data, (Uint32)vertsize)) {
  953. return false;
  954. }
  955. }
  956. void *staging_buf = SDL_MapGPUTransferBuffer(data->device, data->vertices.transfer_buf, true);
  957. SDL_memcpy(staging_buf, vertices, vertsize);
  958. SDL_UnmapGPUTransferBuffer(data->device, data->vertices.transfer_buf);
  959. SDL_GPUCopyPass *pass = SDL_BeginGPUCopyPass(data->state.command_buffer);
  960. if (!pass) {
  961. return false;
  962. }
  963. SDL_GPUTransferBufferLocation src;
  964. SDL_zero(src);
  965. src.transfer_buffer = data->vertices.transfer_buf;
  966. SDL_GPUBufferRegion dst;
  967. SDL_zero(dst);
  968. dst.buffer = data->vertices.buffer;
  969. dst.size = (Uint32)vertsize;
  970. SDL_UploadToGPUBuffer(pass, &src, &dst, true);
  971. SDL_EndGPUCopyPass(pass);
  972. return true;
  973. }
  974. // *** FIXME ***
  975. // We might be able to run these data uploads on a separate command buffer
  976. // which would allow us to avoid breaking render passes.
  977. // Honestly I'm a little skeptical of this entire approach,
  978. // we already have a command buffer structure
  979. // so it feels weird to be deferring the operations manually.
  980. // We could also fairly easily run the geometry transformations
  981. // on compute shaders instead of the CPU, which would be a HUGE performance win.
  982. // -cosmonaut
  983. static bool GPU_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  984. {
  985. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  986. if (!UploadVertices(data, vertices, vertsize)) {
  987. return false;
  988. }
  989. data->state.color_attachment.load_op = SDL_GPU_LOADOP_LOAD;
  990. if (renderer->target) {
  991. GPU_TextureData *tdata = renderer->target->internal;
  992. data->state.color_attachment.texture = tdata->texture;
  993. } else {
  994. data->state.color_attachment.texture = data->backbuffer.texture;
  995. }
  996. if (!data->state.color_attachment.texture) {
  997. return SDL_SetError("Render target texture is NULL");
  998. }
  999. while (cmd) {
  1000. switch (cmd->command) {
  1001. case SDL_RENDERCMD_SETDRAWCOLOR:
  1002. {
  1003. data->state.draw_color = GetDrawCmdColor(renderer, cmd);
  1004. break;
  1005. }
  1006. case SDL_RENDERCMD_SETVIEWPORT:
  1007. {
  1008. SDL_Rect *viewport = &cmd->data.viewport.rect;
  1009. data->state.viewport.x = viewport->x;
  1010. data->state.viewport.y = viewport->y;
  1011. data->state.viewport.w = viewport->w;
  1012. data->state.viewport.h = viewport->h;
  1013. break;
  1014. }
  1015. case SDL_RENDERCMD_SETCLIPRECT:
  1016. {
  1017. const SDL_Rect *rect = &cmd->data.cliprect.rect;
  1018. data->state.scissor.x = (int)data->state.viewport.x + rect->x;
  1019. data->state.scissor.y = (int)data->state.viewport.y + rect->y;
  1020. data->state.scissor.w = rect->w;
  1021. data->state.scissor.h = rect->h;
  1022. data->state.scissor_enabled = cmd->data.cliprect.enabled;
  1023. break;
  1024. }
  1025. case SDL_RENDERCMD_CLEAR:
  1026. {
  1027. data->state.color_attachment.clear_color = GetDrawCmdColor(renderer, cmd);
  1028. data->state.color_attachment.load_op = SDL_GPU_LOADOP_CLEAR;
  1029. break;
  1030. }
  1031. case SDL_RENDERCMD_FILL_RECTS: // unused
  1032. break;
  1033. case SDL_RENDERCMD_COPY: // unused
  1034. break;
  1035. case SDL_RENDERCMD_COPY_EX: // unused
  1036. break;
  1037. case SDL_RENDERCMD_DRAW_LINES:
  1038. {
  1039. Uint32 count = (Uint32)cmd->data.draw.count;
  1040. Uint32 offset = (Uint32)cmd->data.draw.first;
  1041. if (count > 2) {
  1042. // joined lines cannot be grouped
  1043. Draw(data, cmd, count, offset, SDL_GPU_PRIMITIVETYPE_LINESTRIP);
  1044. } else {
  1045. // let's group non joined lines
  1046. SDL_RenderCommand *finalcmd = cmd;
  1047. SDL_RenderCommand *nextcmd = cmd->next;
  1048. SDL_BlendMode thisblend = cmd->data.draw.blend;
  1049. while (nextcmd) {
  1050. const SDL_RenderCommandType nextcmdtype = nextcmd->command;
  1051. if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) {
  1052. break; // can't go any further on this draw call, different render command up next.
  1053. } else if (nextcmd->data.draw.count != 2) {
  1054. break; // can't go any further on this draw call, those are joined lines
  1055. } else if (nextcmd->data.draw.blend != thisblend) {
  1056. break; // can't go any further on this draw call, different blendmode copy up next.
  1057. } else {
  1058. finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
  1059. count += (Uint32)nextcmd->data.draw.count;
  1060. }
  1061. nextcmd = nextcmd->next;
  1062. }
  1063. Draw(data, cmd, count, offset, SDL_GPU_PRIMITIVETYPE_LINELIST);
  1064. cmd = finalcmd; // skip any copy commands we just combined in here.
  1065. }
  1066. break;
  1067. }
  1068. case SDL_RENDERCMD_DRAW_POINTS:
  1069. case SDL_RENDERCMD_GEOMETRY:
  1070. {
  1071. /* as long as we have the same copy command in a row, with the
  1072. same texture, we can combine them all into a single draw call. */
  1073. SDL_Texture *thistexture = cmd->data.draw.texture;
  1074. SDL_BlendMode thisblend = cmd->data.draw.blend;
  1075. SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode;
  1076. SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u;
  1077. SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v;
  1078. const SDL_RenderCommandType thiscmdtype = cmd->command;
  1079. SDL_RenderCommand *finalcmd = cmd;
  1080. SDL_RenderCommand *nextcmd = cmd->next;
  1081. Uint32 count = (Uint32)cmd->data.draw.count;
  1082. Uint32 offset = (Uint32)cmd->data.draw.first;
  1083. while (nextcmd) {
  1084. const SDL_RenderCommandType nextcmdtype = nextcmd->command;
  1085. if (nextcmdtype != thiscmdtype) {
  1086. break; // can't go any further on this draw call, different render command up next.
  1087. } else if (nextcmd->data.draw.texture != thistexture ||
  1088. nextcmd->data.draw.texture_scale_mode != thisscalemode ||
  1089. nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u ||
  1090. nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v ||
  1091. nextcmd->data.draw.blend != thisblend) {
  1092. // FIXME should we check address mode too?
  1093. break; // can't go any further on this draw call, different texture/blendmode copy up next.
  1094. } else {
  1095. finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
  1096. count += (Uint32)nextcmd->data.draw.count;
  1097. }
  1098. nextcmd = nextcmd->next;
  1099. }
  1100. SDL_GPUPrimitiveType prim = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST; // SDL_RENDERCMD_GEOMETRY
  1101. if (thiscmdtype == SDL_RENDERCMD_DRAW_POINTS) {
  1102. prim = SDL_GPU_PRIMITIVETYPE_POINTLIST;
  1103. }
  1104. Draw(data, cmd, count, offset, prim);
  1105. cmd = finalcmd; // skip any copy commands we just combined in here.
  1106. break;
  1107. }
  1108. case SDL_RENDERCMD_NO_OP:
  1109. break;
  1110. }
  1111. cmd = cmd->next;
  1112. }
  1113. if (data->state.color_attachment.load_op == SDL_GPU_LOADOP_CLEAR) {
  1114. RestartRenderPass(data);
  1115. }
  1116. if (data->state.render_pass) {
  1117. SDL_EndGPURenderPass(data->state.render_pass);
  1118. data->state.render_pass = NULL;
  1119. }
  1120. return true;
  1121. }
  1122. static SDL_Surface *GPU_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
  1123. {
  1124. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  1125. SDL_GPUTexture *gpu_tex;
  1126. SDL_PixelFormat pixfmt;
  1127. if (data->state.render_target) {
  1128. SDL_Texture *texture = data->state.render_target;
  1129. GPU_TextureData *texdata = texture->internal;
  1130. gpu_tex = texdata->texture;
  1131. pixfmt = texture->format;
  1132. } else {
  1133. gpu_tex = data->backbuffer.texture;
  1134. pixfmt = SDL_GetPixelFormatFromGPUTextureFormat(data->backbuffer.format);
  1135. if (pixfmt == SDL_PIXELFORMAT_UNKNOWN) {
  1136. SDL_SetError("Unsupported backbuffer format");
  1137. return NULL;
  1138. }
  1139. }
  1140. Uint32 bpp = SDL_BYTESPERPIXEL(pixfmt);
  1141. size_t row_size, image_size;
  1142. if (!SDL_size_mul_check_overflow(rect->w, bpp, &row_size) ||
  1143. !SDL_size_mul_check_overflow(rect->h, row_size, &image_size)) {
  1144. SDL_SetError("read size overflow");
  1145. return NULL;
  1146. }
  1147. SDL_Surface *surface = SDL_CreateSurface(rect->w, rect->h, pixfmt);
  1148. if (!surface) {
  1149. return NULL;
  1150. }
  1151. SDL_GPUTransferBufferCreateInfo tbci;
  1152. SDL_zero(tbci);
  1153. tbci.size = (Uint32)image_size;
  1154. tbci.usage = SDL_GPU_TRANSFERBUFFERUSAGE_DOWNLOAD;
  1155. SDL_GPUTransferBuffer *tbuf = SDL_CreateGPUTransferBuffer(data->device, &tbci);
  1156. if (!tbuf) {
  1157. return NULL;
  1158. }
  1159. SDL_GPUCopyPass *pass = SDL_BeginGPUCopyPass(data->state.command_buffer);
  1160. SDL_GPUTextureRegion src;
  1161. SDL_zero(src);
  1162. src.texture = gpu_tex;
  1163. src.x = rect->x;
  1164. src.y = rect->y;
  1165. src.w = rect->w;
  1166. src.h = rect->h;
  1167. src.d = 1;
  1168. SDL_GPUTextureTransferInfo dst;
  1169. SDL_zero(dst);
  1170. dst.transfer_buffer = tbuf;
  1171. dst.rows_per_layer = rect->h;
  1172. dst.pixels_per_row = rect->w;
  1173. SDL_DownloadFromGPUTexture(pass, &src, &dst);
  1174. SDL_EndGPUCopyPass(pass);
  1175. SDL_GPUFence *fence = SDL_SubmitGPUCommandBufferAndAcquireFence(data->state.command_buffer);
  1176. SDL_WaitForGPUFences(data->device, true, &fence, 1);
  1177. SDL_ReleaseGPUFence(data->device, fence);
  1178. data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device);
  1179. void *mapped_tbuf = SDL_MapGPUTransferBuffer(data->device, tbuf, false);
  1180. if ((size_t)surface->pitch == row_size) {
  1181. SDL_memcpy(surface->pixels, mapped_tbuf, image_size);
  1182. } else {
  1183. Uint8 *input = mapped_tbuf;
  1184. Uint8 *output = surface->pixels;
  1185. for (int row = 0; row < rect->h; ++row) {
  1186. SDL_memcpy(output, input, row_size);
  1187. output += surface->pitch;
  1188. input += row_size;
  1189. }
  1190. }
  1191. SDL_UnmapGPUTransferBuffer(data->device, tbuf);
  1192. SDL_ReleaseGPUTransferBuffer(data->device, tbuf);
  1193. return surface;
  1194. }
  1195. static bool CreateBackbuffer(GPU_RenderData *data, Uint32 w, Uint32 h, SDL_GPUTextureFormat fmt)
  1196. {
  1197. SDL_GPUTextureCreateInfo tci;
  1198. SDL_zero(tci);
  1199. tci.width = w;
  1200. tci.height = h;
  1201. tci.format = fmt;
  1202. tci.layer_count_or_depth = 1;
  1203. tci.num_levels = 1;
  1204. tci.sample_count = SDL_GPU_SAMPLECOUNT_1;
  1205. tci.usage = SDL_GPU_TEXTUREUSAGE_COLOR_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER;
  1206. data->backbuffer.texture = SDL_CreateGPUTexture(data->device, &tci);
  1207. data->backbuffer.width = w;
  1208. data->backbuffer.height = h;
  1209. data->backbuffer.format = fmt;
  1210. if (!data->backbuffer.texture) {
  1211. return false;
  1212. }
  1213. return true;
  1214. }
  1215. static bool GPU_RenderPresent(SDL_Renderer *renderer)
  1216. {
  1217. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  1218. if (renderer->window) {
  1219. SDL_GPUTexture *swapchain;
  1220. Uint32 swapchain_texture_width, swapchain_texture_height;
  1221. bool result = SDL_WaitAndAcquireGPUSwapchainTexture(data->state.command_buffer, renderer->window, &swapchain, &swapchain_texture_width, &swapchain_texture_height);
  1222. if (!result) {
  1223. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Failed to acquire swapchain texture: %s", SDL_GetError());
  1224. }
  1225. if (swapchain != NULL) {
  1226. SDL_GPUBlitInfo blit_info;
  1227. SDL_zero(blit_info);
  1228. blit_info.source.texture = data->backbuffer.texture;
  1229. blit_info.source.w = data->backbuffer.width;
  1230. blit_info.source.h = data->backbuffer.height;
  1231. blit_info.destination.texture = swapchain;
  1232. blit_info.destination.w = swapchain_texture_width;
  1233. blit_info.destination.h = swapchain_texture_height;
  1234. blit_info.load_op = SDL_GPU_LOADOP_DONT_CARE;
  1235. blit_info.filter = SDL_GPU_FILTER_LINEAR;
  1236. SDL_BlitGPUTexture(data->state.command_buffer, &blit_info);
  1237. SDL_SubmitGPUCommandBuffer(data->state.command_buffer);
  1238. if (swapchain_texture_width != data->backbuffer.width || swapchain_texture_height != data->backbuffer.height) {
  1239. CreateBackbuffer(data, swapchain_texture_width, swapchain_texture_height, SDL_GetGPUSwapchainTextureFormat(data->device, renderer->window));
  1240. }
  1241. } else {
  1242. SDL_SubmitGPUCommandBuffer(data->state.command_buffer);
  1243. }
  1244. } else {
  1245. SDL_SubmitGPUCommandBuffer(data->state.command_buffer);
  1246. }
  1247. data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device);
  1248. return true;
  1249. }
  1250. static void GPU_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  1251. {
  1252. GPU_RenderData *renderdata = (GPU_RenderData *)renderer->internal;
  1253. GPU_TextureData *data = (GPU_TextureData *)texture->internal;
  1254. if (renderdata->state.render_target == texture) {
  1255. renderdata->state.render_target = NULL;
  1256. }
  1257. if (!data) {
  1258. return;
  1259. }
  1260. SDL_ReleaseGPUTexture(renderdata->device, data->texture);
  1261. #ifdef SDL_HAVE_YUV
  1262. SDL_ReleaseGPUTexture(renderdata->device, data->textureU);
  1263. SDL_ReleaseGPUTexture(renderdata->device, data->textureV);
  1264. SDL_ReleaseGPUTexture(renderdata->device, data->textureNV);
  1265. #endif
  1266. SDL_free(data->pixels);
  1267. SDL_free(data);
  1268. texture->internal = NULL;
  1269. }
  1270. static void GPU_DestroyRenderer(SDL_Renderer *renderer)
  1271. {
  1272. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  1273. if (!data) {
  1274. return;
  1275. }
  1276. if (data->state.command_buffer) {
  1277. SDL_CancelGPUCommandBuffer(data->state.command_buffer);
  1278. data->state.command_buffer = NULL;
  1279. }
  1280. for (Uint32 i = 0; i < SDL_arraysize(data->samplers); ++i) {
  1281. if (data->samplers[i]) {
  1282. SDL_ReleaseGPUSampler(data->device, data->samplers[i]);
  1283. }
  1284. }
  1285. if (data->backbuffer.texture) {
  1286. SDL_ReleaseGPUTexture(data->device, data->backbuffer.texture);
  1287. }
  1288. if (renderer->window && data->device) {
  1289. SDL_ReleaseWindowFromGPUDevice(data->device, renderer->window);
  1290. }
  1291. ReleaseVertexBuffer(data);
  1292. GPU_DestroyPipelineCache(&data->pipeline_cache);
  1293. if (data->device) {
  1294. GPU_ReleaseShaders(&data->shaders, data->device);
  1295. if (!data->external_device) {
  1296. SDL_DestroyGPUDevice(data->device);
  1297. }
  1298. }
  1299. SDL_free(data);
  1300. }
  1301. static bool ChoosePresentMode(SDL_GPUDevice *device, SDL_Window *window, const int vsync, SDL_GPUPresentMode *out_mode)
  1302. {
  1303. SDL_GPUPresentMode mode;
  1304. switch (vsync) {
  1305. case 0:
  1306. mode = SDL_GPU_PRESENTMODE_MAILBOX;
  1307. if (!SDL_WindowSupportsGPUPresentMode(device, window, mode)) {
  1308. mode = SDL_GPU_PRESENTMODE_IMMEDIATE;
  1309. if (!SDL_WindowSupportsGPUPresentMode(device, window, mode)) {
  1310. mode = SDL_GPU_PRESENTMODE_VSYNC;
  1311. }
  1312. }
  1313. // FIXME should we return an error if both mailbox and immediate fail?
  1314. break;
  1315. case 1:
  1316. mode = SDL_GPU_PRESENTMODE_VSYNC;
  1317. break;
  1318. default:
  1319. return SDL_Unsupported();
  1320. }
  1321. *out_mode = mode;
  1322. return true;
  1323. }
  1324. static bool GPU_SetVSync(SDL_Renderer *renderer, const int vsync)
  1325. {
  1326. GPU_RenderData *data = (GPU_RenderData *)renderer->internal;
  1327. SDL_GPUPresentMode mode = SDL_GPU_PRESENTMODE_VSYNC;
  1328. if (!renderer->window) {
  1329. if (!vsync) {
  1330. return true;
  1331. } else {
  1332. return SDL_Unsupported();
  1333. }
  1334. }
  1335. if (!ChoosePresentMode(data->device, renderer->window, vsync, &mode)) {
  1336. return false;
  1337. }
  1338. if (mode != data->swapchain.present_mode) {
  1339. // XXX returns bool instead of SDL-style error code
  1340. if (SDL_SetGPUSwapchainParameters(data->device, renderer->window, data->swapchain.composition, mode)) {
  1341. data->swapchain.present_mode = mode;
  1342. return true;
  1343. } else {
  1344. return false;
  1345. }
  1346. }
  1347. return true;
  1348. }
  1349. static bool GPU_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
  1350. {
  1351. GPU_RenderData *data = NULL;
  1352. SDL_SetupRendererColorspace(renderer, create_props);
  1353. if (renderer->output_colorspace != SDL_COLORSPACE_SRGB &&
  1354. renderer->output_colorspace != SDL_COLORSPACE_SRGB_LINEAR
  1355. /*&& renderer->output_colorspace != SDL_COLORSPACE_HDR10*/) {
  1356. return SDL_SetError("Unsupported output colorspace");
  1357. }
  1358. data = (GPU_RenderData *)SDL_calloc(1, sizeof(*data));
  1359. if (!data) {
  1360. return false;
  1361. }
  1362. renderer->SupportsBlendMode = GPU_SupportsBlendMode;
  1363. renderer->CreatePalette = GPU_CreatePalette;
  1364. renderer->UpdatePalette = GPU_UpdatePalette;
  1365. renderer->DestroyPalette = GPU_DestroyPalette;
  1366. renderer->CreateTexture = GPU_CreateTexture;
  1367. renderer->UpdateTexture = GPU_UpdateTexture;
  1368. #ifdef SDL_HAVE_YUV
  1369. renderer->UpdateTextureYUV = GPU_UpdateTextureYUV;
  1370. renderer->UpdateTextureNV = GPU_UpdateTextureNV;
  1371. #endif
  1372. renderer->LockTexture = GPU_LockTexture;
  1373. renderer->UnlockTexture = GPU_UnlockTexture;
  1374. renderer->SetRenderTarget = GPU_SetRenderTarget;
  1375. renderer->QueueSetViewport = GPU_QueueNoOp;
  1376. renderer->QueueSetDrawColor = GPU_QueueNoOp;
  1377. renderer->QueueDrawPoints = GPU_QueueDrawPoints;
  1378. renderer->QueueDrawLines = GPU_QueueDrawPoints; // lines and points queue vertices the same way.
  1379. renderer->QueueGeometry = GPU_QueueGeometry;
  1380. renderer->InvalidateCachedState = GPU_InvalidateCachedState;
  1381. renderer->RunCommandQueue = GPU_RunCommandQueue;
  1382. renderer->RenderReadPixels = GPU_RenderReadPixels;
  1383. renderer->RenderPresent = GPU_RenderPresent;
  1384. renderer->DestroyTexture = GPU_DestroyTexture;
  1385. renderer->DestroyRenderer = GPU_DestroyRenderer;
  1386. renderer->SetVSync = GPU_SetVSync;
  1387. renderer->internal = data;
  1388. renderer->window = window;
  1389. renderer->name = GPU_RenderDriver.name;
  1390. data->device = SDL_GetPointerProperty(create_props, SDL_PROP_RENDERER_CREATE_GPU_DEVICE_POINTER, NULL);
  1391. if (data->device) {
  1392. data->external_device = true;
  1393. } else {
  1394. bool debug = SDL_GetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, false);
  1395. bool lowpower = SDL_GetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, false);
  1396. // Prefer environment variables/hints if they exist, otherwise defer to properties
  1397. debug = SDL_GetHintBoolean(SDL_HINT_RENDER_GPU_DEBUG, debug);
  1398. lowpower = SDL_GetHintBoolean(SDL_HINT_RENDER_GPU_LOW_POWER, lowpower);
  1399. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOLEAN, debug);
  1400. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOLEAN, lowpower);
  1401. // Set hints for the greatest hardware compatibility
  1402. // This property allows using the renderer on Intel Haswell and Broadwell GPUs.
  1403. if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN)) {
  1404. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_D3D12_ALLOW_FEWER_RESOURCE_SLOTS_BOOLEAN, true);
  1405. }
  1406. // These properties allow using the renderer on more Android devices.
  1407. if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN)) {
  1408. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_CLIP_DISTANCE_BOOLEAN, false);
  1409. }
  1410. if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN)) {
  1411. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_DEPTH_CLAMPING_BOOLEAN, false);
  1412. }
  1413. if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN)) {
  1414. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_INDIRECT_DRAW_FIRST_INSTANCE_BOOLEAN, false);
  1415. }
  1416. if (!SDL_HasProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN)) {
  1417. SDL_SetBooleanProperty(create_props, SDL_PROP_GPU_DEVICE_CREATE_FEATURE_ANISOTROPY_BOOLEAN, false);
  1418. }
  1419. GPU_FillSupportedShaderFormats(create_props);
  1420. data->device = SDL_CreateGPUDeviceWithProperties(create_props);
  1421. if (!data->device) {
  1422. return false;
  1423. }
  1424. }
  1425. if (!GPU_InitShaders(&data->shaders, data->device)) {
  1426. return false;
  1427. }
  1428. if (!GPU_InitPipelineCache(&data->pipeline_cache, data->device)) {
  1429. return false;
  1430. }
  1431. // FIXME: What's a good initial size?
  1432. if (!InitVertexBuffer(data, 1 << 16)) {
  1433. return false;
  1434. }
  1435. if (window) {
  1436. if (!SDL_ClaimWindowForGPUDevice(data->device, window)) {
  1437. return false;
  1438. }
  1439. switch (renderer->output_colorspace) {
  1440. case SDL_COLORSPACE_SRGB_LINEAR:
  1441. data->swapchain.composition = SDL_GPU_SWAPCHAINCOMPOSITION_HDR_EXTENDED_LINEAR;
  1442. break;
  1443. case SDL_COLORSPACE_HDR10:
  1444. data->swapchain.composition = SDL_GPU_SWAPCHAINCOMPOSITION_HDR10_ST2084;
  1445. break;
  1446. case SDL_COLORSPACE_SRGB:
  1447. default:
  1448. data->swapchain.composition = SDL_GPU_SWAPCHAINCOMPOSITION_SDR;
  1449. break;
  1450. }
  1451. data->swapchain.present_mode = SDL_GPU_PRESENTMODE_VSYNC;
  1452. int vsync = (int)SDL_GetNumberProperty(create_props, SDL_PROP_RENDERER_CREATE_PRESENT_VSYNC_NUMBER, 0);
  1453. ChoosePresentMode(data->device, window, vsync, &data->swapchain.present_mode);
  1454. SDL_SetGPUSwapchainParameters(data->device, window, data->swapchain.composition, data->swapchain.present_mode);
  1455. SDL_SetGPUAllowedFramesInFlight(data->device, 1);
  1456. int w, h;
  1457. SDL_GetWindowSizeInPixels(window, &w, &h);
  1458. if (!CreateBackbuffer(data, w, h, SDL_GetGPUSwapchainTextureFormat(data->device, window))) {
  1459. return false;
  1460. }
  1461. }
  1462. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRA32);
  1463. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA32);
  1464. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_BGRX32);
  1465. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBX32);
  1466. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_ABGR2101010);
  1467. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_RGBA64_FLOAT);
  1468. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
  1469. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
  1470. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV);
  1471. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV12);
  1472. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_NV21);
  1473. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P010);
  1474. SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, 16384);
  1475. data->state.draw_color.r = 1.0f;
  1476. data->state.draw_color.g = 1.0f;
  1477. data->state.draw_color.b = 1.0f;
  1478. data->state.draw_color.a = 1.0f;
  1479. data->state.viewport.min_depth = 0;
  1480. data->state.viewport.max_depth = 1;
  1481. data->state.command_buffer = SDL_AcquireGPUCommandBuffer(data->device);
  1482. SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_GPU_DEVICE_POINTER, data->device);
  1483. return true;
  1484. }
  1485. SDL_RenderDriver GPU_RenderDriver = {
  1486. GPU_CreateRenderer, "gpu"
  1487. };
  1488. #endif // SDL_VIDEO_RENDER_GPU