SDL  2.0
SDL_render_d3d.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2016 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 int D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
129 static int D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
130 static int D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
131  const SDL_Rect * rect, const void *pixels,
132  int pitch);
133 static int D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
134  const SDL_Rect * rect,
135  const Uint8 *Yplane, int Ypitch,
136  const Uint8 *Uplane, int Upitch,
137  const Uint8 *Vplane, int Vpitch);
138 static int D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
139  const SDL_Rect * rect, void **pixels, int *pitch);
140 static void D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
141 static int D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture);
142 static int D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
143 static int D3D_UpdateViewport(SDL_Renderer * renderer);
144 static int D3D_UpdateClipRect(SDL_Renderer * renderer);
145 static int D3D_RenderClear(SDL_Renderer * renderer);
146 static int D3D_RenderDrawPoints(SDL_Renderer * renderer,
147  const SDL_FPoint * points, int count);
148 static int D3D_RenderDrawLines(SDL_Renderer * renderer,
149  const SDL_FPoint * points, int count);
150 static int D3D_RenderFillRects(SDL_Renderer * renderer,
151  const SDL_FRect * rects, int count);
152 static int D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
153  const SDL_Rect * srcrect, const SDL_FRect * dstrect);
154 static int D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
155  const SDL_Rect * srcrect, const SDL_FRect * dstrect,
156  const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
157 static int D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
158  Uint32 format, void * pixels, int pitch);
159 static void D3D_RenderPresent(SDL_Renderer * renderer);
160 static void D3D_DestroyTexture(SDL_Renderer * renderer,
161  SDL_Texture * texture);
162 static void D3D_DestroyRenderer(SDL_Renderer * renderer);
163 
164 
165 SDL_RenderDriver D3D_RenderDriver = {
166  D3D_CreateRenderer,
167  {
168  "direct3d",
170  1,
172  0,
173  0}
174 };
175 
176 typedef struct
177 {
178  void* d3dDLL;
179  IDirect3D9 *d3d;
180  IDirect3DDevice9 *device;
181  UINT adapter;
182  D3DPRESENT_PARAMETERS pparams;
183  SDL_bool updateSize;
184  SDL_bool beginScene;
185  SDL_bool enableSeparateAlphaBlend;
186  D3DTEXTUREFILTERTYPE scaleMode[8];
187  IDirect3DSurface9 *defaultRenderTarget;
188  IDirect3DSurface9 *currentRenderTarget;
189  void* d3dxDLL;
190  LPDIRECT3DPIXELSHADER9 ps_yuv;
191 } D3D_RenderData;
192 
193 typedef struct
194 {
195  SDL_bool dirty;
196  int w, h;
197  DWORD usage;
198  Uint32 format;
199  IDirect3DTexture9 *texture;
200  IDirect3DTexture9 *staging;
201 } D3D_TextureRep;
202 
203 typedef struct
204 {
205  D3D_TextureRep texture;
206  D3DTEXTUREFILTERTYPE scaleMode;
207 
208  /* YV12 texture support */
209  SDL_bool yuv;
210  D3D_TextureRep utexture;
211  D3D_TextureRep vtexture;
212  Uint8 *pixels;
213  int pitch;
214  SDL_Rect locked_rect;
215 } D3D_TextureData;
216 
217 typedef struct
218 {
219  float x, y, z;
220  DWORD color;
221  float u, v;
222 } Vertex;
223 
224 static int
225 D3D_SetError(const char *prefix, HRESULT result)
226 {
227  const char *error;
228 
229  switch (result) {
230  case D3DERR_WRONGTEXTUREFORMAT:
231  error = "WRONGTEXTUREFORMAT";
232  break;
233  case D3DERR_UNSUPPORTEDCOLOROPERATION:
234  error = "UNSUPPORTEDCOLOROPERATION";
235  break;
236  case D3DERR_UNSUPPORTEDCOLORARG:
237  error = "UNSUPPORTEDCOLORARG";
238  break;
239  case D3DERR_UNSUPPORTEDALPHAOPERATION:
240  error = "UNSUPPORTEDALPHAOPERATION";
241  break;
242  case D3DERR_UNSUPPORTEDALPHAARG:
243  error = "UNSUPPORTEDALPHAARG";
244  break;
245  case D3DERR_TOOMANYOPERATIONS:
246  error = "TOOMANYOPERATIONS";
247  break;
248  case D3DERR_CONFLICTINGTEXTUREFILTER:
249  error = "CONFLICTINGTEXTUREFILTER";
250  break;
251  case D3DERR_UNSUPPORTEDFACTORVALUE:
252  error = "UNSUPPORTEDFACTORVALUE";
253  break;
254  case D3DERR_CONFLICTINGRENDERSTATE:
255  error = "CONFLICTINGRENDERSTATE";
256  break;
257  case D3DERR_UNSUPPORTEDTEXTUREFILTER:
258  error = "UNSUPPORTEDTEXTUREFILTER";
259  break;
260  case D3DERR_CONFLICTINGTEXTUREPALETTE:
261  error = "CONFLICTINGTEXTUREPALETTE";
262  break;
263  case D3DERR_DRIVERINTERNALERROR:
264  error = "DRIVERINTERNALERROR";
265  break;
266  case D3DERR_NOTFOUND:
267  error = "NOTFOUND";
268  break;
269  case D3DERR_MOREDATA:
270  error = "MOREDATA";
271  break;
272  case D3DERR_DEVICELOST:
273  error = "DEVICELOST";
274  break;
275  case D3DERR_DEVICENOTRESET:
276  error = "DEVICENOTRESET";
277  break;
278  case D3DERR_NOTAVAILABLE:
279  error = "NOTAVAILABLE";
280  break;
281  case D3DERR_OUTOFVIDEOMEMORY:
282  error = "OUTOFVIDEOMEMORY";
283  break;
284  case D3DERR_INVALIDDEVICE:
285  error = "INVALIDDEVICE";
286  break;
287  case D3DERR_INVALIDCALL:
288  error = "INVALIDCALL";
289  break;
290  case D3DERR_DRIVERINVALIDCALL:
291  error = "DRIVERINVALIDCALL";
292  break;
293  case D3DERR_WASSTILLDRAWING:
294  error = "WASSTILLDRAWING";
295  break;
296  default:
297  error = "UNKNOWN";
298  break;
299  }
300  return SDL_SetError("%s: %s", prefix, error);
301 }
302 
303 static D3DFORMAT
304 PixelFormatToD3DFMT(Uint32 format)
305 {
306  switch (format) {
308  return D3DFMT_R5G6B5;
310  return D3DFMT_X8R8G8B8;
312  return D3DFMT_A8R8G8B8;
315  return D3DFMT_L8;
316  default:
317  return D3DFMT_UNKNOWN;
318  }
319 }
320 
321 static Uint32
322 D3DFMTToPixelFormat(D3DFORMAT format)
323 {
324  switch (format) {
325  case D3DFMT_R5G6B5:
326  return SDL_PIXELFORMAT_RGB565;
327  case D3DFMT_X8R8G8B8:
328  return SDL_PIXELFORMAT_RGB888;
329  case D3DFMT_A8R8G8B8:
331  default:
333  }
334 }
335 
336 static void
337 D3D_InitRenderState(D3D_RenderData *data)
338 {
339  D3DMATRIX matrix;
340 
341  IDirect3DDevice9 *device = data->device;
342 
343  IDirect3DDevice9_SetVertexShader(device, NULL);
344  IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
345  IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
346  IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
347  IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
348 
349  /* Enable color modulation by diffuse color */
350  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
351  D3DTOP_MODULATE);
352  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
353  D3DTA_TEXTURE);
354  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
355  D3DTA_DIFFUSE);
356 
357  /* Enable alpha modulation by diffuse sw_64 */
358  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
359  D3DTOP_MODULATE);
360  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
361  D3DTA_TEXTURE);
362  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
363  D3DTA_DIFFUSE);
364 
365  /* Enable separate alpha blend function, if possible */
366  if (data->enableSeparateAlphaBlend) {
367  IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
368  }
369 
370  /* Disable second texture stage, since we're done */
371  IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
372  D3DTOP_DISABLE);
373  IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
374  D3DTOP_DISABLE);
375 
376  /* Set an identity world and view matrix */
377  matrix.m[0][0] = 1.0f;
378  matrix.m[0][1] = 0.0f;
379  matrix.m[0][2] = 0.0f;
380  matrix.m[0][3] = 0.0f;
381  matrix.m[1][0] = 0.0f;
382  matrix.m[1][1] = 1.0f;
383  matrix.m[1][2] = 0.0f;
384  matrix.m[1][3] = 0.0f;
385  matrix.m[2][0] = 0.0f;
386  matrix.m[2][1] = 0.0f;
387  matrix.m[2][2] = 1.0f;
388  matrix.m[2][3] = 0.0f;
389  matrix.m[3][0] = 0.0f;
390  matrix.m[3][1] = 0.0f;
391  matrix.m[3][2] = 0.0f;
392  matrix.m[3][3] = 1.0f;
393  IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
394  IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
395 
396  /* Reset our current scale mode */
397  SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
398 
399  /* Start the render with beginScene */
400  data->beginScene = SDL_TRUE;
401 }
402 
403 static int
404 D3D_Reset(SDL_Renderer * renderer)
405 {
406  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
407  HRESULT result;
409 
410  /* Release the default render target before reset */
411  if (data->defaultRenderTarget) {
412  IDirect3DSurface9_Release(data->defaultRenderTarget);
413  data->defaultRenderTarget = NULL;
414  }
415  if (data->currentRenderTarget != NULL) {
416  IDirect3DSurface9_Release(data->currentRenderTarget);
417  data->currentRenderTarget = NULL;
418  }
419 
420  /* Release application render targets */
421  for (texture = renderer->textures; texture; texture = texture->next) {
422  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
423  D3D_DestroyTexture(renderer, texture);
424  } else {
425  D3D_RecreateTexture(renderer, texture);
426  }
427  }
428 
429  result = IDirect3DDevice9_Reset(data->device, &data->pparams);
430  if (FAILED(result)) {
431  if (result == D3DERR_DEVICELOST) {
432  /* Don't worry about it, we'll reset later... */
433  return 0;
434  } else {
435  return D3D_SetError("Reset()", result);
436  }
437  }
438 
439  /* Allocate application render targets */
440  for (texture = renderer->textures; texture; texture = texture->next) {
441  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
442  D3D_CreateTexture(renderer, texture);
443  }
444  }
445 
446  IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
447  D3D_InitRenderState(data);
448  D3D_SetRenderTargetInternal(renderer, renderer->target);
449  D3D_UpdateViewport(renderer);
450 
451  /* Let the application know that render targets were reset */
452  {
454  event.type = SDL_RENDER_TARGETS_RESET;
455  SDL_PushEvent(&event);
456  }
457 
458  return 0;
459 }
460 
461 static int
462 D3D_ActivateRenderer(SDL_Renderer * renderer)
463 {
464  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
465  HRESULT result;
466 
467  if (data->updateSize) {
468  SDL_Window *window = renderer->window;
469  int w, h;
470  Uint32 window_flags = SDL_GetWindowFlags(window);
471 
472  SDL_GetWindowSize(window, &w, &h);
473  data->pparams.BackBufferWidth = w;
474  data->pparams.BackBufferHeight = h;
475  if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
476  SDL_DisplayMode fullscreen_mode;
477  SDL_GetWindowDisplayMode(window, &fullscreen_mode);
478  data->pparams.Windowed = FALSE;
479  data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
480  data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
481  } else {
482  data->pparams.Windowed = TRUE;
483  data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
484  data->pparams.FullScreen_RefreshRateInHz = 0;
485  }
486  if (D3D_Reset(renderer) < 0) {
487  return -1;
488  }
489 
490  data->updateSize = SDL_FALSE;
491  }
492  if (data->beginScene) {
493  result = IDirect3DDevice9_BeginScene(data->device);
494  if (result == D3DERR_DEVICELOST) {
495  if (D3D_Reset(renderer) < 0) {
496  return -1;
497  }
498  result = IDirect3DDevice9_BeginScene(data->device);
499  }
500  if (FAILED(result)) {
501  return D3D_SetError("BeginScene()", result);
502  }
503  data->beginScene = SDL_FALSE;
504  }
505  return 0;
506 }
507 
508 SDL_Renderer *
509 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
510 {
512  D3D_RenderData *data;
513  SDL_SysWMinfo windowinfo;
514  HRESULT result;
515  const char *hint;
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->CreateTexture = D3D_CreateTexture;
547  renderer->UpdateTexture = D3D_UpdateTexture;
548  renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
549  renderer->LockTexture = D3D_LockTexture;
550  renderer->UnlockTexture = D3D_UnlockTexture;
551  renderer->SetRenderTarget = D3D_SetRenderTarget;
552  renderer->UpdateViewport = D3D_UpdateViewport;
553  renderer->UpdateClipRect = D3D_UpdateClipRect;
554  renderer->RenderClear = D3D_RenderClear;
555  renderer->RenderDrawPoints = D3D_RenderDrawPoints;
556  renderer->RenderDrawLines = D3D_RenderDrawLines;
557  renderer->RenderFillRects = D3D_RenderFillRects;
558  renderer->RenderCopy = D3D_RenderCopy;
559  renderer->RenderCopyEx = D3D_RenderCopyEx;
560  renderer->RenderReadPixels = D3D_RenderReadPixels;
561  renderer->RenderPresent = D3D_RenderPresent;
562  renderer->DestroyTexture = D3D_DestroyTexture;
563  renderer->DestroyRenderer = D3D_DestroyRenderer;
564  renderer->info = D3D_RenderDriver.info;
566  renderer->driverdata = data;
567 
568  SDL_VERSION(&windowinfo.version);
569  SDL_GetWindowWMInfo(window, &windowinfo);
570 
571  window_flags = SDL_GetWindowFlags(window);
572  SDL_GetWindowSize(window, &w, &h);
573  SDL_GetWindowDisplayMode(window, &fullscreen_mode);
574 
575  SDL_zero(pparams);
576  pparams.hDeviceWindow = windowinfo.info.win.window;
577  pparams.BackBufferWidth = w;
578  pparams.BackBufferHeight = h;
579  pparams.BackBufferCount = 1;
580  pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
581 
582  if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
583  pparams.Windowed = FALSE;
584  pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
585  pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
586  } else {
587  pparams.Windowed = TRUE;
588  pparams.BackBufferFormat = D3DFMT_UNKNOWN;
589  pparams.FullScreen_RefreshRateInHz = 0;
590  }
591  if (flags & SDL_RENDERER_PRESENTVSYNC) {
592  pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
593  } else {
594  pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
595  }
596 
597  /* Get the adapter for the display that the window is on */
598  displayIndex = SDL_GetWindowDisplayIndex(window);
599  data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
600 
601  IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
602 
603  device_flags = D3DCREATE_FPU_PRESERVE;
604  if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
605  device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
606  } else {
607  device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
608  }
609 
611  if (hint && SDL_atoi(hint)) {
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 #else
765  const DWORD shader_data[] = {
766  0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081,
767  0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
768  0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
769  0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
770  0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
771  0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
772  0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
773  0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
774  0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
775  0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
776  0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
777  0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
778  0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
779  0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
780  0x80e40000, 0x0000ffff
781  };
782 #endif
783  if (shader_data != NULL) {
784  result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
785  if (!FAILED(result)) {
788  } else {
789  D3D_SetError("CreatePixelShader()", result);
790  }
791  }
792  }
793 
794  return renderer;
795 }
796 
797 static void
798 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
799 {
800  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
801 
802  if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
803  data->updateSize = SDL_TRUE;
804  }
805 }
806 
807 static D3DTEXTUREFILTERTYPE
808 GetScaleQuality(void)
809 {
810  const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
811 
812  if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
813  return D3DTEXF_POINT;
814  } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
815  return D3DTEXF_LINEAR;
816  }
817 }
818 
819 static int
820 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
821 {
822  HRESULT result;
823 
824  texture->dirty = SDL_FALSE;
825  texture->w = w;
826  texture->h = h;
827  texture->usage = usage;
828  texture->format = format;
829 
830  result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
831  PixelFormatToD3DFMT(format),
832  D3DPOOL_DEFAULT, &texture->texture, NULL);
833  if (FAILED(result)) {
834  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
835  }
836  return 0;
837 }
838 
839 
840 static int
841 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
842 {
843  HRESULT result;
844 
845  if (texture->staging == NULL) {
846  result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
847  PixelFormatToD3DFMT(texture->format),
848  D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
849  if (FAILED(result)) {
850  return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
851  }
852  }
853  return 0;
854 }
855 
856 static int
857 D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
858 {
859  HRESULT result;
860 
861  if (texture->dirty && texture->staging) {
862  if (!texture->texture) {
863  result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
864  PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
865  if (FAILED(result)) {
866  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
867  }
868  }
869 
870  result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
871  if (FAILED(result)) {
872  return D3D_SetError("UpdateTexture()", result);
873  }
874  texture->dirty = SDL_FALSE;
875  }
876  result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
877  if (FAILED(result)) {
878  return D3D_SetError("SetTexture()", result);
879  }
880  return 0;
881 }
882 
883 static int
884 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
885 {
886  if (texture->texture) {
887  IDirect3DTexture9_Release(texture->texture);
888  texture->texture = NULL;
889  }
890  if (texture->staging) {
891  IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
892  texture->dirty = SDL_TRUE;
893  }
894  return 0;
895 }
896 
897 static int
898 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
899 {
900  RECT d3drect;
901  D3DLOCKED_RECT locked;
902  const Uint8 *src;
903  Uint8 *dst;
904  int row, length;
905  HRESULT result;
906 
907  if (D3D_CreateStagingTexture(device, texture) < 0) {
908  return -1;
909  }
910 
911  d3drect.left = x;
912  d3drect.right = x + w;
913  d3drect.top = y;
914  d3drect.bottom = y + h;
915 
916  result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
917  if (FAILED(result)) {
918  return D3D_SetError("LockRect()", result);
919  }
920 
921  src = (const Uint8 *)pixels;
922  dst = locked.pBits;
923  length = w * SDL_BYTESPERPIXEL(format);
924  if (length == pitch && length == locked.Pitch) {
925  SDL_memcpy(dst, src, length*h);
926  } else {
927  if (length > pitch) {
928  length = pitch;
929  }
930  if (length > locked.Pitch) {
931  length = locked.Pitch;
932  }
933  for (row = 0; row < h; ++row) {
934  SDL_memcpy(dst, src, length);
935  src += pitch;
936  dst += locked.Pitch;
937  }
938  }
939  result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
940  if (FAILED(result)) {
941  return D3D_SetError("UnlockRect()", result);
942  }
943  texture->dirty = SDL_TRUE;
944 
945  return 0;
946 }
947 
948 static void
949 D3D_DestroyTextureRep(D3D_TextureRep *texture)
950 {
951  if (texture->texture) {
952  IDirect3DTexture9_Release(texture->texture);
953  texture->texture = NULL;
954  }
955  if (texture->staging) {
956  IDirect3DTexture9_Release(texture->staging);
957  texture->staging = NULL;
958  }
959 }
960 
961 static int
962 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
963 {
964  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
965  D3D_TextureData *texturedata;
966  DWORD usage;
967 
968  texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
969  if (!texturedata) {
970  return SDL_OutOfMemory();
971  }
972  texturedata->scaleMode = GetScaleQuality();
973 
974  texture->driverdata = texturedata;
975 
976  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
977  usage = D3DUSAGE_RENDERTARGET;
978  } else {
979  usage = 0;
980  }
981 
982  if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
983  return -1;
984  }
985 
986  if (texture->format == SDL_PIXELFORMAT_YV12 ||
987  texture->format == SDL_PIXELFORMAT_IYUV) {
988  texturedata->yuv = SDL_TRUE;
989 
990  if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
991  return -1;
992  }
993 
994  if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
995  return -1;
996  }
997  }
998  return 0;
999 }
1000 
1001 static int
1002 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1003 {
1004  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1005  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1006 
1007  if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
1008  return -1;
1009  }
1010 
1011  if (texturedata->yuv) {
1012  if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
1013  return -1;
1014  }
1015 
1016  if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
1017  return -1;
1018  }
1019  }
1020  return 0;
1021 }
1022 
1023 static int
1024 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1025  const SDL_Rect * rect, const void *pixels, int pitch)
1026 {
1027  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1028  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
1029 
1030  if (!texturedata) {
1031  SDL_SetError("Texture is not currently available");
1032  return -1;
1033  }
1034 
1035  if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
1036  return -1;
1037  }
1038 
1039  if (texturedata->yuv) {
1040  /* Skip to the correct offset into the next texture */
1041  pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
1042 
1043  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) {
1044  return -1;
1045  }
1046 
1047  /* Skip to the correct offset into the next texture */
1048  pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
1049  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) {
1050  return -1;
1051  }
1052  }
1053  return 0;
1054 }
1055 
1056 static int
1057 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
1058  const SDL_Rect * rect,
1059  const Uint8 *Yplane, int Ypitch,
1060  const Uint8 *Uplane, int Upitch,
1061  const Uint8 *Vplane, int Vpitch)
1062 {
1063  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1064  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
1065 
1066  if (!texturedata) {
1067  SDL_SetError("Texture is not currently available");
1068  return -1;
1069  }
1070 
1071  if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
1072  return -1;
1073  }
1074  if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
1075  return -1;
1076  }
1077  if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
1078  return -1;
1079  }
1080  return 0;
1081 }
1082 
1083 static int
1084 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1085  const SDL_Rect * rect, void **pixels, int *pitch)
1086 {
1087  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1088  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1089  IDirect3DDevice9 *device = data->device;
1090 
1091  if (!texturedata) {
1092  SDL_SetError("Texture is not currently available");
1093  return -1;
1094  }
1095 
1096  texturedata->locked_rect = *rect;
1097 
1098  if (texturedata->yuv) {
1099  /* It's more efficient to upload directly... */
1100  if (!texturedata->pixels) {
1101  texturedata->pitch = texture->w;
1102  texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
1103  if (!texturedata->pixels) {
1104  return SDL_OutOfMemory();
1105  }
1106  }
1107  *pixels =
1108  (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
1109  rect->x * SDL_BYTESPERPIXEL(texture->format));
1110  *pitch = texturedata->pitch;
1111  } else {
1112  RECT d3drect;
1113  D3DLOCKED_RECT locked;
1114  HRESULT result;
1115 
1116  if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
1117  return -1;
1118  }
1119 
1120  d3drect.left = rect->x;
1121  d3drect.right = rect->x + rect->w;
1122  d3drect.top = rect->y;
1123  d3drect.bottom = rect->y + rect->h;
1124 
1125  result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
1126  if (FAILED(result)) {
1127  return D3D_SetError("LockRect()", result);
1128  }
1129  *pixels = locked.pBits;
1130  *pitch = locked.Pitch;
1131  }
1132  return 0;
1133 }
1134 
1135 static void
1136 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1137 {
1138  /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
1139  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1140 
1141  if (!texturedata) {
1142  return;
1143  }
1144 
1145  if (texturedata->yuv) {
1146  const SDL_Rect *rect = &texturedata->locked_rect;
1147  void *pixels =
1148  (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
1149  rect->x * SDL_BYTESPERPIXEL(texture->format));
1150  D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
1151  } else {
1152  IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
1153  texturedata->texture.dirty = SDL_TRUE;
1154  }
1155 }
1156 
1157 static int
1158 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
1159 {
1160  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1161  D3D_TextureData *texturedata;
1162  D3D_TextureRep *texturerep;
1163  HRESULT result;
1164  IDirect3DDevice9 *device = data->device;
1165 
1166  /* Release the previous render target if it wasn't the default one */
1167  if (data->currentRenderTarget != NULL) {
1168  IDirect3DSurface9_Release(data->currentRenderTarget);
1169  data->currentRenderTarget = NULL;
1170  }
1171 
1172  if (texture == NULL) {
1173  IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
1174  return 0;
1175  }
1176 
1177  texturedata = (D3D_TextureData *)texture->driverdata;
1178  if (!texturedata) {
1179  SDL_SetError("Texture is not currently available");
1180  return -1;
1181  }
1182 
1183  /* Make sure the render target is updated if it was locked and written to */
1184  texturerep = &texturedata->texture;
1185  if (texturerep->dirty && texturerep->staging) {
1186  if (!texturerep->texture) {
1187  result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
1188  PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
1189  if (FAILED(result)) {
1190  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
1191  }
1192  }
1193 
1194  result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
1195  if (FAILED(result)) {
1196  return D3D_SetError("UpdateTexture()", result);
1197  }
1198  texturerep->dirty = SDL_FALSE;
1199  }
1200 
1201  result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
1202  if(FAILED(result)) {
1203  return D3D_SetError("GetSurfaceLevel()", result);
1204  }
1205  result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
1206  if(FAILED(result)) {
1207  return D3D_SetError("SetRenderTarget()", result);
1208  }
1209 
1210  return 0;
1211 }
1212 
1213 static int
1214 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
1215 {
1216  D3D_ActivateRenderer(renderer);
1217 
1218  return D3D_SetRenderTargetInternal(renderer, texture);
1219 }
1220 
1221 static int
1222 D3D_UpdateViewport(SDL_Renderer * renderer)
1223 {
1224  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1225  D3DVIEWPORT9 viewport;
1226  D3DMATRIX matrix;
1227 
1228  /* Set the viewport */
1229  viewport.X = renderer->viewport.x;
1230  viewport.Y = renderer->viewport.y;
1231  viewport.Width = renderer->viewport.w;
1232  viewport.Height = renderer->viewport.h;
1233  viewport.MinZ = 0.0f;
1234  viewport.MaxZ = 1.0f;
1235  IDirect3DDevice9_SetViewport(data->device, &viewport);
1236 
1237  /* Set an orthographic projection matrix */
1238  if (renderer->viewport.w && renderer->viewport.h) {
1239  matrix.m[0][0] = 2.0f / renderer->viewport.w;
1240  matrix.m[0][1] = 0.0f;
1241  matrix.m[0][2] = 0.0f;
1242  matrix.m[0][3] = 0.0f;
1243  matrix.m[1][0] = 0.0f;
1244  matrix.m[1][1] = -2.0f / renderer->viewport.h;
1245  matrix.m[1][2] = 0.0f;
1246  matrix.m[1][3] = 0.0f;
1247  matrix.m[2][0] = 0.0f;
1248  matrix.m[2][1] = 0.0f;
1249  matrix.m[2][2] = 1.0f;
1250  matrix.m[2][3] = 0.0f;
1251  matrix.m[3][0] = -1.0f;
1252  matrix.m[3][1] = 1.0f;
1253  matrix.m[3][2] = 0.0f;
1254  matrix.m[3][3] = 1.0f;
1255  IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
1256  }
1257 
1258  return 0;
1259 }
1260 
1261 static int
1262 D3D_UpdateClipRect(SDL_Renderer * renderer)
1263 {
1264  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1265 
1266  if (renderer->clipping_enabled) {
1267  const SDL_Rect *rect = &renderer->clip_rect;
1268  RECT r;
1269  HRESULT result;
1270 
1271  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
1272  r.left = renderer->viewport.x + rect->x;
1273  r.top = renderer->viewport.y + rect->y;
1274  r.right = renderer->viewport.x + rect->x + rect->w;
1275  r.bottom = renderer->viewport.y + rect->y + rect->h;
1276 
1277  result = IDirect3DDevice9_SetScissorRect(data->device, &r);
1278  if (result != D3D_OK) {
1279  D3D_SetError("SetScissor()", result);
1280  return -1;
1281  }
1282  } else {
1283  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
1284  }
1285  return 0;
1286 }
1287 
1288 static int
1289 D3D_RenderClear(SDL_Renderer * renderer)
1290 {
1291  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1292  DWORD color;
1293  HRESULT result;
1294  int BackBufferWidth, BackBufferHeight;
1295 
1296  if (D3D_ActivateRenderer(renderer) < 0) {
1297  return -1;
1298  }
1299 
1300  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1301 
1302  if (renderer->target) {
1303  BackBufferWidth = renderer->target->w;
1304  BackBufferHeight = renderer->target->h;
1305  } else {
1306  BackBufferWidth = data->pparams.BackBufferWidth;
1307  BackBufferHeight = data->pparams.BackBufferHeight;
1308  }
1309 
1310  /* Don't reset the viewport if we don't have to! */
1311  if (!renderer->viewport.x && !renderer->viewport.y &&
1312  renderer->viewport.w == BackBufferWidth &&
1313  renderer->viewport.h == BackBufferHeight) {
1314  result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
1315  } else {
1316  D3DVIEWPORT9 viewport;
1317 
1318  /* Clear is defined to clear the entire render target */
1319  viewport.X = 0;
1320  viewport.Y = 0;
1321  viewport.Width = BackBufferWidth;
1322  viewport.Height = BackBufferHeight;
1323  viewport.MinZ = 0.0f;
1324  viewport.MaxZ = 1.0f;
1325  IDirect3DDevice9_SetViewport(data->device, &viewport);
1326 
1327  result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
1328 
1329  /* Reset the viewport */
1330  viewport.X = renderer->viewport.x;
1331  viewport.Y = renderer->viewport.y;
1332  viewport.Width = renderer->viewport.w;
1333  viewport.Height = renderer->viewport.h;
1334  viewport.MinZ = 0.0f;
1335  viewport.MaxZ = 1.0f;
1336  IDirect3DDevice9_SetViewport(data->device, &viewport);
1337  }
1338 
1339  if (FAILED(result)) {
1340  return D3D_SetError("Clear()", result);
1341  }
1342  return 0;
1343 }
1344 
1345 static void
1346 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
1347 {
1348  switch (blendMode) {
1349  case SDL_BLENDMODE_NONE:
1350  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1351  FALSE);
1352  break;
1353  case SDL_BLENDMODE_BLEND:
1354  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1355  TRUE);
1356  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1357  D3DBLEND_SRCALPHA);
1358  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1359  D3DBLEND_INVSRCALPHA);
1360  if (data->enableSeparateAlphaBlend) {
1361  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1362  D3DBLEND_ONE);
1363  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1364  D3DBLEND_INVSRCALPHA);
1365  }
1366  break;
1367  case SDL_BLENDMODE_ADD:
1368  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1369  TRUE);
1370  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1371  D3DBLEND_SRCALPHA);
1372  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1373  D3DBLEND_ONE);
1374  if (data->enableSeparateAlphaBlend) {
1375  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1376  D3DBLEND_ZERO);
1377  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1378  D3DBLEND_ONE);
1379  }
1380  break;
1381  case SDL_BLENDMODE_MOD:
1382  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1383  TRUE);
1384  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1385  D3DBLEND_ZERO);
1386  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1387  D3DBLEND_SRCCOLOR);
1388  if (data->enableSeparateAlphaBlend) {
1389  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1390  D3DBLEND_ZERO);
1391  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1392  D3DBLEND_ONE);
1393  }
1394  break;
1395  }
1396 }
1397 
1398 static int
1399 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
1400  int count)
1401 {
1402  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1403  DWORD color;
1404  Vertex *vertices;
1405  int i;
1406  HRESULT result;
1407 
1408  if (D3D_ActivateRenderer(renderer) < 0) {
1409  return -1;
1410  }
1411 
1412  D3D_SetBlendMode(data, renderer->blendMode);
1413 
1414  result =
1415  IDirect3DDevice9_SetTexture(data->device, 0,
1416  (IDirect3DBaseTexture9 *) 0);
1417  if (FAILED(result)) {
1418  return D3D_SetError("SetTexture()", result);
1419  }
1420 
1421  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1422 
1423  vertices = SDL_stack_alloc(Vertex, count);
1424  for (i = 0; i < count; ++i) {
1425  vertices[i].x = points[i].x;
1426  vertices[i].y = points[i].y;
1427  vertices[i].z = 0.0f;
1428  vertices[i].color = color;
1429  vertices[i].u = 0.0f;
1430  vertices[i].v = 0.0f;
1431  }
1432  result =
1433  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
1434  vertices, sizeof(*vertices));
1435  SDL_stack_free(vertices);
1436  if (FAILED(result)) {
1437  return D3D_SetError("DrawPrimitiveUP()", result);
1438  }
1439  return 0;
1440 }
1441 
1442 static int
1443 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
1444  int count)
1445 {
1446  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1447  DWORD color;
1448  Vertex *vertices;
1449  int i;
1450  HRESULT result;
1451 
1452  if (D3D_ActivateRenderer(renderer) < 0) {
1453  return -1;
1454  }
1455 
1456  D3D_SetBlendMode(data, renderer->blendMode);
1457 
1458  result =
1459  IDirect3DDevice9_SetTexture(data->device, 0,
1460  (IDirect3DBaseTexture9 *) 0);
1461  if (FAILED(result)) {
1462  return D3D_SetError("SetTexture()", result);
1463  }
1464 
1465  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1466 
1467  vertices = SDL_stack_alloc(Vertex, count);
1468  for (i = 0; i < count; ++i) {
1469  vertices[i].x = points[i].x;
1470  vertices[i].y = points[i].y;
1471  vertices[i].z = 0.0f;
1472  vertices[i].color = color;
1473  vertices[i].u = 0.0f;
1474  vertices[i].v = 0.0f;
1475  }
1476  result =
1477  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
1478  vertices, sizeof(*vertices));
1479 
1480  /* DirectX 9 has the same line rasterization semantics as GDI,
1481  so we need to close the endpoint of the line */
1482  if (count == 2 ||
1483  points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
1484  vertices[0].x = points[count-1].x;
1485  vertices[0].y = points[count-1].y;
1486  result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
1487  }
1488 
1489  SDL_stack_free(vertices);
1490  if (FAILED(result)) {
1491  return D3D_SetError("DrawPrimitiveUP()", result);
1492  }
1493  return 0;
1494 }
1495 
1496 static int
1497 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
1498  int count)
1499 {
1500  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1501  DWORD color;
1502  int i;
1503  float minx, miny, maxx, maxy;
1504  Vertex vertices[4];
1505  HRESULT result;
1506 
1507  if (D3D_ActivateRenderer(renderer) < 0) {
1508  return -1;
1509  }
1510 
1511  D3D_SetBlendMode(data, renderer->blendMode);
1512 
1513  result =
1514  IDirect3DDevice9_SetTexture(data->device, 0,
1515  (IDirect3DBaseTexture9 *) 0);
1516  if (FAILED(result)) {
1517  return D3D_SetError("SetTexture()", result);
1518  }
1519 
1520  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1521 
1522  for (i = 0; i < count; ++i) {
1523  const SDL_FRect *rect = &rects[i];
1524 
1525  minx = rect->x;
1526  miny = rect->y;
1527  maxx = rect->x + rect->w;
1528  maxy = rect->y + rect->h;
1529 
1530  vertices[0].x = minx;
1531  vertices[0].y = miny;
1532  vertices[0].z = 0.0f;
1533  vertices[0].color = color;
1534  vertices[0].u = 0.0f;
1535  vertices[0].v = 0.0f;
1536 
1537  vertices[1].x = maxx;
1538  vertices[1].y = miny;
1539  vertices[1].z = 0.0f;
1540  vertices[1].color = color;
1541  vertices[1].u = 0.0f;
1542  vertices[1].v = 0.0f;
1543 
1544  vertices[2].x = maxx;
1545  vertices[2].y = maxy;
1546  vertices[2].z = 0.0f;
1547  vertices[2].color = color;
1548  vertices[2].u = 0.0f;
1549  vertices[2].v = 0.0f;
1550 
1551  vertices[3].x = minx;
1552  vertices[3].y = maxy;
1553  vertices[3].z = 0.0f;
1554  vertices[3].color = color;
1555  vertices[3].u = 0.0f;
1556  vertices[3].v = 0.0f;
1557 
1558  result =
1559  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
1560  2, vertices, sizeof(*vertices));
1561  if (FAILED(result)) {
1562  return D3D_SetError("DrawPrimitiveUP()", result);
1563  }
1564  }
1565  return 0;
1566 }
1567 
1568 static void
1569 D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
1570 {
1571  if (texturedata->scaleMode != data->scaleMode[index]) {
1572  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
1573  texturedata->scaleMode);
1574  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
1575  texturedata->scaleMode);
1576  data->scaleMode[index] = texturedata->scaleMode;
1577  }
1578 }
1579 
1580 static int
1581 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
1582  const SDL_Rect * srcrect, const SDL_FRect * dstrect)
1583 {
1584  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1585  D3D_TextureData *texturedata;
1586  LPDIRECT3DPIXELSHADER9 shader = NULL;
1587  float minx, miny, maxx, maxy;
1588  float minu, maxu, minv, maxv;
1589  DWORD color;
1590  Vertex vertices[4];
1591  HRESULT result;
1592 
1593  if (D3D_ActivateRenderer(renderer) < 0) {
1594  return -1;
1595  }
1596 
1597  texturedata = (D3D_TextureData *)texture->driverdata;
1598  if (!texturedata) {
1599  SDL_SetError("Texture is not currently available");
1600  return -1;
1601  }
1602 
1603  minx = dstrect->x - 0.5f;
1604  miny = dstrect->y - 0.5f;
1605  maxx = dstrect->x + dstrect->w - 0.5f;
1606  maxy = dstrect->y + dstrect->h - 0.5f;
1607 
1608  minu = (float) srcrect->x / texture->w;
1609  maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1610  minv = (float) srcrect->y / texture->h;
1611  maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1612 
1613  color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
1614 
1615  vertices[0].x = minx;
1616  vertices[0].y = miny;
1617  vertices[0].z = 0.0f;
1618  vertices[0].color = color;
1619  vertices[0].u = minu;
1620  vertices[0].v = minv;
1621 
1622  vertices[1].x = maxx;
1623  vertices[1].y = miny;
1624  vertices[1].z = 0.0f;
1625  vertices[1].color = color;
1626  vertices[1].u = maxu;
1627  vertices[1].v = minv;
1628 
1629  vertices[2].x = maxx;
1630  vertices[2].y = maxy;
1631  vertices[2].z = 0.0f;
1632  vertices[2].color = color;
1633  vertices[2].u = maxu;
1634  vertices[2].v = maxv;
1635 
1636  vertices[3].x = minx;
1637  vertices[3].y = maxy;
1638  vertices[3].z = 0.0f;
1639  vertices[3].color = color;
1640  vertices[3].u = minu;
1641  vertices[3].v = maxv;
1642 
1643  D3D_SetBlendMode(data, texture->blendMode);
1644 
1645  D3D_UpdateTextureScaleMode(data, texturedata, 0);
1646 
1647  if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
1648  return -1;
1649  }
1650 
1651  if (texturedata->yuv) {
1652  shader = data->ps_yuv;
1653 
1654  D3D_UpdateTextureScaleMode(data, texturedata, 1);
1655  D3D_UpdateTextureScaleMode(data, texturedata, 2);
1656 
1657  if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
1658  return -1;
1659  }
1660  if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
1661  return -1;
1662  }
1663  }
1664 
1665  if (shader) {
1666  result = IDirect3DDevice9_SetPixelShader(data->device, shader);
1667  if (FAILED(result)) {
1668  return D3D_SetError("SetShader()", result);
1669  }
1670  }
1671  result =
1672  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
1673  vertices, sizeof(*vertices));
1674  if (FAILED(result)) {
1675  return D3D_SetError("DrawPrimitiveUP()", result);
1676  }
1677  if (shader) {
1678  result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
1679  if (FAILED(result)) {
1680  return D3D_SetError("SetShader()", result);
1681  }
1682  }
1683  return 0;
1684 }
1685 
1686 
1687 static int
1688 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
1689  const SDL_Rect * srcrect, const SDL_FRect * dstrect,
1690  const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
1691 {
1692  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1693  D3D_TextureData *texturedata;
1694  LPDIRECT3DPIXELSHADER9 shader = NULL;
1695  float minx, miny, maxx, maxy;
1696  float minu, maxu, minv, maxv;
1697  float centerx, centery;
1698  DWORD color;
1699  Vertex vertices[4];
1700  Float4X4 modelMatrix;
1701  HRESULT result;
1702 
1703  if (D3D_ActivateRenderer(renderer) < 0) {
1704  return -1;
1705  }
1706 
1707  texturedata = (D3D_TextureData *)texture->driverdata;
1708  if (!texturedata) {
1709  SDL_SetError("Texture is not currently available");
1710  return -1;
1711  }
1712 
1713  centerx = center->x;
1714  centery = center->y;
1715 
1716  if (flip & SDL_FLIP_HORIZONTAL) {
1717  minx = dstrect->w - centerx - 0.5f;
1718  maxx = -centerx - 0.5f;
1719  }
1720  else {
1721  minx = -centerx - 0.5f;
1722  maxx = dstrect->w - centerx - 0.5f;
1723  }
1724 
1725  if (flip & SDL_FLIP_VERTICAL) {
1726  miny = dstrect->h - centery - 0.5f;
1727  maxy = -centery - 0.5f;
1728  }
1729  else {
1730  miny = -centery - 0.5f;
1731  maxy = dstrect->h - centery - 0.5f;
1732  }
1733 
1734  minu = (float) srcrect->x / texture->w;
1735  maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1736  minv = (float) srcrect->y / texture->h;
1737  maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1738 
1739  color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
1740 
1741  vertices[0].x = minx;
1742  vertices[0].y = miny;
1743  vertices[0].z = 0.0f;
1744  vertices[0].color = color;
1745  vertices[0].u = minu;
1746  vertices[0].v = minv;
1747 
1748  vertices[1].x = maxx;
1749  vertices[1].y = miny;
1750  vertices[1].z = 0.0f;
1751  vertices[1].color = color;
1752  vertices[1].u = maxu;
1753  vertices[1].v = minv;
1754 
1755  vertices[2].x = maxx;
1756  vertices[2].y = maxy;
1757  vertices[2].z = 0.0f;
1758  vertices[2].color = color;
1759  vertices[2].u = maxu;
1760  vertices[2].v = maxv;
1761 
1762  vertices[3].x = minx;
1763  vertices[3].y = maxy;
1764  vertices[3].z = 0.0f;
1765  vertices[3].color = color;
1766  vertices[3].u = minu;
1767  vertices[3].v = maxv;
1768 
1769  D3D_SetBlendMode(data, texture->blendMode);
1770 
1771  /* Rotate and translate */
1772  modelMatrix = MatrixMultiply(
1773  MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
1774  MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
1775 );
1776  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
1777 
1778  D3D_UpdateTextureScaleMode(data, texturedata, 0);
1779 
1780  if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
1781  return -1;
1782  }
1783 
1784  if (texturedata->yuv) {
1785  shader = data->ps_yuv;
1786 
1787  D3D_UpdateTextureScaleMode(data, texturedata, 1);
1788  D3D_UpdateTextureScaleMode(data, texturedata, 2);
1789 
1790  if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
1791  return -1;
1792  }
1793  if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
1794  return -1;
1795  }
1796  }
1797 
1798  if (shader) {
1799  result = IDirect3DDevice9_SetPixelShader(data->device, shader);
1800  if (FAILED(result)) {
1801  return D3D_SetError("SetShader()", result);
1802  }
1803  }
1804  result =
1805  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
1806  vertices, sizeof(*vertices));
1807  if (FAILED(result)) {
1808  return D3D_SetError("DrawPrimitiveUP()", result);
1809  }
1810  if (shader) {
1811  result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
1812  if (FAILED(result)) {
1813  return D3D_SetError("SetShader()", result);
1814  }
1815  }
1816 
1817  modelMatrix = MatrixIdentity();
1818  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
1819  return 0;
1820 }
1821 
1822 static int
1823 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1824  Uint32 format, void * pixels, int pitch)
1825 {
1826  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1827  D3DSURFACE_DESC desc;
1828  LPDIRECT3DSURFACE9 backBuffer;
1829  LPDIRECT3DSURFACE9 surface;
1830  RECT d3drect;
1831  D3DLOCKED_RECT locked;
1832  HRESULT result;
1833 
1834  if (data->currentRenderTarget) {
1835  backBuffer = data->currentRenderTarget;
1836  } else {
1837  backBuffer = data->defaultRenderTarget;
1838  }
1839 
1840  result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
1841  if (FAILED(result)) {
1842  IDirect3DSurface9_Release(backBuffer);
1843  return D3D_SetError("GetDesc()", result);
1844  }
1845 
1846  result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
1847  if (FAILED(result)) {
1848  IDirect3DSurface9_Release(backBuffer);
1849  return D3D_SetError("CreateOffscreenPlainSurface()", result);
1850  }
1851 
1852  result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
1853  if (FAILED(result)) {
1854  IDirect3DSurface9_Release(surface);
1855  IDirect3DSurface9_Release(backBuffer);
1856  return D3D_SetError("GetRenderTargetData()", result);
1857  }
1858 
1859  d3drect.left = rect->x;
1860  d3drect.right = rect->x + rect->w;
1861  d3drect.top = rect->y;
1862  d3drect.bottom = rect->y + rect->h;
1863 
1864  result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
1865  if (FAILED(result)) {
1866  IDirect3DSurface9_Release(surface);
1867  IDirect3DSurface9_Release(backBuffer);
1868  return D3D_SetError("LockRect()", result);
1869  }
1870 
1871  SDL_ConvertPixels(rect->w, rect->h,
1872  D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
1873  format, pixels, pitch);
1874 
1875  IDirect3DSurface9_UnlockRect(surface);
1876 
1877  IDirect3DSurface9_Release(surface);
1878 
1879  return 0;
1880 }
1881 
1882 static void
1883 D3D_RenderPresent(SDL_Renderer * renderer)
1884 {
1885  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1886  HRESULT result;
1887 
1888  if (!data->beginScene) {
1889  IDirect3DDevice9_EndScene(data->device);
1890  data->beginScene = SDL_TRUE;
1891  }
1892 
1893  result = IDirect3DDevice9_TestCooperativeLevel(data->device);
1894  if (result == D3DERR_DEVICELOST) {
1895  /* We'll reset later */
1896  return;
1897  }
1898  if (result == D3DERR_DEVICENOTRESET) {
1899  D3D_Reset(renderer);
1900  }
1901  result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
1902  if (FAILED(result)) {
1903  D3D_SetError("Present()", result);
1904  }
1905 }
1906 
1907 static void
1908 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1909 {
1910  D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
1911 
1912  if (!data) {
1913  return;
1914  }
1915  D3D_DestroyTextureRep(&data->texture);
1916  D3D_DestroyTextureRep(&data->utexture);
1917  D3D_DestroyTextureRep(&data->vtexture);
1918  SDL_free(data->pixels);
1919  SDL_free(data);
1920  texture->driverdata = NULL;
1921 }
1922 
1923 static void
1924 D3D_DestroyRenderer(SDL_Renderer * renderer)
1925 {
1926  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1927 
1928  if (data) {
1929  /* Release the render target */
1930  if (data->defaultRenderTarget) {
1931  IDirect3DSurface9_Release(data->defaultRenderTarget);
1932  data->defaultRenderTarget = NULL;
1933  }
1934  if (data->currentRenderTarget != NULL) {
1935  IDirect3DSurface9_Release(data->currentRenderTarget);
1936  data->currentRenderTarget = NULL;
1937  }
1938  if (data->ps_yuv) {
1939  IDirect3DPixelShader9_Release(data->ps_yuv);
1940  }
1941  if (data->device) {
1942  IDirect3DDevice9_Release(data->device);
1943  }
1944  if (data->d3d) {
1945  IDirect3D9_Release(data->d3d);
1946  SDL_UnloadObject(data->d3dDLL);
1947  }
1948  SDL_free(data);
1949  }
1950  SDL_free(renderer);
1951 }
1952 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
1953 
1954 #ifdef __WIN32__
1955 /* This function needs to always exist on Windows, for the Dynamic API. */
1958 {
1959  IDirect3DDevice9 *device = NULL;
1960 
1961 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
1962  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1963 
1964  /* Make sure that this is a D3D renderer */
1965  if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
1966  SDL_SetError("Renderer is not a D3D renderer");
1967  return NULL;
1968  }
1969 
1970  device = data->device;
1971  if (device) {
1972  IDirect3DDevice9_AddRef(device);
1973  }
1974 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
1975 
1976  return device;
1977 }
1978 #endif /* __WIN32__ */
1979 
1980 /* vi: set ts=4 sw=4 expandtab: */
int(* RenderDrawLines)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
GLuint GLenum matrix
SDL_BlendMode blendMode
Definition: SDL_sysrender.h:57
struct IDirect3D9 IDirect3D9
GLenum GLenum dst
int(* RenderDrawPoints)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2072
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
Definition: SDL_sysrender.h:97
#define SDL_GetWindowDisplayIndex
GLuint GLfloat GLfloat GLfloat x1
GLuint64EXT * result
GLuint sampler
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:155
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
SDL_RendererInfo info
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1564
SDL_Rect rect
Definition: testrelative.c:27
SDL_Window * window
#define SDL_HINT_RENDER_SCALE_QUALITY
A variable controlling the scaling quality.
Definition: SDL_hints.h:131
GLenum GLenum GLuint texture
void * driverdata
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1967
Uint32 texture_formats[16]
Definition: SDL_render.h:83
The structure that defines a display mode.
Definition: SDL_video.h:53
#define SDL_GetHint
#define SDL_GetWindowFlags
SDL_version version
Definition: SDL_syswm.h:183
GLfloat f
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:127
int(* RenderFillRects)(SDL_Renderer *renderer, const SDL_FRect *rects, int count)
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: SDL_opengl.h:1565
SDL_Rect clip_rect
#define SDL_strcasecmp
SDL_Texture * textures
#define SDL_UnloadObject
int max_texture_height
Definition: SDL_render.h:85
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
SDL_Window * window
SDL_RendererInfo info
GLfixed GLfixed x2
int(* RenderClear)(SDL_Renderer *renderer)
void(* DestroyRenderer)(SDL_Renderer *renderer)
GLfixed GLfixed GLint GLint GLfixed points
#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
SDL_bool
Definition: SDL_stdinc.h:126
const GLdouble * v
Definition: SDL_opengl.h:2057
int(* UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
Definition: SDL_sysrender.h:89
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:92
SDL_Renderer * renderer
#define SDL_GetWindowSize
#define FAILED(x)
Definition: SDL_directx.h:54
SDL_Texture * next
Definition: SDL_sysrender.h:72
#define SDL_memcpy
GLsizeiptr const void GLenum usage
void * SDL_calloc(size_t nmemb, size_t size)
#define SDL_GetWindowDisplayMode
SDL_Texture * target
#define FAR
Definition: SDL_directx.h:37
static int GetScaleQuality(void)
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:139
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:324
struct _cl_event * event
SDL_BlendMode blendMode
void SDL_free(void *mem)
#define TRUE
Definition: edid-parse.c:31
#define SDL_PushEvent
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:99
#define SDL_zero(x)
Definition: SDL_stdinc.h:355
int x
Definition: SDL_rect.h:66
int(* SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* UpdateViewport)(SDL_Renderer *renderer)
int w
Definition: SDL_rect.h:67
#define SDL_atoi
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
int(* RenderCopy)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
Window state change event data (event.window.*)
Definition: SDL_events.h:171
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:42
#define SDL_GetWindowWMInfo
Window window
Definition: SDL_syswm.h:204
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
#define SDL_SetError
#define M_PI
Definition: SDL_stdinc.h:436
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)
GLdouble GLdouble z
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
SDL_Rect viewport
#define SDL_strlen
int h
Definition: SDL_rect.h:67
The type used to identify a window.
Definition: SDL_sysvideo.h:71
SDL_Rect rects[MAX_RECTS]
SDL_Rect viewport
Definition: testviewport.c:28
GLuint color
void(* WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event)
Definition: SDL_sysrender.h:80
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
GLbitfield flags
General event structure.
Definition: SDL_events.h:521
#define SDL_malloc
GLubyte GLubyte GLubyte GLubyte w
#define SDL_ConvertPixels
void(* DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:82
void(* RenderPresent)(SDL_Renderer *renderer)
Uint32 format
Definition: SDL_video.h:55
#define SDL_stack_free(data)
Definition: SDL_stdinc.h:325
GLuint GLsizei GLsizei * length
#define FALSE
Definition: edid-parse.c:32
int(* UpdateClipRect)(SDL_Renderer *renderer)
GLenum src
GLenum GLenum void * row
int y
Definition: SDL_rect.h:66
GLfloat GLfloat GLfloat GLfloat h
IDirect3DDevice9 * SDL_RenderGetD3D9Device(SDL_Renderer *renderer)
Returns the D3D device associated with a renderer, or NULL if it&#39;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