SDL_render_d3d.c 64 KB

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