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