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 alpha */
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  D3DPRESENT_PARAMETERS pparams;
516  IDirect3DSwapChain9 *chain;
517  D3DCAPS9 caps;
518  DWORD device_flags;
519  Uint32 window_flags;
520  int w, h;
521  SDL_DisplayMode fullscreen_mode;
522  int displayIndex;
523 
524  renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
525  if (!renderer) {
526  SDL_OutOfMemory();
527  return NULL;
528  }
529 
530  data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
531  if (!data) {
532  SDL_free(renderer);
533  SDL_OutOfMemory();
534  return NULL;
535  }
536 
537  if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
538  SDL_free(renderer);
539  SDL_free(data);
540  SDL_SetError("Unable to create Direct3D interface");
541  return NULL;
542  }
543 
544  renderer->WindowEvent = D3D_WindowEvent;
545  renderer->CreateTexture = D3D_CreateTexture;
546  renderer->UpdateTexture = D3D_UpdateTexture;
547  renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
548  renderer->LockTexture = D3D_LockTexture;
549  renderer->UnlockTexture = D3D_UnlockTexture;
550  renderer->SetRenderTarget = D3D_SetRenderTarget;
551  renderer->UpdateViewport = D3D_UpdateViewport;
552  renderer->UpdateClipRect = D3D_UpdateClipRect;
553  renderer->RenderClear = D3D_RenderClear;
554  renderer->RenderDrawPoints = D3D_RenderDrawPoints;
555  renderer->RenderDrawLines = D3D_RenderDrawLines;
556  renderer->RenderFillRects = D3D_RenderFillRects;
557  renderer->RenderCopy = D3D_RenderCopy;
558  renderer->RenderCopyEx = D3D_RenderCopyEx;
559  renderer->RenderReadPixels = D3D_RenderReadPixels;
560  renderer->RenderPresent = D3D_RenderPresent;
561  renderer->DestroyTexture = D3D_DestroyTexture;
562  renderer->DestroyRenderer = D3D_DestroyRenderer;
563  renderer->info = D3D_RenderDriver.info;
565  renderer->driverdata = data;
566 
567  SDL_VERSION(&windowinfo.version);
568  SDL_GetWindowWMInfo(window, &windowinfo);
569 
570  window_flags = SDL_GetWindowFlags(window);
571  SDL_GetWindowSize(window, &w, &h);
572  SDL_GetWindowDisplayMode(window, &fullscreen_mode);
573 
574  SDL_zero(pparams);
575  pparams.hDeviceWindow = windowinfo.info.win.window;
576  pparams.BackBufferWidth = w;
577  pparams.BackBufferHeight = h;
578  pparams.BackBufferCount = 1;
579  pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
580 
581  if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
582  pparams.Windowed = FALSE;
583  pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
584  pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
585  } else {
586  pparams.Windowed = TRUE;
587  pparams.BackBufferFormat = D3DFMT_UNKNOWN;
588  pparams.FullScreen_RefreshRateInHz = 0;
589  }
590  if (flags & SDL_RENDERER_PRESENTVSYNC) {
591  pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
592  } else {
593  pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
594  }
595 
596  /* Get the adapter for the display that the window is on */
597  displayIndex = SDL_GetWindowDisplayIndex(window);
598  data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
599 
600  IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
601 
602  device_flags = D3DCREATE_FPU_PRESERVE;
603  if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
604  device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
605  } else {
606  device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
607  }
608 
610  device_flags |= D3DCREATE_MULTITHREADED;
611  }
612 
613  result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
614  D3DDEVTYPE_HAL,
615  pparams.hDeviceWindow,
616  device_flags,
617  &pparams, &data->device);
618  if (FAILED(result)) {
619  D3D_DestroyRenderer(renderer);
620  D3D_SetError("CreateDevice()", result);
621  return NULL;
622  }
623 
624  /* Get presentation parameters to fill info */
625  result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
626  if (FAILED(result)) {
627  D3D_DestroyRenderer(renderer);
628  D3D_SetError("GetSwapChain()", result);
629  return NULL;
630  }
631  result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
632  if (FAILED(result)) {
633  IDirect3DSwapChain9_Release(chain);
634  D3D_DestroyRenderer(renderer);
635  D3D_SetError("GetPresentParameters()", result);
636  return NULL;
637  }
638  IDirect3DSwapChain9_Release(chain);
639  if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
640  renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
641  }
642  data->pparams = pparams;
643 
644  IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
645  renderer->info.max_texture_width = caps.MaxTextureWidth;
646  renderer->info.max_texture_height = caps.MaxTextureHeight;
647  if (caps.NumSimultaneousRTs >= 2) {
649  }
650 
651  if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
652  data->enableSeparateAlphaBlend = SDL_TRUE;
653  }
654 
655  /* Store the default render target */
656  IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
657  data->currentRenderTarget = NULL;
658 
659  /* Set up parameters for rendering */
660  D3D_InitRenderState(data);
661 
662  if (caps.MaxSimultaneousTextures >= 3)
663  {
664 #ifdef ASSEMBLE_SHADER
665  /* This shader was created by running the following HLSL through the fxc compiler
666  and then tuning the generated assembly.
667 
668  fxc /T fx_4_0 /O3 /Gfa /Fc yuv.fxc yuv.fx
669 
670  --- yuv.fx ---
671  Texture2D g_txY;
672  Texture2D g_txU;
673  Texture2D g_txV;
674 
675  SamplerState samLinear
676  {
677  Filter = ANISOTROPIC;
678  AddressU = Clamp;
679  AddressV = Clamp;
680  MaxAnisotropy = 1;
681  };
682 
683  struct VS_OUTPUT
684  {
685  float2 TextureUV : TEXCOORD0;
686  };
687 
688  struct PS_OUTPUT
689  {
690  float4 RGBAColor : SV_Target;
691  };
692 
693  PS_OUTPUT YUV420( VS_OUTPUT In )
694  {
695  const float3 offset = {-0.0627451017, -0.501960814, -0.501960814};
696  const float3 Rcoeff = {1.164, 0.000, 1.596};
697  const float3 Gcoeff = {1.164, -0.391, -0.813};
698  const float3 Bcoeff = {1.164, 2.018, 0.000};
699 
700  PS_OUTPUT Output;
701  float2 TextureUV = In.TextureUV;
702 
703  float3 yuv;
704  yuv.x = g_txY.Sample( samLinear, TextureUV ).r;
705  yuv.y = g_txU.Sample( samLinear, TextureUV ).r;
706  yuv.z = g_txV.Sample( samLinear, TextureUV ).r;
707 
708  yuv += offset;
709  Output.RGBAColor.r = dot(yuv, Rcoeff);
710  Output.RGBAColor.g = dot(yuv, Gcoeff);
711  Output.RGBAColor.b = dot(yuv, Bcoeff);
712  Output.RGBAColor.a = 1.0f;
713 
714  return Output;
715  }
716 
717  technique10 RenderYUV420
718  {
719  pass P0
720  {
721  SetPixelShader( CompileShader( ps_4_0_level_9_0, YUV420() ) );
722  }
723  }
724  */
725  const char *shader_text =
726  "ps_2_0\n"
727  "def c0, -0.0627451017, -0.501960814, -0.501960814, 1\n"
728  "def c1, 1.16400003, 0, 1.59599996, 0\n"
729  "def c2, 1.16400003, -0.391000003, -0.813000023, 0\n"
730  "def c3, 1.16400003, 2.01799989, 0, 0\n"
731  "dcl t0.xy\n"
732  "dcl v0.xyzw\n"
733  "dcl_2d s0\n"
734  "dcl_2d s1\n"
735  "dcl_2d s2\n"
736  "texld r0, t0, s0\n"
737  "texld r1, t0, s1\n"
738  "texld r2, t0, s2\n"
739  "mov r0.y, r1.x\n"
740  "mov r0.z, r2.x\n"
741  "add r0.xyz, r0, c0\n"
742  "dp3 r1.x, r0, c1\n"
743  "dp3 r1.y, r0, c2\n"
744  "dp2add r1.z, r0, c3, c3.z\n" /* Logically this is "dp3 r1.z, r0, c3" but the optimizer did its magic */
745  "mov r1.w, c0.w\n"
746  "mul r0, r1, v0\n" /* Not in the HLSL, multiply by vertex color */
747  "mov oC0, r0\n"
748  ;
749  LPD3DXBUFFER pCode;
750  LPD3DXBUFFER pErrorMsgs;
751  LPDWORD shader_data = NULL;
752  DWORD shader_size = 0;
753  result = D3DXAssembleShader(shader_text, SDL_strlen(shader_text), NULL, NULL, 0, &pCode, &pErrorMsgs);
754  if (!FAILED(result)) {
755  shader_data = (DWORD*)pCode->lpVtbl->GetBufferPointer(pCode);
756  shader_size = pCode->lpVtbl->GetBufferSize(pCode);
757  PrintShaderData(shader_data, shader_size);
758  } else {
759  const char *error = (const char *)pErrorMsgs->lpVtbl->GetBufferPointer(pErrorMsgs);
760  SDL_SetError("Couldn't assemble shader: %s", error);
761  }
762 #else
763  const DWORD shader_data[] = {
764  0xffff0200, 0x05000051, 0xa00f0000, 0xbd808081, 0xbf008081, 0xbf008081,
765  0x3f800000, 0x05000051, 0xa00f0001, 0x3f94fdf4, 0x00000000, 0x3fcc49ba,
766  0x00000000, 0x05000051, 0xa00f0002, 0x3f94fdf4, 0xbec83127, 0xbf5020c5,
767  0x00000000, 0x05000051, 0xa00f0003, 0x3f94fdf4, 0x400126e9, 0x00000000,
768  0x00000000, 0x0200001f, 0x80000000, 0xb0030000, 0x0200001f, 0x80000000,
769  0x900f0000, 0x0200001f, 0x90000000, 0xa00f0800, 0x0200001f, 0x90000000,
770  0xa00f0801, 0x0200001f, 0x90000000, 0xa00f0802, 0x03000042, 0x800f0000,
771  0xb0e40000, 0xa0e40800, 0x03000042, 0x800f0001, 0xb0e40000, 0xa0e40801,
772  0x03000042, 0x800f0002, 0xb0e40000, 0xa0e40802, 0x02000001, 0x80020000,
773  0x80000001, 0x02000001, 0x80040000, 0x80000002, 0x03000002, 0x80070000,
774  0x80e40000, 0xa0e40000, 0x03000008, 0x80010001, 0x80e40000, 0xa0e40001,
775  0x03000008, 0x80020001, 0x80e40000, 0xa0e40002, 0x0400005a, 0x80040001,
776  0x80e40000, 0xa0e40003, 0xa0aa0003, 0x02000001, 0x80080001, 0xa0ff0000,
777  0x03000005, 0x800f0000, 0x80e40001, 0x90e40000, 0x02000001, 0x800f0800,
778  0x80e40000, 0x0000ffff
779  };
780 #endif
781  if (shader_data != NULL) {
782  result = IDirect3DDevice9_CreatePixelShader(data->device, shader_data, &data->ps_yuv);
783  if (!FAILED(result)) {
786  } else {
787  D3D_SetError("CreatePixelShader()", result);
788  }
789  }
790  }
791 
792  return renderer;
793 }
794 
795 static void
796 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
797 {
798  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
799 
800  if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
801  data->updateSize = SDL_TRUE;
802  }
803 }
804 
805 static D3DTEXTUREFILTERTYPE
806 GetScaleQuality(void)
807 {
808  const char *hint = SDL_GetHint(SDL_HINT_RENDER_SCALE_QUALITY);
809 
810  if (!hint || *hint == '0' || SDL_strcasecmp(hint, "nearest") == 0) {
811  return D3DTEXF_POINT;
812  } else /* if (*hint == '1' || SDL_strcasecmp(hint, "linear") == 0) */ {
813  return D3DTEXF_LINEAR;
814  }
815 }
816 
817 static int
818 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, int w, int h)
819 {
820  HRESULT result;
821 
822  texture->dirty = SDL_FALSE;
823  texture->w = w;
824  texture->h = h;
825  texture->usage = usage;
826  texture->format = format;
827 
828  result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
829  PixelFormatToD3DFMT(format),
830  D3DPOOL_DEFAULT, &texture->texture, NULL);
831  if (FAILED(result)) {
832  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
833  }
834  return 0;
835 }
836 
837 
838 static int
839 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
840 {
841  HRESULT result;
842 
843  if (texture->staging == NULL) {
844  result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
845  PixelFormatToD3DFMT(texture->format),
846  D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
847  if (FAILED(result)) {
848  return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
849  }
850  }
851  return 0;
852 }
853 
854 static int
855 D3D_BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
856 {
857  HRESULT result;
858 
859  if (texture->dirty && texture->staging) {
860  if (!texture->texture) {
861  result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
862  PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
863  if (FAILED(result)) {
864  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
865  }
866  }
867 
868  result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
869  if (FAILED(result)) {
870  return D3D_SetError("UpdateTexture()", result);
871  }
872  texture->dirty = SDL_FALSE;
873  }
874  result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
875  if (FAILED(result)) {
876  return D3D_SetError("SetTexture()", result);
877  }
878  return 0;
879 }
880 
881 static int
882 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int w, int h)
883 {
884  if (texture->texture) {
885  IDirect3DTexture9_Release(texture->texture);
886  texture->texture = NULL;
887  }
888  if (texture->staging) {
889  IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
890  texture->dirty = SDL_TRUE;
891  }
892  return 0;
893 }
894 
895 static int
896 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, Uint32 format, int x, int y, int w, int h, const void *pixels, int pitch)
897 {
898  RECT d3drect;
899  D3DLOCKED_RECT locked;
900  const Uint8 *src;
901  Uint8 *dst;
902  int row, length;
903  HRESULT result;
904 
905  if (D3D_CreateStagingTexture(device, texture) < 0) {
906  return -1;
907  }
908 
909  d3drect.left = x;
910  d3drect.right = x + w;
911  d3drect.top = y;
912  d3drect.bottom = y + h;
913 
914  result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
915  if (FAILED(result)) {
916  return D3D_SetError("LockRect()", result);
917  }
918 
919  src = (const Uint8 *)pixels;
920  dst = locked.pBits;
921  length = w * SDL_BYTESPERPIXEL(format);
922  if (length == pitch && length == locked.Pitch) {
923  SDL_memcpy(dst, src, length*h);
924  } else {
925  if (length > pitch) {
926  length = pitch;
927  }
928  if (length > locked.Pitch) {
929  length = locked.Pitch;
930  }
931  for (row = 0; row < h; ++row) {
932  SDL_memcpy(dst, src, length);
933  src += pitch;
934  dst += locked.Pitch;
935  }
936  }
937  result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
938  if (FAILED(result)) {
939  return D3D_SetError("UnlockRect()", result);
940  }
941  texture->dirty = SDL_TRUE;
942 
943  return 0;
944 }
945 
946 static void
947 D3D_DestroyTextureRep(D3D_TextureRep *texture)
948 {
949  if (texture->texture) {
950  IDirect3DTexture9_Release(texture->texture);
951  texture->texture = NULL;
952  }
953  if (texture->staging) {
954  IDirect3DTexture9_Release(texture->staging);
955  texture->staging = NULL;
956  }
957 }
958 
959 static int
960 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
961 {
962  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
963  D3D_TextureData *texturedata;
964  DWORD usage;
965 
966  texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
967  if (!texturedata) {
968  return SDL_OutOfMemory();
969  }
970  texturedata->scaleMode = GetScaleQuality();
971 
972  texture->driverdata = texturedata;
973 
974  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
975  usage = D3DUSAGE_RENDERTARGET;
976  } else {
977  usage = 0;
978  }
979 
980  if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, texture->w, texture->h) < 0) {
981  return -1;
982  }
983 
984  if (texture->format == SDL_PIXELFORMAT_YV12 ||
985  texture->format == SDL_PIXELFORMAT_IYUV) {
986  texturedata->yuv = SDL_TRUE;
987 
988  if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
989  return -1;
990  }
991 
992  if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, texture->w / 2, texture->h / 2) < 0) {
993  return -1;
994  }
995  }
996  return 0;
997 }
998 
999 static int
1000 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1001 {
1002  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1003  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1004 
1005  if (!texturedata) {
1006  return 0;
1007  }
1008 
1009  if (D3D_RecreateTextureRep(data->device, &texturedata->texture, texture->format, texture->w, texture->h) < 0) {
1010  return -1;
1011  }
1012 
1013  if (texturedata->yuv) {
1014  if (D3D_RecreateTextureRep(data->device, &texturedata->utexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
1015  return -1;
1016  }
1017 
1018  if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture, texture->format, texture->w / 2, texture->h / 2) < 0) {
1019  return -1;
1020  }
1021  }
1022  return 0;
1023 }
1024 
1025 static int
1026 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1027  const SDL_Rect * rect, const void *pixels, int pitch)
1028 {
1029  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1030  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
1031 
1032  if (!texturedata) {
1033  SDL_SetError("Texture is not currently available");
1034  return -1;
1035  }
1036 
1037  if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
1038  return -1;
1039  }
1040 
1041  if (texturedata->yuv) {
1042  /* Skip to the correct offset into the next texture */
1043  pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
1044 
1045  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) {
1046  return -1;
1047  }
1048 
1049  /* Skip to the correct offset into the next texture */
1050  pixels = (const void*)((const Uint8*)pixels + (rect->h * pitch)/4);
1051  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) {
1052  return -1;
1053  }
1054  }
1055  return 0;
1056 }
1057 
1058 static int
1059 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
1060  const SDL_Rect * rect,
1061  const Uint8 *Yplane, int Ypitch,
1062  const Uint8 *Uplane, int Upitch,
1063  const Uint8 *Vplane, int Vpitch)
1064 {
1065  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1066  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
1067 
1068  if (!texturedata) {
1069  SDL_SetError("Texture is not currently available");
1070  return -1;
1071  }
1072 
1073  if (D3D_UpdateTextureRep(data->device, &texturedata->texture, texture->format, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
1074  return -1;
1075  }
1076  if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
1077  return -1;
1078  }
1079  if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, texture->format, rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
1080  return -1;
1081  }
1082  return 0;
1083 }
1084 
1085 static int
1086 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1087  const SDL_Rect * rect, void **pixels, int *pitch)
1088 {
1089  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
1090  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1091  IDirect3DDevice9 *device = data->device;
1092 
1093  if (!texturedata) {
1094  SDL_SetError("Texture is not currently available");
1095  return -1;
1096  }
1097 
1098  texturedata->locked_rect = *rect;
1099 
1100  if (texturedata->yuv) {
1101  /* It's more efficient to upload directly... */
1102  if (!texturedata->pixels) {
1103  texturedata->pitch = texture->w;
1104  texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
1105  if (!texturedata->pixels) {
1106  return SDL_OutOfMemory();
1107  }
1108  }
1109  *pixels =
1110  (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
1111  rect->x * SDL_BYTESPERPIXEL(texture->format));
1112  *pitch = texturedata->pitch;
1113  } else {
1114  RECT d3drect;
1115  D3DLOCKED_RECT locked;
1116  HRESULT result;
1117 
1118  if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
1119  return -1;
1120  }
1121 
1122  d3drect.left = rect->x;
1123  d3drect.right = rect->x + rect->w;
1124  d3drect.top = rect->y;
1125  d3drect.bottom = rect->y + rect->h;
1126 
1127  result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
1128  if (FAILED(result)) {
1129  return D3D_SetError("LockRect()", result);
1130  }
1131  *pixels = locked.pBits;
1132  *pitch = locked.Pitch;
1133  }
1134  return 0;
1135 }
1136 
1137 static void
1138 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1139 {
1140  /*D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;*/
1141  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1142 
1143  if (!texturedata) {
1144  return;
1145  }
1146 
1147  if (texturedata->yuv) {
1148  const SDL_Rect *rect = &texturedata->locked_rect;
1149  void *pixels =
1150  (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
1151  rect->x * SDL_BYTESPERPIXEL(texture->format));
1152  D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
1153  } else {
1154  IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
1155  texturedata->texture.dirty = SDL_TRUE;
1156  }
1157 }
1158 
1159 static int
1160 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
1161 {
1162  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1163  D3D_TextureData *texturedata;
1164  D3D_TextureRep *texturerep;
1165  HRESULT result;
1166  IDirect3DDevice9 *device = data->device;
1167 
1168  /* Release the previous render target if it wasn't the default one */
1169  if (data->currentRenderTarget != NULL) {
1170  IDirect3DSurface9_Release(data->currentRenderTarget);
1171  data->currentRenderTarget = NULL;
1172  }
1173 
1174  if (texture == NULL) {
1175  IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
1176  return 0;
1177  }
1178 
1179  texturedata = (D3D_TextureData *)texture->driverdata;
1180  if (!texturedata) {
1181  SDL_SetError("Texture is not currently available");
1182  return -1;
1183  }
1184 
1185  /* Make sure the render target is updated if it was locked and written to */
1186  texturerep = &texturedata->texture;
1187  if (texturerep->dirty && texturerep->staging) {
1188  if (!texturerep->texture) {
1189  result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
1190  PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
1191  if (FAILED(result)) {
1192  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
1193  }
1194  }
1195 
1196  result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
1197  if (FAILED(result)) {
1198  return D3D_SetError("UpdateTexture()", result);
1199  }
1200  texturerep->dirty = SDL_FALSE;
1201  }
1202 
1203  result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
1204  if(FAILED(result)) {
1205  return D3D_SetError("GetSurfaceLevel()", result);
1206  }
1207  result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
1208  if(FAILED(result)) {
1209  return D3D_SetError("SetRenderTarget()", result);
1210  }
1211 
1212  return 0;
1213 }
1214 
1215 static int
1216 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
1217 {
1218  D3D_ActivateRenderer(renderer);
1219 
1220  return D3D_SetRenderTargetInternal(renderer, texture);
1221 }
1222 
1223 static int
1224 D3D_UpdateViewport(SDL_Renderer * renderer)
1225 {
1226  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1227  D3DVIEWPORT9 viewport;
1228  D3DMATRIX matrix;
1229 
1230  /* Set the viewport */
1231  viewport.X = renderer->viewport.x;
1232  viewport.Y = renderer->viewport.y;
1233  viewport.Width = renderer->viewport.w;
1234  viewport.Height = renderer->viewport.h;
1235  viewport.MinZ = 0.0f;
1236  viewport.MaxZ = 1.0f;
1237  IDirect3DDevice9_SetViewport(data->device, &viewport);
1238 
1239  /* Set an orthographic projection matrix */
1240  if (renderer->viewport.w && renderer->viewport.h) {
1241  matrix.m[0][0] = 2.0f / renderer->viewport.w;
1242  matrix.m[0][1] = 0.0f;
1243  matrix.m[0][2] = 0.0f;
1244  matrix.m[0][3] = 0.0f;
1245  matrix.m[1][0] = 0.0f;
1246  matrix.m[1][1] = -2.0f / renderer->viewport.h;
1247  matrix.m[1][2] = 0.0f;
1248  matrix.m[1][3] = 0.0f;
1249  matrix.m[2][0] = 0.0f;
1250  matrix.m[2][1] = 0.0f;
1251  matrix.m[2][2] = 1.0f;
1252  matrix.m[2][3] = 0.0f;
1253  matrix.m[3][0] = -1.0f;
1254  matrix.m[3][1] = 1.0f;
1255  matrix.m[3][2] = 0.0f;
1256  matrix.m[3][3] = 1.0f;
1257  IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &matrix);
1258  }
1259 
1260  return 0;
1261 }
1262 
1263 static int
1264 D3D_UpdateClipRect(SDL_Renderer * renderer)
1265 {
1266  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1267 
1268  if (renderer->clipping_enabled) {
1269  const SDL_Rect *rect = &renderer->clip_rect;
1270  RECT r;
1271  HRESULT result;
1272 
1273  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
1274  r.left = renderer->viewport.x + rect->x;
1275  r.top = renderer->viewport.y + rect->y;
1276  r.right = renderer->viewport.x + rect->x + rect->w;
1277  r.bottom = renderer->viewport.y + rect->y + rect->h;
1278 
1279  result = IDirect3DDevice9_SetScissorRect(data->device, &r);
1280  if (result != D3D_OK) {
1281  D3D_SetError("SetScissor()", result);
1282  return -1;
1283  }
1284  } else {
1285  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
1286  }
1287  return 0;
1288 }
1289 
1290 static int
1291 D3D_RenderClear(SDL_Renderer * renderer)
1292 {
1293  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1294  DWORD color;
1295  HRESULT result;
1296  int BackBufferWidth, BackBufferHeight;
1297 
1298  if (D3D_ActivateRenderer(renderer) < 0) {
1299  return -1;
1300  }
1301 
1302  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1303 
1304  if (renderer->target) {
1305  BackBufferWidth = renderer->target->w;
1306  BackBufferHeight = renderer->target->h;
1307  } else {
1308  BackBufferWidth = data->pparams.BackBufferWidth;
1309  BackBufferHeight = data->pparams.BackBufferHeight;
1310  }
1311 
1312  if (renderer->clipping_enabled) {
1313  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
1314  }
1315 
1316  /* Don't reset the viewport if we don't have to! */
1317  if (!renderer->viewport.x && !renderer->viewport.y &&
1318  renderer->viewport.w == BackBufferWidth &&
1319  renderer->viewport.h == BackBufferHeight) {
1320  result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
1321  } else {
1322  D3DVIEWPORT9 viewport;
1323 
1324  /* Clear is defined to clear the entire render target */
1325  viewport.X = 0;
1326  viewport.Y = 0;
1327  viewport.Width = BackBufferWidth;
1328  viewport.Height = BackBufferHeight;
1329  viewport.MinZ = 0.0f;
1330  viewport.MaxZ = 1.0f;
1331  IDirect3DDevice9_SetViewport(data->device, &viewport);
1332 
1333  result = IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
1334 
1335  /* Reset the viewport */
1336  viewport.X = renderer->viewport.x;
1337  viewport.Y = renderer->viewport.y;
1338  viewport.Width = renderer->viewport.w;
1339  viewport.Height = renderer->viewport.h;
1340  viewport.MinZ = 0.0f;
1341  viewport.MaxZ = 1.0f;
1342  IDirect3DDevice9_SetViewport(data->device, &viewport);
1343  }
1344 
1345  if (renderer->clipping_enabled) {
1346  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, TRUE);
1347  }
1348 
1349  if (FAILED(result)) {
1350  return D3D_SetError("Clear()", result);
1351  }
1352  return 0;
1353 }
1354 
1355 static void
1356 D3D_SetBlendMode(D3D_RenderData * data, int blendMode)
1357 {
1358  switch (blendMode) {
1359  case SDL_BLENDMODE_NONE:
1360  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1361  FALSE);
1362  break;
1363  case SDL_BLENDMODE_BLEND:
1364  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1365  TRUE);
1366  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1367  D3DBLEND_SRCALPHA);
1368  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1369  D3DBLEND_INVSRCALPHA);
1370  if (data->enableSeparateAlphaBlend) {
1371  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1372  D3DBLEND_ONE);
1373  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1374  D3DBLEND_INVSRCALPHA);
1375  }
1376  break;
1377  case SDL_BLENDMODE_ADD:
1378  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1379  TRUE);
1380  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1381  D3DBLEND_SRCALPHA);
1382  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1383  D3DBLEND_ONE);
1384  if (data->enableSeparateAlphaBlend) {
1385  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1386  D3DBLEND_ZERO);
1387  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1388  D3DBLEND_ONE);
1389  }
1390  break;
1391  case SDL_BLENDMODE_MOD:
1392  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE,
1393  TRUE);
1394  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1395  D3DBLEND_ZERO);
1396  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1397  D3DBLEND_SRCCOLOR);
1398  if (data->enableSeparateAlphaBlend) {
1399  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1400  D3DBLEND_ZERO);
1401  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1402  D3DBLEND_ONE);
1403  }
1404  break;
1405  }
1406 }
1407 
1408 static int
1409 D3D_RenderDrawPoints(SDL_Renderer * renderer, const SDL_FPoint * points,
1410  int count)
1411 {
1412  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1413  DWORD color;
1414  Vertex *vertices;
1415  int i;
1416  HRESULT result;
1417 
1418  if (D3D_ActivateRenderer(renderer) < 0) {
1419  return -1;
1420  }
1421 
1422  D3D_SetBlendMode(data, renderer->blendMode);
1423 
1424  result =
1425  IDirect3DDevice9_SetTexture(data->device, 0,
1426  (IDirect3DBaseTexture9 *) 0);
1427  if (FAILED(result)) {
1428  return D3D_SetError("SetTexture()", result);
1429  }
1430 
1431  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1432 
1433  vertices = SDL_stack_alloc(Vertex, count);
1434  for (i = 0; i < count; ++i) {
1435  vertices[i].x = points[i].x;
1436  vertices[i].y = points[i].y;
1437  vertices[i].z = 0.0f;
1438  vertices[i].color = color;
1439  vertices[i].u = 0.0f;
1440  vertices[i].v = 0.0f;
1441  }
1442  result =
1443  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, count,
1444  vertices, sizeof(*vertices));
1445  SDL_stack_free(vertices);
1446  if (FAILED(result)) {
1447  return D3D_SetError("DrawPrimitiveUP()", result);
1448  }
1449  return 0;
1450 }
1451 
1452 static int
1453 D3D_RenderDrawLines(SDL_Renderer * renderer, const SDL_FPoint * points,
1454  int count)
1455 {
1456  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1457  DWORD color;
1458  Vertex *vertices;
1459  int i;
1460  HRESULT result;
1461 
1462  if (D3D_ActivateRenderer(renderer) < 0) {
1463  return -1;
1464  }
1465 
1466  D3D_SetBlendMode(data, renderer->blendMode);
1467 
1468  result =
1469  IDirect3DDevice9_SetTexture(data->device, 0,
1470  (IDirect3DBaseTexture9 *) 0);
1471  if (FAILED(result)) {
1472  return D3D_SetError("SetTexture()", result);
1473  }
1474 
1475  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1476 
1477  vertices = SDL_stack_alloc(Vertex, count);
1478  for (i = 0; i < count; ++i) {
1479  vertices[i].x = points[i].x;
1480  vertices[i].y = points[i].y;
1481  vertices[i].z = 0.0f;
1482  vertices[i].color = color;
1483  vertices[i].u = 0.0f;
1484  vertices[i].v = 0.0f;
1485  }
1486  result =
1487  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, count-1,
1488  vertices, sizeof(*vertices));
1489 
1490  /* DirectX 9 has the same line rasterization semantics as GDI,
1491  so we need to close the endpoint of the line */
1492  if (count == 2 ||
1493  points[0].x != points[count-1].x || points[0].y != points[count-1].y) {
1494  vertices[0].x = points[count-1].x;
1495  vertices[0].y = points[count-1].y;
1496  result = IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, vertices, sizeof(*vertices));
1497  }
1498 
1499  SDL_stack_free(vertices);
1500  if (FAILED(result)) {
1501  return D3D_SetError("DrawPrimitiveUP()", result);
1502  }
1503  return 0;
1504 }
1505 
1506 static int
1507 D3D_RenderFillRects(SDL_Renderer * renderer, const SDL_FRect * rects,
1508  int count)
1509 {
1510  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1511  DWORD color;
1512  int i;
1513  float minx, miny, maxx, maxy;
1514  Vertex vertices[4];
1515  HRESULT result;
1516 
1517  if (D3D_ActivateRenderer(renderer) < 0) {
1518  return -1;
1519  }
1520 
1521  D3D_SetBlendMode(data, renderer->blendMode);
1522 
1523  result =
1524  IDirect3DDevice9_SetTexture(data->device, 0,
1525  (IDirect3DBaseTexture9 *) 0);
1526  if (FAILED(result)) {
1527  return D3D_SetError("SetTexture()", result);
1528  }
1529 
1530  color = D3DCOLOR_ARGB(renderer->a, renderer->r, renderer->g, renderer->b);
1531 
1532  for (i = 0; i < count; ++i) {
1533  const SDL_FRect *rect = &rects[i];
1534 
1535  minx = rect->x;
1536  miny = rect->y;
1537  maxx = rect->x + rect->w;
1538  maxy = rect->y + rect->h;
1539 
1540  vertices[0].x = minx;
1541  vertices[0].y = miny;
1542  vertices[0].z = 0.0f;
1543  vertices[0].color = color;
1544  vertices[0].u = 0.0f;
1545  vertices[0].v = 0.0f;
1546 
1547  vertices[1].x = maxx;
1548  vertices[1].y = miny;
1549  vertices[1].z = 0.0f;
1550  vertices[1].color = color;
1551  vertices[1].u = 0.0f;
1552  vertices[1].v = 0.0f;
1553 
1554  vertices[2].x = maxx;
1555  vertices[2].y = maxy;
1556  vertices[2].z = 0.0f;
1557  vertices[2].color = color;
1558  vertices[2].u = 0.0f;
1559  vertices[2].v = 0.0f;
1560 
1561  vertices[3].x = minx;
1562  vertices[3].y = maxy;
1563  vertices[3].z = 0.0f;
1564  vertices[3].color = color;
1565  vertices[3].u = 0.0f;
1566  vertices[3].v = 0.0f;
1567 
1568  result =
1569  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN,
1570  2, vertices, sizeof(*vertices));
1571  if (FAILED(result)) {
1572  return D3D_SetError("DrawPrimitiveUP()", result);
1573  }
1574  }
1575  return 0;
1576 }
1577 
1578 static void
1579 D3D_UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
1580 {
1581  if (texturedata->scaleMode != data->scaleMode[index]) {
1582  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
1583  texturedata->scaleMode);
1584  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
1585  texturedata->scaleMode);
1586  data->scaleMode[index] = texturedata->scaleMode;
1587  }
1588 }
1589 
1590 static int
1591 D3D_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
1592  const SDL_Rect * srcrect, const SDL_FRect * dstrect)
1593 {
1594  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1595  D3D_TextureData *texturedata;
1596  LPDIRECT3DPIXELSHADER9 shader = NULL;
1597  float minx, miny, maxx, maxy;
1598  float minu, maxu, minv, maxv;
1599  DWORD color;
1600  Vertex vertices[4];
1601  HRESULT result;
1602 
1603  if (D3D_ActivateRenderer(renderer) < 0) {
1604  return -1;
1605  }
1606 
1607  texturedata = (D3D_TextureData *)texture->driverdata;
1608  if (!texturedata) {
1609  SDL_SetError("Texture is not currently available");
1610  return -1;
1611  }
1612 
1613  minx = dstrect->x - 0.5f;
1614  miny = dstrect->y - 0.5f;
1615  maxx = dstrect->x + dstrect->w - 0.5f;
1616  maxy = dstrect->y + dstrect->h - 0.5f;
1617 
1618  minu = (float) srcrect->x / texture->w;
1619  maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1620  minv = (float) srcrect->y / texture->h;
1621  maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1622 
1623  color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
1624 
1625  vertices[0].x = minx;
1626  vertices[0].y = miny;
1627  vertices[0].z = 0.0f;
1628  vertices[0].color = color;
1629  vertices[0].u = minu;
1630  vertices[0].v = minv;
1631 
1632  vertices[1].x = maxx;
1633  vertices[1].y = miny;
1634  vertices[1].z = 0.0f;
1635  vertices[1].color = color;
1636  vertices[1].u = maxu;
1637  vertices[1].v = minv;
1638 
1639  vertices[2].x = maxx;
1640  vertices[2].y = maxy;
1641  vertices[2].z = 0.0f;
1642  vertices[2].color = color;
1643  vertices[2].u = maxu;
1644  vertices[2].v = maxv;
1645 
1646  vertices[3].x = minx;
1647  vertices[3].y = maxy;
1648  vertices[3].z = 0.0f;
1649  vertices[3].color = color;
1650  vertices[3].u = minu;
1651  vertices[3].v = maxv;
1652 
1653  D3D_SetBlendMode(data, texture->blendMode);
1654 
1655  D3D_UpdateTextureScaleMode(data, texturedata, 0);
1656 
1657  if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
1658  return -1;
1659  }
1660 
1661  if (texturedata->yuv) {
1662  shader = data->ps_yuv;
1663 
1664  D3D_UpdateTextureScaleMode(data, texturedata, 1);
1665  D3D_UpdateTextureScaleMode(data, texturedata, 2);
1666 
1667  if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
1668  return -1;
1669  }
1670  if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
1671  return -1;
1672  }
1673  }
1674 
1675  if (shader) {
1676  result = IDirect3DDevice9_SetPixelShader(data->device, shader);
1677  if (FAILED(result)) {
1678  return D3D_SetError("SetShader()", result);
1679  }
1680  }
1681  result =
1682  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
1683  vertices, sizeof(*vertices));
1684  if (FAILED(result)) {
1685  return D3D_SetError("DrawPrimitiveUP()", result);
1686  }
1687  if (shader) {
1688  result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
1689  if (FAILED(result)) {
1690  return D3D_SetError("SetShader()", result);
1691  }
1692  }
1693  return 0;
1694 }
1695 
1696 
1697 static int
1698 D3D_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
1699  const SDL_Rect * srcrect, const SDL_FRect * dstrect,
1700  const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip)
1701 {
1702  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1703  D3D_TextureData *texturedata;
1704  LPDIRECT3DPIXELSHADER9 shader = NULL;
1705  float minx, miny, maxx, maxy;
1706  float minu, maxu, minv, maxv;
1707  float centerx, centery;
1708  DWORD color;
1709  Vertex vertices[4];
1710  Float4X4 modelMatrix;
1711  HRESULT result;
1712 
1713  if (D3D_ActivateRenderer(renderer) < 0) {
1714  return -1;
1715  }
1716 
1717  texturedata = (D3D_TextureData *)texture->driverdata;
1718  if (!texturedata) {
1719  SDL_SetError("Texture is not currently available");
1720  return -1;
1721  }
1722 
1723  centerx = center->x;
1724  centery = center->y;
1725 
1726  if (flip & SDL_FLIP_HORIZONTAL) {
1727  minx = dstrect->w - centerx - 0.5f;
1728  maxx = -centerx - 0.5f;
1729  }
1730  else {
1731  minx = -centerx - 0.5f;
1732  maxx = dstrect->w - centerx - 0.5f;
1733  }
1734 
1735  if (flip & SDL_FLIP_VERTICAL) {
1736  miny = dstrect->h - centery - 0.5f;
1737  maxy = -centery - 0.5f;
1738  }
1739  else {
1740  miny = -centery - 0.5f;
1741  maxy = dstrect->h - centery - 0.5f;
1742  }
1743 
1744  minu = (float) srcrect->x / texture->w;
1745  maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1746  minv = (float) srcrect->y / texture->h;
1747  maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1748 
1749  color = D3DCOLOR_ARGB(texture->a, texture->r, texture->g, texture->b);
1750 
1751  vertices[0].x = minx;
1752  vertices[0].y = miny;
1753  vertices[0].z = 0.0f;
1754  vertices[0].color = color;
1755  vertices[0].u = minu;
1756  vertices[0].v = minv;
1757 
1758  vertices[1].x = maxx;
1759  vertices[1].y = miny;
1760  vertices[1].z = 0.0f;
1761  vertices[1].color = color;
1762  vertices[1].u = maxu;
1763  vertices[1].v = minv;
1764 
1765  vertices[2].x = maxx;
1766  vertices[2].y = maxy;
1767  vertices[2].z = 0.0f;
1768  vertices[2].color = color;
1769  vertices[2].u = maxu;
1770  vertices[2].v = maxv;
1771 
1772  vertices[3].x = minx;
1773  vertices[3].y = maxy;
1774  vertices[3].z = 0.0f;
1775  vertices[3].color = color;
1776  vertices[3].u = minu;
1777  vertices[3].v = maxv;
1778 
1779  D3D_SetBlendMode(data, texture->blendMode);
1780 
1781  /* Rotate and translate */
1782  modelMatrix = MatrixMultiply(
1783  MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)),
1784  MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0)
1785 );
1786  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
1787 
1788  D3D_UpdateTextureScaleMode(data, texturedata, 0);
1789 
1790  if (D3D_BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
1791  return -1;
1792  }
1793 
1794  if (texturedata->yuv) {
1795  shader = data->ps_yuv;
1796 
1797  D3D_UpdateTextureScaleMode(data, texturedata, 1);
1798  D3D_UpdateTextureScaleMode(data, texturedata, 2);
1799 
1800  if (D3D_BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
1801  return -1;
1802  }
1803  if (D3D_BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
1804  return -1;
1805  }
1806  }
1807 
1808  if (shader) {
1809  result = IDirect3DDevice9_SetPixelShader(data->device, shader);
1810  if (FAILED(result)) {
1811  return D3D_SetError("SetShader()", result);
1812  }
1813  }
1814  result =
1815  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2,
1816  vertices, sizeof(*vertices));
1817  if (FAILED(result)) {
1818  return D3D_SetError("DrawPrimitiveUP()", result);
1819  }
1820  if (shader) {
1821  result = IDirect3DDevice9_SetPixelShader(data->device, NULL);
1822  if (FAILED(result)) {
1823  return D3D_SetError("SetShader()", result);
1824  }
1825  }
1826 
1827  modelMatrix = MatrixIdentity();
1828  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&modelMatrix);
1829  return 0;
1830 }
1831 
1832 static int
1833 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1834  Uint32 format, void * pixels, int pitch)
1835 {
1836  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1837  D3DSURFACE_DESC desc;
1838  LPDIRECT3DSURFACE9 backBuffer;
1839  LPDIRECT3DSURFACE9 surface;
1840  RECT d3drect;
1841  D3DLOCKED_RECT locked;
1842  HRESULT result;
1843 
1844  if (data->currentRenderTarget) {
1845  backBuffer = data->currentRenderTarget;
1846  } else {
1847  backBuffer = data->defaultRenderTarget;
1848  }
1849 
1850  result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
1851  if (FAILED(result)) {
1852  IDirect3DSurface9_Release(backBuffer);
1853  return D3D_SetError("GetDesc()", result);
1854  }
1855 
1856  result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
1857  if (FAILED(result)) {
1858  IDirect3DSurface9_Release(backBuffer);
1859  return D3D_SetError("CreateOffscreenPlainSurface()", result);
1860  }
1861 
1862  result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
1863  if (FAILED(result)) {
1864  IDirect3DSurface9_Release(surface);
1865  IDirect3DSurface9_Release(backBuffer);
1866  return D3D_SetError("GetRenderTargetData()", result);
1867  }
1868 
1869  d3drect.left = rect->x;
1870  d3drect.right = rect->x + rect->w;
1871  d3drect.top = rect->y;
1872  d3drect.bottom = rect->y + rect->h;
1873 
1874  result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
1875  if (FAILED(result)) {
1876  IDirect3DSurface9_Release(surface);
1877  IDirect3DSurface9_Release(backBuffer);
1878  return D3D_SetError("LockRect()", result);
1879  }
1880 
1881  SDL_ConvertPixels(rect->w, rect->h,
1882  D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
1883  format, pixels, pitch);
1884 
1885  IDirect3DSurface9_UnlockRect(surface);
1886 
1887  IDirect3DSurface9_Release(surface);
1888 
1889  return 0;
1890 }
1891 
1892 static void
1893 D3D_RenderPresent(SDL_Renderer * renderer)
1894 {
1895  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1896  HRESULT result;
1897 
1898  if (!data->beginScene) {
1899  IDirect3DDevice9_EndScene(data->device);
1900  data->beginScene = SDL_TRUE;
1901  }
1902 
1903  result = IDirect3DDevice9_TestCooperativeLevel(data->device);
1904  if (result == D3DERR_DEVICELOST) {
1905  /* We'll reset later */
1906  return;
1907  }
1908  if (result == D3DERR_DEVICENOTRESET) {
1909  D3D_Reset(renderer);
1910  }
1911  result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
1912  if (FAILED(result)) {
1913  D3D_SetError("Present()", result);
1914  }
1915 }
1916 
1917 static void
1918 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1919 {
1920  D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
1921 
1922  if (!data) {
1923  return;
1924  }
1925  D3D_DestroyTextureRep(&data->texture);
1926  D3D_DestroyTextureRep(&data->utexture);
1927  D3D_DestroyTextureRep(&data->vtexture);
1928  SDL_free(data->pixels);
1929  SDL_free(data);
1930  texture->driverdata = NULL;
1931 }
1932 
1933 static void
1934 D3D_DestroyRenderer(SDL_Renderer * renderer)
1935 {
1936  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1937 
1938  if (data) {
1939  /* Release the render target */
1940  if (data->defaultRenderTarget) {
1941  IDirect3DSurface9_Release(data->defaultRenderTarget);
1942  data->defaultRenderTarget = NULL;
1943  }
1944  if (data->currentRenderTarget != NULL) {
1945  IDirect3DSurface9_Release(data->currentRenderTarget);
1946  data->currentRenderTarget = NULL;
1947  }
1948  if (data->ps_yuv) {
1949  IDirect3DPixelShader9_Release(data->ps_yuv);
1950  }
1951  if (data->device) {
1952  IDirect3DDevice9_Release(data->device);
1953  }
1954  if (data->d3d) {
1955  IDirect3D9_Release(data->d3d);
1956  SDL_UnloadObject(data->d3dDLL);
1957  }
1958  SDL_free(data);
1959  }
1960  SDL_free(renderer);
1961 }
1962 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
1963 
1964 #ifdef __WIN32__
1965 /* This function needs to always exist on Windows, for the Dynamic API. */
1968 {
1969  IDirect3DDevice9 *device = NULL;
1970 
1971 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
1972  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1973 
1974  /* Make sure that this is a D3D renderer */
1975  if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
1976  SDL_SetError("Renderer is not a D3D renderer");
1977  return NULL;
1978  }
1979 
1980  device = data->device;
1981  if (device) {
1982  IDirect3DDevice9_AddRef(device);
1983  }
1984 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
1985 
1986  return device;
1987 }
1988 #endif /* __WIN32__ */
1989 
1990 /* 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
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1565
int(* RenderDrawPoints)(SDL_Renderer *renderer, const SDL_FPoint *points, int count)
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
GLdouble GLdouble GLdouble r
Definition: SDL_opengl.h:2072
GLuint64EXT * result
GLuint sampler
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
SDL_RendererInfo info
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1567
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1564
SDL_Rect rect
Definition: testrelative.c:27
#define SDL_HINT_RENDER_SCALE_QUALITY
A variable controlling the scaling quality.
Definition: SDL_hints.h:131
static SDL_Window * window
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:195
GLfloat f
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:128
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
uint32_t Uint32
An unsigned 32-bit integer type.
Definition: SDL_stdinc.h:161
#define SDL_strcasecmp
SDL_Texture * textures
#define SDL_UnloadObject
int max_texture_height
Definition: SDL_render.h:85
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_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
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
#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
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1567
SDL_Texture * target
#define FAR
Definition: SDL_directx.h:37
static int GetScaleQuality(void)
static SDL_Renderer * renderer
uint8_t Uint8
An unsigned 8-bit integer type.
Definition: SDL_stdinc.h:143
#define SDL_stack_alloc(type, count)
Definition: SDL_stdinc.h:330
struct _cl_event * event
SDL_BlendMode blendMode
void SDL_free(void *mem)
#define TRUE
Definition: edid-parse.c:33
#define SDL_PushEvent
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
Definition: SDL_sysrender.h:99
#define SDL_zero(x)
Definition: SDL_stdinc.h:361
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
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
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
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:174
#define SDL_GetWindowWMInfo
Window window
Definition: SDL_syswm.h:216
#define NULL
Definition: begin_code.h:143
#define SDL_OutOfMemory()
Definition: SDL_error.h:52
SDL_bool
Definition: SDL_stdinc.h:130
GLdouble GLdouble z
#define SDL_SetError
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)
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:525
#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:331
GLuint GLsizei GLsizei * length
#define FALSE
Definition: edid-parse.c:34
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