SDL_render_d3d.c 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2022 Sam Lantinga <[email protected]>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #include "SDL_render.h"
  20. #include "SDL_system.h"
  21. #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  22. #include "../../core/windows/SDL_windows.h"
  23. #include "SDL_hints.h"
  24. #include "SDL_loadso.h"
  25. #include "SDL_syswm.h"
  26. #include "../SDL_sysrender.h"
  27. #include "../SDL_d3dmath.h"
  28. #include "../../video/windows/SDL_windowsvideo.h"
  29. #if SDL_VIDEO_RENDER_D3D
  30. #define D3D_DEBUG_INFO
  31. #include <d3d9.h>
  32. #endif
  33. #include "SDL_shaders_d3d.h"
  34. #ifdef __WATCOMC__
  35. /* FIXME: Remove this once https://github.com/open-watcom/open-watcom-v2/pull/868 is merged */
  36. #define D3DBLENDOP_REVSUBTRACT 3
  37. /* FIXME: Remove this once https://github.com/open-watcom/open-watcom-v2/pull/869 is merged */
  38. #define D3DERR_UNSUPPORTEDCOLOROPERATION MAKE_D3DHRESULT( 2073 )
  39. #endif
  40. typedef struct
  41. {
  42. SDL_Rect viewport;
  43. SDL_bool viewport_dirty;
  44. SDL_Texture *texture;
  45. SDL_BlendMode blend;
  46. SDL_bool cliprect_enabled;
  47. SDL_bool cliprect_enabled_dirty;
  48. SDL_Rect cliprect;
  49. SDL_bool cliprect_dirty;
  50. LPDIRECT3DPIXELSHADER9 shader;
  51. } D3D_DrawStateCache;
  52. /* Direct3D renderer implementation */
  53. typedef struct
  54. {
  55. void* d3dDLL;
  56. IDirect3D9 *d3d;
  57. IDirect3DDevice9 *device;
  58. UINT adapter;
  59. D3DPRESENT_PARAMETERS pparams;
  60. SDL_bool updateSize;
  61. SDL_bool beginScene;
  62. SDL_bool enableSeparateAlphaBlend;
  63. D3DTEXTUREFILTERTYPE scaleMode[8];
  64. IDirect3DSurface9 *defaultRenderTarget;
  65. IDirect3DSurface9 *currentRenderTarget;
  66. void* d3dxDLL;
  67. #if SDL_HAVE_YUV
  68. LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
  69. #endif
  70. LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
  71. size_t vertexBufferSize[8];
  72. int currentVertexBuffer;
  73. SDL_bool reportedVboProblem;
  74. D3D_DrawStateCache drawstate;
  75. } D3D_RenderData;
  76. typedef struct
  77. {
  78. SDL_bool dirty;
  79. int w, h;
  80. DWORD usage;
  81. Uint32 format;
  82. D3DFORMAT d3dfmt;
  83. IDirect3DTexture9 *texture;
  84. IDirect3DTexture9 *staging;
  85. } D3D_TextureRep;
  86. typedef struct
  87. {
  88. D3D_TextureRep texture;
  89. D3DTEXTUREFILTERTYPE scaleMode;
  90. #if SDL_HAVE_YUV
  91. /* YV12 texture support */
  92. SDL_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 int
  107. D3D_SetError(const char *prefix, HRESULT result)
  108. {
  109. const char *error;
  110. switch (result) {
  111. case D3DERR_WRONGTEXTUREFORMAT:
  112. error = "WRONGTEXTUREFORMAT";
  113. break;
  114. case D3DERR_UNSUPPORTEDCOLOROPERATION:
  115. error = "UNSUPPORTEDCOLOROPERATION";
  116. break;
  117. case D3DERR_UNSUPPORTEDCOLORARG:
  118. error = "UNSUPPORTEDCOLORARG";
  119. break;
  120. case D3DERR_UNSUPPORTEDALPHAOPERATION:
  121. error = "UNSUPPORTEDALPHAOPERATION";
  122. break;
  123. case D3DERR_UNSUPPORTEDALPHAARG:
  124. error = "UNSUPPORTEDALPHAARG";
  125. break;
  126. case D3DERR_TOOMANYOPERATIONS:
  127. error = "TOOMANYOPERATIONS";
  128. break;
  129. case D3DERR_CONFLICTINGTEXTUREFILTER:
  130. error = "CONFLICTINGTEXTUREFILTER";
  131. break;
  132. case D3DERR_UNSUPPORTEDFACTORVALUE:
  133. error = "UNSUPPORTEDFACTORVALUE";
  134. break;
  135. case D3DERR_CONFLICTINGRENDERSTATE:
  136. error = "CONFLICTINGRENDERSTATE";
  137. break;
  138. case D3DERR_UNSUPPORTEDTEXTUREFILTER:
  139. error = "UNSUPPORTEDTEXTUREFILTER";
  140. break;
  141. case D3DERR_CONFLICTINGTEXTUREPALETTE:
  142. error = "CONFLICTINGTEXTUREPALETTE";
  143. break;
  144. case D3DERR_DRIVERINTERNALERROR:
  145. error = "DRIVERINTERNALERROR";
  146. break;
  147. case D3DERR_NOTFOUND:
  148. error = "NOTFOUND";
  149. break;
  150. case D3DERR_MOREDATA:
  151. error = "MOREDATA";
  152. break;
  153. case D3DERR_DEVICELOST:
  154. error = "DEVICELOST";
  155. break;
  156. case D3DERR_DEVICENOTRESET:
  157. error = "DEVICENOTRESET";
  158. break;
  159. case D3DERR_NOTAVAILABLE:
  160. error = "NOTAVAILABLE";
  161. break;
  162. case D3DERR_OUTOFVIDEOMEMORY:
  163. error = "OUTOFVIDEOMEMORY";
  164. break;
  165. case D3DERR_INVALIDDEVICE:
  166. error = "INVALIDDEVICE";
  167. break;
  168. case D3DERR_INVALIDCALL:
  169. error = "INVALIDCALL";
  170. break;
  171. case D3DERR_DRIVERINVALIDCALL:
  172. error = "DRIVERINVALIDCALL";
  173. break;
  174. case D3DERR_WASSTILLDRAWING:
  175. error = "WASSTILLDRAWING";
  176. break;
  177. default:
  178. error = "UNKNOWN";
  179. break;
  180. }
  181. return SDL_SetError("%s: %s", prefix, error);
  182. }
  183. static D3DFORMAT
  184. PixelFormatToD3DFMT(Uint32 format)
  185. {
  186. switch (format) {
  187. case SDL_PIXELFORMAT_RGB565:
  188. return D3DFMT_R5G6B5;
  189. case SDL_PIXELFORMAT_RGB888:
  190. return D3DFMT_X8R8G8B8;
  191. case SDL_PIXELFORMAT_ARGB8888:
  192. return D3DFMT_A8R8G8B8;
  193. case SDL_PIXELFORMAT_YV12:
  194. case SDL_PIXELFORMAT_IYUV:
  195. case SDL_PIXELFORMAT_NV12:
  196. case SDL_PIXELFORMAT_NV21:
  197. return D3DFMT_L8;
  198. default:
  199. return D3DFMT_UNKNOWN;
  200. }
  201. }
  202. static Uint32
  203. D3DFMTToPixelFormat(D3DFORMAT format)
  204. {
  205. switch (format) {
  206. case D3DFMT_R5G6B5:
  207. return SDL_PIXELFORMAT_RGB565;
  208. case D3DFMT_X8R8G8B8:
  209. return SDL_PIXELFORMAT_RGB888;
  210. case D3DFMT_A8R8G8B8:
  211. return SDL_PIXELFORMAT_ARGB8888;
  212. default:
  213. return SDL_PIXELFORMAT_UNKNOWN;
  214. }
  215. }
  216. static void
  217. D3D_InitRenderState(D3D_RenderData *data)
  218. {
  219. D3DMATRIX matrix;
  220. IDirect3DDevice9 *device = data->device;
  221. IDirect3DDevice9_SetPixelShader(device, NULL);
  222. IDirect3DDevice9_SetTexture(device, 0, NULL);
  223. IDirect3DDevice9_SetTexture(device, 1, NULL);
  224. IDirect3DDevice9_SetTexture(device, 2, NULL);
  225. IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
  226. IDirect3DDevice9_SetVertexShader(device, NULL);
  227. IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
  228. IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
  229. IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
  230. /* Enable color modulation by diffuse color */
  231. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
  232. D3DTOP_MODULATE);
  233. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
  234. D3DTA_TEXTURE);
  235. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
  236. D3DTA_DIFFUSE);
  237. /* Enable alpha modulation by diffuse alpha */
  238. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
  239. D3DTOP_MODULATE);
  240. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
  241. D3DTA_TEXTURE);
  242. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
  243. D3DTA_DIFFUSE);
  244. /* Enable separate alpha blend function, if possible */
  245. if (data->enableSeparateAlphaBlend) {
  246. IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
  247. }
  248. /* Disable second texture stage, since we're done */
  249. IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
  250. D3DTOP_DISABLE);
  251. IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
  252. D3DTOP_DISABLE);
  253. /* Set an identity world and view matrix */
  254. SDL_zero(matrix);
  255. matrix.m[0][0] = 1.0f;
  256. matrix.m[1][1] = 1.0f;
  257. matrix.m[2][2] = 1.0f;
  258. matrix.m[3][3] = 1.0f;
  259. IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
  260. IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
  261. /* Reset our current scale mode */
  262. SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
  263. /* Start the render with beginScene */
  264. data->beginScene = SDL_TRUE;
  265. }
  266. static int D3D_Reset(SDL_Renderer * renderer);
  267. static int
  268. D3D_ActivateRenderer(SDL_Renderer * renderer)
  269. {
  270. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  271. HRESULT result;
  272. if (data->updateSize) {
  273. SDL_Window *window = renderer->window;
  274. int w, h;
  275. Uint32 window_flags = SDL_GetWindowFlags(window);
  276. WIN_GetDrawableSize(window, &w, &h);
  277. data->pparams.BackBufferWidth = w;
  278. data->pparams.BackBufferHeight = h;
  279. if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  280. SDL_DisplayMode fullscreen_mode;
  281. SDL_GetWindowDisplayMode(window, &fullscreen_mode);
  282. data->pparams.Windowed = FALSE;
  283. data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
  284. data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
  285. } else {
  286. data->pparams.Windowed = TRUE;
  287. data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  288. data->pparams.FullScreen_RefreshRateInHz = 0;
  289. }
  290. if (D3D_Reset(renderer) < 0) {
  291. return -1;
  292. }
  293. data->updateSize = SDL_FALSE;
  294. }
  295. if (data->beginScene) {
  296. result = IDirect3DDevice9_BeginScene(data->device);
  297. if (result == D3DERR_DEVICELOST) {
  298. if (D3D_Reset(renderer) < 0) {
  299. return -1;
  300. }
  301. result = IDirect3DDevice9_BeginScene(data->device);
  302. }
  303. if (FAILED(result)) {
  304. return D3D_SetError("BeginScene()", result);
  305. }
  306. data->beginScene = SDL_FALSE;
  307. }
  308. return 0;
  309. }
  310. static void
  311. D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
  312. {
  313. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  314. if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
  315. data->updateSize = SDL_TRUE;
  316. }
  317. }
  318. static int
  319. D3D_GetOutputSize(SDL_Renderer * renderer, int *w, int *h)
  320. {
  321. WIN_GetDrawableSize(renderer->window, w, h);
  322. return 0;
  323. }
  324. static D3DBLEND
  325. GetBlendFunc(SDL_BlendFactor factor)
  326. {
  327. switch (factor) {
  328. case SDL_BLENDFACTOR_ZERO:
  329. return D3DBLEND_ZERO;
  330. case SDL_BLENDFACTOR_ONE:
  331. return D3DBLEND_ONE;
  332. case SDL_BLENDFACTOR_SRC_COLOR:
  333. return D3DBLEND_SRCCOLOR;
  334. case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
  335. return D3DBLEND_INVSRCCOLOR;
  336. case SDL_BLENDFACTOR_SRC_ALPHA:
  337. return D3DBLEND_SRCALPHA;
  338. case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
  339. return D3DBLEND_INVSRCALPHA;
  340. case SDL_BLENDFACTOR_DST_COLOR:
  341. return D3DBLEND_DESTCOLOR;
  342. case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
  343. return D3DBLEND_INVDESTCOLOR;
  344. case SDL_BLENDFACTOR_DST_ALPHA:
  345. return D3DBLEND_DESTALPHA;
  346. case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
  347. return D3DBLEND_INVDESTALPHA;
  348. default: break;
  349. }
  350. return (D3DBLEND) 0;
  351. }
  352. static D3DBLENDOP
  353. GetBlendEquation(SDL_BlendOperation operation)
  354. {
  355. switch (operation) {
  356. case SDL_BLENDOPERATION_ADD:
  357. return D3DBLENDOP_ADD;
  358. case SDL_BLENDOPERATION_SUBTRACT:
  359. return D3DBLENDOP_SUBTRACT;
  360. case SDL_BLENDOPERATION_REV_SUBTRACT:
  361. return D3DBLENDOP_REVSUBTRACT;
  362. case SDL_BLENDOPERATION_MINIMUM:
  363. return D3DBLENDOP_MIN;
  364. case SDL_BLENDOPERATION_MAXIMUM:
  365. return D3DBLENDOP_MAX;
  366. default: break;
  367. }
  368. return (D3DBLENDOP) 0;
  369. }
  370. static SDL_bool
  371. D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
  372. {
  373. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  374. SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
  375. SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
  376. SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
  377. SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
  378. SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
  379. SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
  380. if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
  381. !GetBlendEquation(colorOperation) ||
  382. !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) ||
  383. !GetBlendEquation(alphaOperation)) {
  384. return SDL_FALSE;
  385. }
  386. if (!data->enableSeparateAlphaBlend) {
  387. if ((srcColorFactor != srcAlphaFactor) || (dstColorFactor != dstAlphaFactor) || (colorOperation != alphaOperation)) {
  388. return SDL_FALSE;
  389. }
  390. }
  391. return SDL_TRUE;
  392. }
  393. static int
  394. D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h)
  395. {
  396. HRESULT result;
  397. texture->dirty = SDL_FALSE;
  398. texture->w = w;
  399. texture->h = h;
  400. texture->usage = usage;
  401. texture->format = format;
  402. texture->d3dfmt = d3dfmt;
  403. result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
  404. PixelFormatToD3DFMT(format),
  405. D3DPOOL_DEFAULT, &texture->texture, NULL);
  406. if (FAILED(result)) {
  407. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  408. }
  409. return 0;
  410. }
  411. static int
  412. D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  413. {
  414. HRESULT result;
  415. if (texture->staging == NULL) {
  416. result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
  417. texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
  418. if (FAILED(result)) {
  419. return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
  420. }
  421. }
  422. return 0;
  423. }
  424. static int
  425. D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  426. {
  427. if (texture->texture) {
  428. IDirect3DTexture9_Release(texture->texture);
  429. texture->texture = NULL;
  430. }
  431. if (texture->staging) {
  432. IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
  433. texture->dirty = SDL_TRUE;
  434. }
  435. return 0;
  436. }
  437. static int
  438. D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, int x, int y, int w, int h, const void *pixels, int pitch)
  439. {
  440. RECT d3drect;
  441. D3DLOCKED_RECT locked;
  442. const Uint8 *src;
  443. Uint8 *dst;
  444. int row, length;
  445. HRESULT result;
  446. if (D3D_CreateStagingTexture(device, texture) < 0) {
  447. return -1;
  448. }
  449. d3drect.left = x;
  450. d3drect.right = x + w;
  451. d3drect.top = y;
  452. d3drect.bottom = y + h;
  453. result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
  454. if (FAILED(result)) {
  455. return D3D_SetError("LockRect()", result);
  456. }
  457. src = (const Uint8 *)pixels;
  458. dst = (Uint8 *)locked.pBits;
  459. length = w * SDL_BYTESPERPIXEL(texture->format);
  460. if (length == pitch && length == locked.Pitch) {
  461. SDL_memcpy(dst, src, length*h);
  462. } else {
  463. if (length > pitch) {
  464. length = pitch;
  465. }
  466. if (length > locked.Pitch) {
  467. length = locked.Pitch;
  468. }
  469. for (row = 0; row < h; ++row) {
  470. SDL_memcpy(dst, src, length);
  471. src += pitch;
  472. dst += locked.Pitch;
  473. }
  474. }
  475. result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
  476. if (FAILED(result)) {
  477. return D3D_SetError("UnlockRect()", result);
  478. }
  479. texture->dirty = SDL_TRUE;
  480. return 0;
  481. }
  482. static void
  483. D3D_DestroyTextureRep(D3D_TextureRep *texture)
  484. {
  485. if (texture->texture) {
  486. IDirect3DTexture9_Release(texture->texture);
  487. texture->texture = NULL;
  488. }
  489. if (texture->staging) {
  490. IDirect3DTexture9_Release(texture->staging);
  491. texture->staging = NULL;
  492. }
  493. }
  494. static int
  495. D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  496. {
  497. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  498. D3D_TextureData *texturedata;
  499. DWORD usage;
  500. texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
  501. if (!texturedata) {
  502. return SDL_OutOfMemory();
  503. }
  504. texturedata->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
  505. texture->driverdata = texturedata;
  506. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  507. usage = D3DUSAGE_RENDERTARGET;
  508. } else {
  509. usage = 0;
  510. }
  511. if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h) < 0) {
  512. return -1;
  513. }
  514. #if SDL_HAVE_YUV
  515. if (texture->format == SDL_PIXELFORMAT_YV12 ||
  516. texture->format == SDL_PIXELFORMAT_IYUV) {
  517. texturedata->yuv = SDL_TRUE;
  518. if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
  519. return -1;
  520. }
  521. if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
  522. return -1;
  523. }
  524. }
  525. #endif
  526. return 0;
  527. }
  528. static int
  529. D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  530. {
  531. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  532. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  533. if (!texturedata) {
  534. return 0;
  535. }
  536. if (D3D_RecreateTextureRep(data->device, &texturedata->texture) < 0) {
  537. return -1;
  538. }
  539. #if SDL_HAVE_YUV
  540. if (texturedata->yuv) {
  541. if (D3D_RecreateTextureRep(data->device, &texturedata->utexture) < 0) {
  542. return -1;
  543. }
  544. if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture) < 0) {
  545. return -1;
  546. }
  547. }
  548. #endif
  549. return 0;
  550. }
  551. static int
  552. D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  553. const SDL_Rect * rect, const void *pixels, int pitch)
  554. {
  555. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  556. D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  557. if (!texturedata) {
  558. return SDL_SetError("Texture is not currently available");
  559. }
  560. if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
  561. return -1;
  562. }
  563. #if SDL_HAVE_YUV
  564. if (texturedata->yuv) {
  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, 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) < 0) {
  568. return -1;
  569. }
  570. /* Skip to the correct offset into the next texture */
  571. pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
  572. 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) < 0) {
  573. return -1;
  574. }
  575. }
  576. #endif
  577. return 0;
  578. }
  579. #if SDL_HAVE_YUV
  580. static int
  581. D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  582. const SDL_Rect * rect,
  583. const Uint8 *Yplane, int Ypitch,
  584. const Uint8 *Uplane, int Upitch,
  585. const Uint8 *Vplane, int Vpitch)
  586. {
  587. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  588. D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  589. if (!texturedata) {
  590. return SDL_SetError("Texture is not currently available");
  591. }
  592. if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
  593. return -1;
  594. }
  595. if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch) < 0) {
  596. return -1;
  597. }
  598. if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch) < 0) {
  599. return -1;
  600. }
  601. return 0;
  602. }
  603. #endif
  604. static int
  605. D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  606. const SDL_Rect * rect, void **pixels, int *pitch)
  607. {
  608. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  609. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  610. IDirect3DDevice9 *device = data->device;
  611. if (!texturedata) {
  612. return SDL_SetError("Texture is not currently available");
  613. }
  614. #if SDL_HAVE_YUV
  615. texturedata->locked_rect = *rect;
  616. if (texturedata->yuv) {
  617. /* It's more efficient to upload directly... */
  618. if (!texturedata->pixels) {
  619. texturedata->pitch = texture->w;
  620. texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
  621. if (!texturedata->pixels) {
  622. return SDL_OutOfMemory();
  623. }
  624. }
  625. *pixels =
  626. (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  627. rect->x * SDL_BYTESPERPIXEL(texture->format));
  628. *pitch = texturedata->pitch;
  629. } else
  630. #endif
  631. {
  632. RECT d3drect;
  633. D3DLOCKED_RECT locked;
  634. HRESULT result;
  635. if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
  636. return -1;
  637. }
  638. d3drect.left = rect->x;
  639. d3drect.right = rect->x + rect->w;
  640. d3drect.top = rect->y;
  641. d3drect.bottom = rect->y + rect->h;
  642. result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
  643. if (FAILED(result)) {
  644. return D3D_SetError("LockRect()", result);
  645. }
  646. *pixels = locked.pBits;
  647. *pitch = locked.Pitch;
  648. }
  649. return 0;
  650. }
  651. static void
  652. D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  653. {
  654. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  655. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  656. if (!texturedata) {
  657. return;
  658. }
  659. #if SDL_HAVE_YUV
  660. if (texturedata->yuv) {
  661. const SDL_Rect *rect = &texturedata->locked_rect;
  662. void *pixels =
  663. (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  664. rect->x * SDL_BYTESPERPIXEL(texture->format));
  665. D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
  666. }
  667. else
  668. #endif
  669. {
  670. IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
  671. texturedata->texture.dirty = SDL_TRUE;
  672. if (data->drawstate.texture == texture) {
  673. data->drawstate.texture = NULL;
  674. data->drawstate.shader = NULL;
  675. IDirect3DDevice9_SetPixelShader(data->device, NULL);
  676. IDirect3DDevice9_SetTexture(data->device, 0, NULL);
  677. }
  678. }
  679. }
  680. static void
  681. D3D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
  682. {
  683. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  684. if (!texturedata) {
  685. return;
  686. }
  687. texturedata->scaleMode = (scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
  688. }
  689. static int
  690. D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
  691. {
  692. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  693. D3D_TextureData *texturedata;
  694. D3D_TextureRep *texturerep;
  695. HRESULT result;
  696. IDirect3DDevice9 *device = data->device;
  697. /* Release the previous render target if it wasn't the default one */
  698. if (data->currentRenderTarget != NULL) {
  699. IDirect3DSurface9_Release(data->currentRenderTarget);
  700. data->currentRenderTarget = NULL;
  701. }
  702. if (texture == NULL) {
  703. IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  704. return 0;
  705. }
  706. texturedata = (D3D_TextureData *)texture->driverdata;
  707. if (!texturedata) {
  708. return SDL_SetError("Texture is not currently available");
  709. }
  710. /* Make sure the render target is updated if it was locked and written to */
  711. texturerep = &texturedata->texture;
  712. if (texturerep->dirty && texturerep->staging) {
  713. if (!texturerep->texture) {
  714. result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
  715. PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
  716. if (FAILED(result)) {
  717. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  718. }
  719. }
  720. result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
  721. if (FAILED(result)) {
  722. return D3D_SetError("UpdateTexture()", result);
  723. }
  724. texturerep->dirty = SDL_FALSE;
  725. }
  726. result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
  727. if(FAILED(result)) {
  728. return D3D_SetError("GetSurfaceLevel()", result);
  729. }
  730. result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  731. if(FAILED(result)) {
  732. return D3D_SetError("SetRenderTarget()", result);
  733. }
  734. return 0;
  735. }
  736. static int
  737. D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  738. {
  739. if (D3D_ActivateRenderer(renderer) < 0) {
  740. return -1;
  741. }
  742. return D3D_SetRenderTargetInternal(renderer, texture);
  743. }
  744. static int
  745. D3D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
  746. {
  747. return 0; /* nothing to do in this backend. */
  748. }
  749. static int
  750. D3D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
  751. {
  752. const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
  753. const size_t vertslen = count * sizeof (Vertex);
  754. Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
  755. int i;
  756. if (!verts) {
  757. return -1;
  758. }
  759. SDL_memset(verts, '\0', vertslen);
  760. cmd->data.draw.count = count;
  761. for (i = 0; i < count; i++, verts++, points++) {
  762. verts->x = points->x;
  763. verts->y = points->y;
  764. verts->color = color;
  765. }
  766. return 0;
  767. }
  768. static int
  769. D3D_QueueGeometry(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture,
  770. const float *xy, int xy_stride, const SDL_Color *color, int color_stride, const float *uv, int uv_stride,
  771. int num_vertices, const void *indices, int num_indices, int size_indices,
  772. float scale_x, float scale_y)
  773. {
  774. int i;
  775. int count = indices ? num_indices : num_vertices;
  776. Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, count * sizeof (Vertex), 0, &cmd->data.draw.first);
  777. if (!verts) {
  778. return -1;
  779. }
  780. cmd->data.draw.count = count;
  781. size_indices = indices ? size_indices : 0;
  782. for (i = 0; i < count; i++) {
  783. int j;
  784. float *xy_;
  785. SDL_Color col_;
  786. if (size_indices == 4) {
  787. j = ((const Uint32 *)indices)[i];
  788. } else if (size_indices == 2) {
  789. j = ((const Uint16 *)indices)[i];
  790. } else if (size_indices == 1) {
  791. j = ((const Uint8 *)indices)[i];
  792. } else {
  793. j = i;
  794. }
  795. xy_ = (float *)((char*)xy + j * xy_stride);
  796. col_ = *(SDL_Color *)((char*)color + j * color_stride);
  797. verts->x = xy_[0] * scale_x - 0.5f;
  798. verts->y = xy_[1] * scale_y - 0.5f;
  799. verts->z = 0.0f;
  800. verts->color = D3DCOLOR_ARGB(col_.a, col_.r, col_.g, col_.b);
  801. if (texture) {
  802. float *uv_ = (float *)((char*)uv + j * uv_stride);
  803. verts->u = uv_[0];
  804. verts->v = uv_[1];
  805. } else {
  806. verts->u = 0.0f;
  807. verts->v = 0.0f;
  808. }
  809. verts += 1;
  810. }
  811. return 0;
  812. }
  813. static int
  814. UpdateDirtyTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  815. {
  816. if (texture->dirty && texture->staging) {
  817. HRESULT result;
  818. if (!texture->texture) {
  819. result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  820. PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
  821. if (FAILED(result)) {
  822. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  823. }
  824. }
  825. result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
  826. if (FAILED(result)) {
  827. return D3D_SetError("UpdateTexture()", result);
  828. }
  829. texture->dirty = SDL_FALSE;
  830. }
  831. return 0;
  832. }
  833. static int
  834. BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
  835. {
  836. HRESULT result;
  837. UpdateDirtyTexture(device, texture);
  838. result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
  839. if (FAILED(result)) {
  840. return D3D_SetError("SetTexture()", result);
  841. }
  842. return 0;
  843. }
  844. static void
  845. UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  846. {
  847. if (texturedata->scaleMode != data->scaleMode[index]) {
  848. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  849. texturedata->scaleMode);
  850. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  851. texturedata->scaleMode);
  852. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU,
  853. D3DTADDRESS_CLAMP);
  854. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV,
  855. D3DTADDRESS_CLAMP);
  856. data->scaleMode[index] = texturedata->scaleMode;
  857. }
  858. }
  859. static int
  860. SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
  861. {
  862. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  863. SDL_assert(*shader == NULL);
  864. if (!texturedata) {
  865. return SDL_SetError("Texture is not currently available");
  866. }
  867. UpdateTextureScaleMode(data, texturedata, 0);
  868. if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  869. return -1;
  870. }
  871. #if SDL_HAVE_YUV
  872. if (texturedata->yuv) {
  873. switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
  874. case SDL_YUV_CONVERSION_JPEG:
  875. *shader = data->shaders[SHADER_YUV_JPEG];
  876. break;
  877. case SDL_YUV_CONVERSION_BT601:
  878. *shader = data->shaders[SHADER_YUV_BT601];
  879. break;
  880. case SDL_YUV_CONVERSION_BT709:
  881. *shader = data->shaders[SHADER_YUV_BT709];
  882. break;
  883. default:
  884. return SDL_SetError("Unsupported YUV conversion mode");
  885. }
  886. UpdateTextureScaleMode(data, texturedata, 1);
  887. UpdateTextureScaleMode(data, texturedata, 2);
  888. if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  889. return -1;
  890. }
  891. if (BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  892. return -1;
  893. }
  894. }
  895. #endif
  896. return 0;
  897. }
  898. static int
  899. SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
  900. {
  901. SDL_Texture *texture = cmd->data.draw.texture;
  902. const SDL_BlendMode blend = cmd->data.draw.blend;
  903. if (texture != data->drawstate.texture) {
  904. #if SDL_HAVE_YUV
  905. D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL;
  906. D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL;
  907. #endif
  908. LPDIRECT3DPIXELSHADER9 shader = NULL;
  909. /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */
  910. if (texture == NULL) {
  911. IDirect3DDevice9_SetTexture(data->device, 0, NULL);
  912. }
  913. #if SDL_HAVE_YUV
  914. if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) {
  915. IDirect3DDevice9_SetTexture(data->device, 1, NULL);
  916. IDirect3DDevice9_SetTexture(data->device, 2, NULL);
  917. }
  918. #endif
  919. if (texture && SetupTextureState(data, texture, &shader) < 0) {
  920. return -1;
  921. }
  922. if (shader != data->drawstate.shader) {
  923. const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  924. if (FAILED(result)) {
  925. return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
  926. }
  927. data->drawstate.shader = shader;
  928. }
  929. data->drawstate.texture = texture;
  930. } else if (texture) {
  931. D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  932. UpdateDirtyTexture(data->device, &texturedata->texture);
  933. #if SDL_HAVE_YUV
  934. if (texturedata->yuv) {
  935. UpdateDirtyTexture(data->device, &texturedata->utexture);
  936. UpdateDirtyTexture(data->device, &texturedata->vtexture);
  937. }
  938. #endif
  939. }
  940. if (blend != data->drawstate.blend) {
  941. if (blend == SDL_BLENDMODE_NONE) {
  942. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
  943. } else {
  944. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
  945. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  946. GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
  947. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  948. GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
  949. IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOP,
  950. GetBlendEquation(SDL_GetBlendModeColorOperation(blend)));
  951. if (data->enableSeparateAlphaBlend) {
  952. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  953. GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
  954. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  955. GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
  956. IDirect3DDevice9_SetRenderState(data->device, D3DRS_BLENDOPALPHA,
  957. GetBlendEquation(SDL_GetBlendModeAlphaOperation(blend)));
  958. }
  959. }
  960. data->drawstate.blend = blend;
  961. }
  962. if (data->drawstate.viewport_dirty) {
  963. const SDL_Rect *viewport = &data->drawstate.viewport;
  964. D3DVIEWPORT9 d3dviewport;
  965. d3dviewport.X = viewport->x;
  966. d3dviewport.Y = viewport->y;
  967. d3dviewport.Width = viewport->w;
  968. d3dviewport.Height = viewport->h;
  969. d3dviewport.MinZ = 0.0f;
  970. d3dviewport.MaxZ = 1.0f;
  971. IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
  972. /* Set an orthographic projection matrix */
  973. if (viewport->w && viewport->h) {
  974. D3DMATRIX d3dmatrix;
  975. SDL_zero(d3dmatrix);
  976. d3dmatrix.m[0][0] = 2.0f / viewport->w;
  977. d3dmatrix.m[1][1] = -2.0f / viewport->h;
  978. d3dmatrix.m[2][2] = 1.0f;
  979. d3dmatrix.m[3][0] = -1.0f;
  980. d3dmatrix.m[3][1] = 1.0f;
  981. d3dmatrix.m[3][3] = 1.0f;
  982. IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
  983. }
  984. data->drawstate.viewport_dirty = SDL_FALSE;
  985. }
  986. if (data->drawstate.cliprect_enabled_dirty) {
  987. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
  988. data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
  989. }
  990. if (data->drawstate.cliprect_dirty) {
  991. const SDL_Rect *viewport = &data->drawstate.viewport;
  992. const SDL_Rect *rect = &data->drawstate.cliprect;
  993. RECT d3drect;
  994. d3drect.left = viewport->x + rect->x;
  995. d3drect.top = viewport->y + rect->y;
  996. d3drect.right = viewport->x + rect->x + rect->w;
  997. d3drect.bottom = viewport->y + rect->y + rect->h;
  998. IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
  999. data->drawstate.cliprect_dirty = SDL_FALSE;
  1000. }
  1001. return 0;
  1002. }
  1003. static int
  1004. D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
  1005. {
  1006. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1007. const int vboidx = data->currentVertexBuffer;
  1008. IDirect3DVertexBuffer9 *vbo = NULL;
  1009. const SDL_bool istarget = renderer->target != NULL;
  1010. if (D3D_ActivateRenderer(renderer) < 0) {
  1011. return -1;
  1012. }
  1013. if (vertices) {
  1014. /* upload the new VBO data for this set of commands. */
  1015. vbo = data->vertexBuffers[vboidx];
  1016. if (data->vertexBufferSize[vboidx] < vertsize) {
  1017. const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
  1018. const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
  1019. if (vbo) {
  1020. IDirect3DVertexBuffer9_Release(vbo);
  1021. }
  1022. if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, (UINT) vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
  1023. vbo = NULL;
  1024. }
  1025. data->vertexBuffers[vboidx] = vbo;
  1026. data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
  1027. }
  1028. if (vbo) {
  1029. void *ptr;
  1030. if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, (UINT) vertsize, &ptr, D3DLOCK_DISCARD))) {
  1031. vbo = NULL; /* oh well, we'll do immediate mode drawing. :( */
  1032. } else {
  1033. SDL_memcpy(ptr, vertices, vertsize);
  1034. if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
  1035. vbo = NULL; /* oh well, we'll do immediate mode drawing. :( */
  1036. }
  1037. }
  1038. }
  1039. /* cycle through a few VBOs so D3D has some time with the data before we replace it. */
  1040. if (vbo) {
  1041. data->currentVertexBuffer++;
  1042. if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
  1043. data->currentVertexBuffer = 0;
  1044. }
  1045. } else if (!data->reportedVboProblem) {
  1046. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
  1047. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
  1048. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
  1049. SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
  1050. data->reportedVboProblem = SDL_TRUE;
  1051. }
  1052. }
  1053. IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof (Vertex));
  1054. while (cmd) {
  1055. switch (cmd->command) {
  1056. case SDL_RENDERCMD_SETDRAWCOLOR: {
  1057. /* currently this is sent with each vertex, but if we move to
  1058. shaders, we can put this in a uniform here and reduce vertex
  1059. buffer bandwidth */
  1060. break;
  1061. }
  1062. case SDL_RENDERCMD_SETVIEWPORT: {
  1063. SDL_Rect *viewport = &data->drawstate.viewport;
  1064. if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof(cmd->data.viewport.rect)) != 0) {
  1065. SDL_copyp(viewport, &cmd->data.viewport.rect);
  1066. data->drawstate.viewport_dirty = SDL_TRUE;
  1067. }
  1068. break;
  1069. }
  1070. case SDL_RENDERCMD_SETCLIPRECT: {
  1071. const SDL_Rect *rect = &cmd->data.cliprect.rect;
  1072. if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
  1073. data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
  1074. data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1075. }
  1076. if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof(*rect)) != 0) {
  1077. SDL_copyp(&data->drawstate.cliprect, rect);
  1078. data->drawstate.cliprect_dirty = SDL_TRUE;
  1079. }
  1080. break;
  1081. }
  1082. case SDL_RENDERCMD_CLEAR: {
  1083. const DWORD color = D3DCOLOR_ARGB(cmd->data.color.a, cmd->data.color.r, cmd->data.color.g, cmd->data.color.b);
  1084. const SDL_Rect *viewport = &data->drawstate.viewport;
  1085. const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
  1086. const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
  1087. const SDL_bool viewport_equal = ((viewport->x == 0) && (viewport->y == 0) && (viewport->w == backw) && (viewport->h == backh)) ? SDL_TRUE : SDL_FALSE;
  1088. if (data->drawstate.cliprect_enabled || data->drawstate.cliprect_enabled_dirty) {
  1089. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1090. data->drawstate.cliprect_enabled_dirty = data->drawstate.cliprect_enabled;
  1091. }
  1092. /* Don't reset the viewport if we don't have to! */
  1093. if (!data->drawstate.viewport_dirty && viewport_equal) {
  1094. IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1095. } else {
  1096. /* Clear is defined to clear the entire render target */
  1097. D3DVIEWPORT9 wholeviewport = { 0, 0, 0, 0, 0.0f, 1.0f };
  1098. wholeviewport.Width = backw;
  1099. wholeviewport.Height = backh;
  1100. IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
  1101. data->drawstate.viewport_dirty = SDL_TRUE; /* we still need to (re)set orthographic projection, so always mark it dirty. */
  1102. IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1103. }
  1104. break;
  1105. }
  1106. case SDL_RENDERCMD_DRAW_POINTS: {
  1107. const size_t count = cmd->data.draw.count;
  1108. const size_t first = cmd->data.draw.first;
  1109. SetDrawState(data, cmd);
  1110. if (vbo) {
  1111. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) (first / sizeof (Vertex)), (UINT) count);
  1112. } else {
  1113. const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1114. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT) count, verts, sizeof (Vertex));
  1115. }
  1116. break;
  1117. }
  1118. case SDL_RENDERCMD_DRAW_LINES: {
  1119. const size_t count = cmd->data.draw.count;
  1120. const size_t first = cmd->data.draw.first;
  1121. const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
  1122. /* DirectX 9 has the same line rasterization semantics as GDI,
  1123. so we need to close the endpoint of the line with a second draw call. */
  1124. const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
  1125. SetDrawState(data, cmd);
  1126. if (vbo) {
  1127. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT) (first / sizeof (Vertex)), (UINT) (count - 1));
  1128. if (close_endpoint) {
  1129. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) ((first / sizeof (Vertex)) + (count - 1)), 1);
  1130. }
  1131. } else {
  1132. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT) (count - 1), verts, sizeof (Vertex));
  1133. if (close_endpoint) {
  1134. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
  1135. }
  1136. }
  1137. break;
  1138. }
  1139. case SDL_RENDERCMD_FILL_RECTS: /* unused */
  1140. break;
  1141. case SDL_RENDERCMD_COPY: /* unused */
  1142. break;
  1143. case SDL_RENDERCMD_COPY_EX: /* unused */
  1144. break;
  1145. case SDL_RENDERCMD_GEOMETRY: {
  1146. const size_t count = cmd->data.draw.count;
  1147. const size_t first = cmd->data.draw.first;
  1148. SetDrawState(data, cmd);
  1149. if (vbo) {
  1150. IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLELIST, (UINT) (first / sizeof (Vertex)), (UINT) count / 3);
  1151. } else {
  1152. const Vertex* verts = (Vertex*)(((Uint8*)vertices) + first);
  1153. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLELIST, (UINT) count / 3, verts, sizeof(Vertex));
  1154. }
  1155. break;
  1156. }
  1157. case SDL_RENDERCMD_NO_OP:
  1158. break;
  1159. }
  1160. cmd = cmd->next;
  1161. }
  1162. return 0;
  1163. }
  1164. static int
  1165. D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1166. Uint32 format, void * pixels, int pitch)
  1167. {
  1168. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1169. D3DSURFACE_DESC desc;
  1170. LPDIRECT3DSURFACE9 backBuffer;
  1171. LPDIRECT3DSURFACE9 surface;
  1172. RECT d3drect;
  1173. D3DLOCKED_RECT locked;
  1174. HRESULT result;
  1175. int status;
  1176. if (data->currentRenderTarget) {
  1177. backBuffer = data->currentRenderTarget;
  1178. } else {
  1179. backBuffer = data->defaultRenderTarget;
  1180. }
  1181. result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1182. if (FAILED(result)) {
  1183. return D3D_SetError("GetDesc()", result);
  1184. }
  1185. result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1186. if (FAILED(result)) {
  1187. return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1188. }
  1189. result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1190. if (FAILED(result)) {
  1191. IDirect3DSurface9_Release(surface);
  1192. return D3D_SetError("GetRenderTargetData()", result);
  1193. }
  1194. d3drect.left = rect->x;
  1195. d3drect.right = rect->x + rect->w;
  1196. d3drect.top = rect->y;
  1197. d3drect.bottom = rect->y + rect->h;
  1198. result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1199. if (FAILED(result)) {
  1200. IDirect3DSurface9_Release(surface);
  1201. return D3D_SetError("LockRect()", result);
  1202. }
  1203. status = SDL_ConvertPixels(rect->w, rect->h,
  1204. D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1205. format, pixels, pitch);
  1206. IDirect3DSurface9_UnlockRect(surface);
  1207. IDirect3DSurface9_Release(surface);
  1208. return status;
  1209. }
  1210. static void
  1211. D3D_RenderPresent(SDL_Renderer * renderer)
  1212. {
  1213. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1214. HRESULT result;
  1215. if (!data->beginScene) {
  1216. IDirect3DDevice9_EndScene(data->device);
  1217. data->beginScene = SDL_TRUE;
  1218. }
  1219. result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1220. if (result == D3DERR_DEVICELOST) {
  1221. /* We'll reset later */
  1222. return;
  1223. }
  1224. if (result == D3DERR_DEVICENOTRESET) {
  1225. D3D_Reset(renderer);
  1226. }
  1227. result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1228. if (FAILED(result)) {
  1229. D3D_SetError("Present()", result);
  1230. }
  1231. }
  1232. static void
  1233. D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1234. {
  1235. D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
  1236. D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1237. if (renderdata->drawstate.texture == texture) {
  1238. renderdata->drawstate.texture = NULL;
  1239. renderdata->drawstate.shader = NULL;
  1240. IDirect3DDevice9_SetPixelShader(renderdata->device, NULL);
  1241. IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL);
  1242. #if SDL_HAVE_YUV
  1243. if (data->yuv) {
  1244. IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL);
  1245. IDirect3DDevice9_SetTexture(renderdata->device, 2, NULL);
  1246. }
  1247. #endif
  1248. }
  1249. if (!data) {
  1250. return;
  1251. }
  1252. D3D_DestroyTextureRep(&data->texture);
  1253. #if SDL_HAVE_YUV
  1254. D3D_DestroyTextureRep(&data->utexture);
  1255. D3D_DestroyTextureRep(&data->vtexture);
  1256. SDL_free(data->pixels);
  1257. #endif
  1258. SDL_free(data);
  1259. texture->driverdata = NULL;
  1260. }
  1261. static void
  1262. D3D_DestroyRenderer(SDL_Renderer * renderer)
  1263. {
  1264. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1265. if (data) {
  1266. int i;
  1267. /* Release the render target */
  1268. if (data->defaultRenderTarget) {
  1269. IDirect3DSurface9_Release(data->defaultRenderTarget);
  1270. data->defaultRenderTarget = NULL;
  1271. }
  1272. if (data->currentRenderTarget != NULL) {
  1273. IDirect3DSurface9_Release(data->currentRenderTarget);
  1274. data->currentRenderTarget = NULL;
  1275. }
  1276. #if SDL_HAVE_YUV
  1277. for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
  1278. if (data->shaders[i]) {
  1279. IDirect3DPixelShader9_Release(data->shaders[i]);
  1280. data->shaders[i] = NULL;
  1281. }
  1282. }
  1283. #endif
  1284. /* Release all vertex buffers */
  1285. for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
  1286. if (data->vertexBuffers[i]) {
  1287. IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
  1288. }
  1289. data->vertexBuffers[i] = NULL;
  1290. }
  1291. if (data->device) {
  1292. IDirect3DDevice9_Release(data->device);
  1293. data->device = NULL;
  1294. }
  1295. if (data->d3d) {
  1296. IDirect3D9_Release(data->d3d);
  1297. SDL_UnloadObject(data->d3dDLL);
  1298. }
  1299. SDL_free(data);
  1300. }
  1301. SDL_free(renderer);
  1302. }
  1303. static int
  1304. D3D_Reset(SDL_Renderer * renderer)
  1305. {
  1306. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1307. const Float4X4 d3dmatrix = MatrixIdentity();
  1308. HRESULT result;
  1309. SDL_Texture *texture;
  1310. int i;
  1311. /* Cancel any scene that we've started */
  1312. if (!data->beginScene) {
  1313. IDirect3DDevice9_EndScene(data->device);
  1314. data->beginScene = SDL_TRUE;
  1315. }
  1316. /* Release the default render target before reset */
  1317. if (data->defaultRenderTarget) {
  1318. IDirect3DSurface9_Release(data->defaultRenderTarget);
  1319. data->defaultRenderTarget = NULL;
  1320. }
  1321. if (data->currentRenderTarget != NULL) {
  1322. IDirect3DSurface9_Release(data->currentRenderTarget);
  1323. data->currentRenderTarget = NULL;
  1324. }
  1325. /* Release application render targets */
  1326. for (texture = renderer->textures; texture; texture = texture->next) {
  1327. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1328. D3D_DestroyTexture(renderer, texture);
  1329. } else {
  1330. D3D_RecreateTexture(renderer, texture);
  1331. }
  1332. }
  1333. /* Release all vertex buffers */
  1334. for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
  1335. if (data->vertexBuffers[i]) {
  1336. IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
  1337. }
  1338. data->vertexBuffers[i] = NULL;
  1339. data->vertexBufferSize[i] = 0;
  1340. }
  1341. result = IDirect3DDevice9_Reset(data->device, &data->pparams);
  1342. if (FAILED(result)) {
  1343. if (result == D3DERR_DEVICELOST) {
  1344. /* Don't worry about it, we'll reset later... */
  1345. return 0;
  1346. } else {
  1347. return D3D_SetError("Reset()", result);
  1348. }
  1349. }
  1350. /* Allocate application render targets */
  1351. for (texture = renderer->textures; texture; texture = texture->next) {
  1352. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  1353. D3D_CreateTexture(renderer, texture);
  1354. }
  1355. }
  1356. IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  1357. D3D_InitRenderState(data);
  1358. D3D_SetRenderTargetInternal(renderer, renderer->target);
  1359. data->drawstate.viewport_dirty = SDL_TRUE;
  1360. data->drawstate.cliprect_dirty = SDL_TRUE;
  1361. data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1362. data->drawstate.texture = NULL;
  1363. data->drawstate.shader = NULL;
  1364. data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1365. IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
  1366. /* Let the application know that render targets were reset */
  1367. {
  1368. SDL_Event event;
  1369. event.type = SDL_RENDER_TARGETS_RESET;
  1370. SDL_PushEvent(&event);
  1371. }
  1372. return 0;
  1373. }
  1374. static int
  1375. D3D_SetVSync(SDL_Renderer * renderer, const int vsync)
  1376. {
  1377. D3D_RenderData *data = renderer->driverdata;
  1378. if (vsync) {
  1379. data->pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1380. renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1381. } else {
  1382. data->pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1383. renderer->info.flags &= ~SDL_RENDERER_PRESENTVSYNC;
  1384. }
  1385. if (D3D_Reset(renderer) < 0) {
  1386. /* D3D_Reset will call SDL_SetError() */
  1387. return -1;
  1388. }
  1389. return 0;
  1390. }
  1391. SDL_Renderer *
  1392. D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
  1393. {
  1394. SDL_Renderer *renderer;
  1395. D3D_RenderData *data;
  1396. SDL_SysWMinfo windowinfo;
  1397. HRESULT result;
  1398. D3DPRESENT_PARAMETERS pparams;
  1399. IDirect3DSwapChain9 *chain;
  1400. D3DCAPS9 caps;
  1401. DWORD device_flags;
  1402. Uint32 window_flags;
  1403. int w, h;
  1404. SDL_DisplayMode fullscreen_mode;
  1405. int displayIndex;
  1406. renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  1407. if (!renderer) {
  1408. SDL_OutOfMemory();
  1409. return NULL;
  1410. }
  1411. data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
  1412. if (!data) {
  1413. SDL_free(renderer);
  1414. SDL_OutOfMemory();
  1415. return NULL;
  1416. }
  1417. if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
  1418. SDL_free(renderer);
  1419. SDL_free(data);
  1420. SDL_SetError("Unable to create Direct3D interface");
  1421. return NULL;
  1422. }
  1423. renderer->WindowEvent = D3D_WindowEvent;
  1424. renderer->GetOutputSize = D3D_GetOutputSize;
  1425. renderer->SupportsBlendMode = D3D_SupportsBlendMode;
  1426. renderer->CreateTexture = D3D_CreateTexture;
  1427. renderer->UpdateTexture = D3D_UpdateTexture;
  1428. #if SDL_HAVE_YUV
  1429. renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
  1430. #endif
  1431. renderer->LockTexture = D3D_LockTexture;
  1432. renderer->UnlockTexture = D3D_UnlockTexture;
  1433. renderer->SetTextureScaleMode = D3D_SetTextureScaleMode;
  1434. renderer->SetRenderTarget = D3D_SetRenderTarget;
  1435. renderer->QueueSetViewport = D3D_QueueSetViewport;
  1436. renderer->QueueSetDrawColor = D3D_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
  1437. renderer->QueueDrawPoints = D3D_QueueDrawPoints;
  1438. renderer->QueueDrawLines = D3D_QueueDrawPoints; /* lines and points queue vertices the same way. */
  1439. renderer->QueueGeometry = D3D_QueueGeometry;
  1440. renderer->RunCommandQueue = D3D_RunCommandQueue;
  1441. renderer->RenderReadPixels = D3D_RenderReadPixels;
  1442. renderer->RenderPresent = D3D_RenderPresent;
  1443. renderer->DestroyTexture = D3D_DestroyTexture;
  1444. renderer->DestroyRenderer = D3D_DestroyRenderer;
  1445. renderer->SetVSync = D3D_SetVSync;
  1446. renderer->info = D3D_RenderDriver.info;
  1447. renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  1448. renderer->driverdata = data;
  1449. SDL_VERSION(&windowinfo.version);
  1450. SDL_GetWindowWMInfo(window, &windowinfo);
  1451. window_flags = SDL_GetWindowFlags(window);
  1452. WIN_GetDrawableSize(window, &w, &h);
  1453. SDL_GetWindowDisplayMode(window, &fullscreen_mode);
  1454. SDL_zero(pparams);
  1455. pparams.hDeviceWindow = windowinfo.info.win.window;
  1456. pparams.BackBufferWidth = w;
  1457. pparams.BackBufferHeight = h;
  1458. pparams.BackBufferCount = 1;
  1459. pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
  1460. if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  1461. pparams.Windowed = FALSE;
  1462. pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
  1463. pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
  1464. } else {
  1465. pparams.Windowed = TRUE;
  1466. pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  1467. pparams.FullScreen_RefreshRateInHz = 0;
  1468. }
  1469. if (flags & SDL_RENDERER_PRESENTVSYNC) {
  1470. pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  1471. } else {
  1472. pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  1473. }
  1474. /* Get the adapter for the display that the window is on */
  1475. displayIndex = SDL_GetWindowDisplayIndex(window);
  1476. data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
  1477. IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
  1478. device_flags = D3DCREATE_FPU_PRESERVE;
  1479. if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
  1480. device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  1481. } else {
  1482. device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  1483. }
  1484. if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D_THREADSAFE, SDL_FALSE)) {
  1485. device_flags |= D3DCREATE_MULTITHREADED;
  1486. }
  1487. result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
  1488. D3DDEVTYPE_HAL,
  1489. pparams.hDeviceWindow,
  1490. device_flags,
  1491. &pparams, &data->device);
  1492. if (FAILED(result)) {
  1493. D3D_DestroyRenderer(renderer);
  1494. D3D_SetError("CreateDevice()", result);
  1495. return NULL;
  1496. }
  1497. /* Get presentation parameters to fill info */
  1498. result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
  1499. if (FAILED(result)) {
  1500. D3D_DestroyRenderer(renderer);
  1501. D3D_SetError("GetSwapChain()", result);
  1502. return NULL;
  1503. }
  1504. result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
  1505. if (FAILED(result)) {
  1506. IDirect3DSwapChain9_Release(chain);
  1507. D3D_DestroyRenderer(renderer);
  1508. D3D_SetError("GetPresentParameters()", result);
  1509. return NULL;
  1510. }
  1511. IDirect3DSwapChain9_Release(chain);
  1512. if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
  1513. renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  1514. }
  1515. data->pparams = pparams;
  1516. IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
  1517. renderer->info.max_texture_width = caps.MaxTextureWidth;
  1518. renderer->info.max_texture_height = caps.MaxTextureHeight;
  1519. if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
  1520. data->enableSeparateAlphaBlend = SDL_TRUE;
  1521. }
  1522. /* Store the default render target */
  1523. IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  1524. data->currentRenderTarget = NULL;
  1525. /* Set up parameters for rendering */
  1526. D3D_InitRenderState(data);
  1527. #if SDL_HAVE_YUV
  1528. if (caps.MaxSimultaneousTextures >= 3) {
  1529. int i;
  1530. for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
  1531. result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
  1532. if (FAILED(result)) {
  1533. D3D_SetError("CreatePixelShader()", result);
  1534. }
  1535. }
  1536. if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
  1537. renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
  1538. renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
  1539. }
  1540. }
  1541. #endif
  1542. data->drawstate.viewport_dirty = SDL_TRUE;
  1543. data->drawstate.cliprect_dirty = SDL_TRUE;
  1544. data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
  1545. data->drawstate.blend = SDL_BLENDMODE_INVALID;
  1546. return renderer;
  1547. }
  1548. SDL_RenderDriver D3D_RenderDriver = {
  1549. D3D_CreateRenderer,
  1550. {
  1551. "direct3d",
  1552. (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
  1553. 1,
  1554. {SDL_PIXELFORMAT_ARGB8888},
  1555. 0,
  1556. 0}
  1557. };
  1558. #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1559. #if defined(__WIN32__) || defined(__WINGDK__)
  1560. /* This function needs to always exist on Windows, for the Dynamic API. */
  1561. IDirect3DDevice9 *
  1562. SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
  1563. {
  1564. IDirect3DDevice9 *device = NULL;
  1565. #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  1566. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1567. /* Make sure that this is a D3D renderer */
  1568. if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1569. SDL_SetError("Renderer is not a D3D renderer");
  1570. return NULL;
  1571. }
  1572. device = data->device;
  1573. if (device) {
  1574. IDirect3DDevice9_AddRef(device);
  1575. }
  1576. #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1577. return device;
  1578. }
  1579. #endif /* defined(__WIN32__) || defined(__WINGDK__) */
  1580. /* vi: set ts=4 sw=4 expandtab: */