SDL_gpu.c 79 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2024 Sam Lantinga <slouken@libsdl.org>
  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. #include "SDL_sysgpu.h"
  20. // FIXME: This could probably use SDL_ObjectValid
  21. #define CHECK_DEVICE_MAGIC(device, retval) \
  22. if (device == NULL) { \
  23. SDL_SetError("Invalid GPU device"); \
  24. return retval; \
  25. }
  26. #define CHECK_COMMAND_BUFFER \
  27. if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \
  28. SDL_assert_release(!"Command buffer already submitted!"); \
  29. return; \
  30. }
  31. #define CHECK_COMMAND_BUFFER_RETURN_NULL \
  32. if (((CommandBufferCommonHeader *)command_buffer)->submitted) { \
  33. SDL_assert_release(!"Command buffer already submitted!"); \
  34. return NULL; \
  35. }
  36. #define CHECK_ANY_PASS_IN_PROGRESS(msg, retval) \
  37. if ( \
  38. ((CommandBufferCommonHeader *)command_buffer)->render_pass.in_progress || \
  39. ((CommandBufferCommonHeader *)command_buffer)->compute_pass.in_progress || \
  40. ((CommandBufferCommonHeader *)command_buffer)->copy_pass.in_progress) { \
  41. SDL_assert_release(!msg); \
  42. return retval; \
  43. }
  44. #define CHECK_RENDERPASS \
  45. if (!((Pass *)render_pass)->in_progress) { \
  46. SDL_assert_release(!"Render pass not in progress!"); \
  47. return; \
  48. }
  49. #define CHECK_GRAPHICS_PIPELINE_BOUND \
  50. if (!((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->graphics_pipeline_bound) { \
  51. SDL_assert_release(!"Graphics pipeline not bound!"); \
  52. return; \
  53. }
  54. #define CHECK_COMPUTEPASS \
  55. if (!((Pass *)compute_pass)->in_progress) { \
  56. SDL_assert_release(!"Compute pass not in progress!"); \
  57. return; \
  58. }
  59. #define CHECK_COMPUTE_PIPELINE_BOUND \
  60. if (!((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->compute_pipeline_bound) { \
  61. SDL_assert_release(!"Compute pipeline not bound!"); \
  62. return; \
  63. }
  64. #define CHECK_COPYPASS \
  65. if (!((Pass *)copy_pass)->in_progress) { \
  66. SDL_assert_release(!"Copy pass not in progress!"); \
  67. return; \
  68. }
  69. #define CHECK_TEXTUREFORMAT_ENUM_INVALID(enumval, retval) \
  70. if (enumval <= SDL_GPU_TEXTUREFORMAT_INVALID || enumval >= SDL_GPU_TEXTUREFORMAT_MAX_ENUM_VALUE) { \
  71. SDL_assert_release(!"Invalid texture format enum!"); \
  72. return retval; \
  73. }
  74. #define CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(enumval, retval) \
  75. if (enumval <= SDL_GPU_VERTEXELEMENTFORMAT_INVALID || enumval >= SDL_GPU_VERTEXELEMENTFORMAT_MAX_ENUM_VALUE) { \
  76. SDL_assert_release(!"Invalid vertex format enum!"); \
  77. return retval; \
  78. }
  79. #define CHECK_COMPAREOP_ENUM_INVALID(enumval, retval) \
  80. if (enumval <= SDL_GPU_COMPAREOP_INVALID || enumval >= SDL_GPU_COMPAREOP_MAX_ENUM_VALUE) { \
  81. SDL_assert_release(!"Invalid compare op enum!"); \
  82. return retval; \
  83. }
  84. #define CHECK_STENCILOP_ENUM_INVALID(enumval, retval) \
  85. if (enumval <= SDL_GPU_STENCILOP_INVALID || enumval >= SDL_GPU_STENCILOP_MAX_ENUM_VALUE) { \
  86. SDL_assert_release(!"Invalid stencil op enum!"); \
  87. return retval; \
  88. }
  89. #define CHECK_BLENDOP_ENUM_INVALID(enumval, retval) \
  90. if (enumval <= SDL_GPU_BLENDOP_INVALID || enumval >= SDL_GPU_BLENDOP_MAX_ENUM_VALUE) { \
  91. SDL_assert_release(!"Invalid blend op enum!"); \
  92. return retval; \
  93. }
  94. #define CHECK_BLENDFACTOR_ENUM_INVALID(enumval, retval) \
  95. if (enumval <= SDL_GPU_BLENDFACTOR_INVALID || enumval >= SDL_GPU_BLENDFACTOR_MAX_ENUM_VALUE) { \
  96. SDL_assert_release(!"Invalid blend factor enum!"); \
  97. return retval; \
  98. }
  99. #define CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(enumval, retval) \
  100. if (enumval < 0 || enumval >= SDL_GPU_SWAPCHAINCOMPOSITION_MAX_ENUM_VALUE) { \
  101. SDL_assert_release(!"Invalid swapchain composition enum!"); \
  102. return retval; \
  103. }
  104. #define CHECK_PRESENTMODE_ENUM_INVALID(enumval, retval) \
  105. if (enumval < 0 || enumval >= SDL_GPU_PRESENTMODE_MAX_ENUM_VALUE) { \
  106. SDL_assert_release(!"Invalid present mode enum!"); \
  107. return retval; \
  108. }
  109. #define COMMAND_BUFFER_DEVICE \
  110. ((CommandBufferCommonHeader *)command_buffer)->device
  111. #define RENDERPASS_COMMAND_BUFFER \
  112. ((Pass *)render_pass)->command_buffer
  113. #define RENDERPASS_DEVICE \
  114. ((CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER)->device
  115. #define COMPUTEPASS_COMMAND_BUFFER \
  116. ((Pass *)compute_pass)->command_buffer
  117. #define COMPUTEPASS_DEVICE \
  118. ((CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER)->device
  119. #define COPYPASS_COMMAND_BUFFER \
  120. ((Pass *)copy_pass)->command_buffer
  121. #define COPYPASS_DEVICE \
  122. ((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->device
  123. // Drivers
  124. #ifndef SDL_GPU_DISABLED
  125. static const SDL_GPUBootstrap *backends[] = {
  126. #ifdef SDL_GPU_METAL
  127. &MetalDriver,
  128. #endif
  129. #ifdef SDL_GPU_D3D12
  130. &D3D12Driver,
  131. #endif
  132. #ifdef SDL_GPU_VULKAN
  133. &VulkanDriver,
  134. #endif
  135. #ifdef SDL_GPU_D3D11
  136. &D3D11Driver,
  137. #endif
  138. NULL
  139. };
  140. #endif // SDL_GPU_DISABLED
  141. // Internal Utility Functions
  142. SDL_GPUGraphicsPipeline *SDL_GPU_FetchBlitPipeline(
  143. SDL_GPUDevice *device,
  144. SDL_GPUTextureType source_texture_type,
  145. SDL_GPUTextureFormat destination_format,
  146. SDL_GPUShader *blit_vertex_shader,
  147. SDL_GPUShader *blit_from_2d_shader,
  148. SDL_GPUShader *blit_from_2d_array_shader,
  149. SDL_GPUShader *blit_from_3d_shader,
  150. SDL_GPUShader *blit_from_cube_shader,
  151. SDL_GPUShader *blit_from_cube_array_shader,
  152. BlitPipelineCacheEntry **blit_pipelines,
  153. Uint32 *blit_pipeline_count,
  154. Uint32 *blit_pipeline_capacity)
  155. {
  156. SDL_GPUGraphicsPipelineCreateInfo blit_pipeline_create_info;
  157. SDL_GPUColorTargetDescription color_target_desc;
  158. SDL_GPUGraphicsPipeline *pipeline;
  159. if (blit_pipeline_count == NULL) {
  160. // use pre-created, format-agnostic pipelines
  161. return (*blit_pipelines)[source_texture_type].pipeline;
  162. }
  163. for (Uint32 i = 0; i < *blit_pipeline_count; i += 1) {
  164. if ((*blit_pipelines)[i].type == source_texture_type && (*blit_pipelines)[i].format == destination_format) {
  165. return (*blit_pipelines)[i].pipeline;
  166. }
  167. }
  168. // No pipeline found, we'll need to make one!
  169. SDL_zero(blit_pipeline_create_info);
  170. SDL_zero(color_target_desc);
  171. color_target_desc.blend_state.color_write_mask = 0xF;
  172. color_target_desc.format = destination_format;
  173. blit_pipeline_create_info.target_info.color_target_descriptions = &color_target_desc;
  174. blit_pipeline_create_info.target_info.num_color_targets = 1;
  175. blit_pipeline_create_info.target_info.depth_stencil_format = SDL_GPU_TEXTUREFORMAT_D16_UNORM; // arbitrary
  176. blit_pipeline_create_info.target_info.has_depth_stencil_target = false;
  177. blit_pipeline_create_info.vertex_shader = blit_vertex_shader;
  178. if (source_texture_type == SDL_GPU_TEXTURETYPE_CUBE) {
  179. blit_pipeline_create_info.fragment_shader = blit_from_cube_shader;
  180. } else if (source_texture_type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
  181. blit_pipeline_create_info.fragment_shader = blit_from_cube_array_shader;
  182. } else if (source_texture_type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
  183. blit_pipeline_create_info.fragment_shader = blit_from_2d_array_shader;
  184. } else if (source_texture_type == SDL_GPU_TEXTURETYPE_3D) {
  185. blit_pipeline_create_info.fragment_shader = blit_from_3d_shader;
  186. } else {
  187. blit_pipeline_create_info.fragment_shader = blit_from_2d_shader;
  188. }
  189. blit_pipeline_create_info.multisample_state.sample_count = SDL_GPU_SAMPLECOUNT_1;
  190. blit_pipeline_create_info.multisample_state.enable_mask = SDL_FALSE;
  191. blit_pipeline_create_info.primitive_type = SDL_GPU_PRIMITIVETYPE_TRIANGLELIST;
  192. pipeline = SDL_CreateGPUGraphicsPipeline(
  193. device,
  194. &blit_pipeline_create_info);
  195. if (pipeline == NULL) {
  196. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Failed to create graphics pipeline for blit");
  197. return NULL;
  198. }
  199. // Cache the new pipeline
  200. EXPAND_ARRAY_IF_NEEDED(
  201. (*blit_pipelines),
  202. BlitPipelineCacheEntry,
  203. *blit_pipeline_count + 1,
  204. *blit_pipeline_capacity,
  205. *blit_pipeline_capacity * 2)
  206. (*blit_pipelines)[*blit_pipeline_count].pipeline = pipeline;
  207. (*blit_pipelines)[*blit_pipeline_count].type = source_texture_type;
  208. (*blit_pipelines)[*blit_pipeline_count].format = destination_format;
  209. *blit_pipeline_count += 1;
  210. return pipeline;
  211. }
  212. void SDL_GPU_BlitCommon(
  213. SDL_GPUCommandBuffer *command_buffer,
  214. const SDL_GPUBlitInfo *info,
  215. SDL_GPUSampler *blit_linear_sampler,
  216. SDL_GPUSampler *blit_nearest_sampler,
  217. SDL_GPUShader *blit_vertex_shader,
  218. SDL_GPUShader *blit_from_2d_shader,
  219. SDL_GPUShader *blit_from_2d_array_shader,
  220. SDL_GPUShader *blit_from_3d_shader,
  221. SDL_GPUShader *blit_from_cube_shader,
  222. SDL_GPUShader *blit_from_cube_array_shader,
  223. BlitPipelineCacheEntry **blit_pipelines,
  224. Uint32 *blit_pipeline_count,
  225. Uint32 *blit_pipeline_capacity)
  226. {
  227. CommandBufferCommonHeader *cmdbufHeader = (CommandBufferCommonHeader *)command_buffer;
  228. SDL_GPURenderPass *render_pass;
  229. TextureCommonHeader *src_header = (TextureCommonHeader *)info->source.texture;
  230. TextureCommonHeader *dst_header = (TextureCommonHeader *)info->destination.texture;
  231. SDL_GPUGraphicsPipeline *blit_pipeline;
  232. SDL_GPUColorTargetInfo color_target_info;
  233. SDL_GPUViewport viewport;
  234. SDL_GPUTextureSamplerBinding texture_sampler_binding;
  235. BlitFragmentUniforms blit_fragment_uniforms;
  236. Uint32 layer_divisor;
  237. blit_pipeline = SDL_GPU_FetchBlitPipeline(
  238. cmdbufHeader->device,
  239. src_header->info.type,
  240. dst_header->info.format,
  241. blit_vertex_shader,
  242. blit_from_2d_shader,
  243. blit_from_2d_array_shader,
  244. blit_from_3d_shader,
  245. blit_from_cube_shader,
  246. blit_from_cube_array_shader,
  247. blit_pipelines,
  248. blit_pipeline_count,
  249. blit_pipeline_capacity);
  250. if (blit_pipeline == NULL) {
  251. SDL_LogWarn(SDL_LOG_CATEGORY_GPU, "Could not fetch blit pipeline");
  252. return;
  253. }
  254. color_target_info.load_op = info->load_op;
  255. color_target_info.clear_color = info->clear_color;
  256. color_target_info.store_op = SDL_GPU_STOREOP_STORE;
  257. color_target_info.texture = info->destination.texture;
  258. color_target_info.mip_level = info->destination.mip_level;
  259. color_target_info.layer_or_depth_plane = info->destination.layer_or_depth_plane;
  260. color_target_info.cycle = info->cycle;
  261. render_pass = SDL_BeginGPURenderPass(
  262. command_buffer,
  263. &color_target_info,
  264. 1,
  265. NULL);
  266. viewport.x = (float)info->destination.x;
  267. viewport.y = (float)info->destination.y;
  268. viewport.w = (float)info->destination.w;
  269. viewport.h = (float)info->destination.h;
  270. viewport.min_depth = 0;
  271. viewport.max_depth = 1;
  272. SDL_SetGPUViewport(
  273. render_pass,
  274. &viewport);
  275. SDL_BindGPUGraphicsPipeline(
  276. render_pass,
  277. blit_pipeline);
  278. texture_sampler_binding.texture = info->source.texture;
  279. texture_sampler_binding.sampler =
  280. info->filter == SDL_GPU_FILTER_NEAREST ? blit_nearest_sampler : blit_linear_sampler;
  281. SDL_BindGPUFragmentSamplers(
  282. render_pass,
  283. 0,
  284. &texture_sampler_binding,
  285. 1);
  286. blit_fragment_uniforms.left = (float)info->source.x / (src_header->info.width >> info->source.mip_level);
  287. blit_fragment_uniforms.top = (float)info->source.y / (src_header->info.height >> info->source.mip_level);
  288. blit_fragment_uniforms.width = (float)info->source.w / (src_header->info.width >> info->source.mip_level);
  289. blit_fragment_uniforms.height = (float)info->source.h / (src_header->info.height >> info->source.mip_level);
  290. blit_fragment_uniforms.mip_level = info->source.mip_level;
  291. layer_divisor = (src_header->info.type == SDL_GPU_TEXTURETYPE_3D) ? src_header->info.layer_count_or_depth : 1;
  292. blit_fragment_uniforms.layer_or_depth = (float)info->source.layer_or_depth_plane / layer_divisor;
  293. if (info->flip_mode & SDL_FLIP_HORIZONTAL) {
  294. blit_fragment_uniforms.left += blit_fragment_uniforms.width;
  295. blit_fragment_uniforms.width *= -1;
  296. }
  297. if (info->flip_mode & SDL_FLIP_VERTICAL) {
  298. blit_fragment_uniforms.top += blit_fragment_uniforms.height;
  299. blit_fragment_uniforms.height *= -1;
  300. }
  301. SDL_PushGPUFragmentUniformData(
  302. command_buffer,
  303. 0,
  304. &blit_fragment_uniforms,
  305. sizeof(blit_fragment_uniforms));
  306. SDL_DrawGPUPrimitives(render_pass, 3, 1, 0, 0);
  307. SDL_EndGPURenderPass(render_pass);
  308. }
  309. // Driver Functions
  310. #ifndef SDL_GPU_DISABLED
  311. static SDL_GPUDriver SDL_GPUSelectBackend(
  312. SDL_VideoDevice *_this,
  313. const char *gpudriver,
  314. SDL_GPUShaderFormat format_flags)
  315. {
  316. Uint32 i;
  317. // Environment/Properties override...
  318. if (gpudriver != NULL) {
  319. for (i = 0; backends[i]; i += 1) {
  320. if (SDL_strcasecmp(gpudriver, backends[i]->name) == 0) {
  321. if (!(backends[i]->shader_formats & format_flags)) {
  322. SDL_LogError(SDL_LOG_CATEGORY_GPU, "Required shader format for backend %s not provided!", gpudriver);
  323. return SDL_GPU_DRIVER_INVALID;
  324. }
  325. if (backends[i]->PrepareDriver(_this)) {
  326. return backends[i]->backendflag;
  327. }
  328. }
  329. }
  330. SDL_LogError(SDL_LOG_CATEGORY_GPU, "SDL_HINT_GPU_DRIVER %s unsupported!", gpudriver);
  331. return SDL_GPU_DRIVER_INVALID;
  332. }
  333. for (i = 0; backends[i]; i += 1) {
  334. if ((backends[i]->shader_formats & format_flags) == 0) {
  335. // Don't select a backend which doesn't support the app's shaders.
  336. continue;
  337. }
  338. if (backends[i]->PrepareDriver(_this)) {
  339. return backends[i]->backendflag;
  340. }
  341. }
  342. SDL_LogError(SDL_LOG_CATEGORY_GPU, "No supported SDL_GPU backend found!");
  343. return SDL_GPU_DRIVER_INVALID;
  344. }
  345. #endif // SDL_GPU_DISABLED
  346. SDL_GPUDevice *SDL_CreateGPUDevice(
  347. SDL_GPUShaderFormat format_flags,
  348. SDL_bool debug_mode,
  349. const char *name)
  350. {
  351. #ifndef SDL_GPU_DISABLED
  352. SDL_GPUDevice *result;
  353. SDL_PropertiesID props = SDL_CreateProperties();
  354. if (format_flags & SDL_GPU_SHADERFORMAT_PRIVATE) {
  355. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, true);
  356. }
  357. if (format_flags & SDL_GPU_SHADERFORMAT_SPIRV) {
  358. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOL, true);
  359. }
  360. if (format_flags & SDL_GPU_SHADERFORMAT_DXBC) {
  361. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOL, true);
  362. }
  363. if (format_flags & SDL_GPU_SHADERFORMAT_DXIL) {
  364. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOL, true);
  365. }
  366. if (format_flags & SDL_GPU_SHADERFORMAT_MSL) {
  367. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOL, true);
  368. }
  369. if (format_flags & SDL_GPU_SHADERFORMAT_METALLIB) {
  370. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, true);
  371. }
  372. SDL_SetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, debug_mode);
  373. SDL_SetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, name);
  374. result = SDL_CreateGPUDeviceWithProperties(props);
  375. SDL_DestroyProperties(props);
  376. return result;
  377. #else
  378. SDL_SetError("SDL not built with GPU support");
  379. return NULL;
  380. #endif // SDL_GPU_DISABLED
  381. }
  382. SDL_GPUDevice *SDL_CreateGPUDeviceWithProperties(SDL_PropertiesID props)
  383. {
  384. #ifndef SDL_GPU_DISABLED
  385. SDL_GPUShaderFormat format_flags = 0;
  386. bool debug_mode;
  387. bool preferLowPower;
  388. int i;
  389. const char *gpudriver;
  390. SDL_GPUDevice *result = NULL;
  391. SDL_GPUDriver selectedBackend;
  392. SDL_VideoDevice *_this = SDL_GetVideoDevice();
  393. if (_this == NULL) {
  394. SDL_SetError("Video subsystem not initialized");
  395. return NULL;
  396. }
  397. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_PRIVATE_BOOL, false)) {
  398. format_flags |= SDL_GPU_SHADERFORMAT_PRIVATE;
  399. }
  400. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_SPIRV_BOOL, false)) {
  401. format_flags |= SDL_GPU_SHADERFORMAT_SPIRV;
  402. }
  403. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXBC_BOOL, false)) {
  404. format_flags |= SDL_GPU_SHADERFORMAT_DXBC;
  405. }
  406. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_DXIL_BOOL, false)) {
  407. format_flags |= SDL_GPU_SHADERFORMAT_DXIL;
  408. }
  409. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_MSL_BOOL, false)) {
  410. format_flags |= SDL_GPU_SHADERFORMAT_MSL;
  411. }
  412. if (SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_SHADERS_METALLIB_BOOL, false)) {
  413. format_flags |= SDL_GPU_SHADERFORMAT_METALLIB;
  414. }
  415. debug_mode = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_DEBUGMODE_BOOL, true);
  416. preferLowPower = SDL_GetBooleanProperty(props, SDL_PROP_GPU_DEVICE_CREATE_PREFERLOWPOWER_BOOL, false);
  417. gpudriver = SDL_GetHint(SDL_HINT_GPU_DRIVER);
  418. if (gpudriver == NULL) {
  419. gpudriver = SDL_GetStringProperty(props, SDL_PROP_GPU_DEVICE_CREATE_NAME_STRING, NULL);
  420. }
  421. selectedBackend = SDL_GPUSelectBackend(_this, gpudriver, format_flags);
  422. if (selectedBackend != SDL_GPU_DRIVER_INVALID) {
  423. for (i = 0; backends[i]; i += 1) {
  424. if (backends[i]->backendflag == selectedBackend) {
  425. result = backends[i]->CreateDevice(debug_mode, preferLowPower, props);
  426. if (result != NULL) {
  427. result->backend = backends[i]->backendflag;
  428. result->shader_formats = backends[i]->shader_formats;
  429. result->debug_mode = debug_mode;
  430. break;
  431. }
  432. }
  433. }
  434. }
  435. return result;
  436. #else
  437. SDL_SetError("SDL not built with GPU support");
  438. return NULL;
  439. #endif // SDL_GPU_DISABLED
  440. }
  441. void SDL_DestroyGPUDevice(SDL_GPUDevice *device)
  442. {
  443. CHECK_DEVICE_MAGIC(device, );
  444. device->DestroyDevice(device);
  445. }
  446. SDL_GPUDriver SDL_GetGPUDriver(SDL_GPUDevice *device)
  447. {
  448. CHECK_DEVICE_MAGIC(device, SDL_GPU_DRIVER_INVALID);
  449. return device->backend;
  450. }
  451. Uint32 SDL_GPUTextureFormatTexelBlockSize(
  452. SDL_GPUTextureFormat format)
  453. {
  454. switch (format) {
  455. case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM:
  456. case SDL_GPU_TEXTUREFORMAT_BC1_RGBA_UNORM_SRGB:
  457. case SDL_GPU_TEXTUREFORMAT_BC4_R_UNORM:
  458. return 8;
  459. case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM:
  460. case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM:
  461. case SDL_GPU_TEXTUREFORMAT_BC5_RG_UNORM:
  462. case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM:
  463. case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_FLOAT:
  464. case SDL_GPU_TEXTUREFORMAT_BC6H_RGB_UFLOAT:
  465. case SDL_GPU_TEXTUREFORMAT_BC2_RGBA_UNORM_SRGB:
  466. case SDL_GPU_TEXTUREFORMAT_BC3_RGBA_UNORM_SRGB:
  467. case SDL_GPU_TEXTUREFORMAT_BC7_RGBA_UNORM_SRGB:
  468. return 16;
  469. case SDL_GPU_TEXTUREFORMAT_R8_UNORM:
  470. case SDL_GPU_TEXTUREFORMAT_R8_SNORM:
  471. case SDL_GPU_TEXTUREFORMAT_A8_UNORM:
  472. case SDL_GPU_TEXTUREFORMAT_R8_UINT:
  473. return 1;
  474. case SDL_GPU_TEXTUREFORMAT_B5G6R5_UNORM:
  475. case SDL_GPU_TEXTUREFORMAT_B4G4R4A4_UNORM:
  476. case SDL_GPU_TEXTUREFORMAT_B5G5R5A1_UNORM:
  477. case SDL_GPU_TEXTUREFORMAT_R16_FLOAT:
  478. case SDL_GPU_TEXTUREFORMAT_R8G8_SNORM:
  479. case SDL_GPU_TEXTUREFORMAT_R8G8_UNORM:
  480. case SDL_GPU_TEXTUREFORMAT_R8G8_UINT:
  481. case SDL_GPU_TEXTUREFORMAT_R16_UNORM:
  482. case SDL_GPU_TEXTUREFORMAT_R16_SNORM:
  483. case SDL_GPU_TEXTUREFORMAT_R16_UINT:
  484. return 2;
  485. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM:
  486. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM:
  487. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UNORM_SRGB:
  488. case SDL_GPU_TEXTUREFORMAT_B8G8R8A8_UNORM_SRGB:
  489. case SDL_GPU_TEXTUREFORMAT_R32_FLOAT:
  490. case SDL_GPU_TEXTUREFORMAT_R16G16_FLOAT:
  491. case SDL_GPU_TEXTUREFORMAT_R11G11B10_UFLOAT:
  492. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_SNORM:
  493. case SDL_GPU_TEXTUREFORMAT_R10G10B10A2_UNORM:
  494. case SDL_GPU_TEXTUREFORMAT_R8G8B8A8_UINT:
  495. case SDL_GPU_TEXTUREFORMAT_R16G16_UINT:
  496. case SDL_GPU_TEXTUREFORMAT_R16G16_UNORM:
  497. case SDL_GPU_TEXTUREFORMAT_R16G16_SNORM:
  498. return 4;
  499. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_FLOAT:
  500. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UNORM:
  501. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_SNORM:
  502. case SDL_GPU_TEXTUREFORMAT_R32G32_FLOAT:
  503. case SDL_GPU_TEXTUREFORMAT_R16G16B16A16_UINT:
  504. return 8;
  505. case SDL_GPU_TEXTUREFORMAT_R32G32B32A32_FLOAT:
  506. return 16;
  507. default:
  508. SDL_assert_release(!"Unrecognized TextureFormat!");
  509. return 0;
  510. }
  511. }
  512. SDL_bool SDL_GPUTextureSupportsFormat(
  513. SDL_GPUDevice *device,
  514. SDL_GPUTextureFormat format,
  515. SDL_GPUTextureType type,
  516. SDL_GPUTextureUsageFlags usage)
  517. {
  518. CHECK_DEVICE_MAGIC(device, false);
  519. if (device->debug_mode) {
  520. CHECK_TEXTUREFORMAT_ENUM_INVALID(format, false)
  521. }
  522. return device->SupportsTextureFormat(
  523. device->driverData,
  524. format,
  525. type,
  526. usage);
  527. }
  528. SDL_bool SDL_GPUTextureSupportsSampleCount(
  529. SDL_GPUDevice *device,
  530. SDL_GPUTextureFormat format,
  531. SDL_GPUSampleCount sample_count)
  532. {
  533. CHECK_DEVICE_MAGIC(device, 0);
  534. if (device->debug_mode) {
  535. CHECK_TEXTUREFORMAT_ENUM_INVALID(format, 0)
  536. }
  537. return device->SupportsSampleCount(
  538. device->driverData,
  539. format,
  540. sample_count);
  541. }
  542. // State Creation
  543. SDL_GPUComputePipeline *SDL_CreateGPUComputePipeline(
  544. SDL_GPUDevice *device,
  545. const SDL_GPUComputePipelineCreateInfo *createinfo)
  546. {
  547. CHECK_DEVICE_MAGIC(device, NULL);
  548. if (createinfo == NULL) {
  549. SDL_InvalidParamError("createinfo");
  550. return NULL;
  551. }
  552. if (device->debug_mode) {
  553. if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) {
  554. SDL_assert_release(!"Shader format cannot be INVALID!");
  555. return NULL;
  556. }
  557. if (!(createinfo->format & device->shader_formats)) {
  558. SDL_assert_release(!"Incompatible shader format for GPU backend");
  559. return NULL;
  560. }
  561. if (createinfo->num_writeonly_storage_textures > MAX_COMPUTE_WRITE_TEXTURES) {
  562. SDL_assert_release(!"Compute pipeline write-only texture count cannot be higher than 8!");
  563. return NULL;
  564. }
  565. if (createinfo->num_writeonly_storage_buffers > MAX_COMPUTE_WRITE_BUFFERS) {
  566. SDL_assert_release(!"Compute pipeline write-only buffer count cannot be higher than 8!");
  567. return NULL;
  568. }
  569. if (createinfo->threadcount_x == 0 ||
  570. createinfo->threadcount_y == 0 ||
  571. createinfo->threadcount_z == 0) {
  572. SDL_assert_release(!"Compute pipeline threadCount dimensions must be at least 1!");
  573. return NULL;
  574. }
  575. }
  576. return device->CreateComputePipeline(
  577. device->driverData,
  578. createinfo);
  579. }
  580. SDL_GPUGraphicsPipeline *SDL_CreateGPUGraphicsPipeline(
  581. SDL_GPUDevice *device,
  582. const SDL_GPUGraphicsPipelineCreateInfo *graphicsPipelineCreateInfo)
  583. {
  584. CHECK_DEVICE_MAGIC(device, NULL);
  585. if (graphicsPipelineCreateInfo == NULL) {
  586. SDL_InvalidParamError("graphicsPipelineCreateInfo");
  587. return NULL;
  588. }
  589. if (device->debug_mode) {
  590. if (graphicsPipelineCreateInfo->target_info.num_color_targets > 0 && graphicsPipelineCreateInfo->target_info.color_target_descriptions == NULL) {
  591. SDL_assert_release(!"Color target descriptions array pointer cannot be NULL if num_color_targets is greater than zero!");
  592. return NULL;
  593. }
  594. for (Uint32 i = 0; i < graphicsPipelineCreateInfo->target_info.num_color_targets; i += 1) {
  595. CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format, NULL);
  596. if (IsDepthFormat(graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].format)) {
  597. SDL_assert_release(!"Color target formats cannot be a depth format!");
  598. return NULL;
  599. }
  600. if (graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state.enable_blend) {
  601. const SDL_GPUColorTargetBlendState *blend_state = &graphicsPipelineCreateInfo->target_info.color_target_descriptions[i].blend_state;
  602. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_color_blendfactor, NULL)
  603. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_color_blendfactor, NULL)
  604. CHECK_BLENDOP_ENUM_INVALID(blend_state->color_blend_op, NULL)
  605. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->src_alpha_blendfactor, NULL)
  606. CHECK_BLENDFACTOR_ENUM_INVALID(blend_state->dst_alpha_blendfactor, NULL)
  607. CHECK_BLENDOP_ENUM_INVALID(blend_state->alpha_blend_op, NULL)
  608. }
  609. }
  610. if (graphicsPipelineCreateInfo->target_info.has_depth_stencil_target) {
  611. CHECK_TEXTUREFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->target_info.depth_stencil_format, NULL);
  612. if (!IsDepthFormat(graphicsPipelineCreateInfo->target_info.depth_stencil_format)) {
  613. SDL_assert_release(!"Depth-stencil target format must be a depth format!");
  614. return NULL;
  615. }
  616. }
  617. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_buffer_descriptions == NULL) {
  618. SDL_assert_release(!"Vertex buffer descriptions array pointer cannot be NULL!");
  619. return NULL;
  620. }
  621. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_buffers > MAX_VERTEX_BUFFERS) {
  622. SDL_assert_release(!"The number of vertex buffer descriptions in a vertex input state must not exceed 16!");
  623. return NULL;
  624. }
  625. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > 0 && graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes == NULL) {
  626. SDL_assert_release(!"Vertex attributes array pointer cannot be NULL!");
  627. return NULL;
  628. }
  629. if (graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes > MAX_VERTEX_ATTRIBUTES) {
  630. SDL_assert_release(!"The number of vertex attributes in a vertex input state must not exceed 16!");
  631. return NULL;
  632. }
  633. Uint32 locations[MAX_VERTEX_ATTRIBUTES];
  634. for (Uint32 i = 0; i < graphicsPipelineCreateInfo->vertex_input_state.num_vertex_attributes; i += 1) {
  635. CHECK_VERTEXELEMENTFORMAT_ENUM_INVALID(graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].format, NULL);
  636. locations[i] = graphicsPipelineCreateInfo->vertex_input_state.vertex_attributes[i].location;
  637. for (Uint32 j = 0; j < i; j += 1) {
  638. if (locations[j] == locations[i]) {
  639. SDL_assert_release(!"Each vertex attribute location in a vertex input state must be unique!");
  640. }
  641. }
  642. }
  643. if (graphicsPipelineCreateInfo->depth_stencil_state.enable_depth_test) {
  644. CHECK_COMPAREOP_ENUM_INVALID(graphicsPipelineCreateInfo->depth_stencil_state.compare_op, NULL)
  645. }
  646. if (graphicsPipelineCreateInfo->depth_stencil_state.enable_stencil_test) {
  647. const SDL_GPUStencilOpState *stencil_state = &graphicsPipelineCreateInfo->depth_stencil_state.back_stencil_state;
  648. CHECK_COMPAREOP_ENUM_INVALID(stencil_state->compare_op, NULL)
  649. CHECK_STENCILOP_ENUM_INVALID(stencil_state->fail_op, NULL)
  650. CHECK_STENCILOP_ENUM_INVALID(stencil_state->pass_op, NULL)
  651. CHECK_STENCILOP_ENUM_INVALID(stencil_state->depth_fail_op, NULL)
  652. }
  653. }
  654. return device->CreateGraphicsPipeline(
  655. device->driverData,
  656. graphicsPipelineCreateInfo);
  657. }
  658. SDL_GPUSampler *SDL_CreateGPUSampler(
  659. SDL_GPUDevice *device,
  660. const SDL_GPUSamplerCreateInfo *createinfo)
  661. {
  662. CHECK_DEVICE_MAGIC(device, NULL);
  663. if (createinfo == NULL) {
  664. SDL_InvalidParamError("createinfo");
  665. return NULL;
  666. }
  667. return device->CreateSampler(
  668. device->driverData,
  669. createinfo);
  670. }
  671. SDL_GPUShader *SDL_CreateGPUShader(
  672. SDL_GPUDevice *device,
  673. const SDL_GPUShaderCreateInfo *createinfo)
  674. {
  675. CHECK_DEVICE_MAGIC(device, NULL);
  676. if (createinfo == NULL) {
  677. SDL_InvalidParamError("createinfo");
  678. return NULL;
  679. }
  680. if (device->debug_mode) {
  681. if (createinfo->format == SDL_GPU_SHADERFORMAT_INVALID) {
  682. SDL_assert_release(!"Shader format cannot be INVALID!");
  683. return NULL;
  684. }
  685. if (!(createinfo->format & device->shader_formats)) {
  686. SDL_assert_release(!"Incompatible shader format for GPU backend");
  687. return NULL;
  688. }
  689. }
  690. return device->CreateShader(
  691. device->driverData,
  692. createinfo);
  693. }
  694. SDL_GPUTexture *SDL_CreateGPUTexture(
  695. SDL_GPUDevice *device,
  696. const SDL_GPUTextureCreateInfo *createinfo)
  697. {
  698. CHECK_DEVICE_MAGIC(device, NULL);
  699. if (createinfo == NULL) {
  700. SDL_InvalidParamError("createinfo");
  701. return NULL;
  702. }
  703. if (device->debug_mode) {
  704. bool failed = false;
  705. const Uint32 MAX_2D_DIMENSION = 16384;
  706. const Uint32 MAX_3D_DIMENSION = 2048;
  707. // Common checks for all texture types
  708. CHECK_TEXTUREFORMAT_ENUM_INVALID(createinfo->format, NULL)
  709. if (createinfo->width <= 0 || createinfo->height <= 0 || createinfo->layer_count_or_depth <= 0) {
  710. SDL_assert_release(!"For any texture: width, height, and layer_count_or_depth must be >= 1");
  711. failed = true;
  712. }
  713. if (createinfo->num_levels <= 0) {
  714. SDL_assert_release(!"For any texture: num_levels must be >= 1");
  715. failed = true;
  716. }
  717. if ((createinfo->usage & SDL_GPU_TEXTUREUSAGE_GRAPHICS_STORAGE_READ) && (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER)) {
  718. SDL_assert_release(!"For any texture: usage cannot contain both GRAPHICS_STORAGE_READ and SAMPLER");
  719. failed = true;
  720. }
  721. if (IsDepthFormat(createinfo->format) && (createinfo->usage & ~(SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET | SDL_GPU_TEXTUREUSAGE_SAMPLER))) {
  722. SDL_assert_release(!"For depth textures: usage cannot contain any flags except for DEPTH_STENCIL_TARGET and SAMPLER");
  723. failed = true;
  724. }
  725. if (IsIntegerFormat(createinfo->format) && (createinfo->usage & SDL_GPU_TEXTUREUSAGE_SAMPLER)) {
  726. SDL_assert_release(!"For any texture: usage cannot contain SAMPLER for textures with an integer format");
  727. failed = true;
  728. }
  729. if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE) {
  730. // Cubemap validation
  731. if (createinfo->width != createinfo->height) {
  732. SDL_assert_release(!"For cube textures: width and height must be identical");
  733. failed = true;
  734. }
  735. if (createinfo->width > MAX_2D_DIMENSION || createinfo->height > MAX_2D_DIMENSION) {
  736. SDL_assert_release(!"For cube textures: width and height must be <= 16384");
  737. failed = true;
  738. }
  739. if (createinfo->layer_count_or_depth != 6) {
  740. SDL_assert_release(!"For cube textures: layer_count_or_depth must be 6");
  741. failed = true;
  742. }
  743. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  744. SDL_assert_release(!"For cube textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  745. failed = true;
  746. }
  747. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_CUBE, createinfo->usage)) {
  748. SDL_assert_release(!"For cube textures: the format is unsupported for the given usage");
  749. failed = true;
  750. }
  751. } else if (createinfo->type == SDL_GPU_TEXTURETYPE_CUBE_ARRAY) {
  752. // Cubemap array validation
  753. if (createinfo->width != createinfo->height) {
  754. SDL_assert_release(!"For cube array textures: width and height must be identical");
  755. failed = true;
  756. }
  757. if (createinfo->width > MAX_2D_DIMENSION || createinfo->height > MAX_2D_DIMENSION) {
  758. SDL_assert_release(!"For cube array textures: width and height must be <= 16384");
  759. failed = true;
  760. }
  761. if (createinfo->layer_count_or_depth % 6 != 0) {
  762. SDL_assert_release(!"For cube array textures: layer_count_or_depth must be a multiple of 6");
  763. failed = true;
  764. }
  765. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  766. SDL_assert_release(!"For cube array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  767. failed = true;
  768. }
  769. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_CUBE_ARRAY, createinfo->usage)) {
  770. SDL_assert_release(!"For cube array textures: the format is unsupported for the given usage");
  771. failed = true;
  772. }
  773. } else if (createinfo->type == SDL_GPU_TEXTURETYPE_3D) {
  774. // 3D Texture Validation
  775. if (createinfo->width > MAX_3D_DIMENSION || createinfo->height > MAX_3D_DIMENSION || createinfo->layer_count_or_depth > MAX_3D_DIMENSION) {
  776. SDL_assert_release(!"For 3D textures: width, height, and layer_count_or_depth must be <= 2048");
  777. failed = true;
  778. }
  779. if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
  780. SDL_assert_release(!"For 3D textures: usage must not contain DEPTH_STENCIL_TARGET");
  781. failed = true;
  782. }
  783. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  784. SDL_assert_release(!"For 3D textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  785. failed = true;
  786. }
  787. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_3D, createinfo->usage)) {
  788. SDL_assert_release(!"For 3D textures: the format is unsupported for the given usage");
  789. failed = true;
  790. }
  791. } else {
  792. if (createinfo->type == SDL_GPU_TEXTURETYPE_2D_ARRAY) {
  793. // Array Texture Validation
  794. if (createinfo->usage & SDL_GPU_TEXTUREUSAGE_DEPTH_STENCIL_TARGET) {
  795. SDL_assert_release(!"For array textures: usage must not contain DEPTH_STENCIL_TARGET");
  796. failed = true;
  797. }
  798. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1) {
  799. SDL_assert_release(!"For array textures: sample_count must be SDL_GPU_SAMPLECOUNT_1");
  800. failed = true;
  801. }
  802. } else {
  803. // 2D Texture Validation
  804. if (createinfo->sample_count > SDL_GPU_SAMPLECOUNT_1 && createinfo->num_levels > 1) {
  805. SDL_assert_release(!"For 2D textures: if sample_count is >= SDL_GPU_SAMPLECOUNT_1, then num_levels must be 1");
  806. failed = true;
  807. }
  808. }
  809. if (!SDL_GPUTextureSupportsFormat(device, createinfo->format, SDL_GPU_TEXTURETYPE_2D, createinfo->usage)) {
  810. SDL_assert_release(!"For 2D textures: the format is unsupported for the given usage");
  811. failed = true;
  812. }
  813. }
  814. if (failed) {
  815. return NULL;
  816. }
  817. }
  818. return device->CreateTexture(
  819. device->driverData,
  820. createinfo);
  821. }
  822. SDL_GPUBuffer *SDL_CreateGPUBuffer(
  823. SDL_GPUDevice *device,
  824. const SDL_GPUBufferCreateInfo *createinfo)
  825. {
  826. CHECK_DEVICE_MAGIC(device, NULL);
  827. if (createinfo == NULL) {
  828. SDL_InvalidParamError("createinfo");
  829. return NULL;
  830. }
  831. return device->CreateBuffer(
  832. device->driverData,
  833. createinfo->usage,
  834. createinfo->size);
  835. }
  836. SDL_GPUTransferBuffer *SDL_CreateGPUTransferBuffer(
  837. SDL_GPUDevice *device,
  838. const SDL_GPUTransferBufferCreateInfo *createinfo)
  839. {
  840. CHECK_DEVICE_MAGIC(device, NULL);
  841. if (createinfo == NULL) {
  842. SDL_InvalidParamError("createinfo");
  843. return NULL;
  844. }
  845. return device->CreateTransferBuffer(
  846. device->driverData,
  847. createinfo->usage,
  848. createinfo->size);
  849. }
  850. // Debug Naming
  851. void SDL_SetGPUBufferName(
  852. SDL_GPUDevice *device,
  853. SDL_GPUBuffer *buffer,
  854. const char *text)
  855. {
  856. CHECK_DEVICE_MAGIC(device, );
  857. if (buffer == NULL) {
  858. SDL_InvalidParamError("buffer");
  859. return;
  860. }
  861. if (text == NULL) {
  862. SDL_InvalidParamError("text");
  863. }
  864. device->SetBufferName(
  865. device->driverData,
  866. buffer,
  867. text);
  868. }
  869. void SDL_SetGPUTextureName(
  870. SDL_GPUDevice *device,
  871. SDL_GPUTexture *texture,
  872. const char *text)
  873. {
  874. CHECK_DEVICE_MAGIC(device, );
  875. if (texture == NULL) {
  876. SDL_InvalidParamError("texture");
  877. return;
  878. }
  879. if (text == NULL) {
  880. SDL_InvalidParamError("text");
  881. }
  882. device->SetTextureName(
  883. device->driverData,
  884. texture,
  885. text);
  886. }
  887. void SDL_InsertGPUDebugLabel(
  888. SDL_GPUCommandBuffer *command_buffer,
  889. const char *text)
  890. {
  891. if (command_buffer == NULL) {
  892. SDL_InvalidParamError("command_buffer");
  893. return;
  894. }
  895. if (text == NULL) {
  896. SDL_InvalidParamError("text");
  897. return;
  898. }
  899. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  900. CHECK_COMMAND_BUFFER
  901. }
  902. COMMAND_BUFFER_DEVICE->InsertDebugLabel(
  903. command_buffer,
  904. text);
  905. }
  906. void SDL_PushGPUDebugGroup(
  907. SDL_GPUCommandBuffer *command_buffer,
  908. const char *name)
  909. {
  910. if (command_buffer == NULL) {
  911. SDL_InvalidParamError("command_buffer");
  912. return;
  913. }
  914. if (name == NULL) {
  915. SDL_InvalidParamError("name");
  916. return;
  917. }
  918. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  919. CHECK_COMMAND_BUFFER
  920. }
  921. COMMAND_BUFFER_DEVICE->PushDebugGroup(
  922. command_buffer,
  923. name);
  924. }
  925. void SDL_PopGPUDebugGroup(
  926. SDL_GPUCommandBuffer *command_buffer)
  927. {
  928. if (command_buffer == NULL) {
  929. SDL_InvalidParamError("command_buffer");
  930. return;
  931. }
  932. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  933. CHECK_COMMAND_BUFFER
  934. }
  935. COMMAND_BUFFER_DEVICE->PopDebugGroup(
  936. command_buffer);
  937. }
  938. // Disposal
  939. void SDL_ReleaseGPUTexture(
  940. SDL_GPUDevice *device,
  941. SDL_GPUTexture *texture)
  942. {
  943. CHECK_DEVICE_MAGIC(device, );
  944. if (texture == NULL) {
  945. return;
  946. }
  947. device->ReleaseTexture(
  948. device->driverData,
  949. texture);
  950. }
  951. void SDL_ReleaseGPUSampler(
  952. SDL_GPUDevice *device,
  953. SDL_GPUSampler *sampler)
  954. {
  955. CHECK_DEVICE_MAGIC(device, );
  956. if (sampler == NULL) {
  957. return;
  958. }
  959. device->ReleaseSampler(
  960. device->driverData,
  961. sampler);
  962. }
  963. void SDL_ReleaseGPUBuffer(
  964. SDL_GPUDevice *device,
  965. SDL_GPUBuffer *buffer)
  966. {
  967. CHECK_DEVICE_MAGIC(device, );
  968. if (buffer == NULL) {
  969. return;
  970. }
  971. device->ReleaseBuffer(
  972. device->driverData,
  973. buffer);
  974. }
  975. void SDL_ReleaseGPUTransferBuffer(
  976. SDL_GPUDevice *device,
  977. SDL_GPUTransferBuffer *transfer_buffer)
  978. {
  979. CHECK_DEVICE_MAGIC(device, );
  980. if (transfer_buffer == NULL) {
  981. return;
  982. }
  983. device->ReleaseTransferBuffer(
  984. device->driverData,
  985. transfer_buffer);
  986. }
  987. void SDL_ReleaseGPUShader(
  988. SDL_GPUDevice *device,
  989. SDL_GPUShader *shader)
  990. {
  991. CHECK_DEVICE_MAGIC(device, );
  992. if (shader == NULL) {
  993. return;
  994. }
  995. device->ReleaseShader(
  996. device->driverData,
  997. shader);
  998. }
  999. void SDL_ReleaseGPUComputePipeline(
  1000. SDL_GPUDevice *device,
  1001. SDL_GPUComputePipeline *compute_pipeline)
  1002. {
  1003. CHECK_DEVICE_MAGIC(device, );
  1004. if (compute_pipeline == NULL) {
  1005. return;
  1006. }
  1007. device->ReleaseComputePipeline(
  1008. device->driverData,
  1009. compute_pipeline);
  1010. }
  1011. void SDL_ReleaseGPUGraphicsPipeline(
  1012. SDL_GPUDevice *device,
  1013. SDL_GPUGraphicsPipeline *graphics_pipeline)
  1014. {
  1015. CHECK_DEVICE_MAGIC(device, );
  1016. if (graphics_pipeline == NULL) {
  1017. return;
  1018. }
  1019. device->ReleaseGraphicsPipeline(
  1020. device->driverData,
  1021. graphics_pipeline);
  1022. }
  1023. // Command Buffer
  1024. SDL_GPUCommandBuffer *SDL_AcquireGPUCommandBuffer(
  1025. SDL_GPUDevice *device)
  1026. {
  1027. SDL_GPUCommandBuffer *command_buffer;
  1028. CommandBufferCommonHeader *commandBufferHeader;
  1029. CHECK_DEVICE_MAGIC(device, NULL);
  1030. command_buffer = device->AcquireCommandBuffer(
  1031. device->driverData);
  1032. if (command_buffer == NULL) {
  1033. return NULL;
  1034. }
  1035. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  1036. commandBufferHeader->device = device;
  1037. commandBufferHeader->render_pass.command_buffer = command_buffer;
  1038. commandBufferHeader->render_pass.in_progress = false;
  1039. commandBufferHeader->graphics_pipeline_bound = false;
  1040. commandBufferHeader->compute_pass.command_buffer = command_buffer;
  1041. commandBufferHeader->compute_pass.in_progress = false;
  1042. commandBufferHeader->compute_pipeline_bound = false;
  1043. commandBufferHeader->copy_pass.command_buffer = command_buffer;
  1044. commandBufferHeader->copy_pass.in_progress = false;
  1045. commandBufferHeader->submitted = false;
  1046. return command_buffer;
  1047. }
  1048. // Uniforms
  1049. void SDL_PushGPUVertexUniformData(
  1050. SDL_GPUCommandBuffer *command_buffer,
  1051. Uint32 slot_index,
  1052. const void *data,
  1053. Uint32 length)
  1054. {
  1055. if (command_buffer == NULL) {
  1056. SDL_InvalidParamError("command_buffer");
  1057. return;
  1058. }
  1059. if (data == NULL) {
  1060. SDL_InvalidParamError("data");
  1061. return;
  1062. }
  1063. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1064. CHECK_COMMAND_BUFFER
  1065. }
  1066. COMMAND_BUFFER_DEVICE->PushVertexUniformData(
  1067. command_buffer,
  1068. slot_index,
  1069. data,
  1070. length);
  1071. }
  1072. void SDL_PushGPUFragmentUniformData(
  1073. SDL_GPUCommandBuffer *command_buffer,
  1074. Uint32 slot_index,
  1075. const void *data,
  1076. Uint32 length)
  1077. {
  1078. if (command_buffer == NULL) {
  1079. SDL_InvalidParamError("command_buffer");
  1080. return;
  1081. }
  1082. if (data == NULL) {
  1083. SDL_InvalidParamError("data");
  1084. return;
  1085. }
  1086. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1087. CHECK_COMMAND_BUFFER
  1088. }
  1089. COMMAND_BUFFER_DEVICE->PushFragmentUniformData(
  1090. command_buffer,
  1091. slot_index,
  1092. data,
  1093. length);
  1094. }
  1095. void SDL_PushGPUComputeUniformData(
  1096. SDL_GPUCommandBuffer *command_buffer,
  1097. Uint32 slot_index,
  1098. const void *data,
  1099. Uint32 length)
  1100. {
  1101. if (command_buffer == NULL) {
  1102. SDL_InvalidParamError("command_buffer");
  1103. return;
  1104. }
  1105. if (data == NULL) {
  1106. SDL_InvalidParamError("data");
  1107. return;
  1108. }
  1109. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1110. CHECK_COMMAND_BUFFER
  1111. }
  1112. COMMAND_BUFFER_DEVICE->PushComputeUniformData(
  1113. command_buffer,
  1114. slot_index,
  1115. data,
  1116. length);
  1117. }
  1118. // Render Pass
  1119. SDL_GPURenderPass *SDL_BeginGPURenderPass(
  1120. SDL_GPUCommandBuffer *command_buffer,
  1121. const SDL_GPUColorTargetInfo *color_target_infos,
  1122. Uint32 num_color_targets,
  1123. const SDL_GPUDepthStencilTargetInfo *depth_stencil_target_info)
  1124. {
  1125. CommandBufferCommonHeader *commandBufferHeader;
  1126. if (command_buffer == NULL) {
  1127. SDL_InvalidParamError("command_buffer");
  1128. return NULL;
  1129. }
  1130. if (color_target_infos == NULL && num_color_targets > 0) {
  1131. SDL_InvalidParamError("color_target_infos");
  1132. return NULL;
  1133. }
  1134. if (num_color_targets > MAX_COLOR_TARGET_BINDINGS) {
  1135. SDL_SetError("num_color_targets exceeds MAX_COLOR_TARGET_BINDINGS");
  1136. return NULL;
  1137. }
  1138. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1139. CHECK_COMMAND_BUFFER_RETURN_NULL
  1140. CHECK_ANY_PASS_IN_PROGRESS("Cannot begin render pass during another pass!", NULL)
  1141. for (Uint32 i = 0; i < num_color_targets; i += 1) {
  1142. if (color_target_infos[i].cycle && color_target_infos[i].load_op == SDL_GPU_LOADOP_LOAD) {
  1143. SDL_assert_release(!"Cannot cycle color target when load op is LOAD!");
  1144. }
  1145. }
  1146. if (depth_stencil_target_info != NULL && depth_stencil_target_info->cycle && (depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD || depth_stencil_target_info->load_op == SDL_GPU_LOADOP_LOAD)) {
  1147. SDL_assert_release(!"Cannot cycle depth target when load op or stencil load op is LOAD!");
  1148. }
  1149. }
  1150. COMMAND_BUFFER_DEVICE->BeginRenderPass(
  1151. command_buffer,
  1152. color_target_infos,
  1153. num_color_targets,
  1154. depth_stencil_target_info);
  1155. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  1156. commandBufferHeader->render_pass.in_progress = true;
  1157. return (SDL_GPURenderPass *)&(commandBufferHeader->render_pass);
  1158. }
  1159. void SDL_BindGPUGraphicsPipeline(
  1160. SDL_GPURenderPass *render_pass,
  1161. SDL_GPUGraphicsPipeline *graphics_pipeline)
  1162. {
  1163. CommandBufferCommonHeader *commandBufferHeader;
  1164. if (render_pass == NULL) {
  1165. SDL_InvalidParamError("render_pass");
  1166. return;
  1167. }
  1168. if (graphics_pipeline == NULL) {
  1169. SDL_InvalidParamError("graphics_pipeline");
  1170. return;
  1171. }
  1172. RENDERPASS_DEVICE->BindGraphicsPipeline(
  1173. RENDERPASS_COMMAND_BUFFER,
  1174. graphics_pipeline);
  1175. commandBufferHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
  1176. commandBufferHeader->graphics_pipeline_bound = true;
  1177. }
  1178. void SDL_SetGPUViewport(
  1179. SDL_GPURenderPass *render_pass,
  1180. const SDL_GPUViewport *viewport)
  1181. {
  1182. if (render_pass == NULL) {
  1183. SDL_InvalidParamError("render_pass");
  1184. return;
  1185. }
  1186. if (viewport == NULL) {
  1187. SDL_InvalidParamError("viewport");
  1188. return;
  1189. }
  1190. if (RENDERPASS_DEVICE->debug_mode) {
  1191. CHECK_RENDERPASS
  1192. }
  1193. RENDERPASS_DEVICE->SetViewport(
  1194. RENDERPASS_COMMAND_BUFFER,
  1195. viewport);
  1196. }
  1197. void SDL_SetGPUScissor(
  1198. SDL_GPURenderPass *render_pass,
  1199. const SDL_Rect *scissor)
  1200. {
  1201. if (render_pass == NULL) {
  1202. SDL_InvalidParamError("render_pass");
  1203. return;
  1204. }
  1205. if (scissor == NULL) {
  1206. SDL_InvalidParamError("scissor");
  1207. return;
  1208. }
  1209. if (RENDERPASS_DEVICE->debug_mode) {
  1210. CHECK_RENDERPASS
  1211. }
  1212. RENDERPASS_DEVICE->SetScissor(
  1213. RENDERPASS_COMMAND_BUFFER,
  1214. scissor);
  1215. }
  1216. void SDL_SetGPUBlendConstants(
  1217. SDL_GPURenderPass *render_pass,
  1218. SDL_FColor blend_constants)
  1219. {
  1220. if (render_pass == NULL) {
  1221. SDL_InvalidParamError("render_pass");
  1222. return;
  1223. }
  1224. if (RENDERPASS_DEVICE->debug_mode) {
  1225. CHECK_RENDERPASS
  1226. }
  1227. RENDERPASS_DEVICE->SetBlendConstants(
  1228. RENDERPASS_COMMAND_BUFFER,
  1229. blend_constants);
  1230. }
  1231. void SDL_SetGPUStencilReference(
  1232. SDL_GPURenderPass *render_pass,
  1233. Uint8 reference)
  1234. {
  1235. if (render_pass == NULL) {
  1236. SDL_InvalidParamError("render_pass");
  1237. return;
  1238. }
  1239. if (RENDERPASS_DEVICE->debug_mode) {
  1240. CHECK_RENDERPASS
  1241. }
  1242. RENDERPASS_DEVICE->SetStencilReference(
  1243. RENDERPASS_COMMAND_BUFFER,
  1244. reference);
  1245. }
  1246. void SDL_BindGPUVertexBuffers(
  1247. SDL_GPURenderPass *render_pass,
  1248. Uint32 first_binding,
  1249. const SDL_GPUBufferBinding *bindings,
  1250. Uint32 num_bindings)
  1251. {
  1252. if (render_pass == NULL) {
  1253. SDL_InvalidParamError("render_pass");
  1254. return;
  1255. }
  1256. if (bindings == NULL && num_bindings > 0) {
  1257. SDL_InvalidParamError("bindings");
  1258. return;
  1259. }
  1260. if (RENDERPASS_DEVICE->debug_mode) {
  1261. CHECK_RENDERPASS
  1262. }
  1263. RENDERPASS_DEVICE->BindVertexBuffers(
  1264. RENDERPASS_COMMAND_BUFFER,
  1265. first_binding,
  1266. bindings,
  1267. num_bindings);
  1268. }
  1269. void SDL_BindGPUIndexBuffer(
  1270. SDL_GPURenderPass *render_pass,
  1271. const SDL_GPUBufferBinding *binding,
  1272. SDL_GPUIndexElementSize index_element_size)
  1273. {
  1274. if (render_pass == NULL) {
  1275. SDL_InvalidParamError("render_pass");
  1276. return;
  1277. }
  1278. if (binding == NULL) {
  1279. SDL_InvalidParamError("binding");
  1280. return;
  1281. }
  1282. if (RENDERPASS_DEVICE->debug_mode) {
  1283. CHECK_RENDERPASS
  1284. }
  1285. RENDERPASS_DEVICE->BindIndexBuffer(
  1286. RENDERPASS_COMMAND_BUFFER,
  1287. binding,
  1288. index_element_size);
  1289. }
  1290. void SDL_BindGPUVertexSamplers(
  1291. SDL_GPURenderPass *render_pass,
  1292. Uint32 first_slot,
  1293. const SDL_GPUTextureSamplerBinding *texture_sampler_bindings,
  1294. Uint32 num_bindings)
  1295. {
  1296. if (render_pass == NULL) {
  1297. SDL_InvalidParamError("render_pass");
  1298. return;
  1299. }
  1300. if (texture_sampler_bindings == NULL && num_bindings > 0) {
  1301. SDL_InvalidParamError("texture_sampler_bindings");
  1302. return;
  1303. }
  1304. if (RENDERPASS_DEVICE->debug_mode) {
  1305. CHECK_RENDERPASS
  1306. }
  1307. RENDERPASS_DEVICE->BindVertexSamplers(
  1308. RENDERPASS_COMMAND_BUFFER,
  1309. first_slot,
  1310. texture_sampler_bindings,
  1311. num_bindings);
  1312. }
  1313. void SDL_BindGPUVertexStorageTextures(
  1314. SDL_GPURenderPass *render_pass,
  1315. Uint32 first_slot,
  1316. SDL_GPUTexture *const *storage_textures,
  1317. Uint32 num_bindings)
  1318. {
  1319. if (render_pass == NULL) {
  1320. SDL_InvalidParamError("render_pass");
  1321. return;
  1322. }
  1323. if (storage_textures == NULL && num_bindings > 0) {
  1324. SDL_InvalidParamError("storage_textures");
  1325. return;
  1326. }
  1327. if (RENDERPASS_DEVICE->debug_mode) {
  1328. CHECK_RENDERPASS
  1329. }
  1330. RENDERPASS_DEVICE->BindVertexStorageTextures(
  1331. RENDERPASS_COMMAND_BUFFER,
  1332. first_slot,
  1333. storage_textures,
  1334. num_bindings);
  1335. }
  1336. void SDL_BindGPUVertexStorageBuffers(
  1337. SDL_GPURenderPass *render_pass,
  1338. Uint32 first_slot,
  1339. SDL_GPUBuffer *const *storage_buffers,
  1340. Uint32 num_bindings)
  1341. {
  1342. if (render_pass == NULL) {
  1343. SDL_InvalidParamError("render_pass");
  1344. return;
  1345. }
  1346. if (storage_buffers == NULL && num_bindings > 0) {
  1347. SDL_InvalidParamError("storage_buffers");
  1348. return;
  1349. }
  1350. if (RENDERPASS_DEVICE->debug_mode) {
  1351. CHECK_RENDERPASS
  1352. }
  1353. RENDERPASS_DEVICE->BindVertexStorageBuffers(
  1354. RENDERPASS_COMMAND_BUFFER,
  1355. first_slot,
  1356. storage_buffers,
  1357. num_bindings);
  1358. }
  1359. void SDL_BindGPUFragmentSamplers(
  1360. SDL_GPURenderPass *render_pass,
  1361. Uint32 first_slot,
  1362. const SDL_GPUTextureSamplerBinding *texture_sampler_bindings,
  1363. Uint32 num_bindings)
  1364. {
  1365. if (render_pass == NULL) {
  1366. SDL_InvalidParamError("render_pass");
  1367. return;
  1368. }
  1369. if (texture_sampler_bindings == NULL && num_bindings > 0) {
  1370. SDL_InvalidParamError("texture_sampler_bindings");
  1371. return;
  1372. }
  1373. if (RENDERPASS_DEVICE->debug_mode) {
  1374. CHECK_RENDERPASS
  1375. }
  1376. RENDERPASS_DEVICE->BindFragmentSamplers(
  1377. RENDERPASS_COMMAND_BUFFER,
  1378. first_slot,
  1379. texture_sampler_bindings,
  1380. num_bindings);
  1381. }
  1382. void SDL_BindGPUFragmentStorageTextures(
  1383. SDL_GPURenderPass *render_pass,
  1384. Uint32 first_slot,
  1385. SDL_GPUTexture *const *storage_textures,
  1386. Uint32 num_bindings)
  1387. {
  1388. if (render_pass == NULL) {
  1389. SDL_InvalidParamError("render_pass");
  1390. return;
  1391. }
  1392. if (storage_textures == NULL && num_bindings > 0) {
  1393. SDL_InvalidParamError("storage_textures");
  1394. return;
  1395. }
  1396. if (RENDERPASS_DEVICE->debug_mode) {
  1397. CHECK_RENDERPASS
  1398. }
  1399. RENDERPASS_DEVICE->BindFragmentStorageTextures(
  1400. RENDERPASS_COMMAND_BUFFER,
  1401. first_slot,
  1402. storage_textures,
  1403. num_bindings);
  1404. }
  1405. void SDL_BindGPUFragmentStorageBuffers(
  1406. SDL_GPURenderPass *render_pass,
  1407. Uint32 first_slot,
  1408. SDL_GPUBuffer *const *storage_buffers,
  1409. Uint32 num_bindings)
  1410. {
  1411. if (render_pass == NULL) {
  1412. SDL_InvalidParamError("render_pass");
  1413. return;
  1414. }
  1415. if (storage_buffers == NULL && num_bindings > 0) {
  1416. SDL_InvalidParamError("storage_buffers");
  1417. return;
  1418. }
  1419. if (RENDERPASS_DEVICE->debug_mode) {
  1420. CHECK_RENDERPASS
  1421. }
  1422. RENDERPASS_DEVICE->BindFragmentStorageBuffers(
  1423. RENDERPASS_COMMAND_BUFFER,
  1424. first_slot,
  1425. storage_buffers,
  1426. num_bindings);
  1427. }
  1428. void SDL_DrawGPUIndexedPrimitives(
  1429. SDL_GPURenderPass *render_pass,
  1430. Uint32 num_indices,
  1431. Uint32 num_instances,
  1432. Uint32 first_index,
  1433. Sint32 vertex_offset,
  1434. Uint32 first_instance)
  1435. {
  1436. if (render_pass == NULL) {
  1437. SDL_InvalidParamError("render_pass");
  1438. return;
  1439. }
  1440. if (RENDERPASS_DEVICE->debug_mode) {
  1441. CHECK_RENDERPASS
  1442. CHECK_GRAPHICS_PIPELINE_BOUND
  1443. }
  1444. RENDERPASS_DEVICE->DrawIndexedPrimitives(
  1445. RENDERPASS_COMMAND_BUFFER,
  1446. num_indices,
  1447. num_instances,
  1448. first_index,
  1449. vertex_offset,
  1450. first_instance);
  1451. }
  1452. void SDL_DrawGPUPrimitives(
  1453. SDL_GPURenderPass *render_pass,
  1454. Uint32 num_vertices,
  1455. Uint32 num_instances,
  1456. Uint32 first_vertex,
  1457. Uint32 first_instance)
  1458. {
  1459. if (render_pass == NULL) {
  1460. SDL_InvalidParamError("render_pass");
  1461. return;
  1462. }
  1463. if (RENDERPASS_DEVICE->debug_mode) {
  1464. CHECK_RENDERPASS
  1465. CHECK_GRAPHICS_PIPELINE_BOUND
  1466. }
  1467. RENDERPASS_DEVICE->DrawPrimitives(
  1468. RENDERPASS_COMMAND_BUFFER,
  1469. num_vertices,
  1470. num_instances,
  1471. first_vertex,
  1472. first_instance);
  1473. }
  1474. void SDL_DrawGPUPrimitivesIndirect(
  1475. SDL_GPURenderPass *render_pass,
  1476. SDL_GPUBuffer *buffer,
  1477. Uint32 offset,
  1478. Uint32 draw_count)
  1479. {
  1480. if (render_pass == NULL) {
  1481. SDL_InvalidParamError("render_pass");
  1482. return;
  1483. }
  1484. if (buffer == NULL) {
  1485. SDL_InvalidParamError("buffer");
  1486. return;
  1487. }
  1488. if (RENDERPASS_DEVICE->debug_mode) {
  1489. CHECK_RENDERPASS
  1490. CHECK_GRAPHICS_PIPELINE_BOUND
  1491. }
  1492. RENDERPASS_DEVICE->DrawPrimitivesIndirect(
  1493. RENDERPASS_COMMAND_BUFFER,
  1494. buffer,
  1495. offset,
  1496. draw_count);
  1497. }
  1498. void SDL_DrawGPUIndexedPrimitivesIndirect(
  1499. SDL_GPURenderPass *render_pass,
  1500. SDL_GPUBuffer *buffer,
  1501. Uint32 offset,
  1502. Uint32 draw_count)
  1503. {
  1504. if (render_pass == NULL) {
  1505. SDL_InvalidParamError("render_pass");
  1506. return;
  1507. }
  1508. if (buffer == NULL) {
  1509. SDL_InvalidParamError("buffer");
  1510. return;
  1511. }
  1512. if (RENDERPASS_DEVICE->debug_mode) {
  1513. CHECK_RENDERPASS
  1514. CHECK_GRAPHICS_PIPELINE_BOUND
  1515. }
  1516. RENDERPASS_DEVICE->DrawIndexedPrimitivesIndirect(
  1517. RENDERPASS_COMMAND_BUFFER,
  1518. buffer,
  1519. offset,
  1520. draw_count);
  1521. }
  1522. void SDL_EndGPURenderPass(
  1523. SDL_GPURenderPass *render_pass)
  1524. {
  1525. CommandBufferCommonHeader *commandBufferCommonHeader;
  1526. if (render_pass == NULL) {
  1527. SDL_InvalidParamError("render_pass");
  1528. return;
  1529. }
  1530. if (RENDERPASS_DEVICE->debug_mode) {
  1531. CHECK_RENDERPASS
  1532. }
  1533. RENDERPASS_DEVICE->EndRenderPass(
  1534. RENDERPASS_COMMAND_BUFFER);
  1535. commandBufferCommonHeader = (CommandBufferCommonHeader *)RENDERPASS_COMMAND_BUFFER;
  1536. commandBufferCommonHeader->render_pass.in_progress = false;
  1537. commandBufferCommonHeader->graphics_pipeline_bound = false;
  1538. }
  1539. // Compute Pass
  1540. SDL_GPUComputePass *SDL_BeginGPUComputePass(
  1541. SDL_GPUCommandBuffer *command_buffer,
  1542. const SDL_GPUStorageTextureWriteOnlyBinding *storage_texture_bindings,
  1543. Uint32 num_storage_texture_bindings,
  1544. const SDL_GPUStorageBufferWriteOnlyBinding *storage_buffer_bindings,
  1545. Uint32 num_storage_buffer_bindings)
  1546. {
  1547. CommandBufferCommonHeader *commandBufferHeader;
  1548. if (command_buffer == NULL) {
  1549. SDL_InvalidParamError("command_buffer");
  1550. return NULL;
  1551. }
  1552. if (storage_texture_bindings == NULL && num_storage_texture_bindings > 0) {
  1553. SDL_InvalidParamError("storage_texture_bindings");
  1554. return NULL;
  1555. }
  1556. if (storage_buffer_bindings == NULL && num_storage_buffer_bindings > 0) {
  1557. SDL_InvalidParamError("storage_buffer_bindings");
  1558. return NULL;
  1559. }
  1560. if (num_storage_texture_bindings > MAX_COMPUTE_WRITE_TEXTURES) {
  1561. SDL_InvalidParamError("num_storage_texture_bindings");
  1562. return NULL;
  1563. }
  1564. if (num_storage_buffer_bindings > MAX_COMPUTE_WRITE_BUFFERS) {
  1565. SDL_InvalidParamError("num_storage_buffer_bindings");
  1566. return NULL;
  1567. }
  1568. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1569. CHECK_COMMAND_BUFFER_RETURN_NULL
  1570. CHECK_ANY_PASS_IN_PROGRESS("Cannot begin compute pass during another pass!", NULL)
  1571. }
  1572. COMMAND_BUFFER_DEVICE->BeginComputePass(
  1573. command_buffer,
  1574. storage_texture_bindings,
  1575. num_storage_texture_bindings,
  1576. storage_buffer_bindings,
  1577. num_storage_buffer_bindings);
  1578. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  1579. commandBufferHeader->compute_pass.in_progress = true;
  1580. return (SDL_GPUComputePass *)&(commandBufferHeader->compute_pass);
  1581. }
  1582. void SDL_BindGPUComputePipeline(
  1583. SDL_GPUComputePass *compute_pass,
  1584. SDL_GPUComputePipeline *compute_pipeline)
  1585. {
  1586. CommandBufferCommonHeader *commandBufferHeader;
  1587. if (compute_pass == NULL) {
  1588. SDL_InvalidParamError("compute_pass");
  1589. return;
  1590. }
  1591. if (compute_pipeline == NULL) {
  1592. SDL_InvalidParamError("compute_pipeline");
  1593. return;
  1594. }
  1595. if (COMPUTEPASS_DEVICE->debug_mode) {
  1596. CHECK_COMPUTEPASS
  1597. }
  1598. COMPUTEPASS_DEVICE->BindComputePipeline(
  1599. COMPUTEPASS_COMMAND_BUFFER,
  1600. compute_pipeline);
  1601. commandBufferHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
  1602. commandBufferHeader->compute_pipeline_bound = true;
  1603. }
  1604. void SDL_BindGPUComputeSamplers(
  1605. SDL_GPUComputePass *compute_pass,
  1606. Uint32 first_slot,
  1607. const SDL_GPUTextureSamplerBinding *texture_sampler_bindings,
  1608. Uint32 num_bindings)
  1609. {
  1610. if (compute_pass == NULL) {
  1611. SDL_InvalidParamError("compute_pass");
  1612. return;
  1613. }
  1614. if (texture_sampler_bindings == NULL && num_bindings > 0) {
  1615. SDL_InvalidParamError("texture_sampler_bindings");
  1616. return;
  1617. }
  1618. if (COMPUTEPASS_DEVICE->debug_mode) {
  1619. CHECK_COMPUTEPASS
  1620. }
  1621. COMPUTEPASS_DEVICE->BindComputeSamplers(
  1622. COMPUTEPASS_COMMAND_BUFFER,
  1623. first_slot,
  1624. texture_sampler_bindings,
  1625. num_bindings);
  1626. }
  1627. void SDL_BindGPUComputeStorageTextures(
  1628. SDL_GPUComputePass *compute_pass,
  1629. Uint32 first_slot,
  1630. SDL_GPUTexture *const *storage_textures,
  1631. Uint32 num_bindings)
  1632. {
  1633. if (compute_pass == NULL) {
  1634. SDL_InvalidParamError("compute_pass");
  1635. return;
  1636. }
  1637. if (storage_textures == NULL && num_bindings > 0) {
  1638. SDL_InvalidParamError("storage_textures");
  1639. return;
  1640. }
  1641. if (COMPUTEPASS_DEVICE->debug_mode) {
  1642. CHECK_COMPUTEPASS
  1643. }
  1644. COMPUTEPASS_DEVICE->BindComputeStorageTextures(
  1645. COMPUTEPASS_COMMAND_BUFFER,
  1646. first_slot,
  1647. storage_textures,
  1648. num_bindings);
  1649. }
  1650. void SDL_BindGPUComputeStorageBuffers(
  1651. SDL_GPUComputePass *compute_pass,
  1652. Uint32 first_slot,
  1653. SDL_GPUBuffer *const *storage_buffers,
  1654. Uint32 num_bindings)
  1655. {
  1656. if (compute_pass == NULL) {
  1657. SDL_InvalidParamError("compute_pass");
  1658. return;
  1659. }
  1660. if (storage_buffers == NULL && num_bindings > 0) {
  1661. SDL_InvalidParamError("storage_buffers");
  1662. return;
  1663. }
  1664. if (COMPUTEPASS_DEVICE->debug_mode) {
  1665. CHECK_COMPUTEPASS
  1666. }
  1667. COMPUTEPASS_DEVICE->BindComputeStorageBuffers(
  1668. COMPUTEPASS_COMMAND_BUFFER,
  1669. first_slot,
  1670. storage_buffers,
  1671. num_bindings);
  1672. }
  1673. void SDL_DispatchGPUCompute(
  1674. SDL_GPUComputePass *compute_pass,
  1675. Uint32 groupcount_x,
  1676. Uint32 groupcount_y,
  1677. Uint32 groupcount_z)
  1678. {
  1679. if (compute_pass == NULL) {
  1680. SDL_InvalidParamError("compute_pass");
  1681. return;
  1682. }
  1683. if (COMPUTEPASS_DEVICE->debug_mode) {
  1684. CHECK_COMPUTEPASS
  1685. CHECK_COMPUTE_PIPELINE_BOUND
  1686. }
  1687. COMPUTEPASS_DEVICE->DispatchCompute(
  1688. COMPUTEPASS_COMMAND_BUFFER,
  1689. groupcount_x,
  1690. groupcount_y,
  1691. groupcount_z);
  1692. }
  1693. void SDL_DispatchGPUComputeIndirect(
  1694. SDL_GPUComputePass *compute_pass,
  1695. SDL_GPUBuffer *buffer,
  1696. Uint32 offset)
  1697. {
  1698. if (compute_pass == NULL) {
  1699. SDL_InvalidParamError("compute_pass");
  1700. return;
  1701. }
  1702. if (COMPUTEPASS_DEVICE->debug_mode) {
  1703. CHECK_COMPUTEPASS
  1704. CHECK_COMPUTE_PIPELINE_BOUND
  1705. }
  1706. COMPUTEPASS_DEVICE->DispatchComputeIndirect(
  1707. COMPUTEPASS_COMMAND_BUFFER,
  1708. buffer,
  1709. offset);
  1710. }
  1711. void SDL_EndGPUComputePass(
  1712. SDL_GPUComputePass *compute_pass)
  1713. {
  1714. CommandBufferCommonHeader *commandBufferCommonHeader;
  1715. if (compute_pass == NULL) {
  1716. SDL_InvalidParamError("compute_pass");
  1717. return;
  1718. }
  1719. if (COMPUTEPASS_DEVICE->debug_mode) {
  1720. CHECK_COMPUTEPASS
  1721. }
  1722. COMPUTEPASS_DEVICE->EndComputePass(
  1723. COMPUTEPASS_COMMAND_BUFFER);
  1724. commandBufferCommonHeader = (CommandBufferCommonHeader *)COMPUTEPASS_COMMAND_BUFFER;
  1725. commandBufferCommonHeader->compute_pass.in_progress = false;
  1726. commandBufferCommonHeader->compute_pipeline_bound = false;
  1727. }
  1728. // TransferBuffer Data
  1729. void *SDL_MapGPUTransferBuffer(
  1730. SDL_GPUDevice *device,
  1731. SDL_GPUTransferBuffer *transfer_buffer,
  1732. SDL_bool cycle)
  1733. {
  1734. CHECK_DEVICE_MAGIC(device, NULL);
  1735. if (transfer_buffer == NULL) {
  1736. SDL_InvalidParamError("transfer_buffer");
  1737. return NULL;
  1738. }
  1739. return device->MapTransferBuffer(
  1740. device->driverData,
  1741. transfer_buffer,
  1742. cycle);
  1743. }
  1744. void SDL_UnmapGPUTransferBuffer(
  1745. SDL_GPUDevice *device,
  1746. SDL_GPUTransferBuffer *transfer_buffer)
  1747. {
  1748. CHECK_DEVICE_MAGIC(device, );
  1749. if (transfer_buffer == NULL) {
  1750. SDL_InvalidParamError("transfer_buffer");
  1751. return;
  1752. }
  1753. device->UnmapTransferBuffer(
  1754. device->driverData,
  1755. transfer_buffer);
  1756. }
  1757. // Copy Pass
  1758. SDL_GPUCopyPass *SDL_BeginGPUCopyPass(
  1759. SDL_GPUCommandBuffer *command_buffer)
  1760. {
  1761. CommandBufferCommonHeader *commandBufferHeader;
  1762. if (command_buffer == NULL) {
  1763. SDL_InvalidParamError("command_buffer");
  1764. return NULL;
  1765. }
  1766. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  1767. CHECK_COMMAND_BUFFER_RETURN_NULL
  1768. CHECK_ANY_PASS_IN_PROGRESS("Cannot begin copy pass during another pass!", NULL)
  1769. }
  1770. COMMAND_BUFFER_DEVICE->BeginCopyPass(
  1771. command_buffer);
  1772. commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  1773. commandBufferHeader->copy_pass.in_progress = true;
  1774. return (SDL_GPUCopyPass *)&(commandBufferHeader->copy_pass);
  1775. }
  1776. void SDL_UploadToGPUTexture(
  1777. SDL_GPUCopyPass *copy_pass,
  1778. const SDL_GPUTextureTransferInfo *source,
  1779. const SDL_GPUTextureRegion *destination,
  1780. SDL_bool cycle)
  1781. {
  1782. if (copy_pass == NULL) {
  1783. SDL_InvalidParamError("copy_pass");
  1784. return;
  1785. }
  1786. if (source == NULL) {
  1787. SDL_InvalidParamError("source");
  1788. return;
  1789. }
  1790. if (destination == NULL) {
  1791. SDL_InvalidParamError("destination");
  1792. return;
  1793. }
  1794. if (COPYPASS_DEVICE->debug_mode) {
  1795. CHECK_COPYPASS
  1796. if (source->transfer_buffer == NULL) {
  1797. SDL_assert_release(!"Source transfer buffer cannot be NULL!");
  1798. return;
  1799. }
  1800. if (destination->texture == NULL) {
  1801. SDL_assert_release(!"Destination texture cannot be NULL!");
  1802. return;
  1803. }
  1804. }
  1805. COPYPASS_DEVICE->UploadToTexture(
  1806. COPYPASS_COMMAND_BUFFER,
  1807. source,
  1808. destination,
  1809. cycle);
  1810. }
  1811. void SDL_UploadToGPUBuffer(
  1812. SDL_GPUCopyPass *copy_pass,
  1813. const SDL_GPUTransferBufferLocation *source,
  1814. const SDL_GPUBufferRegion *destination,
  1815. SDL_bool cycle)
  1816. {
  1817. if (copy_pass == NULL) {
  1818. SDL_InvalidParamError("copy_pass");
  1819. return;
  1820. }
  1821. if (source == NULL) {
  1822. SDL_InvalidParamError("source");
  1823. return;
  1824. }
  1825. if (destination == NULL) {
  1826. SDL_InvalidParamError("destination");
  1827. return;
  1828. }
  1829. if (COPYPASS_DEVICE->debug_mode) {
  1830. CHECK_COPYPASS
  1831. if (source->transfer_buffer == NULL) {
  1832. SDL_assert_release(!"Source transfer buffer cannot be NULL!");
  1833. return;
  1834. }
  1835. if (destination->buffer == NULL) {
  1836. SDL_assert_release(!"Destination buffer cannot be NULL!");
  1837. return;
  1838. }
  1839. }
  1840. COPYPASS_DEVICE->UploadToBuffer(
  1841. COPYPASS_COMMAND_BUFFER,
  1842. source,
  1843. destination,
  1844. cycle);
  1845. }
  1846. void SDL_CopyGPUTextureToTexture(
  1847. SDL_GPUCopyPass *copy_pass,
  1848. const SDL_GPUTextureLocation *source,
  1849. const SDL_GPUTextureLocation *destination,
  1850. Uint32 w,
  1851. Uint32 h,
  1852. Uint32 d,
  1853. SDL_bool cycle)
  1854. {
  1855. if (copy_pass == NULL) {
  1856. SDL_InvalidParamError("copy_pass");
  1857. return;
  1858. }
  1859. if (source == NULL) {
  1860. SDL_InvalidParamError("source");
  1861. return;
  1862. }
  1863. if (destination == NULL) {
  1864. SDL_InvalidParamError("destination");
  1865. return;
  1866. }
  1867. if (COPYPASS_DEVICE->debug_mode) {
  1868. CHECK_COPYPASS
  1869. if (source->texture == NULL) {
  1870. SDL_assert_release(!"Source texture cannot be NULL!");
  1871. return;
  1872. }
  1873. if (destination->texture == NULL) {
  1874. SDL_assert_release(!"Destination texture cannot be NULL!");
  1875. return;
  1876. }
  1877. }
  1878. COPYPASS_DEVICE->CopyTextureToTexture(
  1879. COPYPASS_COMMAND_BUFFER,
  1880. source,
  1881. destination,
  1882. w,
  1883. h,
  1884. d,
  1885. cycle);
  1886. }
  1887. void SDL_CopyGPUBufferToBuffer(
  1888. SDL_GPUCopyPass *copy_pass,
  1889. const SDL_GPUBufferLocation *source,
  1890. const SDL_GPUBufferLocation *destination,
  1891. Uint32 size,
  1892. SDL_bool cycle)
  1893. {
  1894. if (copy_pass == NULL) {
  1895. SDL_InvalidParamError("copy_pass");
  1896. return;
  1897. }
  1898. if (source == NULL) {
  1899. SDL_InvalidParamError("source");
  1900. return;
  1901. }
  1902. if (destination == NULL) {
  1903. SDL_InvalidParamError("destination");
  1904. return;
  1905. }
  1906. if (COPYPASS_DEVICE->debug_mode) {
  1907. CHECK_COPYPASS
  1908. if (source->buffer == NULL) {
  1909. SDL_assert_release(!"Source buffer cannot be NULL!");
  1910. return;
  1911. }
  1912. if (destination->buffer == NULL) {
  1913. SDL_assert_release(!"Destination buffer cannot be NULL!");
  1914. return;
  1915. }
  1916. }
  1917. COPYPASS_DEVICE->CopyBufferToBuffer(
  1918. COPYPASS_COMMAND_BUFFER,
  1919. source,
  1920. destination,
  1921. size,
  1922. cycle);
  1923. }
  1924. void SDL_DownloadFromGPUTexture(
  1925. SDL_GPUCopyPass *copy_pass,
  1926. const SDL_GPUTextureRegion *source,
  1927. const SDL_GPUTextureTransferInfo *destination)
  1928. {
  1929. if (copy_pass == NULL) {
  1930. SDL_InvalidParamError("copy_pass");
  1931. return;
  1932. }
  1933. if (source == NULL) {
  1934. SDL_InvalidParamError("source");
  1935. return;
  1936. }
  1937. if (destination == NULL) {
  1938. SDL_InvalidParamError("destination");
  1939. return;
  1940. }
  1941. if (COPYPASS_DEVICE->debug_mode) {
  1942. CHECK_COPYPASS
  1943. if (source->texture == NULL) {
  1944. SDL_assert_release(!"Source texture cannot be NULL!");
  1945. return;
  1946. }
  1947. if (destination->transfer_buffer == NULL) {
  1948. SDL_assert_release(!"Destination transfer buffer cannot be NULL!");
  1949. return;
  1950. }
  1951. }
  1952. COPYPASS_DEVICE->DownloadFromTexture(
  1953. COPYPASS_COMMAND_BUFFER,
  1954. source,
  1955. destination);
  1956. }
  1957. void SDL_DownloadFromGPUBuffer(
  1958. SDL_GPUCopyPass *copy_pass,
  1959. const SDL_GPUBufferRegion *source,
  1960. const SDL_GPUTransferBufferLocation *destination)
  1961. {
  1962. if (copy_pass == NULL) {
  1963. SDL_InvalidParamError("copy_pass");
  1964. return;
  1965. }
  1966. if (source == NULL) {
  1967. SDL_InvalidParamError("source");
  1968. return;
  1969. }
  1970. if (destination == NULL) {
  1971. SDL_InvalidParamError("destination");
  1972. return;
  1973. }
  1974. if (COPYPASS_DEVICE->debug_mode) {
  1975. CHECK_COPYPASS
  1976. if (source->buffer == NULL) {
  1977. SDL_assert_release(!"Source buffer cannot be NULL!");
  1978. return;
  1979. }
  1980. if (destination->transfer_buffer == NULL) {
  1981. SDL_assert_release(!"Destination transfer buffer cannot be NULL!");
  1982. return;
  1983. }
  1984. }
  1985. COPYPASS_DEVICE->DownloadFromBuffer(
  1986. COPYPASS_COMMAND_BUFFER,
  1987. source,
  1988. destination);
  1989. }
  1990. void SDL_EndGPUCopyPass(
  1991. SDL_GPUCopyPass *copy_pass)
  1992. {
  1993. if (copy_pass == NULL) {
  1994. SDL_InvalidParamError("copy_pass");
  1995. return;
  1996. }
  1997. if (COPYPASS_DEVICE->debug_mode) {
  1998. CHECK_COPYPASS
  1999. }
  2000. COPYPASS_DEVICE->EndCopyPass(
  2001. COPYPASS_COMMAND_BUFFER);
  2002. ((CommandBufferCommonHeader *)COPYPASS_COMMAND_BUFFER)->copy_pass.in_progress = false;
  2003. }
  2004. void SDL_GenerateMipmapsForGPUTexture(
  2005. SDL_GPUCommandBuffer *command_buffer,
  2006. SDL_GPUTexture *texture)
  2007. {
  2008. if (command_buffer == NULL) {
  2009. SDL_InvalidParamError("command_buffer");
  2010. return;
  2011. }
  2012. if (texture == NULL) {
  2013. SDL_InvalidParamError("texture");
  2014. return;
  2015. }
  2016. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2017. CHECK_COMMAND_BUFFER
  2018. CHECK_ANY_PASS_IN_PROGRESS("Cannot generate mipmaps during a pass!", )
  2019. TextureCommonHeader *header = (TextureCommonHeader *)texture;
  2020. if (header->info.num_levels <= 1) {
  2021. SDL_assert_release(!"Cannot generate mipmaps for texture with num_levels <= 1!");
  2022. return;
  2023. }
  2024. if (!(header->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) || !(header->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET)) {
  2025. SDL_assert_release(!"GenerateMipmaps texture must be created with SAMPLER and COLOR_TARGET usage flags!");
  2026. return;
  2027. }
  2028. }
  2029. COMMAND_BUFFER_DEVICE->GenerateMipmaps(
  2030. command_buffer,
  2031. texture);
  2032. }
  2033. void SDL_BlitGPUTexture(
  2034. SDL_GPUCommandBuffer *command_buffer,
  2035. const SDL_GPUBlitInfo *info)
  2036. {
  2037. if (command_buffer == NULL) {
  2038. SDL_InvalidParamError("command_buffer");
  2039. return;
  2040. }
  2041. if (info == NULL) {
  2042. SDL_InvalidParamError("info");
  2043. return;
  2044. }
  2045. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2046. CHECK_COMMAND_BUFFER
  2047. CHECK_ANY_PASS_IN_PROGRESS("Cannot blit during a pass!", )
  2048. // Validation
  2049. bool failed = false;
  2050. TextureCommonHeader *srcHeader = (TextureCommonHeader *)info->source.texture;
  2051. TextureCommonHeader *dstHeader = (TextureCommonHeader *)info->destination.texture;
  2052. if (srcHeader == NULL) {
  2053. SDL_assert_release(!"Blit source texture must be non-NULL");
  2054. return; // attempting to proceed will crash
  2055. }
  2056. if (dstHeader == NULL) {
  2057. SDL_assert_release(!"Blit destination texture must be non-NULL");
  2058. return; // attempting to proceed will crash
  2059. }
  2060. if ((srcHeader->info.usage & SDL_GPU_TEXTUREUSAGE_SAMPLER) == 0) {
  2061. SDL_assert_release(!"Blit source texture must be created with the SAMPLER usage flag");
  2062. failed = true;
  2063. }
  2064. if ((dstHeader->info.usage & SDL_GPU_TEXTUREUSAGE_COLOR_TARGET) == 0) {
  2065. SDL_assert_release(!"Blit destination texture must be created with the COLOR_TARGET usage flag");
  2066. failed = true;
  2067. }
  2068. if (IsDepthFormat(srcHeader->info.format)) {
  2069. SDL_assert_release(!"Blit source texture cannot have a depth format");
  2070. failed = true;
  2071. }
  2072. if (info->source.w == 0 || info->source.h == 0 || info->destination.w == 0 || info->destination.h == 0) {
  2073. SDL_assert_release(!"Blit source/destination regions must have non-zero width, height, and depth");
  2074. failed = true;
  2075. }
  2076. if (failed) {
  2077. return;
  2078. }
  2079. }
  2080. COMMAND_BUFFER_DEVICE->Blit(
  2081. command_buffer,
  2082. info);
  2083. }
  2084. // Submission/Presentation
  2085. SDL_bool SDL_WindowSupportsGPUSwapchainComposition(
  2086. SDL_GPUDevice *device,
  2087. SDL_Window *window,
  2088. SDL_GPUSwapchainComposition swapchain_composition)
  2089. {
  2090. CHECK_DEVICE_MAGIC(device, false);
  2091. if (window == NULL) {
  2092. SDL_InvalidParamError("window");
  2093. return false;
  2094. }
  2095. if (device->debug_mode) {
  2096. CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(swapchain_composition, false)
  2097. }
  2098. return device->SupportsSwapchainComposition(
  2099. device->driverData,
  2100. window,
  2101. swapchain_composition);
  2102. }
  2103. SDL_bool SDL_WindowSupportsGPUPresentMode(
  2104. SDL_GPUDevice *device,
  2105. SDL_Window *window,
  2106. SDL_GPUPresentMode present_mode)
  2107. {
  2108. CHECK_DEVICE_MAGIC(device, false);
  2109. if (window == NULL) {
  2110. SDL_InvalidParamError("window");
  2111. return false;
  2112. }
  2113. if (device->debug_mode) {
  2114. CHECK_PRESENTMODE_ENUM_INVALID(present_mode, false)
  2115. }
  2116. return device->SupportsPresentMode(
  2117. device->driverData,
  2118. window,
  2119. present_mode);
  2120. }
  2121. SDL_bool SDL_ClaimWindowForGPUDevice(
  2122. SDL_GPUDevice *device,
  2123. SDL_Window *window)
  2124. {
  2125. CHECK_DEVICE_MAGIC(device, false);
  2126. if (window == NULL) {
  2127. SDL_InvalidParamError("window");
  2128. return false;
  2129. }
  2130. return device->ClaimWindow(
  2131. device->driverData,
  2132. window);
  2133. }
  2134. void SDL_ReleaseWindowFromGPUDevice(
  2135. SDL_GPUDevice *device,
  2136. SDL_Window *window)
  2137. {
  2138. CHECK_DEVICE_MAGIC(device, );
  2139. if (window == NULL) {
  2140. SDL_InvalidParamError("window");
  2141. return;
  2142. }
  2143. device->ReleaseWindow(
  2144. device->driverData,
  2145. window);
  2146. }
  2147. SDL_bool SDL_SetGPUSwapchainParameters(
  2148. SDL_GPUDevice *device,
  2149. SDL_Window *window,
  2150. SDL_GPUSwapchainComposition swapchain_composition,
  2151. SDL_GPUPresentMode present_mode)
  2152. {
  2153. CHECK_DEVICE_MAGIC(device, false);
  2154. if (window == NULL) {
  2155. SDL_InvalidParamError("window");
  2156. return false;
  2157. }
  2158. if (device->debug_mode) {
  2159. CHECK_SWAPCHAINCOMPOSITION_ENUM_INVALID(swapchain_composition, false)
  2160. CHECK_PRESENTMODE_ENUM_INVALID(present_mode, false)
  2161. }
  2162. return device->SetSwapchainParameters(
  2163. device->driverData,
  2164. window,
  2165. swapchain_composition,
  2166. present_mode);
  2167. }
  2168. SDL_GPUTextureFormat SDL_GetGPUSwapchainTextureFormat(
  2169. SDL_GPUDevice *device,
  2170. SDL_Window *window)
  2171. {
  2172. CHECK_DEVICE_MAGIC(device, SDL_GPU_TEXTUREFORMAT_INVALID);
  2173. if (window == NULL) {
  2174. SDL_InvalidParamError("window");
  2175. return SDL_GPU_TEXTUREFORMAT_INVALID;
  2176. }
  2177. return device->GetSwapchainTextureFormat(
  2178. device->driverData,
  2179. window);
  2180. }
  2181. SDL_GPUTexture *SDL_AcquireGPUSwapchainTexture(
  2182. SDL_GPUCommandBuffer *command_buffer,
  2183. SDL_Window *window,
  2184. Uint32 *w,
  2185. Uint32 *h)
  2186. {
  2187. if (command_buffer == NULL) {
  2188. SDL_InvalidParamError("command_buffer");
  2189. return NULL;
  2190. }
  2191. if (window == NULL) {
  2192. SDL_InvalidParamError("window");
  2193. return NULL;
  2194. }
  2195. if (w == NULL) {
  2196. SDL_InvalidParamError("w");
  2197. return NULL;
  2198. }
  2199. if (h == NULL) {
  2200. SDL_InvalidParamError("h");
  2201. return NULL;
  2202. }
  2203. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2204. CHECK_COMMAND_BUFFER_RETURN_NULL
  2205. CHECK_ANY_PASS_IN_PROGRESS("Cannot acquire a swapchain texture during a pass!", NULL)
  2206. }
  2207. return COMMAND_BUFFER_DEVICE->AcquireSwapchainTexture(
  2208. command_buffer,
  2209. window,
  2210. w,
  2211. h);
  2212. }
  2213. void SDL_SubmitGPUCommandBuffer(
  2214. SDL_GPUCommandBuffer *command_buffer)
  2215. {
  2216. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2217. if (command_buffer == NULL) {
  2218. SDL_InvalidParamError("command_buffer");
  2219. return;
  2220. }
  2221. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2222. CHECK_COMMAND_BUFFER
  2223. if (
  2224. commandBufferHeader->render_pass.in_progress ||
  2225. commandBufferHeader->compute_pass.in_progress ||
  2226. commandBufferHeader->copy_pass.in_progress) {
  2227. SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!");
  2228. return;
  2229. }
  2230. }
  2231. commandBufferHeader->submitted = true;
  2232. COMMAND_BUFFER_DEVICE->Submit(
  2233. command_buffer);
  2234. }
  2235. SDL_GPUFence *SDL_SubmitGPUCommandBufferAndAcquireFence(
  2236. SDL_GPUCommandBuffer *command_buffer)
  2237. {
  2238. CommandBufferCommonHeader *commandBufferHeader = (CommandBufferCommonHeader *)command_buffer;
  2239. if (command_buffer == NULL) {
  2240. SDL_InvalidParamError("command_buffer");
  2241. return NULL;
  2242. }
  2243. if (COMMAND_BUFFER_DEVICE->debug_mode) {
  2244. CHECK_COMMAND_BUFFER_RETURN_NULL
  2245. if (
  2246. commandBufferHeader->render_pass.in_progress ||
  2247. commandBufferHeader->compute_pass.in_progress ||
  2248. commandBufferHeader->copy_pass.in_progress) {
  2249. SDL_assert_release(!"Cannot submit command buffer while a pass is in progress!");
  2250. return NULL;
  2251. }
  2252. }
  2253. commandBufferHeader->submitted = true;
  2254. return COMMAND_BUFFER_DEVICE->SubmitAndAcquireFence(
  2255. command_buffer);
  2256. }
  2257. void SDL_WaitForGPUIdle(
  2258. SDL_GPUDevice *device)
  2259. {
  2260. CHECK_DEVICE_MAGIC(device, );
  2261. device->Wait(
  2262. device->driverData);
  2263. }
  2264. void SDL_WaitForGPUFences(
  2265. SDL_GPUDevice *device,
  2266. SDL_bool wait_all,
  2267. SDL_GPUFence *const *fences,
  2268. Uint32 num_fences)
  2269. {
  2270. CHECK_DEVICE_MAGIC(device, );
  2271. if (fences == NULL && num_fences > 0) {
  2272. SDL_InvalidParamError("fences");
  2273. return;
  2274. }
  2275. device->WaitForFences(
  2276. device->driverData,
  2277. wait_all,
  2278. fences,
  2279. num_fences);
  2280. }
  2281. SDL_bool SDL_QueryGPUFence(
  2282. SDL_GPUDevice *device,
  2283. SDL_GPUFence *fence)
  2284. {
  2285. CHECK_DEVICE_MAGIC(device, false);
  2286. if (fence == NULL) {
  2287. SDL_InvalidParamError("fence");
  2288. return false;
  2289. }
  2290. return device->QueryFence(
  2291. device->driverData,
  2292. fence);
  2293. }
  2294. void SDL_ReleaseGPUFence(
  2295. SDL_GPUDevice *device,
  2296. SDL_GPUFence *fence)
  2297. {
  2298. CHECK_DEVICE_MAGIC(device, );
  2299. if (fence == NULL) {
  2300. return;
  2301. }
  2302. device->ReleaseFence(
  2303. device->driverData,
  2304. fence);
  2305. }