SDL_render_d3d.c 63 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980
  1. /*
  2. Simple DirectMedia Layer
  3. Copyright (C) 1997-2015 Sam Lantinga <slouken@libsdl.org>
  4. This software is provided 'as-is', without any express or implied
  5. warranty. In no event will the authors be held liable for any damages
  6. arising from the use of this software.
  7. Permission is granted to anyone to use this software for any purpose,
  8. including commercial applications, and to alter it and redistribute it
  9. freely, subject to the following restrictions:
  10. 1. The origin of this software must not be misrepresented; you must not
  11. claim that you wrote the original software. If you use this software
  12. in a product, an acknowledgment in the product documentation would be
  13. appreciated but is not required.
  14. 2. Altered source versions must be plainly marked as such, and must not be
  15. misrepresented as being the original software.
  16. 3. This notice may not be removed or altered from any source distribution.
  17. */
  18. #include "../../SDL_internal.h"
  19. #include "SDL_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. #ifdef ASSEMBLE_SHADER
  34. #pragma comment(lib, "d3dx9.lib")
  35. /**************************************************************************
  36. * ID3DXBuffer:
  37. * ------------
  38. * The buffer object is used by D3DX to return arbitrary size data.
  39. *
  40. * GetBufferPointer -
  41. * Returns a pointer to the beginning of the buffer.
  42. *
  43. * GetBufferSize -
  44. * Returns the size of the buffer, in bytes.
  45. **************************************************************************/
  46. typedef interface ID3DXBuffer ID3DXBuffer;
  47. typedef interface ID3DXBuffer *LPD3DXBUFFER;
  48. /* {8BA5FB08-5195-40e2-AC58-0D989C3A0102} */
  49. DEFINE_GUID(IID_ID3DXBuffer,
  50. 0x8ba5fb08, 0x5195, 0x40e2, 0xac, 0x58, 0xd, 0x98, 0x9c, 0x3a, 0x1, 0x2);
  51. #undef INTERFACE
  52. #define INTERFACE ID3DXBuffer
  53. typedef interface ID3DXBuffer {
  54. const struct ID3DXBufferVtbl FAR* lpVtbl;
  55. } ID3DXBuffer;
  56. typedef const struct ID3DXBufferVtbl ID3DXBufferVtbl;
  57. const struct ID3DXBufferVtbl
  58. {
  59. /* IUnknown */
  60. STDMETHOD(QueryInterface)(THIS_ REFIID iid, LPVOID *ppv) PURE;
  61. STDMETHOD_(ULONG, AddRef)(THIS) PURE;
  62. STDMETHOD_(ULONG, Release)(THIS) PURE;
  63. /* ID3DXBuffer */
  64. STDMETHOD_(LPVOID, GetBufferPointer)(THIS) PURE;
  65. STDMETHOD_(DWORD, GetBufferSize)(THIS) PURE;
  66. };
  67. HRESULT WINAPI
  68. D3DXAssembleShader(
  69. LPCSTR pSrcData,
  70. UINT SrcDataLen,
  71. CONST LPVOID* pDefines,
  72. LPVOID pInclude,
  73. DWORD Flags,
  74. LPD3DXBUFFER* ppShader,
  75. LPD3DXBUFFER* ppErrorMsgs);
  76. static void PrintShaderData(LPDWORD shader_data, DWORD shader_size)
  77. {
  78. OutputDebugStringA("const DWORD shader_data[] = {\n\t");
  79. {
  80. SDL_bool newline = SDL_FALSE;
  81. unsigned i;
  82. for (i = 0; i < shader_size / sizeof(DWORD); ++i) {
  83. char dword[11];
  84. if (i > 0) {
  85. if ((i%6) == 0) {
  86. newline = SDL_TRUE;
  87. }
  88. if (newline) {
  89. OutputDebugStringA(",\n ");
  90. newline = SDL_FALSE;
  91. } else {
  92. OutputDebugStringA(", ");
  93. }
  94. }
  95. SDL_snprintf(dword, sizeof(dword), "0x%8.8x", shader_data[i]);
  96. OutputDebugStringA(dword);
  97. }
  98. OutputDebugStringA("\n};\n");
  99. }
  100. }
  101. #endif /* ASSEMBLE_SHADER */
  102. /* Direct3D renderer implementation */
  103. static SDL_Renderer *D3D_CreateRenderer(SDL_Window * window, Uint32 flags);
  104. static void D3D_WindowEvent(SDL_Renderer * renderer,
  105. const SDL_WindowEvent *event);
  106. static int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
  107. static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
  108. static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  109. const SDL_Rect * rect, const void *pixels,
  110. int pitch);
  111. static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  112. const SDL_Rect * rect,
  113. const Uint8 *Yplane, int Ypitch,
  114. const Uint8 *Uplane, int Upitch,
  115. const Uint8 *Vplane, int Vpitch);
  116. static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  117. const SDL_Rect * rect, void **pixels, int *pitch);
  118. static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
  119. static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
  120. static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
  121. static int D3D_UpdateViewport(SDL_Renderer * renderer);
  122. static int D3D_UpdateClipRect(SDL_Renderer * renderer);
  123. static int D3D_RenderClear(SDL_Renderer * renderer);
  124. static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
  125. const SDL_FPoint * points, int count);
  126. static int D3D_RenderDrawLines(SDL_Renderer * renderer,
  127. const SDL_FPoint * points, int count);
  128. static int D3D_RenderFillRects(SDL_Renderer * renderer,
  129. const SDL_FRect * rects, int count);
  130. static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  131. const SDL_Rect * srcrect, const SDL_FRect * dstrect);
  132. static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  133. const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  134. const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
  135. static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  136. Uint32 format, void * pixels, int pitch);
  137. static void D3D_RenderPresent(SDL_Renderer * renderer);
  138. static void D3D_DestroyTexture(SDL_Renderer * renderer,
  139. SDL_Texture * texture);
  140. static void D3D_DestroyRenderer(SDL_Renderer * renderer);
  141. SDL_RenderDriver D3D_RenderDriver = {
  142. D3D_CreateRenderer,
  143. {
  144. "direct3d",
  145. (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
  146. 1,
  147. {SDL_PIXELFORMAT_ARGB8888},
  148. 0,
  149. 0}
  150. };
  151. typedef struct
  152. {
  153. void* d3dDLL;
  154. IDirect3D9 *d3d;
  155. IDirect3DDevice9 *device;
  156. UINT adapter;
  157. D3DPRESENT_PARAMETERS pparams;
  158. SDL_bool updateSize;
  159. SDL_bool beginScene;
  160. SDL_bool enableSeparateAlphaBlend;
  161. D3DTEXTUREFILTERTYPE scaleMode[8];
  162. IDirect3DSurface9 *defaultRenderTarget;
  163. IDirect3DSurface9 *currentRenderTarget;
  164. void* d3dxDLL;
  165. LPDIRECT3DPIXELSHADER9 ps_yuv;
  166. } D3D_RenderData;
  167. typedef struct
  168. {
  169. SDL_bool dirty;
  170. int w, h;
  171. DWORD usage;
  172. Uint32 format;
  173. IDirect3DTexture9 *texture;
  174. IDirect3DTexture9 *staging;
  175. } D3D_TextureRep;
  176. typedef struct
  177. {
  178. D3D_TextureRep texture;
  179. D3DTEXTUREFILTERTYPE scaleMode;
  180. /* YV12 texture support */
  181. SDL_bool yuv;
  182. D3D_TextureRep utexture;
  183. D3D_TextureRep vtexture;
  184. Uint8 *pixels;
  185. int pitch;
  186. SDL_Rect locked_rect;
  187. } D3D_TextureData;
  188. typedef struct
  189. {
  190. float x, y, z;
  191. DWORD color;
  192. float u, v;
  193. } Vertex;
  194. static int
  195. D3D_SetError(const char *prefix, HRESULT result)
  196. {
  197. const char *error;
  198. switch (result) {
  199. case D3DERR_WRONGTEXTUREFORMAT:
  200. error = "WRONGTEXTUREFORMAT";
  201. break;
  202. case D3DERR_UNSUPPORTEDCOLOROPERATION:
  203. error = "UNSUPPORTEDCOLOROPERATION";
  204. break;
  205. case D3DERR_UNSUPPORTEDCOLORARG:
  206. error = "UNSUPPORTEDCOLORARG";
  207. break;
  208. case D3DERR_UNSUPPORTEDALPHAOPERATION:
  209. error = "UNSUPPORTEDALPHAOPERATION";
  210. break;
  211. case D3DERR_UNSUPPORTEDALPHAARG:
  212. error = "UNSUPPORTEDALPHAARG";
  213. break;
  214. case D3DERR_TOOMANYOPERATIONS:
  215. error = "TOOMANYOPERATIONS";
  216. break;
  217. case D3DERR_CONFLICTINGTEXTUREFILTER:
  218. error = "CONFLICTINGTEXTUREFILTER";
  219. break;
  220. case D3DERR_UNSUPPORTEDFACTORVALUE:
  221. error = "UNSUPPORTEDFACTORVALUE";
  222. break;
  223. case D3DERR_CONFLICTINGRENDERSTATE:
  224. error = "CONFLICTINGRENDERSTATE";
  225. break;
  226. case D3DERR_UNSUPPORTEDTEXTUREFILTER:
  227. error = "UNSUPPORTEDTEXTUREFILTER";
  228. break;
  229. case D3DERR_CONFLICTINGTEXTUREPALETTE:
  230. error = "CONFLICTINGTEXTUREPALETTE";
  231. break;
  232. case D3DERR_DRIVERINTERNALERROR:
  233. error = "DRIVERINTERNALERROR";
  234. break;
  235. case D3DERR_NOTFOUND:
  236. error = "NOTFOUND";
  237. break;
  238. case D3DERR_MOREDATA:
  239. error = "MOREDATA";
  240. break;
  241. case D3DERR_DEVICELOST:
  242. error = "DEVICELOST";
  243. break;
  244. case D3DERR_DEVICENOTRESET:
  245. error = "DEVICENOTRESET";
  246. break;
  247. case D3DERR_NOTAVAILABLE:
  248. error = "NOTAVAILABLE";
  249. break;
  250. case D3DERR_OUTOFVIDEOMEMORY:
  251. error = "OUTOFVIDEOMEMORY";
  252. break;
  253. case D3DERR_INVALIDDEVICE:
  254. error = "INVALIDDEVICE";
  255. break;
  256. case D3DERR_INVALIDCALL:
  257. error = "INVALIDCALL";
  258. break;
  259. case D3DERR_DRIVERINVALIDCALL:
  260. error = "DRIVERINVALIDCALL";
  261. break;
  262. case D3DERR_WASSTILLDRAWING:
  263. error = "WASSTILLDRAWING";
  264. break;
  265. default:
  266. error = "UNKNOWN";
  267. break;
  268. }
  269. return SDL_SetError("%s: %s", prefix, error);
  270. }
  271. static D3DFORMAT
  272. PixelFormatToD3DFMT(Uint32 format)
  273. {
  274. switch (format) {
  275. case SDL_PIXELFORMAT_RGB565:
  276. return D3DFMT_R5G6B5;
  277. case SDL_PIXELFORMAT_RGB888:
  278. return D3DFMT_X8R8G8B8;
  279. case SDL_PIXELFORMAT_ARGB8888:
  280. return D3DFMT_A8R8G8B8;
  281. case SDL_PIXELFORMAT_YV12:
  282. case SDL_PIXELFORMAT_IYUV:
  283. return D3DFMT_L8;
  284. default:
  285. return D3DFMT_UNKNOWN;
  286. }
  287. }
  288. static Uint32
  289. D3DFMTToPixelFormat(D3DFORMAT format)
  290. {
  291. switch (format) {
  292. case D3DFMT_R5G6B5:
  293. return SDL_PIXELFORMAT_RGB565;
  294. case D3DFMT_X8R8G8B8:
  295. return SDL_PIXELFORMAT_RGB888;
  296. case D3DFMT_A8R8G8B8:
  297. return SDL_PIXELFORMAT_ARGB8888;
  298. default:
  299. return SDL_PIXELFORMAT_UNKNOWN;
  300. }
  301. }
  302. static void
  303. D3D_InitRenderState(D3D_RenderData *data)
  304. {
  305. D3DMATRIX matrix;
  306. IDirect3DDevice9 *device = data->device;
  307. IDirect3DDevice9_SetVertexShader(device, NULL);
  308. IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
  309. IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
  310. IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
  311. IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
  312. /* Enable color modulation by diffuse color */
  313. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
  314. D3DTOP_MODULATE);
  315. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
  316. D3DTA_TEXTURE);
  317. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
  318. D3DTA_DIFFUSE);
  319. /* Enable alpha modulation by diffuse alpha */
  320. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
  321. D3DTOP_MODULATE);
  322. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
  323. D3DTA_TEXTURE);
  324. IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
  325. D3DTA_DIFFUSE);
  326. /* Enable separate alpha blend function, if possible */
  327. if (data->enableSeparateAlphaBlend) {
  328. IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
  329. }
  330. /* Disable second texture stage, since we're done */
  331. IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
  332. D3DTOP_DISABLE);
  333. IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
  334. D3DTOP_DISABLE);
  335. /* Set an identity world and view matrix */
  336. matrix.m[0][0] = 1.0f;
  337. matrix.m[0][1] = 0.0f;
  338. matrix.m[0][2] = 0.0f;
  339. matrix.m[0][3] = 0.0f;
  340. matrix.m[1][0] = 0.0f;
  341. matrix.m[1][1] = 1.0f;
  342. matrix.m[1][2] = 0.0f;
  343. matrix.m[1][3] = 0.0f;
  344. matrix.m[2][0] = 0.0f;
  345. matrix.m[2][1] = 0.0f;
  346. matrix.m[2][2] = 1.0f;
  347. matrix.m[2][3] = 0.0f;
  348. matrix.m[3][0] = 0.0f;
  349. matrix.m[3][1] = 0.0f;
  350. matrix.m[3][2] = 0.0f;
  351. matrix.m[3][3] = 1.0f;
  352. IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
  353. IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
  354. /* Reset our current scale mode */
  355. SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
  356. /* Start the render with beginScene */
  357. data->beginScene = SDL_TRUE;
  358. }
  359. static int
  360. D3D_Reset(SDL_Renderer * renderer)
  361. {
  362. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  363. HRESULT result;
  364. SDL_Texture *texture;
  365. /* Release the default render target before reset */
  366. if (data->defaultRenderTarget) {
  367. IDirect3DSurface9_Release(data->defaultRenderTarget);
  368. data->defaultRenderTarget = NULL;
  369. }
  370. if (data->currentRenderTarget != NULL) {
  371. IDirect3DSurface9_Release(data->currentRenderTarget);
  372. data->currentRenderTarget = NULL;
  373. }
  374. /* Release application render targets */
  375. for (texture = renderer->textures; texture; texture = texture->next) {
  376. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  377. D3D_DestroyTexture(renderer, texture);
  378. } else {
  379. D3D_RecreateTexture(renderer, texture);
  380. }
  381. }
  382. result = IDirect3DDevice9_Reset(data->device, &data->pparams);
  383. if (FAILED(result)) {
  384. if (result == D3DERR_DEVICELOST) {
  385. /* Don't worry about it, we'll reset later... */
  386. return 0;
  387. } else {
  388. return D3D_SetError("Reset()", result);
  389. }
  390. }
  391. /* Allocate application render targets */
  392. for (texture = renderer->textures; texture; texture = texture->next) {
  393. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  394. D3D_CreateTexture(renderer, texture);
  395. }
  396. }
  397. IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  398. D3D_InitRenderState(data);
  399. D3D_SetRenderTargetInternal(renderer, renderer->target);
  400. D3D_UpdateViewport(renderer);
  401. /* Let the application know that render targets were reset */
  402. {
  403. SDL_Event event;
  404. event.type = SDL_RENDER_TARGETS_RESET;
  405. SDL_PushEvent(&event);
  406. }
  407. return 0;
  408. }
  409. static int
  410. D3D_ActivateRenderer(SDL_Renderer * renderer)
  411. {
  412. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  413. HRESULT result;
  414. if (data->updateSize) {
  415. SDL_Window *window = renderer->window;
  416. int w, h;
  417. Uint32 window_flags = SDL_GetWindowFlags(window);
  418. SDL_GetWindowSize(window, &w, &h);
  419. data->pparams.BackBufferWidth = w;
  420. data->pparams.BackBufferHeight = h;
  421. if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  422. SDL_DisplayMode fullscreen_mode;
  423. SDL_GetWindowDisplayMode(window, &fullscreen_mode);
  424. data->pparams.Windowed = FALSE;
  425. data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
  426. data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
  427. } else {
  428. data->pparams.Windowed = TRUE;
  429. data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  430. data->pparams.FullScreen_RefreshRateInHz = 0;
  431. }
  432. if (D3D_Reset(renderer) < 0) {
  433. return -1;
  434. }
  435. data->updateSize = SDL_FALSE;
  436. }
  437. if (data->beginScene) {
  438. result = IDirect3DDevice9_BeginScene(data->device);
  439. if (result == D3DERR_DEVICELOST) {
  440. if (D3D_Reset(renderer) < 0) {
  441. return -1;
  442. }
  443. result = IDirect3DDevice9_BeginScene(data->device);
  444. }
  445. if (FAILED(result)) {
  446. return D3D_SetError("BeginScene()", result);
  447. }
  448. data->beginScene = SDL_FALSE;
  449. }
  450. return 0;
  451. }
  452. SDL_Renderer *
  453. D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
  454. {
  455. SDL_Renderer *renderer;
  456. D3D_RenderData *data;
  457. SDL_SysWMinfo windowinfo;
  458. HRESULT result;
  459. const char *hint;
  460. D3DPRESENT_PARAMETERS pparams;
  461. IDirect3DSwapChain9 *chain;
  462. D3DCAPS9 caps;
  463. DWORD device_flags;
  464. Uint32 window_flags;
  465. int w, h;
  466. SDL_DisplayMode fullscreen_mode;
  467. int displayIndex;
  468. renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
  469. if (!renderer) {
  470. SDL_OutOfMemory();
  471. return NULL;
  472. }
  473. data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
  474. if (!data) {
  475. SDL_free(renderer);
  476. SDL_OutOfMemory();
  477. return NULL;
  478. }
  479. if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
  480. SDL_free(renderer);
  481. SDL_free(data);
  482. SDL_SetError("Unable to create Direct3D interface");
  483. return NULL;
  484. }
  485. renderer->WindowEvent = D3D_WindowEvent;
  486. renderer->CreateTexture = D3D_CreateTexture;
  487. renderer->UpdateTexture = D3D_UpdateTexture;
  488. renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
  489. renderer->LockTexture = D3D_LockTexture;
  490. renderer->UnlockTexture = D3D_UnlockTexture;
  491. renderer->SetRenderTarget = D3D_SetRenderTarget;
  492. renderer->UpdateViewport = D3D_UpdateViewport;
  493. renderer->UpdateClipRect = D3D_UpdateClipRect;
  494. renderer->RenderClear = D3D_RenderClear;
  495. renderer->RenderDrawPoints = D3D_RenderDrawPoints;
  496. renderer->RenderDrawLines = D3D_RenderDrawLines;
  497. renderer->RenderFillRects = D3D_RenderFillRects;
  498. renderer->RenderCopy = D3D_RenderCopy;
  499. renderer->RenderCopyEx = D3D_RenderCopyEx;
  500. renderer->RenderReadPixels = D3D_RenderReadPixels;
  501. renderer->RenderPresent = D3D_RenderPresent;
  502. renderer->DestroyTexture = D3D_DestroyTexture;
  503. renderer->DestroyRenderer = D3D_DestroyRenderer;
  504. renderer->info = D3D_RenderDriver.info;
  505. renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
  506. renderer->driverdata = data;
  507. SDL_VERSION(&windowinfo.version);
  508. SDL_GetWindowWMInfo(window, &windowinfo);
  509. window_flags = SDL_GetWindowFlags(window);
  510. SDL_GetWindowSize(window, &w, &h);
  511. SDL_GetWindowDisplayMode(window, &fullscreen_mode);
  512. SDL_zero(pparams);
  513. pparams.hDeviceWindow = windowinfo.info.win.window;
  514. pparams.BackBufferWidth = w;
  515. pparams.BackBufferHeight = h;
  516. pparams.BackBufferCount = 1;
  517. pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
  518. if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
  519. pparams.Windowed = FALSE;
  520. pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
  521. pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
  522. } else {
  523. pparams.Windowed = TRUE;
  524. pparams.BackBufferFormat = D3DFMT_UNKNOWN;
  525. pparams.FullScreen_RefreshRateInHz = 0;
  526. }
  527. if (flags & SDL_RENDERER_PRESENTVSYNC) {
  528. pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
  529. } else {
  530. pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
  531. }
  532. /* Get the adapter for the display that the window is on */
  533. displayIndex = SDL_GetWindowDisplayIndex(window);
  534. data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
  535. IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
  536. device_flags = D3DCREATE_FPU_PRESERVE;
  537. if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
  538. device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
  539. } else {
  540. device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
  541. }
  542. hint = SDL_GetHint(SDL_HINT_RENDER_DIRECT3D_THREADSAFE);
  543. if (hint && SDL_atoi(hint)) {
  544. device_flags |= D3DCREATE_MULTITHREADED;
  545. }
  546. result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
  547. D3DDEVTYPE_HAL,
  548. pparams.hDeviceWindow,
  549. device_flags,
  550. &pparams, &data->device);
  551. if (FAILED(result)) {
  552. D3D_DestroyRenderer(renderer);
  553. D3D_SetError("CreateDevice()", result);
  554. return NULL;
  555. }
  556. /* Get presentation parameters to fill info */
  557. result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
  558. if (FAILED(result)) {
  559. D3D_DestroyRenderer(renderer);
  560. D3D_SetError("GetSwapChain()", result);
  561. return NULL;
  562. }
  563. result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
  564. if (FAILED(result)) {
  565. IDirect3DSwapChain9_Release(chain);
  566. D3D_DestroyRenderer(renderer);
  567. D3D_SetError("GetPresentParameters()", result);
  568. return NULL;
  569. }
  570. IDirect3DSwapChain9_Release(chain);
  571. if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
  572. renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
  573. }
  574. data->pparams = pparams;
  575. IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
  576. renderer->info.max_texture_width = caps.MaxTextureWidth;
  577. renderer->info.max_texture_height = caps.MaxTextureHeight;
  578. if (caps.NumSimultaneousRTs >= 2) {
  579. renderer->info.flags |= SDL_RENDERER_TARGETTEXTURE;
  580. }
  581. if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
  582. data->enableSeparateAlphaBlend = SDL_TRUE;
  583. }
  584. /* Store the default render target */
  585. IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
  586. data->currentRenderTarget = NULL;
  587. /* Set up parameters for rendering */
  588. D3D_InitRenderState(data);
  589. if (caps.MaxSimultaneousTextures >= 3)
  590. {
  591. #ifdef ASSEMBLE_SHADER
  592. /* This shader was created by running the following HLSL through the fxc compiler
  593. and then tuning the generated assembly.
  594. fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx
  595. --- yuv.fx ---
  596. Texture2D g_txY;
  597. Texture2D g_txU;
  598. Texture2D g_txV;
  599. SamplerState samLinear
  600. {
  601. Filter = ANISOTROPIC;
  602. AddressU = Clamp;
  603. AddressV = Clamp;
  604. MaxAnisotropy = 1;
  605. };
  606. struct VS_OUTPUT
  607. {
  608. float2 TextureUV : TEXCOORD0;
  609. };
  610. struct PS_OUTPUT
  611. {
  612. float4 RGBAColor : SV_Target;
  613. };
  614. PS_OUTPUT YUV420( VS_OUTPUT In )
  615. {
  616. const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
  617. const float3 Rcoeff = {1.164, 0.000, 1.596};
  618. const float3 Gcoeff = {1.164, -0.391, -0.813};
  619. const float3 Bcoeff = {1.164, 2.018, 0.000};
  620. PS_OUTPUT Output;
  621. float2 TextureUV = In.TextureUV;
  622. float3 yuv;
  623. yuv.x = g_txY.Sample( samLinear, TextureUV ).r;
  624. yuv.y = g_txU.Sample( samLinear, TextureUV ).r;
  625. yuv.z = g_txV.Sample( samLinear, TextureUV ).r;
  626. yuv += offset;
  627. Output.RGBAColor.r = dot(yuv, Rcoeff);
  628. Output.RGBAColor.g = dot(yuv, Gcoeff);
  629. Output.RGBAColor.b = dot(yuv, Bcoeff);
  630. Output.RGBAColor.a = 1.0f;
  631. return Output;
  632. }
  633. technique10 RenderYUV420
  634. {
  635. pass P0
  636. {
  637. SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) );
  638. }
  639. }
  640. */
  641. const char *shader_text =
  642. "ps_2_0\n"
  643. "def c0, -0.0627451017, -0.501960814, -0.501960814, 1\n"
  644. "def c1, 1.16400003, 0, 1.59599996, 0\n"
  645. "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"
  646. "def c3, 1.16400003, 2.01799989, 0, 0\n"
  647. "dcl t0.xy\n"
  648. "dcl v0.xyzw\n"
  649. "dcl_2d s0\n"
  650. "dcl_2d s1\n"
  651. "dcl_2d s2\n"
  652. "texld r0, t0, s0\n"
  653. "texld r1, t0, s1\n"
  654. "texld r2, t0, s2\n"
  655. "mov r0.y, r1.x\n"
  656. "mov r0.z, r2.x\n"
  657. "add r0.xyz, r0, c0\n"
  658. "dp3 r1.x, r0, c1\n"
  659. "dp3 r1.y, r0, c2\n"
  660. "dp2add r1.z, r0, c3, c3.z\n" /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */
  661. "mov r1.w, c0.w\n"
  662. "mul r0, r1, v0\n" /* Not in the HLSL, multiply by vertex color */
  663. "mov oC0, r0\n"
  664. ;
  665. LPD3DXBUFFER pCode;
  666. LPD3DXBUFFER pErrorMsgs;
  667. LPDWORD shader_data = NULL;
  668. DWORD shader_size = 0;
  669. result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);
  670. if (!FAILED(result)) {
  671. shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
  672. shader_size = pCode->lpVtbl->GetBufferSize(pCode);
  673. PrintShaderData(shader_data, shader_size);
  674. } else {
  675. const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);
  676. SDL_SetError("Couldn't assemble shader: %s", error);
  677. }
  678. #else
  679. const DWORD shader_data[] = {
  680. 0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081,
  681. 0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
  682. 0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
  683. 0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
  684. 0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
  685. 0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
  686. 0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
  687. 0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
  688. 0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
  689. 0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
  690. 0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
  691. 0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
  692. 0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
  693. 0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
  694. 0x80e40000, 0x0000ffff
  695. };
  696. #endif
  697. if (shader_data != NULL) {
  698. result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
  699. if (!FAILED(result)) {
  700. renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_YV12;
  701. renderer->info.texture_formats[renderer->info.num_texture_formats++] = SDL_PIXELFORMAT_IYUV;
  702. } else {
  703. D3D_SetError("CreatePixelShader()", result);
  704. }
  705. }
  706. }
  707. return renderer;
  708. }
  709. static void
  710. D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
  711. {
  712. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  713. if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
  714. data->updateSize = SDL_TRUE;
  715. }
  716. }
  717. static D3DTEXTUREFILTERTYPE
  718. GetScaleQuality(void)
  719. {
  720. const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
  721. if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
  722. return D3DTEXF_POINT;
  723. } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
  724. return D3DTEXF_LINEAR;
  725. }
  726. }
  727. static int
  728. D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
  729. {
  730. HRESULT result;
  731. texture->dirty = SDL_FALSE;
  732. texture->w = w;
  733. texture->h = h;
  734. texture->usage = usage;
  735. texture->format = format;
  736. result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
  737. PixelFormatToD3DFMT(format),
  738. D3DPOOL_DEFAULT, &texture->texture, NULL);
  739. if (FAILED(result)) {
  740. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  741. }
  742. return 0;
  743. }
  744. static int
  745. D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
  746. {
  747. HRESULT result;
  748. if (texture->staging == NULL) {
  749. result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  750. PixelFormatToD3DFMT(texture->format),
  751. D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
  752. if (FAILED(result)) {
  753. return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
  754. }
  755. }
  756. return 0;
  757. }
  758. static int
  759. D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
  760. {
  761. HRESULT result;
  762. if (texture->dirty && texture->staging) {
  763. if (!texture->texture) {
  764. result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
  765. PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
  766. if (FAILED(result)) {
  767. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  768. }
  769. }
  770. result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
  771. if (FAILED(result)) {
  772. return D3D_SetError("UpdateTexture()", result);
  773. }
  774. texture->dirty = SDL_FALSE;
  775. }
  776. result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
  777. if (FAILED(result)) {
  778. return D3D_SetError("SetTexture()", result);
  779. }
  780. return 0;
  781. }
  782. static int
  783. D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
  784. {
  785. if (texture->texture) {
  786. IDirect3DTexture9_Release(texture->texture);
  787. texture->texture = NULL;
  788. }
  789. if (texture->staging) {
  790. IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
  791. texture->dirty = SDL_TRUE;
  792. }
  793. return 0;
  794. }
  795. static int
  796. D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
  797. {
  798. RECT d3drect;
  799. D3DLOCKED_RECT locked;
  800. const Uint8 *src;
  801. Uint8 *dst;
  802. int row, length;
  803. HRESULT result;
  804. if (D3D_CreateStagingTexture(device, texture) < 0) {
  805. return -1;
  806. }
  807. d3drect.left = x;
  808. d3drect.right = x + w;
  809. d3drect.top = y;
  810. d3drect.bottom = y + h;
  811. result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
  812. if (FAILED(result)) {
  813. return D3D_SetError("LockRect()", result);
  814. }
  815. src = (const Uint8 *)pixels;
  816. dst = locked.pBits;
  817. length = w * SDL_BYTESPERPIXEL(format);
  818. if (length == pitch && length == locked.Pitch) {
  819. SDL_memcpy(dst, src, length*h);
  820. } else {
  821. if (length > pitch) {
  822. length = pitch;
  823. }
  824. if (length > locked.Pitch) {
  825. length = locked.Pitch;
  826. }
  827. for (row = 0; row < h; ++row) {
  828. SDL_memcpy(dst, src, length);
  829. src += pitch;
  830. dst += locked.Pitch;
  831. }
  832. }
  833. result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
  834. if (FAILED(result)) {
  835. return D3D_SetError("UnlockRect()", result);
  836. }
  837. texture->dirty = SDL_TRUE;
  838. return 0;
  839. }
  840. static void
  841. D3D_DestroyTextureRep(D3D_TextureRep *texture)
  842. {
  843. if (texture->texture) {
  844. IDirect3DTexture9_Release(texture->texture);
  845. texture->texture = NULL;
  846. }
  847. if (texture->staging) {
  848. IDirect3DTexture9_Release(texture->staging);
  849. texture->staging = NULL;
  850. }
  851. }
  852. static int
  853. D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  854. {
  855. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  856. D3D_TextureData *texturedata;
  857. DWORD usage;
  858. texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
  859. if (!texturedata) {
  860. return SDL_OutOfMemory();
  861. }
  862. texturedata->scaleMode = GetScaleQuality();
  863. texture->driverdata = texturedata;
  864. if (texture->access == SDL_TEXTUREACCESS_TARGET) {
  865. usage = D3DUSAGE_RENDERTARGET;
  866. } else {
  867. usage = 0;
  868. }
  869. if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
  870. return -1;
  871. }
  872. if (texture->format == SDL_PIXELFORMAT_YV12 ||
  873. texture->format == SDL_PIXELFORMAT_IYUV) {
  874. texturedata->yuv = SDL_TRUE;
  875. if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
  876. return -1;
  877. }
  878. if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
  879. return -1;
  880. }
  881. }
  882. return 0;
  883. }
  884. static int
  885. D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  886. {
  887. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  888. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  889. if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
  890. return -1;
  891. }
  892. if (texturedata->yuv) {
  893. if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  894. return -1;
  895. }
  896. if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
  897. return -1;
  898. }
  899. }
  900. return 0;
  901. }
  902. static int
  903. D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  904. const SDL_Rect * rect, const void *pixels, int pitch)
  905. {
  906. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  907. D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  908. if (!texturedata) {
  909. SDL_SetError("Texture is not currently available");
  910. return -1;
  911. }
  912. if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
  913. return -1;
  914. }
  915. if (texturedata->yuv) {
  916. /* Skip to the correct offset into the next texture */
  917. pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
  918. if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
  919. return -1;
  920. }
  921. /* Skip to the correct offset into the next texture */
  922. pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
  923. if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, pixels, pitch / 2) < 0) {
  924. return -1;
  925. }
  926. }
  927. return 0;
  928. }
  929. static int
  930. D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
  931. const SDL_Rect * rect,
  932. const Uint8 *Yplane, int Ypitch,
  933. const Uint8 *Uplane, int Upitch,
  934. const Uint8 *Vplane, int Vpitch)
  935. {
  936. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  937. D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
  938. if (!texturedata) {
  939. SDL_SetError("Texture is not currently available");
  940. return -1;
  941. }
  942. if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
  943. return -1;
  944. }
  945. if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
  946. return -1;
  947. }
  948. if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
  949. return -1;
  950. }
  951. return 0;
  952. }
  953. static int
  954. D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
  955. const SDL_Rect * rect, void **pixels, int *pitch)
  956. {
  957. D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
  958. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  959. IDirect3DDevice9 *device = data->device;
  960. if (!texturedata) {
  961. SDL_SetError("Texture is not currently available");
  962. return -1;
  963. }
  964. texturedata->locked_rect = *rect;
  965. if (texturedata->yuv) {
  966. /* It's more efficient to upload directly... */
  967. if (!texturedata->pixels) {
  968. texturedata->pitch = texture->w;
  969. texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
  970. if (!texturedata->pixels) {
  971. return SDL_OutOfMemory();
  972. }
  973. }
  974. *pixels =
  975. (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  976. rect->x * SDL_BYTESPERPIXEL(texture->format));
  977. *pitch = texturedata->pitch;
  978. } else {
  979. RECT d3drect;
  980. D3DLOCKED_RECT locked;
  981. HRESULT result;
  982. if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
  983. return -1;
  984. }
  985. d3drect.left = rect->x;
  986. d3drect.right = rect->x + rect->w;
  987. d3drect.top = rect->y;
  988. d3drect.bottom = rect->y + rect->h;
  989. result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
  990. if (FAILED(result)) {
  991. return D3D_SetError("LockRect()", result);
  992. }
  993. *pixels = locked.pBits;
  994. *pitch = locked.Pitch;
  995. }
  996. return 0;
  997. }
  998. static void
  999. D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1000. {
  1001. /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
  1002. D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
  1003. if (!texturedata) {
  1004. return;
  1005. }
  1006. if (texturedata->yuv) {
  1007. const SDL_Rect *rect = &texturedata->locked_rect;
  1008. void *pixels =
  1009. (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
  1010. rect->x * SDL_BYTESPERPIXEL(texture->format));
  1011. D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
  1012. } else {
  1013. IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
  1014. texturedata->texture.dirty = SDL_TRUE;
  1015. }
  1016. }
  1017. static int
  1018. D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
  1019. {
  1020. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1021. D3D_TextureData *texturedata;
  1022. D3D_TextureRep *texturerep;
  1023. HRESULT result;
  1024. IDirect3DDevice9 *device = data->device;
  1025. /* Release the previous render target if it wasn't the default one */
  1026. if (data->currentRenderTarget != NULL) {
  1027. IDirect3DSurface9_Release(data->currentRenderTarget);
  1028. data->currentRenderTarget = NULL;
  1029. }
  1030. if (texture == NULL) {
  1031. IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
  1032. return 0;
  1033. }
  1034. texturedata = (D3D_TextureData *)texture->driverdata;
  1035. if (!texturedata) {
  1036. SDL_SetError("Texture is not currently available");
  1037. return -1;
  1038. }
  1039. /* Make sure the render target is updated if it was locked and written to */
  1040. texturerep = &texturedata->texture;
  1041. if (texturerep->dirty && texturerep->staging) {
  1042. if (!texturerep->texture) {
  1043. result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
  1044. PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
  1045. if (FAILED(result)) {
  1046. return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
  1047. }
  1048. }
  1049. result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
  1050. if (FAILED(result)) {
  1051. return D3D_SetError("UpdateTexture()", result);
  1052. }
  1053. texturerep->dirty = SDL_FALSE;
  1054. }
  1055. result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
  1056. if(FAILED(result)) {
  1057. return D3D_SetError("GetSurfaceLevel()", result);
  1058. }
  1059. result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
  1060. if(FAILED(result)) {
  1061. return D3D_SetError("SetRenderTarget()", result);
  1062. }
  1063. return 0;
  1064. }
  1065. static int
  1066. D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
  1067. {
  1068. D3D_ActivateRenderer(renderer);
  1069. return D3D_SetRenderTargetInternal(renderer, texture);
  1070. }
  1071. static int
  1072. D3D_UpdateViewport(SDL_Renderer * renderer)
  1073. {
  1074. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1075. D3DVIEWPORT9 viewport;
  1076. D3DMATRIX matrix;
  1077. /* Set the viewport */
  1078. viewport.X = renderer->viewport.x;
  1079. viewport.Y = renderer->viewport.y;
  1080. viewport.Width = renderer->viewport.w;
  1081. viewport.Height = renderer->viewport.h;
  1082. viewport.MinZ = 0.0f;
  1083. viewport.MaxZ = 1.0f;
  1084. IDirect3DDevice9_SetViewport(data->device, &viewport);
  1085. /* Set an orthographic projection matrix */
  1086. if (renderer->viewport.w && renderer->viewport.h) {
  1087. matrix.m[0][0] = 2.0f / renderer->viewport.w;
  1088. matrix.m[0][1] = 0.0f;
  1089. matrix.m[0][2] = 0.0f;
  1090. matrix.m[0][3] = 0.0f;
  1091. matrix.m[1][0] = 0.0f;
  1092. matrix.m[1][1] = -2.0f / renderer->viewport.h;
  1093. matrix.m[1][2] = 0.0f;
  1094. matrix.m[1][3] = 0.0f;
  1095. matrix.m[2][0] = 0.0f;
  1096. matrix.m[2][1] = 0.0f;
  1097. matrix.m[2][2] = 1.0f;
  1098. matrix.m[2][3] = 0.0f;
  1099. matrix.m[3][0] = -1.0f;
  1100. matrix.m[3][1] = 1.0f;
  1101. matrix.m[3][2] = 0.0f;
  1102. matrix.m[3][3] = 1.0f;
  1103. IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
  1104. }
  1105. return 0;
  1106. }
  1107. static int
  1108. D3D_UpdateClipRect(SDL_Renderer * renderer)
  1109. {
  1110. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1111. if (renderer->clipping_enabled) {
  1112. const SDL_Rect *rect = &renderer->clip_rect;
  1113. RECT r;
  1114. HRESULT result;
  1115. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
  1116. r.left = renderer->viewport.x + rect->x;
  1117. r.top = renderer->viewport.y + rect->y;
  1118. r.right = renderer->viewport.x + rect->x + rect->w;
  1119. r.bottom = renderer->viewport.y + rect->y + rect->h;
  1120. result = IDirect3DDevice9_SetScissorRect(data->device, &r);
  1121. if (result != D3D_OK) {
  1122. D3D_SetError("SetScissor()", result);
  1123. return -1;
  1124. }
  1125. } else {
  1126. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
  1127. }
  1128. return 0;
  1129. }
  1130. static int
  1131. D3D_RenderClear(SDL_Renderer * renderer)
  1132. {
  1133. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1134. DWORD color;
  1135. HRESULT result;
  1136. int BackBufferWidth, BackBufferHeight;
  1137. if (D3D_ActivateRenderer(renderer) < 0) {
  1138. return -1;
  1139. }
  1140. color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1141. if (renderer->target) {
  1142. BackBufferWidth = renderer->target->w;
  1143. BackBufferHeight = renderer->target->h;
  1144. } else {
  1145. BackBufferWidth = data->pparams.BackBufferWidth;
  1146. BackBufferHeight = data->pparams.BackBufferHeight;
  1147. }
  1148. /* Don't reset the viewport if we don't have to! */
  1149. if (!renderer->viewport.x && !renderer->viewport.y &&
  1150. renderer->viewport.w == BackBufferWidth &&
  1151. renderer->viewport.h == BackBufferHeight) {
  1152. result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1153. } else {
  1154. D3DVIEWPORT9 viewport;
  1155. /* Clear is defined to clear the entire render target */
  1156. viewport.X = 0;
  1157. viewport.Y = 0;
  1158. viewport.Width = BackBufferWidth;
  1159. viewport.Height = BackBufferHeight;
  1160. viewport.MinZ = 0.0f;
  1161. viewport.MaxZ = 1.0f;
  1162. IDirect3DDevice9_SetViewport(data->device, &viewport);
  1163. result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
  1164. /* Reset the viewport */
  1165. viewport.X = renderer->viewport.x;
  1166. viewport.Y = renderer->viewport.y;
  1167. viewport.Width = renderer->viewport.w;
  1168. viewport.Height = renderer->viewport.h;
  1169. viewport.MinZ = 0.0f;
  1170. viewport.MaxZ = 1.0f;
  1171. IDirect3DDevice9_SetViewport(data->device, &viewport);
  1172. }
  1173. if (FAILED(result)) {
  1174. return D3D_SetError("Clear()", result);
  1175. }
  1176. return 0;
  1177. }
  1178. static void
  1179. D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
  1180. {
  1181. switch (blendMode) {
  1182. case SDL_BLENDMODE_NONE:
  1183. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1184. FALSE);
  1185. break;
  1186. case SDL_BLENDMODE_BLEND:
  1187. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1188. TRUE);
  1189. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1190. D3DBLEND_SRCALPHA);
  1191. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1192. D3DBLEND_INVSRCALPHA);
  1193. if (data->enableSeparateAlphaBlend) {
  1194. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1195. D3DBLEND_ONE);
  1196. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1197. D3DBLEND_INVSRCALPHA);
  1198. }
  1199. break;
  1200. case SDL_BLENDMODE_ADD:
  1201. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1202. TRUE);
  1203. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1204. D3DBLEND_SRCALPHA);
  1205. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1206. D3DBLEND_ONE);
  1207. if (data->enableSeparateAlphaBlend) {
  1208. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1209. D3DBLEND_ZERO);
  1210. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1211. D3DBLEND_ONE);
  1212. }
  1213. break;
  1214. case SDL_BLENDMODE_MOD:
  1215. IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
  1216. TRUE);
  1217. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
  1218. D3DBLEND_ZERO);
  1219. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
  1220. D3DBLEND_SRCCOLOR);
  1221. if (data->enableSeparateAlphaBlend) {
  1222. IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
  1223. D3DBLEND_ZERO);
  1224. IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
  1225. D3DBLEND_ONE);
  1226. }
  1227. break;
  1228. }
  1229. }
  1230. static int
  1231. D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
  1232. int count)
  1233. {
  1234. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1235. DWORD color;
  1236. Vertex *vertices;
  1237. int i;
  1238. HRESULT result;
  1239. if (D3D_ActivateRenderer(renderer) < 0) {
  1240. return -1;
  1241. }
  1242. D3D_SetBlendMode(data, renderer->blendMode);
  1243. result =
  1244. IDirect3DDevice9_SetTexture(data->device, 0,
  1245. (IDirect3DBaseTexture9 *) 0);
  1246. if (FAILED(result)) {
  1247. return D3D_SetError("SetTexture()", result);
  1248. }
  1249. color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1250. vertices = SDL_stack_alloc(Vertex, count);
  1251. for (i = 0; i < count; ++i) {
  1252. vertices[i].x = points[i].x;
  1253. vertices[i].y = points[i].y;
  1254. vertices[i].z = 0.0f;
  1255. vertices[i].color = color;
  1256. vertices[i].u = 0.0f;
  1257. vertices[i].v = 0.0f;
  1258. }
  1259. result =
  1260. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
  1261. vertices, sizeof(*vertices));
  1262. SDL_stack_free(vertices);
  1263. if (FAILED(result)) {
  1264. return D3D_SetError("DrawPrimitiveUP()", result);
  1265. }
  1266. return 0;
  1267. }
  1268. static int
  1269. D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
  1270. int count)
  1271. {
  1272. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1273. DWORD color;
  1274. Vertex *vertices;
  1275. int i;
  1276. HRESULT result;
  1277. if (D3D_ActivateRenderer(renderer) < 0) {
  1278. return -1;
  1279. }
  1280. D3D_SetBlendMode(data, renderer->blendMode);
  1281. result =
  1282. IDirect3DDevice9_SetTexture(data->device, 0,
  1283. (IDirect3DBaseTexture9 *) 0);
  1284. if (FAILED(result)) {
  1285. return D3D_SetError("SetTexture()", result);
  1286. }
  1287. color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1288. vertices = SDL_stack_alloc(Vertex, count);
  1289. for (i = 0; i < count; ++i) {
  1290. vertices[i].x = points[i].x;
  1291. vertices[i].y = points[i].y;
  1292. vertices[i].z = 0.0f;
  1293. vertices[i].color = color;
  1294. vertices[i].u = 0.0f;
  1295. vertices[i].v = 0.0f;
  1296. }
  1297. result =
  1298. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
  1299. vertices, sizeof(*vertices));
  1300. /* DirectX 9 has the same line rasterization semantics as GDI,
  1301. so we need to close the endpoint of the line */
  1302. if (count == 2 ||
  1303. points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
  1304. vertices[0].x = points[count-1].x;
  1305. vertices[0].y = points[count-1].y;
  1306. result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
  1307. }
  1308. SDL_stack_free(vertices);
  1309. if (FAILED(result)) {
  1310. return D3D_SetError("DrawPrimitiveUP()", result);
  1311. }
  1312. return 0;
  1313. }
  1314. static int
  1315. D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
  1316. int count)
  1317. {
  1318. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1319. DWORD color;
  1320. int i;
  1321. float minx, miny, maxx, maxy;
  1322. Vertex vertices[4];
  1323. HRESULT result;
  1324. if (D3D_ActivateRenderer(renderer) < 0) {
  1325. return -1;
  1326. }
  1327. D3D_SetBlendMode(data, renderer->blendMode);
  1328. result =
  1329. IDirect3DDevice9_SetTexture(data->device, 0,
  1330. (IDirect3DBaseTexture9 *) 0);
  1331. if (FAILED(result)) {
  1332. return D3D_SetError("SetTexture()", result);
  1333. }
  1334. color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
  1335. for (i = 0; i < count; ++i) {
  1336. const SDL_FRect *rect = &rects[i];
  1337. minx = rect->x;
  1338. miny = rect->y;
  1339. maxx = rect->x + rect->w;
  1340. maxy = rect->y + rect->h;
  1341. vertices[0].x = minx;
  1342. vertices[0].y = miny;
  1343. vertices[0].z = 0.0f;
  1344. vertices[0].color = color;
  1345. vertices[0].u = 0.0f;
  1346. vertices[0].v = 0.0f;
  1347. vertices[1].x = maxx;
  1348. vertices[1].y = miny;
  1349. vertices[1].z = 0.0f;
  1350. vertices[1].color = color;
  1351. vertices[1].u = 0.0f;
  1352. vertices[1].v = 0.0f;
  1353. vertices[2].x = maxx;
  1354. vertices[2].y = maxy;
  1355. vertices[2].z = 0.0f;
  1356. vertices[2].color = color;
  1357. vertices[2].u = 0.0f;
  1358. vertices[2].v = 0.0f;
  1359. vertices[3].x = minx;
  1360. vertices[3].y = maxy;
  1361. vertices[3].z = 0.0f;
  1362. vertices[3].color = color;
  1363. vertices[3].u = 0.0f;
  1364. vertices[3].v = 0.0f;
  1365. result =
  1366. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
  1367. 2, vertices, sizeof(*vertices));
  1368. if (FAILED(result)) {
  1369. return D3D_SetError("DrawPrimitiveUP()", result);
  1370. }
  1371. }
  1372. return 0;
  1373. }
  1374. static void
  1375. D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
  1376. {
  1377. if (texturedata->scaleMode != data->scaleMode[index]) {
  1378. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
  1379. texturedata->scaleMode);
  1380. IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
  1381. texturedata->scaleMode);
  1382. data->scaleMode[index] = texturedata->scaleMode;
  1383. }
  1384. }
  1385. static int
  1386. D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
  1387. const SDL_Rect * srcrect, const SDL_FRect * dstrect)
  1388. {
  1389. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1390. D3D_TextureData *texturedata;
  1391. LPDIRECT3DPIXELSHADER9 shader = NULL;
  1392. float minx, miny, maxx, maxy;
  1393. float minu, maxu, minv, maxv;
  1394. DWORD color;
  1395. Vertex vertices[4];
  1396. HRESULT result;
  1397. if (D3D_ActivateRenderer(renderer) < 0) {
  1398. return -1;
  1399. }
  1400. texturedata = (D3D_TextureData *)texture->driverdata;
  1401. if (!texturedata) {
  1402. SDL_SetError("Texture is not currently available");
  1403. return -1;
  1404. }
  1405. minx = dstrect->x - 0.5f;
  1406. miny = dstrect->y - 0.5f;
  1407. maxx = dstrect->x + dstrect->w - 0.5f;
  1408. maxy = dstrect->y + dstrect->h - 0.5f;
  1409. minu = (float) srcrect->x / texture->w;
  1410. maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1411. minv = (float) srcrect->y / texture->h;
  1412. maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1413. color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1414. vertices[0].x = minx;
  1415. vertices[0].y = miny;
  1416. vertices[0].z = 0.0f;
  1417. vertices[0].color = color;
  1418. vertices[0].u = minu;
  1419. vertices[0].v = minv;
  1420. vertices[1].x = maxx;
  1421. vertices[1].y = miny;
  1422. vertices[1].z = 0.0f;
  1423. vertices[1].color = color;
  1424. vertices[1].u = maxu;
  1425. vertices[1].v = minv;
  1426. vertices[2].x = maxx;
  1427. vertices[2].y = maxy;
  1428. vertices[2].z = 0.0f;
  1429. vertices[2].color = color;
  1430. vertices[2].u = maxu;
  1431. vertices[2].v = maxv;
  1432. vertices[3].x = minx;
  1433. vertices[3].y = maxy;
  1434. vertices[3].z = 0.0f;
  1435. vertices[3].color = color;
  1436. vertices[3].u = minu;
  1437. vertices[3].v = maxv;
  1438. D3D_SetBlendMode(data, texture->blendMode);
  1439. D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1440. if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1441. return -1;
  1442. }
  1443. if (texturedata->yuv) {
  1444. shader = data->ps_yuv;
  1445. D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1446. D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1447. if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1448. return -1;
  1449. }
  1450. if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1451. return -1;
  1452. }
  1453. }
  1454. if (shader) {
  1455. result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1456. if (FAILED(result)) {
  1457. return D3D_SetError("SetShader()", result);
  1458. }
  1459. }
  1460. result =
  1461. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1462. vertices, sizeof(*vertices));
  1463. if (FAILED(result)) {
  1464. return D3D_SetError("DrawPrimitiveUP()", result);
  1465. }
  1466. if (shader) {
  1467. result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1468. if (FAILED(result)) {
  1469. return D3D_SetError("SetShader()", result);
  1470. }
  1471. }
  1472. return 0;
  1473. }
  1474. static int
  1475. D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
  1476. const SDL_Rect * srcrect, const SDL_FRect * dstrect,
  1477. const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
  1478. {
  1479. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1480. D3D_TextureData *texturedata;
  1481. LPDIRECT3DPIXELSHADER9 shader = NULL;
  1482. float minx, miny, maxx, maxy;
  1483. float minu, maxu, minv, maxv;
  1484. float centerx, centery;
  1485. DWORD color;
  1486. Vertex vertices[4];
  1487. Float4X4 modelMatrix;
  1488. HRESULT result;
  1489. if (D3D_ActivateRenderer(renderer) < 0) {
  1490. return -1;
  1491. }
  1492. texturedata = (D3D_TextureData *)texture->driverdata;
  1493. if (!texturedata) {
  1494. SDL_SetError("Texture is not currently available");
  1495. return -1;
  1496. }
  1497. centerx = center->x;
  1498. centery = center->y;
  1499. if (flip & SDL_FLIP_HORIZONTAL) {
  1500. minx = dstrect->w - centerx - 0.5f;
  1501. maxx = -centerx - 0.5f;
  1502. }
  1503. else {
  1504. minx = -centerx - 0.5f;
  1505. maxx = dstrect->w - centerx - 0.5f;
  1506. }
  1507. if (flip & SDL_FLIP_VERTICAL) {
  1508. miny = dstrect->h - centery - 0.5f;
  1509. maxy = -centery - 0.5f;
  1510. }
  1511. else {
  1512. miny = -centery - 0.5f;
  1513. maxy = dstrect->h - centery - 0.5f;
  1514. }
  1515. minu = (float) srcrect->x / texture->w;
  1516. maxu = (float) (srcrect->x + srcrect->w) / texture->w;
  1517. minv = (float) srcrect->y / texture->h;
  1518. maxv = (float) (srcrect->y + srcrect->h) / texture->h;
  1519. color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
  1520. vertices[0].x = minx;
  1521. vertices[0].y = miny;
  1522. vertices[0].z = 0.0f;
  1523. vertices[0].color = color;
  1524. vertices[0].u = minu;
  1525. vertices[0].v = minv;
  1526. vertices[1].x = maxx;
  1527. vertices[1].y = miny;
  1528. vertices[1].z = 0.0f;
  1529. vertices[1].color = color;
  1530. vertices[1].u = maxu;
  1531. vertices[1].v = minv;
  1532. vertices[2].x = maxx;
  1533. vertices[2].y = maxy;
  1534. vertices[2].z = 0.0f;
  1535. vertices[2].color = color;
  1536. vertices[2].u = maxu;
  1537. vertices[2].v = maxv;
  1538. vertices[3].x = minx;
  1539. vertices[3].y = maxy;
  1540. vertices[3].z = 0.0f;
  1541. vertices[3].color = color;
  1542. vertices[3].u = minu;
  1543. vertices[3].v = maxv;
  1544. D3D_SetBlendMode(data, texture->blendMode);
  1545. /* Rotate and translate */
  1546. modelMatrix = MatrixMultiply(
  1547. MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
  1548. MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
  1549. );
  1550. IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1551. D3D_UpdateTextureScaleMode(data, texturedata, 0);
  1552. if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
  1553. return -1;
  1554. }
  1555. if (texturedata->yuv) {
  1556. shader = data->ps_yuv;
  1557. D3D_UpdateTextureScaleMode(data, texturedata, 1);
  1558. D3D_UpdateTextureScaleMode(data, texturedata, 2);
  1559. if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
  1560. return -1;
  1561. }
  1562. if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
  1563. return -1;
  1564. }
  1565. }
  1566. if (shader) {
  1567. result = IDirect3DDevice9_SetPixelShader(data->device, shader);
  1568. if (FAILED(result)) {
  1569. return D3D_SetError("SetShader()", result);
  1570. }
  1571. }
  1572. result =
  1573. IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
  1574. vertices, sizeof(*vertices));
  1575. if (FAILED(result)) {
  1576. return D3D_SetError("DrawPrimitiveUP()", result);
  1577. }
  1578. if (shader) {
  1579. result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
  1580. if (FAILED(result)) {
  1581. return D3D_SetError("SetShader()", result);
  1582. }
  1583. }
  1584. modelMatrix = MatrixIdentity();
  1585. IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
  1586. return 0;
  1587. }
  1588. static int
  1589. D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
  1590. Uint32 format, void * pixels, int pitch)
  1591. {
  1592. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1593. D3DSURFACE_DESC desc;
  1594. LPDIRECT3DSURFACE9 backBuffer;
  1595. LPDIRECT3DSURFACE9 surface;
  1596. RECT d3drect;
  1597. D3DLOCKED_RECT locked;
  1598. HRESULT result;
  1599. if (data->currentRenderTarget) {
  1600. backBuffer = data->currentRenderTarget;
  1601. } else {
  1602. backBuffer = data->defaultRenderTarget;
  1603. }
  1604. result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
  1605. if (FAILED(result)) {
  1606. IDirect3DSurface9_Release(backBuffer);
  1607. return D3D_SetError("GetDesc()", result);
  1608. }
  1609. result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
  1610. if (FAILED(result)) {
  1611. IDirect3DSurface9_Release(backBuffer);
  1612. return D3D_SetError("CreateOffscreenPlainSurface()", result);
  1613. }
  1614. result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
  1615. if (FAILED(result)) {
  1616. IDirect3DSurface9_Release(surface);
  1617. IDirect3DSurface9_Release(backBuffer);
  1618. return D3D_SetError("GetRenderTargetData()", result);
  1619. }
  1620. d3drect.left = rect->x;
  1621. d3drect.right = rect->x + rect->w;
  1622. d3drect.top = rect->y;
  1623. d3drect.bottom = rect->y + rect->h;
  1624. result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
  1625. if (FAILED(result)) {
  1626. IDirect3DSurface9_Release(surface);
  1627. IDirect3DSurface9_Release(backBuffer);
  1628. return D3D_SetError("LockRect()", result);
  1629. }
  1630. SDL_ConvertPixels(rect->w, rect->h,
  1631. D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
  1632. format, pixels, pitch);
  1633. IDirect3DSurface9_UnlockRect(surface);
  1634. IDirect3DSurface9_Release(surface);
  1635. return 0;
  1636. }
  1637. static void
  1638. D3D_RenderPresent(SDL_Renderer * renderer)
  1639. {
  1640. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1641. HRESULT result;
  1642. if (!data->beginScene) {
  1643. IDirect3DDevice9_EndScene(data->device);
  1644. data->beginScene = SDL_TRUE;
  1645. }
  1646. result = IDirect3DDevice9_TestCooperativeLevel(data->device);
  1647. if (result == D3DERR_DEVICELOST) {
  1648. /* We'll reset later */
  1649. return;
  1650. }
  1651. if (result == D3DERR_DEVICENOTRESET) {
  1652. D3D_Reset(renderer);
  1653. }
  1654. result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
  1655. if (FAILED(result)) {
  1656. D3D_SetError("Present()", result);
  1657. }
  1658. }
  1659. static void
  1660. D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
  1661. {
  1662. D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
  1663. if (!data) {
  1664. return;
  1665. }
  1666. D3D_DestroyTextureRep(&data->texture);
  1667. D3D_DestroyTextureRep(&data->utexture);
  1668. D3D_DestroyTextureRep(&data->vtexture);
  1669. SDL_free(data->pixels);
  1670. SDL_free(data);
  1671. texture->driverdata = NULL;
  1672. }
  1673. static void
  1674. D3D_DestroyRenderer(SDL_Renderer * renderer)
  1675. {
  1676. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1677. if (data) {
  1678. /* Release the render target */
  1679. if (data->defaultRenderTarget) {
  1680. IDirect3DSurface9_Release(data->defaultRenderTarget);
  1681. data->defaultRenderTarget = NULL;
  1682. }
  1683. if (data->currentRenderTarget != NULL) {
  1684. IDirect3DSurface9_Release(data->currentRenderTarget);
  1685. data->currentRenderTarget = NULL;
  1686. }
  1687. if (data->ps_yuv) {
  1688. IDirect3DPixelShader9_Release(data->ps_yuv);
  1689. }
  1690. if (data->device) {
  1691. IDirect3DDevice9_Release(data->device);
  1692. }
  1693. if (data->d3d) {
  1694. IDirect3D9_Release(data->d3d);
  1695. SDL_UnloadObject(data->d3dDLL);
  1696. }
  1697. SDL_free(data);
  1698. }
  1699. SDL_free(renderer);
  1700. }
  1701. #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1702. #ifdef __WIN32__
  1703. /* This function needs to always exist on Windows, for the Dynamic API. */
  1704. IDirect3DDevice9 *
  1705. SDL_RenderGetD3D9Device(SDL_Renderer * renderer)
  1706. {
  1707. IDirect3DDevice9 *device = NULL;
  1708. #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
  1709. D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
  1710. /* Make sure that this is a D3D renderer */
  1711. if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
  1712. SDL_SetError("Renderer is not a D3D renderer");
  1713. return NULL;
  1714. }
  1715. device = data->device;
  1716. if (device) {
  1717. IDirect3DDevice9_AddRef(device);
  1718. }
  1719. #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1720. return device;
  1721. }
  1722. #endif /* __WIN32__ */
  1723. /* vi: set ts=4 sw=4 expandtab: */