SDL_render_d3d.c 75 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2026 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. #ifdef SDL_VIDEO_RENDER_D3D
  20. #include "../../core/windows/SDL_windows.h"
  21. #include "../SDL_sysrender.h"
  22. #include "../SDL_d3dmath.h"
  23. #include "../../video/windows/SDL_windowsvideo.h"
  24. #include "../../video/SDL_pixels_c.h"
  25. #define D3D_DEBUG_INFO
  26. #include <d3d9.h>
  27. #include "SDL_shaders_d3d.h"
  28. typedef struct
  29. {
  30. SDL_Rect viewport;
  31. bool viewport_dirty;
  32. SDL_Texture *texture;
  33. SDL_BlendMode blend;
  34. bool cliprect_enabled;
  35. bool cliprect_enabled_dirty;
  36. SDL_Rect cliprect;
  37. bool cliprect_dirty;
  38. D3D9_Shader shader;
  39. const float *shader_params;
  40. bool texture_state_dirty;
  41. } D3D_DrawStateCache;
  42. typedef struct
  43. {
  44. bool dirty;
  45. int w, h;
  46. DWORD usage;
  47. Uint32 format;
  48. D3DFORMAT d3dfmt;
  49. IDirect3DTexture9 *texture;
  50. IDirect3DTexture9 *staging;
  51. } D3D_TextureRep;
  52. struct D3D_PaletteData
  53. {
  54. D3D_TextureRep texture;
  55. struct D3D_PaletteData *prev;
  56. struct D3D_PaletteData *next;
  57. };
  58. typedef struct D3D_PaletteData D3D_PaletteData;
  59. // Direct3D renderer implementation
  60. typedef struct
  61. {
  62. void *d3dDLL;
  63. IDirect3D9 *d3d;
  64. IDirect3DDevice9 *device;
  65. UINT adapter;
  66. D3DPRESENT_PARAMETERS pparams;
  67. bool updateSize;
  68. bool beginScene;
  69. bool enableSeparateAlphaBlend;
  70. SDL_ScaleMode scaleMode[3];
  71. SDL_TextureAddressMode addressModeU[3];
  72. SDL_TextureAddressMode addressModeV[3];
  73. IDirect3DSurface9 *defaultRenderTarget;
  74. IDirect3DSurface9 *currentRenderTarget;
  75. void *d3dxDLL;
  76. LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
  77. LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
  78. size_t vertexBufferSize[8];
  79. int currentVertexBuffer;
  80. bool reportedVboProblem;
  81. D3D_DrawStateCache drawstate;
  82. D3D_PaletteData *palettes;
  83. } D3D_RenderData;
  84. typedef struct
  85. {
  86. D3D_TextureRep texture;
  87. UINT shader_params_length;
  88. const float *shader_params;
  89. float palette_shader_params[4];
  90. #ifdef SDL_HAVE_YUV
  91. // YV12 texture support
  92. bool yuv;
  93. D3D_TextureRep utexture;
  94. D3D_TextureRep vtexture;
  95. Uint8 *pixels;
  96. int pitch;
  97. SDL_Rect locked_rect;
  98. #endif
  99. } D3D_TextureData;
  100. typedef struct
  101. {
  102. float x, y, z;
  103. DWORD color;
  104. float u, v;
  105. } Vertex;
  106. static bool D3D_SetError(const char *prefix, HRESULT result)
  107. {
  108. const char *error;
  109. switch (result) {
  110. case D3DERR_WRONGTEXTUREFORMAT:
  111. error = "WRONGTEXTUREFORMAT";
  112. break;
  113. case D3DERR_UNSUPPORTEDCOLOROPERATION:
  114. error = "UNSUPPORTEDCOLOROPERATION";
  115. break;
  116. case D3DERR_UNSUPPORTEDCOLORARG:
  117. error = "UNSUPPORTEDCOLORARG";
  118. break;
  119. case D3DERR_UNSUPPORTEDALPHAOPERATION:
  120. error = "UNSUPPORTEDALPHAOPERATION";
  121. break;
  122. case D3DERR_UNSUPPORTEDALPHAARG:
  123. error = "UNSUPPORTEDALPHAARG";
  124. break;
  125. case D3DERR_TOOMANYOPERATIONS:
  126. error = "TOOMANYOPERATIONS";
  127. break;
  128. case D3DERR_CONFLICTINGTEXTUREFILTER:
  129. error = "CONFLICTINGTEXTUREFILTER";
  130. break;
  131. case D3DERR_UNSUPPORTEDFACTORVALUE:
  132. error = "UNSUPPORTEDFACTORVALUE";
  133. break;
  134. case D3DERR_CONFLICTINGRENDERSTATE:
  135. error = "CONFLICTINGRENDERSTATE";
  136. break;
  137. case D3DERR_UNSUPPORTEDTEXTUREFILTER:
  138. error = "UNSUPPORTEDTEXTUREFILTER";
  139. break;
  140. case D3DERR_CONFLICTINGTEXTUREPALETTE:
  141. error = "CONFLICTINGTEXTUREPALETTE";
  142. break;
  143. case D3DERR_DRIVERINTERNALERROR:
  144. error = "DRIVERINTERNALERROR";
  145. break;
  146. case D3DERR_NOTFOUND:
  147. error = "NOTFOUND";
  148. break;
  149. case D3DERR_MOREDATA:
  150. error = "MOREDATA";
  151. break;
  152. case D3DERR_DEVICELOST:
  153. error = "DEVICELOST";
  154. break;
  155. case D3DERR_DEVICENOTRESET:
  156. error = "DEVICENOTRESET";
  157. break;
  158. case D3DERR_NOTAVAILABLE:
  159. error = "NOTAVAILABLE";
  160. break;
  161. case D3DERR_OUTOFVIDEOMEMORY:
  162. error = "OUTOFVIDEOMEMORY";
  163. break;
  164. case D3DERR_INVALIDDEVICE:
  165. error = "INVALIDDEVICE";
  166. break;
  167. case D3DERR_INVALIDCALL:
  168. error = "INVALIDCALL";
  169. break;
  170. case D3DERR_DRIVERINVALIDCALL:
  171. error = "DRIVERINVALIDCALL";
  172. break;
  173. case D3DERR_WASSTILLDRAWING:
  174. error = "WASSTILLDRAWING";
  175. break;
  176. default:
  177. error = "UNKNOWN";
  178. break;
  179. }
  180. return SDL_SetError("%s: %s", prefix, error);
  181. }
  182. static const struct {
  183. Uint32 sdl;
  184. D3DFORMAT d3d;
  185. } d3d_format_map[] = {
  186. { SDL_PIXELFORMAT_ARGB8888, D3DFMT_A8R8G8B8 },
  187. { SDL_PIXELFORMAT_XRGB8888, D3DFMT_X8R8G8B8 },
  188. { SDL_PIXELFORMAT_ABGR8888, D3DFMT_A8B8G8R8 },
  189. { SDL_PIXELFORMAT_XBGR8888, D3DFMT_X8B8G8R8 },
  190. { SDL_PIXELFORMAT_ARGB2101010, D3DFMT_A2R10G10B10 },
  191. { SDL_PIXELFORMAT_RGB565, D3DFMT_R5G6B5 },
  192. { SDL_PIXELFORMAT_ARGB1555, D3DFMT_A1R5G5B5 },
  193. { SDL_PIXELFORMAT_XRGB1555, D3DFMT_X1R5G5B5 },
  194. { SDL_PIXELFORMAT_ARGB4444, D3DFMT_A4R4G4B4 },
  195. { SDL_PIXELFORMAT_XRGB4444, D3DFMT_X4R4G4B4 }
  196. };
  197. static D3DFORMAT PixelFormatToD3DFMT(Uint32 format)
  198. {
  199. switch (format) {
  200. case SDL_PIXELFORMAT_INDEX8:
  201. case SDL_PIXELFORMAT_YV12:
  202. case SDL_PIXELFORMAT_IYUV:
  203. case SDL_PIXELFORMAT_NV12:
  204. case SDL_PIXELFORMAT_NV21:
  205. case SDL_PIXELFORMAT_P408:
  206. return D3DFMT_L8;
  207. default:
  208. for (int i = 0; i < SDL_arraysize(d3d_format_map); i++) {
  209. if (d3d_format_map[i].sdl == format) {
  210. return d3d_format_map[i].d3d;
  211. }
  212. }
  213. return D3DFMT_UNKNOWN;
  214. }
  215. }
  216. static SDL_PixelFormat D3DFMTToPixelFormat(D3DFORMAT format)
  217. {
  218. for (int i = 0; i < SDL_arraysize(d3d_format_map); i++) {
  219. if (d3d_format_map[i].d3d == format) {
  220. return d3d_format_map[i].sdl;
  221. }
  222. }
  223. return SDL_PIXELFORMAT_UNKNOWN;
  224. }
  225. static void D3D_InitRenderState(D3D_RenderData *data)
  226. {
  227. D3DMATRIX matrix;
  228. IDirect3DDevice9 *device = data->device;
  229. IDirect3DDevice9_SetPixelShader(device, NULL);
  230. IDirect3DDevice9_SetTexture(device, 0, NULL);
  231. IDirect3DDevice9_SetTexture(device, 1, NULL);
  232. IDirect3DDevice9_SetTexture(device, 2, NULL);
  233. IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
  234. IDirect3DDevice9_SetVertexShader(device, NULL);
  235. IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
  236. IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
  237. IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
  238. // Enable color modulation by diffuse color
  239. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
  240. D3DTOP_MODULATE);
  241. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
  242. D3DTA_TEXTURE);
  243. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
  244. D3DTA_DIFFUSE);
  245. // Enable alpha modulation by diffuse alpha
  246. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
  247. D3DTOP_MODULATE);
  248. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
  249. D3DTA_TEXTURE);
  250. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
  251. D3DTA_DIFFUSE);
  252. // Enable separate alpha blend function, if possible
  253. if (data->enableSeparateAlphaBlend) {
  254. IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
  255. }
  256. // Disable second texture stage, since we're done
  257. IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
  258. D3DTOP_DISABLE);
  259. IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
  260. D3DTOP_DISABLE);
  261. // Set an identity world and view matrix
  262. SDL_zero(matrix);
  263. matrix.m[0][0] = 1.0f;
  264. matrix.m[1][1] = 1.0f;
  265. matrix.m[2][2] = 1.0f;
  266. matrix.m[3][3] = 1.0f;
  267. IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
  268. IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
  269. // Reset our current scale mode
  270. for (int i = 0; i < SDL_arraysize(data->scaleMode); ++i) {
  271. data->scaleMode[i] = SDL_SCALEMODE_INVALID;
  272. }
  273. // Reset our current address mode
  274. for (int i = 0; i < SDL_arraysize(data->addressModeU); ++i) {
  275. data->addressModeU[i] = SDL_TEXTURE_ADDRESS_INVALID;
  276. }
  277. for (int i = 0; i < SDL_arraysize(data->addressModeV); ++i) {
  278. data->addressModeV[i] = SDL_TEXTURE_ADDRESS_INVALID;
  279. }
  280. // Start the render with beginScene
  281. data->beginScene = true;
  282. }
  283. static bool D3D_Reset(SDL_Renderer *renderer);
  284. static bool D3D_ActivateRenderer(SDL_Renderer *renderer)
  285. {
  286. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  287. HRESULT result;
  288. if (data->updateSize) {
  289. SDL_Window *window = renderer->window;
  290. int w, h;
  291. const SDL_DisplayMode *fullscreen_mode = NULL;
  292. SDL_GetWindowSizeInPixels(window, &w, &h);
  293. data->pparams.BackBufferWidth = w;
  294. data->pparams.BackBufferHeight = h;
  295. if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
  296. fullscreen_mode = SDL_GetWindowFullscreenMode(window);
  297. }
  298. if (fullscreen_mode) {
  299. data->pparams.Windowed = FALSE;
  300. data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode->format);
  301. data->pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode->refresh_rate);
  302. } else {
  303. data->pparams.Windowed = TRUE;
  304. data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  305. data->pparams.FullScreen_RefreshRateInHz = 0;
  306. }
  307. if (!D3D_Reset(renderer)) {
  308. return false;
  309. }
  310. data->updateSize = false;
  311. }
  312. if (data->beginScene) {
  313. result = IDirect3DDevice9_BeginScene(data->device);
  314. if (result == D3DERR_DEVICELOST) {
  315. if (!D3D_Reset(renderer)) {
  316. return false;
  317. }
  318. result = IDirect3DDevice9_BeginScene(data->device);
  319. }
  320. if (FAILED(result)) {
  321. return D3D_SetError("BeginScene()", result);
  322. }
  323. data->beginScene = false;
  324. }
  325. return true;
  326. }
  327. static void D3D_WindowEvent(SDL_Renderer *renderer, const SDL_WindowEvent *event)
  328. {
  329. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  330. if (event->type == SDL_EVENT_WINDOW_PIXEL_SIZE_CHANGED) {
  331. data->updateSize = true;
  332. }
  333. }
  334. static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
  335. {
  336. switch (factor) {
  337. case SDL_BLENDFACTOR_ZERO:
  338. return D3DBLEND_ZERO;
  339. case SDL_BLENDFACTOR_ONE:
  340. return D3DBLEND_ONE;
  341. case SDL_BLENDFACTOR_SRC_COLOR:
  342. return D3DBLEND_SRCCOLOR;
  343. case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
  344. return D3DBLEND_INVSRCCOLOR;
  345. case SDL_BLENDFACTOR_SRC_ALPHA:
  346. return D3DBLEND_SRCALPHA;
  347. case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
  348. return D3DBLEND_INVSRCALPHA;
  349. case SDL_BLENDFACTOR_DST_COLOR:
  350. return D3DBLEND_DESTCOLOR;
  351. case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
  352. return D3DBLEND_INVDESTCOLOR;
  353. case SDL_BLENDFACTOR_DST_ALPHA:
  354. return D3DBLEND_DESTALPHA;
  355. case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
  356. return D3DBLEND_INVDESTALPHA;
  357. default:
  358. break;
  359. }
  360. return (D3DBLEND)0;
  361. }
  362. static D3DBLENDOP GetBlendEquation(SDL_BlendOperation operation)
  363. {
  364. switch (operation) {
  365. case SDL_BLENDOPERATION_ADD:
  366. return D3DBLENDOP_ADD;
  367. case SDL_BLENDOPERATION_SUBTRACT:
  368. return D3DBLENDOP_SUBTRACT;
  369. case SDL_BLENDOPERATION_REV_SUBTRACT:
  370. return D3DBLENDOP_REVSUBTRACT;
  371. case SDL_BLENDOPERATION_MINIMUM:
  372. return D3DBLENDOP_MIN;
  373. case SDL_BLENDOPERATION_MAXIMUM:
  374. return D3DBLENDOP_MAX;
  375. default:
  376. break;
  377. }
  378. return (D3DBLENDOP)0;
  379. }
  380. static bool D3D_SupportsBlendMode(SDL_Renderer *renderer, SDL_BlendMode blendMode)
  381. {
  382. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  383. SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
  384. SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
  385. SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
  386. SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
  387. SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
  388. SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
  389. if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
  390. !GetBlendEquation(colorOperation) ||
  391. !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) ||
  392. !GetBlendEquation(alphaOperation)) {
  393. return false;
  394. }
  395. if (!data->enableSeparateAlphaBlend) {
  396. if ((srcColorFactor != srcAlphaFactor) || (dstColorFactor != dstAlphaFactor) || (colorOperation != alphaOperation)) {
  397. return false;
  398. }
  399. }
  400. return true;
  401. }
  402. static bool D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h)
  403. {
  404. HRESULT result;
  405. texture->dirty = false;
  406. texture->w = w;
  407. texture->h = h;
  408. texture->usage = usage;
  409. texture->format = format;
  410. texture->d3dfmt = d3dfmt;
  411. result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
  412. PixelFormatToD3DFMT(format),
  413. D3DPOOL_DEFAULT, &texture->texture, NULL);
  414. if (FAILED(result)) {
  415. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  416. }
  417. return true;
  418. }
  419. static bool D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  420. {
  421. HRESULT result;
  422. if (!texture->staging) {
  423. result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
  424. texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
  425. if (FAILED(result)) {
  426. return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
  427. }
  428. }
  429. return true;
  430. }
  431. static bool D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  432. {
  433. if (texture->texture) {
  434. IDirect3DTexture9_Release(texture->texture);
  435. texture->texture = NULL;
  436. }
  437. if (texture->staging) {
  438. IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
  439. texture->dirty = true;
  440. }
  441. return true;
  442. }
  443. static bool D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, int x, int y, int w, int h, const void *pixels, int pitch)
  444. {
  445. RECT d3drect;
  446. D3DLOCKED_RECT locked;
  447. const Uint8 *src;
  448. Uint8 *dst;
  449. int row, length;
  450. HRESULT result;
  451. if (!D3D_CreateStagingTexture(device, texture)) {
  452. return false;
  453. }
  454. d3drect.left = x;
  455. d3drect.right = (LONG)x + w;
  456. d3drect.top = y;
  457. d3drect.bottom = (LONG)y + h;
  458. result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
  459. if (FAILED(result)) {
  460. return D3D_SetError("LockRect()", result);
  461. }
  462. src = (const Uint8 *)pixels;
  463. dst = (Uint8 *)locked.pBits;
  464. length = w * SDL_BYTESPERPIXEL(texture->format);
  465. if (length == pitch && length == locked.Pitch) {
  466. SDL_memcpy(dst, src, (size_t)length * h);
  467. } else {
  468. if (length > pitch) {
  469. length = pitch;
  470. }
  471. if (length > locked.Pitch) {
  472. length = locked.Pitch;
  473. }
  474. for (row = 0; row < h; ++row) {
  475. SDL_memcpy(dst, src, length);
  476. src += pitch;
  477. dst += locked.Pitch;
  478. }
  479. }
  480. result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
  481. if (FAILED(result)) {
  482. return D3D_SetError("UnlockRect()", result);
  483. }
  484. texture->dirty = true;
  485. return true;
  486. }
  487. static void D3D_DestroyTextureRep(D3D_TextureRep *texture)
  488. {
  489. if (texture->texture) {
  490. IDirect3DTexture9_Release(texture->texture);
  491. texture->texture = NULL;
  492. }
  493. if (texture->staging) {
  494. IDirect3DTexture9_Release(texture->staging);
  495. texture->staging = NULL;
  496. }
  497. }
  498. static bool D3D_CreatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
  499. {
  500. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  501. D3D_PaletteData *palettedata = (D3D_PaletteData *)SDL_calloc(1, sizeof(*palettedata));
  502. if (!palettedata) {
  503. return false;
  504. }
  505. palette->internal = palettedata;
  506. if (!D3D_CreateTextureRep(data->device, &palettedata->texture, 0, SDL_PIXELFORMAT_ARGB8888, D3DFMT_A8R8G8B8, 256, 1)) {
  507. SDL_free(palettedata);
  508. return false;
  509. }
  510. // Keep a reference to the palette so we can restore the texture if we lose the D3D device
  511. if (data->palettes) {
  512. palettedata->next = data->palettes;
  513. data->palettes->prev = palettedata;
  514. }
  515. data->palettes = palettedata;
  516. return true;
  517. }
  518. static bool D3D_UpdatePalette(SDL_Renderer *renderer, SDL_TexturePalette *palette, int ncolors, SDL_Color *colors)
  519. {
  520. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  521. D3D_PaletteData *palettedata = (D3D_PaletteData *)palette->internal;
  522. bool retval;
  523. Uint32 *entries = SDL_stack_alloc(Uint32, ncolors);
  524. if (!entries) {
  525. return false;
  526. }
  527. for (int i = 0; i < ncolors; ++i) {
  528. entries[i] = (colors[i].a << 24) | (colors[i].r << 16) | (colors[i].g << 8) | colors[i].b;
  529. }
  530. retval = D3D_UpdateTextureRep(data->device, &palettedata->texture, 0, 0, ncolors, 1, entries, ncolors * sizeof(*entries));
  531. SDL_stack_free(entries);
  532. return retval;
  533. }
  534. static void D3D_DestroyPalette(SDL_Renderer *renderer, SDL_TexturePalette *palette)
  535. {
  536. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  537. D3D_PaletteData *palettedata = (D3D_PaletteData *)palette->internal;
  538. if (palettedata) {
  539. D3D_DestroyTextureRep(&palettedata->texture);
  540. if (data->palettes == palettedata) {
  541. data->palettes = palettedata->next;
  542. } else if (palettedata->prev) {
  543. palettedata->prev->next = palettedata->next;
  544. }
  545. if (palettedata->next) {
  546. palettedata->next->prev = palettedata->prev;
  547. }
  548. SDL_free(palettedata);
  549. }
  550. }
  551. static bool D3D_UpdateTexture(SDL_Renderer *renderer, SDL_Texture *texture,
  552. const SDL_Rect *rect, const void *pixels, int pitch)
  553. {
  554. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  555. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  556. if (!texturedata) {
  557. return SDL_SetError("Texture is not currently available");
  558. }
  559. if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
  560. return false;
  561. }
  562. #ifdef SDL_HAVE_YUV
  563. if (texturedata->yuv) {
  564. if (texture->format == SDL_PIXELFORMAT_P408) {
  565. // Skip to the correct offset into the next texture
  566. pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
  567. if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
  568. return false;
  569. }
  570. // Skip to the correct offset into the next texture
  571. pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
  572. if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x, rect->y, rect->w, rect->h, pixels, pitch)) {
  573. return false;
  574. }
  575. } else {
  576. // Skip to the correct offset into the next texture
  577. pixels = (const void *)((const Uint8 *)pixels + rect->h * pitch);
  578. if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
  579. return false;
  580. }
  581. // Skip to the correct offset into the next texture
  582. pixels = (const void *)((const Uint8 *)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
  583. if (!D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2)) {
  584. return false;
  585. }
  586. }
  587. }
  588. #endif
  589. return true;
  590. }
  591. static bool D3D_CreateTexture(SDL_Renderer *renderer, SDL_Texture *texture, SDL_PropertiesID create_props)
  592. {
  593. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  594. D3D_TextureData *texturedata;
  595. DWORD usage;
  596. texturedata = (D3D_TextureData *)SDL_calloc(1, sizeof(*texturedata));
  597. if (!texturedata) {
  598. return false;
  599. }
  600. texture->internal = texturedata;
  601. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  602. usage = D3DUSAGE_RENDERTARGET;
  603. } else {
  604. usage = 0;
  605. }
  606. if (!D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) {
  607. return false;
  608. }
  609. if (texture->format == SDL_PIXELFORMAT_INDEX8) {
  610. texturedata->shader_params_length = 1; // The palette shader takes 1 float4 parameters
  611. texturedata->shader_params = texturedata->palette_shader_params;
  612. texturedata->palette_shader_params[0] = 1.0f / texture->w;
  613. texturedata->palette_shader_params[1] = 1.0f / texture->h;
  614. texturedata->palette_shader_params[2] = texture->w;
  615. texturedata->palette_shader_params[3] = texture->h;
  616. }
  617. #ifdef SDL_HAVE_YUV
  618. if (texture->format == SDL_PIXELFORMAT_YV12 ||
  619. texture->format == SDL_PIXELFORMAT_IYUV) {
  620. texturedata->yuv = true;
  621. if (!D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2)) {
  622. return false;
  623. }
  624. if (!D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2)) {
  625. return false;
  626. }
  627. texturedata->shader_params_length = 4; // The YUV shader takes 4 float4 parameters
  628. texturedata->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
  629. if (texturedata->shader_params == NULL) {
  630. return SDL_SetError("Unsupported YUV colorspace");
  631. }
  632. }
  633. if (texture->format == SDL_PIXELFORMAT_P408) {
  634. texturedata->yuv = true;
  635. if (!D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) {
  636. return false;
  637. }
  638. if (!D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h)) {
  639. return false;
  640. }
  641. texturedata->shader_params_length = 4; // The YUV shader takes 4 float4 parameters
  642. texturedata->shader_params = SDL_GetYCbCRtoRGBConversionMatrix(texture->colorspace, texture->w, texture->h, 8);
  643. if (texturedata->shader_params == NULL) {
  644. return SDL_SetError("Unsupported YUV colorspace");
  645. }
  646. }
  647. #endif
  648. return true;
  649. }
  650. static bool D3D_RecreateTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  651. {
  652. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  653. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  654. if (!texturedata) {
  655. return true;
  656. }
  657. if (!D3D_RecreateTextureRep(data->device, &texturedata->texture)) {
  658. return false;
  659. }
  660. #ifdef SDL_HAVE_YUV
  661. if (texturedata->yuv) {
  662. if (!D3D_RecreateTextureRep(data->device, &texturedata->utexture)) {
  663. return false;
  664. }
  665. if (!D3D_RecreateTextureRep(data->device, &texturedata->vtexture)) {
  666. return false;
  667. }
  668. }
  669. #endif
  670. return true;
  671. }
  672. #ifdef SDL_HAVE_YUV
  673. static bool D3D_UpdateTextureYUV(SDL_Renderer *renderer, SDL_Texture *texture,
  674. const SDL_Rect *rect,
  675. const Uint8 *Yplane, int Ypitch,
  676. const Uint8 *Uplane, int Upitch,
  677. const Uint8 *Vplane, int Vpitch)
  678. {
  679. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  680. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  681. if (!texturedata) {
  682. return SDL_SetError("Texture is not currently available");
  683. }
  684. if (!D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch)) {
  685. return false;
  686. }
  687. if (texture->format == SDL_PIXELFORMAT_P408) {
  688. if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x, rect->y, rect->w, rect->h, Uplane, Upitch)) {
  689. return false;
  690. }
  691. if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x, rect->y, rect->w, rect->h, Vplane, Vpitch)) {
  692. return false;
  693. }
  694. } else {
  695. if (!D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch)) {
  696. return false;
  697. }
  698. if (!D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch)) {
  699. return false;
  700. }
  701. }
  702. return true;
  703. }
  704. #endif
  705. static bool D3D_LockTexture(SDL_Renderer *renderer, SDL_Texture *texture,
  706. const SDL_Rect *rect, void **pixels, int *pitch)
  707. {
  708. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  709. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  710. IDirect3DDevice9 *device = data->device;
  711. if (!texturedata) {
  712. return SDL_SetError("Texture is not currently available");
  713. }
  714. #ifdef SDL_HAVE_YUV
  715. texturedata->locked_rect = *rect;
  716. if (texturedata->yuv) {
  717. // It's more efficient to upload directly...
  718. if (!texturedata->pixels) {
  719. texturedata->pitch = texture->w;
  720. texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
  721. if (!texturedata->pixels) {
  722. return false;
  723. }
  724. }
  725. *pixels =
  726. (void *)(texturedata->pixels + rect->y * texturedata->pitch +
  727. rect->x * SDL_BYTESPERPIXEL(texture->format));
  728. *pitch = texturedata->pitch;
  729. } else
  730. #endif
  731. {
  732. RECT d3drect;
  733. D3DLOCKED_RECT locked;
  734. HRESULT result;
  735. if (!D3D_CreateStagingTexture(device, &texturedata->texture)) {
  736. return false;
  737. }
  738. d3drect.left = rect->x;
  739. d3drect.right = (LONG)rect->x + rect->w;
  740. d3drect.top = rect->y;
  741. d3drect.bottom = (LONG)rect->y + rect->h;
  742. result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
  743. if (FAILED(result)) {
  744. return D3D_SetError("LockRect()", result);
  745. }
  746. *pixels = locked.pBits;
  747. *pitch = locked.Pitch;
  748. }
  749. return true;
  750. }
  751. static void D3D_UnlockTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  752. {
  753. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  754. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  755. if (!texturedata) {
  756. return;
  757. }
  758. #ifdef SDL_HAVE_YUV
  759. if (texturedata->yuv) {
  760. const SDL_Rect *rect = &texturedata->locked_rect;
  761. void *pixels =
  762. (void *)(texturedata->pixels + rect->y * texturedata->pitch +
  763. rect->x * SDL_BYTESPERPIXEL(texture->format));
  764. D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
  765. } else
  766. #endif
  767. {
  768. IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
  769. texturedata->texture.dirty = true;
  770. if (data->drawstate.texture == texture) {
  771. data->drawstate.texture = NULL;
  772. data->drawstate.shader = SHADER_NONE;
  773. data->drawstate.shader_params = NULL;
  774. data->drawstate.texture_state_dirty = false;
  775. IDirect3DDevice9_SetPixelShader(data->device, NULL);
  776. IDirect3DDevice9_SetTexture(data->device, 0, NULL);
  777. }
  778. }
  779. }
  780. static bool D3D_SetRenderTargetInternal(SDL_Renderer *renderer, SDL_Texture *texture)
  781. {
  782. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  783. D3D_TextureData *texturedata;
  784. D3D_TextureRep *texturerep;
  785. HRESULT result;
  786. IDirect3DDevice9 *device = data->device;
  787. // Release the previous render target if it wasn't the default one
  788. if (data->currentRenderTarget) {
  789. IDirect3DSurface9_Release(data->currentRenderTarget);
  790. data->currentRenderTarget = NULL;
  791. }
  792. if (!texture) {
  793. IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  794. return true;
  795. }
  796. texturedata = (D3D_TextureData *)texture->internal;
  797. if (!texturedata) {
  798. return SDL_SetError("Texture is not currently available");
  799. }
  800. // Make sure the render target is updated if it was locked and written to
  801. texturerep = &texturedata->texture;
  802. if (texturerep->dirty && texturerep->staging) {
  803. if (!texturerep->texture) {
  804. result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
  805. PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
  806. if (FAILED(result)) {
  807. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  808. }
  809. }
  810. result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
  811. if (FAILED(result)) {
  812. return D3D_SetError("UpdateTexture()", result);
  813. }
  814. texturerep->dirty = false;
  815. }
  816. result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
  817. if (FAILED(result)) {
  818. return D3D_SetError("GetSurfaceLevel()", result);
  819. }
  820. result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  821. if (FAILED(result)) {
  822. return D3D_SetError("SetRenderTarget()", result);
  823. }
  824. return true;
  825. }
  826. static bool D3D_SetRenderTarget(SDL_Renderer *renderer, SDL_Texture *texture)
  827. {
  828. if (!D3D_ActivateRenderer(renderer)) {
  829. return false;
  830. }
  831. return D3D_SetRenderTargetInternal(renderer, texture);
  832. }
  833. static bool D3D_QueueNoOp(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
  834. {
  835. return true; // nothing to do in this backend.
  836. }
  837. static bool D3D_QueueDrawPoints(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
  838. {
  839. const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.draw.color.r * cmd->data.draw.color_scale,
  840. cmd->data.draw.color.g * cmd->data.draw.color_scale,
  841. cmd->data.draw.color.b * cmd->data.draw.color_scale,
  842. cmd->data.draw.color.a);
  843. const size_t vertslen = count * sizeof(Vertex);
  844. Vertex *verts = (Vertex *)SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
  845. int i;
  846. if (!verts) {
  847. return false;
  848. }
  849. SDL_memset(verts, '\0', vertslen);
  850. cmd->data.draw.count = count;
  851. for (i = 0; i < count; i++, verts++, points++) {
  852. verts->x = points->x;
  853. verts->y = points->y;
  854. verts->color = color;
  855. }
  856. return true;
  857. }
  858. static bool D3D_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
  859. const float *xy, int xy_stride, const SDL_FColor *color, int color_stride, const float *uv, int uv_stride,
  860. int num_vertices, const void *indices, int num_indices, int size_indices,
  861. float scale_x, float scale_y)
  862. {
  863. int i;
  864. int count = indices ? num_indices : num_vertices;
  865. Vertex *verts = (Vertex *)SDL_AllocateRenderVertices(renderer, count * sizeof(Vertex), 0, &cmd->data.draw.first);
  866. const float color_scale = cmd->data.draw.color_scale;
  867. if (!verts) {
  868. return false;
  869. }
  870. cmd->data.draw.count = count;
  871. size_indices = indices ? size_indices : 0;
  872. for (i = 0; i < count; i++) {
  873. int j;
  874. float *xy_;
  875. SDL_FColor *col_;
  876. if (size_indices == 4) {
  877. j = ((const Uint32 *)indices)[i];
  878. } else if (size_indices == 2) {
  879. j = ((const Uint16 *)indices)[i];
  880. } else if (size_indices == 1) {
  881. j = ((const Uint8 *)indices)[i];
  882. } else {
  883. j = i;
  884. }
  885. xy_ = (float *)((char *)xy + j * xy_stride);
  886. col_ = (SDL_FColor *)((char *)color + j * color_stride);
  887. verts->x = xy_[0] * scale_x - 0.5f;
  888. verts->y = xy_[1] * scale_y - 0.5f;
  889. verts->z = 0.0f;
  890. verts->color = D3DCOLOR_COLORVALUE(col_->r * color_scale, col_->g * color_scale, col_->b * color_scale, col_->a);
  891. if (texture) {
  892. float *uv_ = (float *)((char *)uv + j * uv_stride);
  893. verts->u = uv_[0];
  894. verts->v = uv_[1];
  895. } else {
  896. verts->u = 0.0f;
  897. verts->v = 0.0f;
  898. }
  899. verts += 1;
  900. }
  901. return true;
  902. }
  903. static bool UpdateDirtyTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  904. {
  905. if (texture->dirty && texture->staging) {
  906. HRESULT result;
  907. if (!texture->texture) {
  908. result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  909. PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
  910. if (FAILED(result)) {
  911. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  912. }
  913. }
  914. result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
  915. if (FAILED(result)) {
  916. return D3D_SetError("UpdateTexture()", result);
  917. }
  918. texture->dirty = false;
  919. }
  920. return true;
  921. }
  922. static bool BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
  923. {
  924. HRESULT result;
  925. UpdateDirtyTexture(device, texture);
  926. result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
  927. if (FAILED(result)) {
  928. return D3D_SetError("SetTexture()", result);
  929. }
  930. return true;
  931. }
  932. static void UpdateTextureScaleMode(D3D_RenderData *data, SDL_ScaleMode scaleMode, unsigned index)
  933. {
  934. if (scaleMode != data->scaleMode[index]) {
  935. switch (scaleMode) {
  936. case SDL_SCALEMODE_PIXELART:
  937. case SDL_SCALEMODE_NEAREST:
  938. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, D3DTEXF_POINT);
  939. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, D3DTEXF_POINT);
  940. break;
  941. case SDL_SCALEMODE_LINEAR:
  942. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
  943. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
  944. break;
  945. default:
  946. break;
  947. }
  948. data->scaleMode[index] = scaleMode;
  949. }
  950. }
  951. static DWORD TranslateAddressMode(SDL_TextureAddressMode addressMode)
  952. {
  953. switch (addressMode) {
  954. case SDL_TEXTURE_ADDRESS_CLAMP:
  955. return D3DTADDRESS_CLAMP;
  956. case SDL_TEXTURE_ADDRESS_WRAP:
  957. return D3DTADDRESS_WRAP;
  958. default:
  959. SDL_assert(!"Unknown texture address mode");
  960. return D3DTADDRESS_CLAMP;
  961. }
  962. }
  963. static void UpdateTextureAddressMode(D3D_RenderData *data, SDL_TextureAddressMode addressModeU, SDL_TextureAddressMode addressModeV, unsigned index)
  964. {
  965. if (addressModeU != data->addressModeU[index]) {
  966. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU, TranslateAddressMode(addressModeU));
  967. data->addressModeU[index] = addressModeU;
  968. }
  969. if (addressModeV != data->addressModeV[index]) {
  970. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV, TranslateAddressMode(addressModeV));
  971. data->addressModeV[index] = addressModeV;
  972. }
  973. }
  974. static bool SetupTextureState(D3D_RenderData *data, SDL_Texture *texture, SDL_ScaleMode scale_mode, D3D9_Shader *shader, const float **shader_params)
  975. {
  976. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  977. if (!texturedata) {
  978. return SDL_SetError("Texture is not currently available");
  979. }
  980. if (texture->format == SDL_PIXELFORMAT_INDEX8) {
  981. if (scale_mode == SDL_SCALEMODE_LINEAR) {
  982. *shader = SHADER_PALETTE_LINEAR;
  983. } else {
  984. *shader = SHADER_PALETTE_NEAREST;
  985. }
  986. #ifdef SDL_HAVE_YUV
  987. } else if (texturedata->yuv) {
  988. *shader = SHADER_YUV;
  989. #endif // SDL_HAVE_YUV
  990. }
  991. *shader_params = texturedata->shader_params;
  992. if (!BindTextureRep(data->device, &texturedata->texture, 0)) {
  993. return false;
  994. }
  995. if (texture->palette) {
  996. D3D_PaletteData *palette = (D3D_PaletteData *)texture->palette->internal;
  997. if (!BindTextureRep(data->device, &palette->texture, 1)) {
  998. return false;
  999. }
  1000. }
  1001. #ifdef SDL_HAVE_YUV
  1002. if (texturedata->yuv) {
  1003. if (!BindTextureRep(data->device, &texturedata->utexture, 1)) {
  1004. return false;
  1005. }
  1006. if (!BindTextureRep(data->device, &texturedata->vtexture, 2)) {
  1007. return false;
  1008. }
  1009. }
  1010. #endif
  1011. return true;
  1012. }
  1013. static bool SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
  1014. {
  1015. SDL_Texture *texture = cmd->data.draw.texture;
  1016. const SDL_BlendMode blend = cmd->data.draw.blend;
  1017. if (texture != data->drawstate.texture || data->drawstate.texture_state_dirty) {
  1018. D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *)data->drawstate.texture->internal : NULL;
  1019. D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *)texture->internal : NULL;
  1020. D3D9_Shader shader = SHADER_NONE;
  1021. const float *shader_params = NULL;
  1022. // disable any enabled textures we aren't going to use, let SetupTextureState() do the rest.
  1023. if (!texture) {
  1024. IDirect3DDevice9_SetTexture(data->device, 0, NULL);
  1025. }
  1026. if ((!newtexturedata || !texture->palette) &&
  1027. ((oldtexturedata && data->drawstate.texture->palette) || data->drawstate.texture_state_dirty)) {
  1028. IDirect3DDevice9_SetTexture(data->device, 1, NULL);
  1029. }
  1030. #ifdef SDL_HAVE_YUV
  1031. if ((!newtexturedata || !newtexturedata->yuv) && ((oldtexturedata && oldtexturedata->yuv) || data->drawstate.texture_state_dirty)) {
  1032. IDirect3DDevice9_SetTexture(data->device, 1, NULL);
  1033. IDirect3DDevice9_SetTexture(data->device, 2, NULL);
  1034. }
  1035. #endif
  1036. if (texture && !SetupTextureState(data, texture, cmd->data.draw.texture_scale_mode, &shader, &shader_params)) {
  1037. return false;
  1038. }
  1039. if (shader != data->drawstate.shader || data->drawstate.texture_state_dirty) {
  1040. const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, data->shaders[shader]);
  1041. if (FAILED(result)) {
  1042. return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
  1043. }
  1044. data->drawstate.shader = shader;
  1045. }
  1046. if (shader_params != data->drawstate.shader_params || data->drawstate.texture_state_dirty) {
  1047. if (shader_params) {
  1048. const UINT shader_params_length = 4; // The YUV shader takes 4 float4 parameters
  1049. const HRESULT result = IDirect3DDevice9_SetPixelShaderConstantF(data->device, 0, shader_params, shader_params_length);
  1050. if (FAILED(result)) {
  1051. return D3D_SetError("IDirect3DDevice9_SetPixelShaderConstantF()", result);
  1052. }
  1053. }
  1054. data->drawstate.shader_params = shader_params;
  1055. }
  1056. data->drawstate.texture = texture;
  1057. data->drawstate.texture_state_dirty = false;
  1058. } else if (texture) {
  1059. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  1060. if (texturedata) {
  1061. UpdateDirtyTexture(data->device, &texturedata->texture);
  1062. if (texture->palette) {
  1063. D3D_PaletteData *palettedata = (D3D_PaletteData *)texture->palette->internal;
  1064. UpdateDirtyTexture(data->device, &palettedata->texture);
  1065. }
  1066. #ifdef SDL_HAVE_YUV
  1067. if (texturedata->yuv) {
  1068. UpdateDirtyTexture(data->device, &texturedata->utexture);
  1069. UpdateDirtyTexture(data->device, &texturedata->vtexture);
  1070. }
  1071. #endif // SDL_HAVE_YUV
  1072. }
  1073. }
  1074. if (texture) {
  1075. UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 0);
  1076. UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v, 0);
  1077. #ifdef SDL_HAVE_YUV
  1078. D3D_TextureData *texturedata = (D3D_TextureData *)texture->internal;
  1079. if (texturedata && texturedata->yuv) {
  1080. UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 1);
  1081. UpdateTextureScaleMode(data, cmd->data.draw.texture_scale_mode, 2);
  1082. UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v, 1);
  1083. UpdateTextureAddressMode(data, cmd->data.draw.texture_address_mode_u, cmd->data.draw.texture_address_mode_v, 2);
  1084. }
  1085. #endif // SDL_HAVE_YUV
  1086. }
  1087. if (blend != data->drawstate.blend) {
  1088. if (blend == SDL_BLENDMODE_NONE) {
  1089. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
  1090. } else {
  1091. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
  1092. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1093. GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
  1094. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1095. GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
  1096. IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOP,
  1097. GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
  1098. if (data->enableSeparateAlphaBlend) {
  1099. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1100. GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
  1101. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1102. GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
  1103. IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOPALPHA,
  1104. GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
  1105. }
  1106. }
  1107. data->drawstate.blend = blend;
  1108. }
  1109. if (data->drawstate.viewport_dirty) {
  1110. const SDL_Rect *viewport = &data->drawstate.viewport;
  1111. D3DVIEWPORT9 d3dviewport;
  1112. d3dviewport.X = viewport->x;
  1113. d3dviewport.Y = viewport->y;
  1114. d3dviewport.Width = viewport->w;
  1115. d3dviewport.Height = viewport->h;
  1116. d3dviewport.MinZ = 0.0f;
  1117. d3dviewport.MaxZ = 1.0f;
  1118. IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
  1119. // Set an orthographic projection matrix
  1120. if (viewport->w && viewport->h) {
  1121. D3DMATRIX d3dmatrix;
  1122. SDL_zero(d3dmatrix);
  1123. d3dmatrix.m[0][0] = 2.0f / viewport->w;
  1124. d3dmatrix.m[1][1] = -2.0f / viewport->h;
  1125. d3dmatrix.m[2][2] = 1.0f;
  1126. d3dmatrix.m[3][0] = -1.0f;
  1127. d3dmatrix.m[3][1] = 1.0f;
  1128. d3dmatrix.m[3][3] = 1.0f;
  1129. IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
  1130. }
  1131. data->drawstate.viewport_dirty = false;
  1132. }
  1133. if (data->drawstate.cliprect_enabled_dirty) {
  1134. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
  1135. data->drawstate.cliprect_enabled_dirty = false;
  1136. }
  1137. if (data->drawstate.cliprect_dirty) {
  1138. const SDL_Rect *viewport = &data->drawstate.viewport;
  1139. const SDL_Rect *rect = &data->drawstate.cliprect;
  1140. RECT d3drect;
  1141. d3drect.left = (LONG)viewport->x + rect->x;
  1142. d3drect.top = (LONG)viewport->y + rect->y;
  1143. d3drect.right = (LONG)viewport->x + rect->x + rect->w;
  1144. d3drect.bottom = (LONG)viewport->y + rect->y + rect->h;
  1145. IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
  1146. data->drawstate.cliprect_dirty = false;
  1147. }
  1148. return true;
  1149. }
  1150. static void D3D_InvalidateCachedState(SDL_Renderer *renderer)
  1151. {
  1152. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1153. data->drawstate.viewport_dirty = true;
  1154. data->drawstate.cliprect_enabled_dirty = true;
  1155. data->drawstate.cliprect_dirty = true;
  1156. data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1157. data->drawstate.texture = NULL;
  1158. data->drawstate.shader = SHADER_NONE;
  1159. data->drawstate.shader_params = NULL;
  1160. data->drawstate.texture_state_dirty = true;
  1161. }
  1162. static bool D3D_RunCommandQueue(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  1163. {
  1164. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1165. const int vboidx = data->currentVertexBuffer;
  1166. IDirect3DVertexBuffer9 *vbo = NULL;
  1167. const bool istarget = renderer->target != NULL;
  1168. if (!D3D_ActivateRenderer(renderer)) {
  1169. return false;
  1170. }
  1171. if (vertsize > 0) {
  1172. // upload the new VBO data for this set of commands.
  1173. vbo = data->vertexBuffers[vboidx];
  1174. if (data->vertexBufferSize[vboidx] < vertsize) {
  1175. const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
  1176. const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
  1177. if (vbo) {
  1178. IDirect3DVertexBuffer9_Release(vbo);
  1179. }
  1180. if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, (UINT)vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
  1181. vbo = NULL;
  1182. }
  1183. data->vertexBuffers[vboidx] = vbo;
  1184. data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
  1185. }
  1186. if (vbo) {
  1187. void *ptr;
  1188. if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, (UINT)vertsize, &ptr, D3DLOCK_DISCARD))) {
  1189. vbo = NULL; // oh well, we'll do immediate mode drawing. :(
  1190. } else {
  1191. SDL_memcpy(ptr, vertices, vertsize);
  1192. if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
  1193. vbo = NULL; // oh well, we'll do immediate mode drawing. :(
  1194. }
  1195. }
  1196. }
  1197. // cycle through a few VBOs so D3D has some time with the data before we replace it.
  1198. if (vbo) {
  1199. data->currentVertexBuffer++;
  1200. if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
  1201. data->currentVertexBuffer = 0;
  1202. }
  1203. } else if (!data->reportedVboProblem) {
  1204. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
  1205. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
  1206. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
  1207. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
  1208. data->reportedVboProblem = true;
  1209. }
  1210. }
  1211. IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof(Vertex));
  1212. while (cmd) {
  1213. switch (cmd->command) {
  1214. case SDL_RENDERCMD_SETDRAWCOLOR:
  1215. {
  1216. break; // this isn't currently used in this render backend.
  1217. }
  1218. case SDL_RENDERCMD_SETVIEWPORT:
  1219. {
  1220. SDL_Rect *viewport = &data->drawstate.viewport;
  1221. if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) {
  1222. SDL_copyp(viewport, &cmd->data.viewport.rect);
  1223. data->drawstate.viewport_dirty = true;
  1224. data->drawstate.cliprect_dirty = true;
  1225. }
  1226. break;
  1227. }
  1228. case SDL_RENDERCMD_SETCLIPRECT:
  1229. {
  1230. const SDL_Rect *rect = &cmd->data.cliprect.rect;
  1231. if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
  1232. data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
  1233. data->drawstate.cliprect_enabled_dirty = true;
  1234. }
  1235. if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) {
  1236. SDL_copyp(&data->drawstate.cliprect, rect);
  1237. data->drawstate.cliprect_dirty = true;
  1238. }
  1239. break;
  1240. }
  1241. case SDL_RENDERCMD_CLEAR:
  1242. {
  1243. const DWORD color = D3DCOLOR_COLORVALUE(cmd->data.color.color.r * cmd->data.color.color_scale,
  1244. cmd->data.color.color.g * cmd->data.color.color_scale,
  1245. cmd->data.color.color.b * cmd->data.color.color_scale,
  1246. cmd->data.color.color.a);
  1247. const SDL_Rect *viewport = &data->drawstate.viewport;
  1248. const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
  1249. const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
  1250. const bool viewport_equal = ((viewport->x == 0) && (viewport->y == 0) && (viewport->w == backw) && (viewport->h == backh));
  1251. if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
  1252. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1253. data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
  1254. }
  1255. // Don't reset the viewport if we don't have to!
  1256. if (!data->drawstate.viewport_dirty && viewport_equal) {
  1257. IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1258. } else {
  1259. // Clear is defined to clear the entire render target
  1260. D3DVIEWPORT9 wholeviewport = { 0, 0, 0, 0, 0.0f, 1.0f };
  1261. wholeviewport.Width = backw;
  1262. wholeviewport.Height = backh;
  1263. IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
  1264. data->drawstate.viewport_dirty = true; // we still need to (re)set orthographic projection, so always mark it dirty.
  1265. IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1266. }
  1267. break;
  1268. }
  1269. case SDL_RENDERCMD_DRAW_LINES:
  1270. {
  1271. size_t count = cmd->data.draw.count;
  1272. const size_t first = cmd->data.draw.first;
  1273. const size_t start = first / sizeof(Vertex);
  1274. const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
  1275. SetDrawState(data, cmd);
  1276. // Add the final point in the line
  1277. size_t line_start = 0;
  1278. size_t line_end = line_start + count - 1;
  1279. if (count == 2 || verts[line_start].x != verts[line_end].x || verts[line_start].y != verts[line_end].y) {
  1280. if (vbo) {
  1281. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(start + line_end), 1);
  1282. } else {
  1283. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[line_end], sizeof(Vertex));
  1284. }
  1285. }
  1286. if (count > 2) {
  1287. // joined lines cannot be grouped
  1288. if (vbo) {
  1289. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT)start, (UINT)(count - 1));
  1290. } else {
  1291. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT)(count - 1), verts, sizeof(Vertex));
  1292. }
  1293. } else {
  1294. // let's group non joined lines
  1295. SDL_RenderCommand *finalcmd = cmd;
  1296. SDL_RenderCommand *nextcmd;
  1297. SDL_BlendMode thisblend = cmd->data.draw.blend;
  1298. for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) {
  1299. const SDL_RenderCommandType nextcmdtype = nextcmd->command;
  1300. if (nextcmdtype != SDL_RENDERCMD_DRAW_LINES) {
  1301. if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) {
  1302. // The vertex data has the draw color built in, ignore this
  1303. continue;
  1304. }
  1305. break; // can't go any further on this draw call, different render command up next.
  1306. } else if (nextcmd->data.draw.count != 2) {
  1307. break; // can't go any further on this draw call, those are joined lines
  1308. } else if (nextcmd->data.draw.blend != thisblend) {
  1309. break; // can't go any further on this draw call, different blendmode copy up next.
  1310. } else {
  1311. finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
  1312. // Add the final point in the line
  1313. line_start = count;
  1314. line_end = line_start + nextcmd->data.draw.count - 1;
  1315. if (verts[line_start].x != verts[line_end].x || verts[line_start].y != verts[line_end].y) {
  1316. if (vbo) {
  1317. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)(start + line_end), 1);
  1318. } else {
  1319. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[line_end], sizeof(Vertex));
  1320. }
  1321. }
  1322. count += nextcmd->data.draw.count;
  1323. }
  1324. }
  1325. if (vbo) {
  1326. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINELIST, (UINT)start, (UINT)(count - 1));
  1327. } else {
  1328. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINELIST, (UINT)(count - 1), verts, sizeof(Vertex));
  1329. }
  1330. cmd = finalcmd; // skip any copy commands we just combined in here.
  1331. }
  1332. break;
  1333. }
  1334. case SDL_RENDERCMD_FILL_RECTS: // unused
  1335. break;
  1336. case SDL_RENDERCMD_COPY: // unused
  1337. break;
  1338. case SDL_RENDERCMD_COPY_EX: // unused
  1339. break;
  1340. case SDL_RENDERCMD_DRAW_POINTS:
  1341. case SDL_RENDERCMD_GEOMETRY:
  1342. {
  1343. /* as long as we have the same copy command in a row, with the
  1344. same texture, we can combine them all into a single draw call. */
  1345. SDL_Texture *thistexture = cmd->data.draw.texture;
  1346. SDL_BlendMode thisblend = cmd->data.draw.blend;
  1347. SDL_ScaleMode thisscalemode = cmd->data.draw.texture_scale_mode;
  1348. SDL_TextureAddressMode thisaddressmode_u = cmd->data.draw.texture_address_mode_u;
  1349. SDL_TextureAddressMode thisaddressmode_v = cmd->data.draw.texture_address_mode_v;
  1350. const SDL_RenderCommandType thiscmdtype = cmd->command;
  1351. SDL_RenderCommand *finalcmd = cmd;
  1352. SDL_RenderCommand *nextcmd;
  1353. size_t count = cmd->data.draw.count;
  1354. const size_t first = cmd->data.draw.first;
  1355. const size_t start = first / sizeof(Vertex);
  1356. const Vertex *verts = (Vertex *)(((Uint8 *)vertices) + first);
  1357. for (nextcmd = cmd->next; nextcmd; nextcmd = nextcmd->next) {
  1358. const SDL_RenderCommandType nextcmdtype = nextcmd->command;
  1359. if (nextcmdtype != thiscmdtype) {
  1360. if (nextcmdtype == SDL_RENDERCMD_SETDRAWCOLOR) {
  1361. // The vertex data has the draw color built in, ignore this
  1362. continue;
  1363. }
  1364. break; // can't go any further on this draw call, different render command up next.
  1365. } else if (nextcmd->data.draw.texture != thistexture ||
  1366. nextcmd->data.draw.texture_scale_mode != thisscalemode ||
  1367. nextcmd->data.draw.texture_address_mode_u != thisaddressmode_u ||
  1368. nextcmd->data.draw.texture_address_mode_v != thisaddressmode_v ||
  1369. nextcmd->data.draw.blend != thisblend) {
  1370. break; // can't go any further on this draw call, different texture/blendmode copy up next.
  1371. } else {
  1372. finalcmd = nextcmd; // we can combine copy operations here. Mark this one as the furthest okay command.
  1373. count += nextcmd->data.draw.count;
  1374. }
  1375. }
  1376. SetDrawState(data, cmd);
  1377. if (thiscmdtype == SDL_RENDERCMD_GEOMETRY) {
  1378. if (vbo) {
  1379. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT)start, (UINT)count / 3);
  1380. } else {
  1381. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT)count / 3, verts, sizeof(Vertex));
  1382. }
  1383. } else {
  1384. if (vbo) {
  1385. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT)start, (UINT)count);
  1386. } else {
  1387. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT)count, verts, sizeof(Vertex));
  1388. }
  1389. }
  1390. cmd = finalcmd; // skip any copy commands we just combined in here.
  1391. break;
  1392. }
  1393. case SDL_RENDERCMD_NO_OP:
  1394. break;
  1395. }
  1396. cmd = cmd->next;
  1397. }
  1398. return true;
  1399. }
  1400. static SDL_Surface *D3D_RenderReadPixels(SDL_Renderer *renderer, const SDL_Rect *rect)
  1401. {
  1402. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1403. D3DSURFACE_DESC desc;
  1404. LPDIRECT3DSURFACE9 backBuffer;
  1405. LPDIRECT3DSURFACE9 surface;
  1406. RECT d3drect;
  1407. D3DLOCKED_RECT locked;
  1408. HRESULT result;
  1409. SDL_Surface *output;
  1410. if (data->currentRenderTarget) {
  1411. backBuffer = data->currentRenderTarget;
  1412. } else {
  1413. backBuffer = data->defaultRenderTarget;
  1414. }
  1415. result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1416. if (FAILED(result)) {
  1417. D3D_SetError("GetDesc()", result);
  1418. return NULL;
  1419. }
  1420. result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1421. if (FAILED(result)) {
  1422. D3D_SetError("CreateOffscreenPlainSurface()", result);
  1423. return NULL;
  1424. }
  1425. result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1426. if (FAILED(result)) {
  1427. IDirect3DSurface9_Release(surface);
  1428. D3D_SetError("GetRenderTargetData()", result);
  1429. return NULL;
  1430. }
  1431. d3drect.left = rect->x;
  1432. d3drect.right = (LONG)rect->x + rect->w;
  1433. d3drect.top = rect->y;
  1434. d3drect.bottom = (LONG)rect->y + rect->h;
  1435. result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1436. if (FAILED(result)) {
  1437. IDirect3DSurface9_Release(surface);
  1438. D3D_SetError("LockRect()", result);
  1439. return NULL;
  1440. }
  1441. output = SDL_DuplicatePixels(rect->w, rect->h, D3DFMTToPixelFormat(desc.Format), SDL_COLORSPACE_SRGB, locked.pBits, locked.Pitch);
  1442. IDirect3DSurface9_UnlockRect(surface);
  1443. IDirect3DSurface9_Release(surface);
  1444. return output;
  1445. }
  1446. static bool D3D_RenderPresent(SDL_Renderer *renderer)
  1447. {
  1448. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1449. HRESULT result;
  1450. if (!data->beginScene) {
  1451. IDirect3DDevice9_EndScene(data->device);
  1452. data->beginScene = true;
  1453. }
  1454. result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1455. if (result == D3DERR_DEVICELOST) {
  1456. // We'll reset later
  1457. return false;
  1458. }
  1459. if (result == D3DERR_DEVICENOTRESET) {
  1460. D3D_Reset(renderer);
  1461. }
  1462. result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1463. if (FAILED(result)) {
  1464. return D3D_SetError("Present()", result);
  1465. }
  1466. return true;
  1467. }
  1468. static void D3D_DestroyTexture(SDL_Renderer *renderer, SDL_Texture *texture)
  1469. {
  1470. D3D_RenderData *renderdata = (D3D_RenderData *)renderer->internal;
  1471. D3D_TextureData *data = (D3D_TextureData *)texture->internal;
  1472. if (renderdata->drawstate.texture == texture) {
  1473. renderdata->drawstate.texture = NULL;
  1474. renderdata->drawstate.shader = SHADER_NONE;
  1475. renderdata->drawstate.shader_params = NULL;
  1476. renderdata->drawstate.texture_state_dirty = false;
  1477. IDirect3DDevice9_SetPixelShader(renderdata->device, NULL);
  1478. IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL);
  1479. if (texture->palette) {
  1480. IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL);
  1481. }
  1482. #ifdef SDL_HAVE_YUV
  1483. if (data && data->yuv) {
  1484. IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL);
  1485. IDirect3DDevice9_SetTexture(renderdata->device, 2, NULL);
  1486. }
  1487. #endif
  1488. }
  1489. if (!data) {
  1490. return;
  1491. }
  1492. D3D_DestroyTextureRep(&data->texture);
  1493. #ifdef SDL_HAVE_YUV
  1494. D3D_DestroyTextureRep(&data->utexture);
  1495. D3D_DestroyTextureRep(&data->vtexture);
  1496. SDL_free(data->pixels);
  1497. #endif
  1498. SDL_free(data);
  1499. texture->internal = NULL;
  1500. }
  1501. static void D3D_DestroyRenderer(SDL_Renderer *renderer)
  1502. {
  1503. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1504. if (data) {
  1505. int i;
  1506. // Make sure the palettes have been freed
  1507. SDL_assert(!data->palettes);
  1508. // Release the render target
  1509. if (data->defaultRenderTarget) {
  1510. IDirect3DSurface9_Release(data->defaultRenderTarget);
  1511. data->defaultRenderTarget = NULL;
  1512. }
  1513. if (data->currentRenderTarget) {
  1514. IDirect3DSurface9_Release(data->currentRenderTarget);
  1515. data->currentRenderTarget = NULL;
  1516. }
  1517. for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
  1518. if (data->shaders[i]) {
  1519. IDirect3DPixelShader9_Release(data->shaders[i]);
  1520. data->shaders[i] = NULL;
  1521. }
  1522. }
  1523. // Release all vertex buffers
  1524. for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
  1525. if (data->vertexBuffers[i]) {
  1526. IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
  1527. }
  1528. data->vertexBuffers[i] = NULL;
  1529. }
  1530. if (data->device) {
  1531. IDirect3DDevice9_Release(data->device);
  1532. data->device = NULL;
  1533. }
  1534. if (data->d3d) {
  1535. IDirect3D9_Release(data->d3d);
  1536. SDL_UnloadObject(data->d3dDLL);
  1537. }
  1538. SDL_free(data);
  1539. }
  1540. }
  1541. static bool D3D_Reset(SDL_Renderer *renderer)
  1542. {
  1543. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1544. const Float4X4 d3dmatrix = MatrixIdentity();
  1545. HRESULT result;
  1546. SDL_Texture *texture;
  1547. D3D_PaletteData *palette;
  1548. int i;
  1549. // Cancel any scene that we've started
  1550. if (!data->beginScene) {
  1551. IDirect3DDevice9_EndScene(data->device);
  1552. data->beginScene = true;
  1553. }
  1554. // Release the default render target before reset
  1555. if (data->defaultRenderTarget) {
  1556. IDirect3DSurface9_Release(data->defaultRenderTarget);
  1557. data->defaultRenderTarget = NULL;
  1558. }
  1559. if (data->currentRenderTarget) {
  1560. IDirect3DSurface9_Release(data->currentRenderTarget);
  1561. data->currentRenderTarget = NULL;
  1562. }
  1563. // Release application render targets
  1564. for (texture = renderer->textures; texture; texture = texture->next) {
  1565. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1566. D3D_DestroyTexture(renderer, texture);
  1567. } else {
  1568. D3D_RecreateTexture(renderer, texture);
  1569. }
  1570. }
  1571. // Release all palettes
  1572. for (palette = data->palettes; palette; palette = palette->next) {
  1573. D3D_RecreateTextureRep(data->device, &palette->texture);
  1574. }
  1575. // Release all vertex buffers
  1576. for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
  1577. if (data->vertexBuffers[i]) {
  1578. IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
  1579. }
  1580. data->vertexBuffers[i] = NULL;
  1581. data->vertexBufferSize[i] = 0;
  1582. }
  1583. result = IDirect3DDevice9_Reset(data->device, &data->pparams);
  1584. if (FAILED(result)) {
  1585. if (result == D3DERR_DEVICELOST) {
  1586. // Don't worry about it, we'll reset later...
  1587. return true;
  1588. } else {
  1589. return D3D_SetError("Reset()", result);
  1590. }
  1591. }
  1592. // Allocate application render targets
  1593. for (texture = renderer->textures; texture; texture = texture->next) {
  1594. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1595. D3D_CreateTexture(renderer, texture, 0);
  1596. }
  1597. }
  1598. IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  1599. D3D_InitRenderState(data);
  1600. D3D_SetRenderTargetInternal(renderer, renderer->target);
  1601. D3D_InvalidateCachedState(renderer);
  1602. IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX *)&d3dmatrix);
  1603. // Let the application know that render targets were reset
  1604. {
  1605. SDL_Event event;
  1606. SDL_zero(event);
  1607. event.type = SDL_EVENT_RENDER_TARGETS_RESET;
  1608. event.render.windowID = SDL_GetWindowID(SDL_GetRenderWindow(renderer));
  1609. SDL_PushEvent(&event);
  1610. }
  1611. return true;
  1612. }
  1613. static bool D3D_SetVSync(SDL_Renderer *renderer, const int vsync)
  1614. {
  1615. D3D_RenderData *data = (D3D_RenderData *)renderer->internal;
  1616. DWORD PresentationInterval;
  1617. switch (vsync) {
  1618. case 0:
  1619. PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1620. break;
  1621. case 1:
  1622. PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1623. break;
  1624. case 2:
  1625. PresentationInterval = D3DPRESENT_INTERVAL_TWO;
  1626. break;
  1627. case 3:
  1628. PresentationInterval = D3DPRESENT_INTERVAL_THREE;
  1629. break;
  1630. case 4:
  1631. PresentationInterval = D3DPRESENT_INTERVAL_FOUR;
  1632. break;
  1633. default:
  1634. return SDL_Unsupported();
  1635. }
  1636. D3DCAPS9 caps;
  1637. HRESULT result = IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
  1638. if (FAILED(result)) {
  1639. return D3D_SetError("GetDeviceCaps()", result);
  1640. }
  1641. if (!(caps.PresentationIntervals & PresentationInterval)) {
  1642. return SDL_Unsupported();
  1643. }
  1644. data->pparams.PresentationInterval = PresentationInterval;
  1645. if (!D3D_Reset(renderer)) {
  1646. // D3D_Reset will call SDL_SetError()
  1647. return false;
  1648. }
  1649. return true;
  1650. }
  1651. static bool D3D_CreateRenderer(SDL_Renderer *renderer, SDL_Window *window, SDL_PropertiesID create_props)
  1652. {
  1653. D3D_RenderData *data;
  1654. HRESULT result;
  1655. HWND hwnd;
  1656. D3DDISPLAYMODE displayMode;
  1657. D3DPRESENT_PARAMETERS pparams;
  1658. IDirect3DSwapChain9 *chain;
  1659. D3DCAPS9 caps;
  1660. DWORD device_flags;
  1661. int w, h;
  1662. SDL_DisplayID displayID;
  1663. const SDL_DisplayMode *fullscreen_mode = NULL;
  1664. hwnd = (HWND)SDL_GetPointerProperty(SDL_GetWindowProperties(window), SDL_PROP_WINDOW_WIN32_HWND_POINTER, NULL);
  1665. if (!hwnd) {
  1666. return SDL_SetError("Couldn't get window handle");
  1667. }
  1668. SDL_SetupRendererColorspace(renderer, create_props);
  1669. if (renderer->output_colorspace != SDL_COLORSPACE_SRGB) {
  1670. return SDL_SetError("Unsupported output colorspace");
  1671. }
  1672. data = (D3D_RenderData *)SDL_calloc(1, sizeof(*data));
  1673. if (!data) {
  1674. return false;
  1675. }
  1676. if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
  1677. SDL_free(data);
  1678. return SDL_SetError("Unable to create Direct3D interface");
  1679. }
  1680. renderer->WindowEvent = D3D_WindowEvent;
  1681. renderer->SupportsBlendMode = D3D_SupportsBlendMode;
  1682. renderer->CreatePalette = D3D_CreatePalette;
  1683. renderer->UpdatePalette = D3D_UpdatePalette;
  1684. renderer->DestroyPalette = D3D_DestroyPalette;
  1685. renderer->CreateTexture = D3D_CreateTexture;
  1686. renderer->UpdateTexture = D3D_UpdateTexture;
  1687. #ifdef SDL_HAVE_YUV
  1688. renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
  1689. #endif
  1690. renderer->LockTexture = D3D_LockTexture;
  1691. renderer->UnlockTexture = D3D_UnlockTexture;
  1692. renderer->SetRenderTarget = D3D_SetRenderTarget;
  1693. renderer->QueueSetViewport = D3D_QueueNoOp;
  1694. renderer->QueueSetDrawColor = D3D_QueueNoOp;
  1695. renderer->QueueDrawPoints = D3D_QueueDrawPoints;
  1696. renderer->QueueDrawLines = D3D_QueueDrawPoints; // lines and points queue vertices the same way.
  1697. renderer->QueueGeometry = D3D_QueueGeometry;
  1698. renderer->InvalidateCachedState = D3D_InvalidateCachedState;
  1699. renderer->RunCommandQueue = D3D_RunCommandQueue;
  1700. renderer->RenderReadPixels = D3D_RenderReadPixels;
  1701. renderer->RenderPresent = D3D_RenderPresent;
  1702. renderer->DestroyTexture = D3D_DestroyTexture;
  1703. renderer->DestroyRenderer = D3D_DestroyRenderer;
  1704. renderer->SetVSync = D3D_SetVSync;
  1705. renderer->internal = data;
  1706. D3D_InvalidateCachedState(renderer);
  1707. renderer->name = D3D_RenderDriver.name;
  1708. SDL_GetWindowSizeInPixels(window, &w, &h);
  1709. if (SDL_GetWindowFlags(window) & SDL_WINDOW_FULLSCREEN) {
  1710. fullscreen_mode = SDL_GetWindowFullscreenMode(window);
  1711. }
  1712. SDL_zero(pparams);
  1713. pparams.hDeviceWindow = hwnd;
  1714. pparams.BackBufferWidth = w;
  1715. pparams.BackBufferHeight = h;
  1716. pparams.BackBufferCount = 1;
  1717. pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
  1718. if (fullscreen_mode) {
  1719. pparams.Windowed = FALSE;
  1720. pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode->format);
  1721. pparams.FullScreen_RefreshRateInHz = (UINT)SDL_ceilf(fullscreen_mode->refresh_rate);
  1722. } else {
  1723. pparams.Windowed = TRUE;
  1724. pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  1725. pparams.FullScreen_RefreshRateInHz = 0;
  1726. }
  1727. pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1728. // Get the adapter for the display that the window is on
  1729. displayID = SDL_GetDisplayForWindow(window);
  1730. data->adapter = SDL_GetDirect3D9AdapterIndex(displayID);
  1731. result = IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
  1732. if (FAILED(result)) {
  1733. return D3D_SetError("GetDeviceCaps()", result);
  1734. }
  1735. device_flags = D3DCREATE_FPU_PRESERVE;
  1736. if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
  1737. device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1738. } else {
  1739. device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1740. }
  1741. if (caps.TextureCaps & D3DPTEXTURECAPS_POW2) {
  1742. if (caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL) {
  1743. renderer->npot_texture_wrap_unsupported = true;
  1744. } else {
  1745. return SDL_SetError("Non-power-of-two textures are not supported");
  1746. }
  1747. }
  1748. if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, false)) {
  1749. device_flags |= D3DCREATE_MULTITHREADED;
  1750. }
  1751. result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
  1752. D3DDEVTYPE_HAL,
  1753. pparams.hDeviceWindow,
  1754. device_flags,
  1755. &pparams, &data->device);
  1756. if (FAILED(result)) {
  1757. return D3D_SetError("CreateDevice()", result);
  1758. }
  1759. // Get presentation parameters to fill info
  1760. result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
  1761. if (FAILED(result)) {
  1762. return D3D_SetError("GetSwapChain()", result);
  1763. }
  1764. result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
  1765. if (FAILED(result)) {
  1766. IDirect3DSwapChain9_Release(chain);
  1767. return D3D_SetError("GetPresentParameters()", result);
  1768. }
  1769. IDirect3DSwapChain9_Release(chain);
  1770. data->pparams = pparams;
  1771. IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
  1772. SDL_SetNumberProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_MAX_TEXTURE_SIZE_NUMBER, SDL_min(caps.MaxTextureWidth, caps.MaxTextureHeight));
  1773. if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
  1774. data->enableSeparateAlphaBlend = true;
  1775. }
  1776. // Store the default render target
  1777. IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  1778. data->currentRenderTarget = NULL;
  1779. // Detect the supported texture formats
  1780. IDirect3D9_GetAdapterDisplayMode(data->d3d, data->adapter, &displayMode);
  1781. for (int i = 0; i < SDL_arraysize(d3d_format_map); i++) {
  1782. if (SUCCEEDED(IDirect3D9_CheckDeviceFormat(data->d3d,
  1783. data->adapter,
  1784. D3DDEVTYPE_HAL,
  1785. displayMode.Format,
  1786. 0,
  1787. D3DRTYPE_TEXTURE,
  1788. d3d_format_map[i].d3d))) {
  1789. SDL_AddSupportedTextureFormat(renderer, d3d_format_map[i].sdl);
  1790. }
  1791. }
  1792. // Set up parameters for rendering
  1793. D3D_InitRenderState(data);
  1794. for (int i = SHADER_NONE + 1; i < SDL_arraysize(data->shaders); ++i) {
  1795. result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
  1796. if (FAILED(result)) {
  1797. D3D_SetError("CreatePixelShader()", result);
  1798. }
  1799. }
  1800. if (caps.MaxSimultaneousTextures >= 2 &&
  1801. data->shaders[SHADER_PALETTE_NEAREST] &&
  1802. data->shaders[SHADER_PALETTE_LINEAR]) {
  1803. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_INDEX8);
  1804. }
  1805. #ifdef SDL_HAVE_YUV
  1806. if (caps.MaxSimultaneousTextures >= 3 && data->shaders[SHADER_YUV]) {
  1807. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_YV12);
  1808. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_IYUV);
  1809. SDL_AddSupportedTextureFormat(renderer, SDL_PIXELFORMAT_P408);
  1810. }
  1811. #endif
  1812. SDL_SetPointerProperty(SDL_GetRendererProperties(renderer), SDL_PROP_RENDERER_D3D9_DEVICE_POINTER, data->device);
  1813. return true;
  1814. }
  1815. SDL_RenderDriver D3D_RenderDriver = {
  1816. D3D_CreateRenderer, "direct3d"
  1817. };
  1818. #endif // SDL_VIDEO_RENDER_D3D