SDL  2.0
SDL_render_d3d.c
Go to the documentation of this file.
1 /*
2  Simple DirectMedia Layer
3  Copyright (C) 1997-2020 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 #include "SDL_shaders_d3d.h"
43 
44 typedef struct
45 {
47  SDL_bool viewport_dirty;
49  SDL_BlendMode blend;
50  SDL_bool cliprect_enabled;
51  SDL_bool cliprect_enabled_dirty;
52  SDL_Rect cliprect;
53  SDL_bool cliprect_dirty;
54  SDL_bool is_copy_ex;
55  LPDIRECT3DPIXELSHADER9 shader;
56 } D3D_DrawStateCache;
57 
58 
59 /* Direct3D renderer implementation */
60 
61 typedef struct
62 {
63  void* d3dDLL;
64  IDirect3D9 *d3d;
66  UINT adapter;
67  D3DPRESENT_PARAMETERS pparams;
68  SDL_bool updateSize;
69  SDL_bool beginScene;
70  SDL_bool enableSeparateAlphaBlend;
71  D3DTEXTUREFILTERTYPE scaleMode[8];
72  IDirect3DSurface9 *defaultRenderTarget;
73  IDirect3DSurface9 *currentRenderTarget;
74  void* d3dxDLL;
75  LPDIRECT3DPIXELSHADER9 shaders[NUM_SHADERS];
76  LPDIRECT3DVERTEXBUFFER9 vertexBuffers[8];
77  size_t vertexBufferSize[8];
78  int currentVertexBuffer;
79  SDL_bool reportedVboProblem;
80  D3D_DrawStateCache drawstate;
81 } D3D_RenderData;
82 
83 typedef struct
84 {
85  SDL_bool dirty;
86  int w, h;
87  DWORD usage;
88  Uint32 format;
89  D3DFORMAT d3dfmt;
90  IDirect3DTexture9 *texture;
91  IDirect3DTexture9 *staging;
92 } D3D_TextureRep;
93 
94 typedef struct
95 {
96  D3D_TextureRep texture;
97  D3DTEXTUREFILTERTYPE scaleMode;
98 
99  /* YV12 texture support */
100  SDL_bool yuv;
101  D3D_TextureRep utexture;
102  D3D_TextureRep vtexture;
103  Uint8 *pixels;
104  int pitch;
105  SDL_Rect locked_rect;
106 } D3D_TextureData;
107 
108 typedef struct
109 {
110  float x, y, z;
111  DWORD color;
112  float u, v;
113 } Vertex;
114 
115 static int
116 D3D_SetError(const char *prefix, HRESULT result)
117 {
118  const char *error;
119 
120  switch (result) {
121  case D3DERR_WRONGTEXTUREFORMAT:
122  error = "WRONGTEXTUREFORMAT";
123  break;
124  case D3DERR_UNSUPPORTEDCOLOROPERATION:
125  error = "UNSUPPORTEDCOLOROPERATION";
126  break;
127  case D3DERR_UNSUPPORTEDCOLORARG:
128  error = "UNSUPPORTEDCOLORARG";
129  break;
130  case D3DERR_UNSUPPORTEDALPHAOPERATION:
131  error = "UNSUPPORTEDALPHAOPERATION";
132  break;
133  case D3DERR_UNSUPPORTEDALPHAARG:
134  error = "UNSUPPORTEDALPHAARG";
135  break;
136  case D3DERR_TOOMANYOPERATIONS:
137  error = "TOOMANYOPERATIONS";
138  break;
139  case D3DERR_CONFLICTINGTEXTUREFILTER:
140  error = "CONFLICTINGTEXTUREFILTER";
141  break;
142  case D3DERR_UNSUPPORTEDFACTORVALUE:
143  error = "UNSUPPORTEDFACTORVALUE";
144  break;
145  case D3DERR_CONFLICTINGRENDERSTATE:
146  error = "CONFLICTINGRENDERSTATE";
147  break;
148  case D3DERR_UNSUPPORTEDTEXTUREFILTER:
149  error = "UNSUPPORTEDTEXTUREFILTER";
150  break;
151  case D3DERR_CONFLICTINGTEXTUREPALETTE:
152  error = "CONFLICTINGTEXTUREPALETTE";
153  break;
154  case D3DERR_DRIVERINTERNALERROR:
155  error = "DRIVERINTERNALERROR";
156  break;
157  case D3DERR_NOTFOUND:
158  error = "NOTFOUND";
159  break;
160  case D3DERR_MOREDATA:
161  error = "MOREDATA";
162  break;
163  case D3DERR_DEVICELOST:
164  error = "DEVICELOST";
165  break;
166  case D3DERR_DEVICENOTRESET:
167  error = "DEVICENOTRESET";
168  break;
169  case D3DERR_NOTAVAILABLE:
170  error = "NOTAVAILABLE";
171  break;
172  case D3DERR_OUTOFVIDEOMEMORY:
173  error = "OUTOFVIDEOMEMORY";
174  break;
175  case D3DERR_INVALIDDEVICE:
176  error = "INVALIDDEVICE";
177  break;
178  case D3DERR_INVALIDCALL:
179  error = "INVALIDCALL";
180  break;
181  case D3DERR_DRIVERINVALIDCALL:
182  error = "DRIVERINVALIDCALL";
183  break;
184  case D3DERR_WASSTILLDRAWING:
185  error = "WASSTILLDRAWING";
186  break;
187  default:
188  error = "UNKNOWN";
189  break;
190  }
191  return SDL_SetError("%s: %s", prefix, error);
192 }
193 
194 static D3DFORMAT
195 PixelFormatToD3DFMT(Uint32 format)
196 {
197  switch (format) {
199  return D3DFMT_R5G6B5;
201  return D3DFMT_X8R8G8B8;
203  return D3DFMT_A8R8G8B8;
208  return D3DFMT_L8;
209  default:
210  return D3DFMT_UNKNOWN;
211  }
212 }
213 
214 static Uint32
215 D3DFMTToPixelFormat(D3DFORMAT format)
216 {
217  switch (format) {
218  case D3DFMT_R5G6B5:
219  return SDL_PIXELFORMAT_RGB565;
220  case D3DFMT_X8R8G8B8:
221  return SDL_PIXELFORMAT_RGB888;
222  case D3DFMT_A8R8G8B8:
224  default:
226  }
227 }
228 
229 static void
230 D3D_InitRenderState(D3D_RenderData *data)
231 {
232  D3DMATRIX matrix;
233 
234  IDirect3DDevice9 *device = data->device;
235  IDirect3DDevice9_SetPixelShader(device, NULL);
236  IDirect3DDevice9_SetTexture(device, 0, NULL);
237  IDirect3DDevice9_SetTexture(device, 1, NULL);
238  IDirect3DDevice9_SetTexture(device, 2, NULL);
239  IDirect3DDevice9_SetFVF(device, D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1);
240  IDirect3DDevice9_SetVertexShader(device, NULL);
241  IDirect3DDevice9_SetRenderState(device, D3DRS_ZENABLE, D3DZB_FALSE);
242  IDirect3DDevice9_SetRenderState(device, D3DRS_CULLMODE, D3DCULL_NONE);
243  IDirect3DDevice9_SetRenderState(device, D3DRS_LIGHTING, FALSE);
244 
245  /* Enable color modulation by diffuse color */
246  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLOROP,
247  D3DTOP_MODULATE);
248  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG1,
249  D3DTA_TEXTURE);
250  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_COLORARG2,
251  D3DTA_DIFFUSE);
252 
253  /* Enable alpha modulation by diffuse alpha */
254  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAOP,
255  D3DTOP_MODULATE);
256  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG1,
257  D3DTA_TEXTURE);
258  IDirect3DDevice9_SetTextureStageState(device, 0, D3DTSS_ALPHAARG2,
259  D3DTA_DIFFUSE);
260 
261  /* Enable separate alpha blend function, if possible */
262  if (data->enableSeparateAlphaBlend) {
263  IDirect3DDevice9_SetRenderState(device, D3DRS_SEPARATEALPHABLENDENABLE, TRUE);
264  }
265 
266  /* Disable second texture stage, since we're done */
267  IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_COLOROP,
268  D3DTOP_DISABLE);
269  IDirect3DDevice9_SetTextureStageState(device, 1, D3DTSS_ALPHAOP,
270  D3DTOP_DISABLE);
271 
272  /* Set an identity world and view matrix */
273  SDL_zero(matrix);
274  matrix.m[0][0] = 1.0f;
275  matrix.m[1][1] = 1.0f;
276  matrix.m[2][2] = 1.0f;
277  matrix.m[3][3] = 1.0f;
278  IDirect3DDevice9_SetTransform(device, D3DTS_WORLD, &matrix);
279  IDirect3DDevice9_SetTransform(device, D3DTS_VIEW, &matrix);
280 
281  /* Reset our current scale mode */
282  SDL_memset(data->scaleMode, 0xFF, sizeof(data->scaleMode));
283 
284  /* Start the render with beginScene */
285  data->beginScene = SDL_TRUE;
286 }
287 
288 static int D3D_Reset(SDL_Renderer * renderer);
289 
290 static int
291 D3D_ActivateRenderer(SDL_Renderer * renderer)
292 {
293  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
294  HRESULT result;
295 
296  if (data->updateSize) {
298  int w, h;
299  Uint32 window_flags = SDL_GetWindowFlags(window);
300 
302  data->pparams.BackBufferWidth = w;
303  data->pparams.BackBufferHeight = h;
304  if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
305  SDL_DisplayMode fullscreen_mode;
306  SDL_GetWindowDisplayMode(window, &fullscreen_mode);
307  data->pparams.Windowed = FALSE;
308  data->pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
309  data->pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
310  } else {
311  data->pparams.Windowed = TRUE;
312  data->pparams.BackBufferFormat = D3DFMT_UNKNOWN;
313  data->pparams.FullScreen_RefreshRateInHz = 0;
314  }
315  if (D3D_Reset(renderer) < 0) {
316  return -1;
317  }
318 
319  data->updateSize = SDL_FALSE;
320  }
321  if (data->beginScene) {
322  result = IDirect3DDevice9_BeginScene(data->device);
323  if (result == D3DERR_DEVICELOST) {
324  if (D3D_Reset(renderer) < 0) {
325  return -1;
326  }
327  result = IDirect3DDevice9_BeginScene(data->device);
328  }
329  if (FAILED(result)) {
330  return D3D_SetError("BeginScene()", result);
331  }
332  data->beginScene = SDL_FALSE;
333  }
334  return 0;
335 }
336 
337 static void
338 D3D_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
339 {
340  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
341 
343  data->updateSize = SDL_TRUE;
344  }
345 }
346 
347 static D3DBLEND GetBlendFunc(SDL_BlendFactor factor)
348 {
349  switch (factor) {
351  return D3DBLEND_ZERO;
352  case SDL_BLENDFACTOR_ONE:
353  return D3DBLEND_ONE;
355  return D3DBLEND_SRCCOLOR;
357  return D3DBLEND_INVSRCCOLOR;
359  return D3DBLEND_SRCALPHA;
361  return D3DBLEND_INVSRCALPHA;
363  return D3DBLEND_DESTCOLOR;
365  return D3DBLEND_INVDESTCOLOR;
367  return D3DBLEND_DESTALPHA;
369  return D3DBLEND_INVDESTALPHA;
370  default:
371  return (D3DBLEND)0;
372  }
373 }
374 
375 static SDL_bool
376 D3D_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
377 {
378  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
385 
386  if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
387  !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor)) {
388  return SDL_FALSE;
389  }
390  if ((srcColorFactor != srcAlphaFactor || dstColorFactor != dstAlphaFactor) && !data->enableSeparateAlphaBlend) {
391  return SDL_FALSE;
392  }
393  if (colorOperation != SDL_BLENDOPERATION_ADD || alphaOperation != SDL_BLENDOPERATION_ADD) {
394  return SDL_FALSE;
395  }
396  return SDL_TRUE;
397 }
398 
399 static int
400 D3D_CreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD usage, Uint32 format, D3DFORMAT d3dfmt, int w, int h)
401 {
402  HRESULT result;
403 
404  texture->dirty = SDL_FALSE;
405  texture->w = w;
406  texture->h = h;
407  texture->usage = usage;
408  texture->format = format;
409  texture->d3dfmt = d3dfmt;
410 
411  result = IDirect3DDevice9_CreateTexture(device, w, h, 1, usage,
412  PixelFormatToD3DFMT(format),
413  D3DPOOL_DEFAULT, &texture->texture, NULL);
414  if (FAILED(result)) {
415  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
416  }
417  return 0;
418 }
419 
420 
421 static int
422 D3D_CreateStagingTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
423 {
424  HRESULT result;
425 
426  if (texture->staging == NULL) {
427  result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, 0,
428  texture->d3dfmt, D3DPOOL_SYSTEMMEM, &texture->staging, NULL);
429  if (FAILED(result)) {
430  return D3D_SetError("CreateTexture(D3DPOOL_SYSTEMMEM)", result);
431  }
432  }
433  return 0;
434 }
435 
436 static int
437 D3D_RecreateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture)
438 {
439  if (texture->texture) {
440  IDirect3DTexture9_Release(texture->texture);
441  texture->texture = NULL;
442  }
443  if (texture->staging) {
444  IDirect3DTexture9_AddDirtyRect(texture->staging, NULL);
445  texture->dirty = SDL_TRUE;
446  }
447  return 0;
448 }
449 
450 static int
451 D3D_UpdateTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, int x, int y, int w, int h, const void *pixels, int pitch)
452 {
453  RECT d3drect;
454  D3DLOCKED_RECT locked;
455  const Uint8 *src;
456  Uint8 *dst;
457  int row, length;
458  HRESULT result;
459 
460  if (D3D_CreateStagingTexture(device, texture) < 0) {
461  return -1;
462  }
463 
464  d3drect.left = x;
465  d3drect.right = x + w;
466  d3drect.top = y;
467  d3drect.bottom = y + h;
468 
469  result = IDirect3DTexture9_LockRect(texture->staging, 0, &locked, &d3drect, 0);
470  if (FAILED(result)) {
471  return D3D_SetError("LockRect()", result);
472  }
473 
474  src = (const Uint8 *)pixels;
475  dst = (Uint8 *)locked.pBits;
476  length = w * SDL_BYTESPERPIXEL(texture->format);
477  if (length == pitch && length == locked.Pitch) {
479  } else {
480  if (length > pitch) {
481  length = pitch;
482  }
483  if (length > locked.Pitch) {
484  length = locked.Pitch;
485  }
486  for (row = 0; row < h; ++row) {
488  src += pitch;
489  dst += locked.Pitch;
490  }
491  }
492  result = IDirect3DTexture9_UnlockRect(texture->staging, 0);
493  if (FAILED(result)) {
494  return D3D_SetError("UnlockRect()", result);
495  }
496  texture->dirty = SDL_TRUE;
497 
498  return 0;
499 }
500 
501 static void
502 D3D_DestroyTextureRep(D3D_TextureRep *texture)
503 {
504  if (texture->texture) {
505  IDirect3DTexture9_Release(texture->texture);
506  texture->texture = NULL;
507  }
508  if (texture->staging) {
509  IDirect3DTexture9_Release(texture->staging);
510  texture->staging = NULL;
511  }
512 }
513 
514 static int
515 D3D_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
516 {
517  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
518  D3D_TextureData *texturedata;
519  DWORD usage;
520 
521  texturedata = (D3D_TextureData *) SDL_calloc(1, sizeof(*texturedata));
522  if (!texturedata) {
523  return SDL_OutOfMemory();
524  }
525  texturedata->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
526 
527  texture->driverdata = texturedata;
528 
529  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
530  usage = D3DUSAGE_RENDERTARGET;
531  } else {
532  usage = 0;
533  }
534 
535  if (D3D_CreateTextureRep(data->device, &texturedata->texture, usage, texture->format, PixelFormatToD3DFMT(texture->format), texture->w, texture->h) < 0) {
536  return -1;
537  }
538 
539  if (texture->format == SDL_PIXELFORMAT_YV12 ||
540  texture->format == SDL_PIXELFORMAT_IYUV) {
541  texturedata->yuv = SDL_TRUE;
542 
543  if (D3D_CreateTextureRep(data->device, &texturedata->utexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
544  return -1;
545  }
546 
547  if (D3D_CreateTextureRep(data->device, &texturedata->vtexture, usage, texture->format, PixelFormatToD3DFMT(texture->format), (texture->w + 1) / 2, (texture->h + 1) / 2) < 0) {
548  return -1;
549  }
550  }
551  return 0;
552 }
553 
554 static int
555 D3D_RecreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
556 {
557  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
558  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
559 
560  if (!texturedata) {
561  return 0;
562  }
563 
564  if (D3D_RecreateTextureRep(data->device, &texturedata->texture) < 0) {
565  return -1;
566  }
567 
568  if (texturedata->yuv) {
569  if (D3D_RecreateTextureRep(data->device, &texturedata->utexture) < 0) {
570  return -1;
571  }
572 
573  if (D3D_RecreateTextureRep(data->device, &texturedata->vtexture) < 0) {
574  return -1;
575  }
576  }
577  return 0;
578 }
579 
580 static int
581 D3D_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
582  const SDL_Rect * rect, const void *pixels, int pitch)
583 {
584  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
585  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
586 
587  if (!texturedata) {
588  SDL_SetError("Texture is not currently available");
589  return -1;
590  }
591 
592  if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, pixels, pitch) < 0) {
593  return -1;
594  }
595 
596  if (texturedata->yuv) {
597  /* Skip to the correct offset into the next texture */
598  pixels = (const void*)((const Uint8*)pixels + rect->h * pitch);
599 
600  if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->vtexture : &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) {
601  return -1;
602  }
603 
604  /* Skip to the correct offset into the next texture */
605  pixels = (const void*)((const Uint8*)pixels + ((rect->h + 1) / 2) * ((pitch + 1) / 2));
606  if (D3D_UpdateTextureRep(data->device, texture->format == SDL_PIXELFORMAT_YV12 ? &texturedata->utexture : &texturedata->vtexture, rect->x / 2, (rect->y + 1) / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, pixels, (pitch + 1) / 2) < 0) {
607  return -1;
608  }
609  }
610  return 0;
611 }
612 
613 static int
614 D3D_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
615  const SDL_Rect * rect,
616  const Uint8 *Yplane, int Ypitch,
617  const Uint8 *Uplane, int Upitch,
618  const Uint8 *Vplane, int Vpitch)
619 {
620  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
621  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
622 
623  if (!texturedata) {
624  SDL_SetError("Texture is not currently available");
625  return -1;
626  }
627 
628  if (D3D_UpdateTextureRep(data->device, &texturedata->texture, rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
629  return -1;
630  }
631  if (D3D_UpdateTextureRep(data->device, &texturedata->utexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Uplane, Upitch) < 0) {
632  return -1;
633  }
634  if (D3D_UpdateTextureRep(data->device, &texturedata->vtexture, rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, Vplane, Vpitch) < 0) {
635  return -1;
636  }
637  return 0;
638 }
639 
640 static int
641 D3D_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
642  const SDL_Rect * rect, void **pixels, int *pitch)
643 {
644  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
645  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
646  IDirect3DDevice9 *device = data->device;
647 
648  if (!texturedata) {
649  SDL_SetError("Texture is not currently available");
650  return -1;
651  }
652 
653  texturedata->locked_rect = *rect;
654 
655  if (texturedata->yuv) {
656  /* It's more efficient to upload directly... */
657  if (!texturedata->pixels) {
658  texturedata->pitch = texture->w;
659  texturedata->pixels = (Uint8 *)SDL_malloc((texture->h * texturedata->pitch * 3) / 2);
660  if (!texturedata->pixels) {
661  return SDL_OutOfMemory();
662  }
663  }
664  *pixels =
665  (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
666  rect->x * SDL_BYTESPERPIXEL(texture->format));
667  *pitch = texturedata->pitch;
668  } else {
669  RECT d3drect;
670  D3DLOCKED_RECT locked;
671  HRESULT result;
672 
673  if (D3D_CreateStagingTexture(device, &texturedata->texture) < 0) {
674  return -1;
675  }
676 
677  d3drect.left = rect->x;
678  d3drect.right = rect->x + rect->w;
679  d3drect.top = rect->y;
680  d3drect.bottom = rect->y + rect->h;
681 
682  result = IDirect3DTexture9_LockRect(texturedata->texture.staging, 0, &locked, &d3drect, 0);
683  if (FAILED(result)) {
684  return D3D_SetError("LockRect()", result);
685  }
686  *pixels = locked.pBits;
687  *pitch = locked.Pitch;
688  }
689  return 0;
690 }
691 
692 static void
693 D3D_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
694 {
695  D3D_RenderData *data = (D3D_RenderData *)renderer->driverdata;
696  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
697 
698  if (!texturedata) {
699  return;
700  }
701 
702  if (texturedata->yuv) {
703  const SDL_Rect *rect = &texturedata->locked_rect;
704  void *pixels =
705  (void *) ((Uint8 *) texturedata->pixels + rect->y * texturedata->pitch +
706  rect->x * SDL_BYTESPERPIXEL(texture->format));
707  D3D_UpdateTexture(renderer, texture, rect, pixels, texturedata->pitch);
708  } else {
709  IDirect3DTexture9_UnlockRect(texturedata->texture.staging, 0);
710  texturedata->texture.dirty = SDL_TRUE;
711  if (data->drawstate.texture == texture) {
712  data->drawstate.texture = NULL;
713  data->drawstate.shader = NULL;
714  IDirect3DDevice9_SetPixelShader(data->device, NULL);
715  IDirect3DDevice9_SetTexture(data->device, 0, NULL);
716  if (texturedata->yuv) {
717  IDirect3DDevice9_SetTexture(data->device, 1, NULL);
718  IDirect3DDevice9_SetTexture(data->device, 2, NULL);
719  }
720  }
721  }
722 }
723 
724 static void
725 D3D_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
726 {
727  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
728 
729  if (!texturedata) {
730  return;
731  }
732 
733  texturedata->scaleMode = (scaleMode == SDL_ScaleModeNearest) ? D3DTEXF_POINT : D3DTEXF_LINEAR;
734 }
735 
736 static int
737 D3D_SetRenderTargetInternal(SDL_Renderer * renderer, SDL_Texture * texture)
738 {
739  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
740  D3D_TextureData *texturedata;
741  D3D_TextureRep *texturerep;
742  HRESULT result;
743  IDirect3DDevice9 *device = data->device;
744 
745  /* Release the previous render target if it wasn't the default one */
746  if (data->currentRenderTarget != NULL) {
747  IDirect3DSurface9_Release(data->currentRenderTarget);
748  data->currentRenderTarget = NULL;
749  }
750 
751  if (texture == NULL) {
752  IDirect3DDevice9_SetRenderTarget(data->device, 0, data->defaultRenderTarget);
753  return 0;
754  }
755 
756  texturedata = (D3D_TextureData *)texture->driverdata;
757  if (!texturedata) {
758  SDL_SetError("Texture is not currently available");
759  return -1;
760  }
761 
762  /* Make sure the render target is updated if it was locked and written to */
763  texturerep = &texturedata->texture;
764  if (texturerep->dirty && texturerep->staging) {
765  if (!texturerep->texture) {
766  result = IDirect3DDevice9_CreateTexture(device, texturerep->w, texturerep->h, 1, texturerep->usage,
767  PixelFormatToD3DFMT(texturerep->format), D3DPOOL_DEFAULT, &texturerep->texture, NULL);
768  if (FAILED(result)) {
769  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
770  }
771  }
772 
773  result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texturerep->staging, (IDirect3DBaseTexture9 *)texturerep->texture);
774  if (FAILED(result)) {
775  return D3D_SetError("UpdateTexture()", result);
776  }
777  texturerep->dirty = SDL_FALSE;
778  }
779 
780  result = IDirect3DTexture9_GetSurfaceLevel(texturedata->texture.texture, 0, &data->currentRenderTarget);
781  if(FAILED(result)) {
782  return D3D_SetError("GetSurfaceLevel()", result);
783  }
784  result = IDirect3DDevice9_SetRenderTarget(data->device, 0, data->currentRenderTarget);
785  if(FAILED(result)) {
786  return D3D_SetError("SetRenderTarget()", result);
787  }
788 
789  return 0;
790 }
791 
792 static int
793 D3D_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
794 {
795  if (D3D_ActivateRenderer(renderer) < 0) {
796  return -1;
797  }
798 
799  return D3D_SetRenderTargetInternal(renderer, texture);
800 }
801 
802 
803 static int
804 D3D_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
805 {
806  return 0; /* nothing to do in this backend. */
807 }
808 
809 static int
810 D3D_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
811 {
812  const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
813  const size_t vertslen = count * sizeof (Vertex);
814  Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
815  int i;
816 
817  if (!verts) {
818  return -1;
819  }
820 
821  SDL_memset(verts, '\0', vertslen);
822  cmd->data.draw.count = count;
823 
824  for (i = 0; i < count; i++, verts++, points++) {
825  verts->x = points->x;
826  verts->y = points->y;
827  verts->color = color;
828  }
829 
830  return 0;
831 }
832 
833 static int
834 D3D_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
835 {
836  const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
837  const size_t vertslen = count * sizeof (Vertex) * 4;
838  Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
839  int i;
840 
841  if (!verts) {
842  return -1;
843  }
844 
845  SDL_memset(verts, '\0', vertslen);
846  cmd->data.draw.count = count;
847 
848  for (i = 0; i < count; i++) {
849  const SDL_FRect *rect = &rects[i];
850  const float minx = rect->x;
851  const float maxx = rect->x + rect->w;
852  const float miny = rect->y;
853  const float maxy = rect->y + rect->h;
854 
855  verts->x = minx;
856  verts->y = miny;
857  verts->color = color;
858  verts++;
859 
860  verts->x = maxx;
861  verts->y = miny;
862  verts->color = color;
863  verts++;
864 
865  verts->x = maxx;
866  verts->y = maxy;
867  verts->color = color;
868  verts++;
869 
870  verts->x = minx;
871  verts->y = maxy;
872  verts->color = color;
873  verts++;
874  }
875 
876  return 0;
877 }
878 
879 static int
881  const SDL_Rect * srcrect, const SDL_FRect * dstrect)
882 {
883  const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
884  float minx, miny, maxx, maxy;
885  float minu, maxu, minv, maxv;
886  const size_t vertslen = sizeof (Vertex) * 4;
887  Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
888 
889  if (!verts) {
890  return -1;
891  }
892 
893  cmd->data.draw.count = 1;
894 
895  minx = dstrect->x - 0.5f;
896  miny = dstrect->y - 0.5f;
897  maxx = dstrect->x + dstrect->w - 0.5f;
898  maxy = dstrect->y + dstrect->h - 0.5f;
899 
900  minu = (float) srcrect->x / texture->w;
901  maxu = (float) (srcrect->x + srcrect->w) / texture->w;
902  minv = (float) srcrect->y / texture->h;
903  maxv = (float) (srcrect->y + srcrect->h) / texture->h;
904 
905  verts->x = minx;
906  verts->y = miny;
907  verts->z = 0.0f;
908  verts->color = color;
909  verts->u = minu;
910  verts->v = minv;
911  verts++;
912 
913  verts->x = maxx;
914  verts->y = miny;
915  verts->z = 0.0f;
916  verts->color = color;
917  verts->u = maxu;
918  verts->v = minv;
919  verts++;
920 
921  verts->x = maxx;
922  verts->y = maxy;
923  verts->z = 0.0f;
924  verts->color = color;
925  verts->u = maxu;
926  verts->v = maxv;
927  verts++;
928 
929  verts->x = minx;
930  verts->y = maxy;
931  verts->z = 0.0f;
932  verts->color = color;
933  verts->u = minu;
934  verts->v = maxv;
935  verts++;
936 
937  return 0;
938 }
939 
940 static int
941 D3D_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
942  const SDL_Rect * srcquad, const SDL_FRect * dstrect,
943  const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
944 {
945  const DWORD color = D3DCOLOR_ARGB(cmd->data.draw.a, cmd->data.draw.r, cmd->data.draw.g, cmd->data.draw.b);
946  float minx, miny, maxx, maxy;
947  float minu, maxu, minv, maxv;
948  const size_t vertslen = sizeof (Vertex) * 5;
949  Vertex *verts = (Vertex *) SDL_AllocateRenderVertices(renderer, vertslen, 0, &cmd->data.draw.first);
950 
951  if (!verts) {
952  return -1;
953  }
954 
955  cmd->data.draw.count = 1;
956 
957  minx = -center->x;
958  maxx = dstrect->w - center->x;
959  miny = -center->y;
960  maxy = dstrect->h - center->y;
961 
962  if (flip & SDL_FLIP_HORIZONTAL) {
963  minu = (float) (srcquad->x + srcquad->w) / texture->w;
964  maxu = (float) srcquad->x / texture->w;
965  } else {
966  minu = (float) srcquad->x / texture->w;
967  maxu = (float) (srcquad->x + srcquad->w) / texture->w;
968  }
969 
970  if (flip & SDL_FLIP_VERTICAL) {
971  minv = (float) (srcquad->y + srcquad->h) / texture->h;
972  maxv = (float) srcquad->y / texture->h;
973  } else {
974  minv = (float) srcquad->y / texture->h;
975  maxv = (float) (srcquad->y + srcquad->h) / texture->h;
976  }
977 
978  verts->x = minx;
979  verts->y = miny;
980  verts->z = 0.0f;
981  verts->color = color;
982  verts->u = minu;
983  verts->v = minv;
984  verts++;
985 
986  verts->x = maxx;
987  verts->y = miny;
988  verts->z = 0.0f;
989  verts->color = color;
990  verts->u = maxu;
991  verts->v = minv;
992  verts++;
993 
994  verts->x = maxx;
995  verts->y = maxy;
996  verts->z = 0.0f;
997  verts->color = color;
998  verts->u = maxu;
999  verts->v = maxv;
1000  verts++;
1001 
1002  verts->x = minx;
1003  verts->y = maxy;
1004  verts->z = 0.0f;
1005  verts->color = color;
1006  verts->u = minu;
1007  verts->v = maxv;
1008  verts++;
1009 
1010  verts->x = dstrect->x + center->x - 0.5f; /* X translation */
1011  verts->y = dstrect->y + center->y - 0.5f; /* Y translation */
1012  verts->z = (float)(M_PI * (float) angle / 180.0f); /* rotation */
1013  verts->color = 0;
1014  verts->u = 0.0f;
1015  verts->v = 0.0f;
1016  verts++;
1017 
1018  return 0;
1019 }
1020 
1021 static int
1022 UpdateDirtyTexture(IDirect3DDevice9 *device, D3D_TextureRep *texture)
1023 {
1024  if (texture->dirty && texture->staging) {
1025  HRESULT result;
1026  if (!texture->texture) {
1027  result = IDirect3DDevice9_CreateTexture(device, texture->w, texture->h, 1, texture->usage,
1028  PixelFormatToD3DFMT(texture->format), D3DPOOL_DEFAULT, &texture->texture, NULL);
1029  if (FAILED(result)) {
1030  return D3D_SetError("CreateTexture(D3DPOOL_DEFAULT)", result);
1031  }
1032  }
1033 
1034  result = IDirect3DDevice9_UpdateTexture(device, (IDirect3DBaseTexture9 *)texture->staging, (IDirect3DBaseTexture9 *)texture->texture);
1035  if (FAILED(result)) {
1036  return D3D_SetError("UpdateTexture()", result);
1037  }
1038  texture->dirty = SDL_FALSE;
1039  }
1040  return 0;
1041 }
1042 
1043 static int
1044 BindTextureRep(IDirect3DDevice9 *device, D3D_TextureRep *texture, DWORD sampler)
1045 {
1046  HRESULT result;
1047  UpdateDirtyTexture(device, texture);
1048  result = IDirect3DDevice9_SetTexture(device, sampler, (IDirect3DBaseTexture9 *)texture->texture);
1049  if (FAILED(result)) {
1050  return D3D_SetError("SetTexture()", result);
1051  }
1052  return 0;
1053 }
1054 
1055 static void
1056 UpdateTextureScaleMode(D3D_RenderData *data, D3D_TextureData *texturedata, unsigned index)
1057 {
1058  if (texturedata->scaleMode != data->scaleMode[index]) {
1059  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MINFILTER,
1060  texturedata->scaleMode);
1061  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_MAGFILTER,
1062  texturedata->scaleMode);
1063  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSU,
1064  D3DTADDRESS_CLAMP);
1065  IDirect3DDevice9_SetSamplerState(data->device, index, D3DSAMP_ADDRESSV,
1066  D3DTADDRESS_CLAMP);
1067  data->scaleMode[index] = texturedata->scaleMode;
1068  }
1069 }
1070 
1071 static int
1072 SetupTextureState(D3D_RenderData *data, SDL_Texture * texture, LPDIRECT3DPIXELSHADER9 *shader)
1073 {
1074  D3D_TextureData *texturedata = (D3D_TextureData *)texture->driverdata;
1075 
1076  SDL_assert(*shader == NULL);
1077 
1078  if (!texturedata) {
1079  SDL_SetError("Texture is not currently available");
1080  return -1;
1081  }
1082 
1083  UpdateTextureScaleMode(data, texturedata, 0);
1084 
1085  if (BindTextureRep(data->device, &texturedata->texture, 0) < 0) {
1086  return -1;
1087  }
1088 
1089  if (texturedata->yuv) {
1092  *shader = data->shaders[SHADER_YUV_JPEG];
1093  break;
1095  *shader = data->shaders[SHADER_YUV_BT601];
1096  break;
1098  *shader = data->shaders[SHADER_YUV_BT709];
1099  break;
1100  default:
1101  return SDL_SetError("Unsupported YUV conversion mode");
1102  }
1103 
1104  UpdateTextureScaleMode(data, texturedata, 1);
1105  UpdateTextureScaleMode(data, texturedata, 2);
1106 
1107  if (BindTextureRep(data->device, &texturedata->utexture, 1) < 0) {
1108  return -1;
1109  }
1110  if (BindTextureRep(data->device, &texturedata->vtexture, 2) < 0) {
1111  return -1;
1112  }
1113  }
1114  return 0;
1115 }
1116 
1117 static int
1118 SetDrawState(D3D_RenderData *data, const SDL_RenderCommand *cmd)
1119 {
1120  const SDL_bool was_copy_ex = data->drawstate.is_copy_ex;
1121  const SDL_bool is_copy_ex = (cmd->command == SDL_RENDERCMD_COPY_EX);
1122  SDL_Texture *texture = cmd->data.draw.texture;
1123  const SDL_BlendMode blend = cmd->data.draw.blend;
1124 
1125  if (texture != data->drawstate.texture) {
1126  D3D_TextureData *oldtexturedata = data->drawstate.texture ? (D3D_TextureData *) data->drawstate.texture->driverdata : NULL;
1127  D3D_TextureData *newtexturedata = texture ? (D3D_TextureData *) texture->driverdata : NULL;
1128  LPDIRECT3DPIXELSHADER9 shader = NULL;
1129 
1130  /* disable any enabled textures we aren't going to use, let SetupTextureState() do the rest. */
1131  if (texture == NULL) {
1132  IDirect3DDevice9_SetTexture(data->device, 0, NULL);
1133  }
1134  if ((!newtexturedata || !newtexturedata->yuv) && (oldtexturedata && oldtexturedata->yuv)) {
1135  IDirect3DDevice9_SetTexture(data->device, 1, NULL);
1136  IDirect3DDevice9_SetTexture(data->device, 2, NULL);
1137  }
1138  if (texture && SetupTextureState(data, texture, &shader) < 0) {
1139  return -1;
1140  }
1141 
1142  if (shader != data->drawstate.shader) {
1143  const HRESULT result = IDirect3DDevice9_SetPixelShader(data->device, shader);
1144  if (FAILED(result)) {
1145  return D3D_SetError("IDirect3DDevice9_SetPixelShader()", result);
1146  }
1147  data->drawstate.shader = shader;
1148  }
1149 
1150  data->drawstate.texture = texture;
1151  } else if (texture) {
1152  D3D_TextureData *texturedata = (D3D_TextureData *) texture->driverdata;
1153  UpdateDirtyTexture(data->device, &texturedata->texture);
1154  if (texturedata->yuv) {
1155  UpdateDirtyTexture(data->device, &texturedata->utexture);
1156  UpdateDirtyTexture(data->device, &texturedata->vtexture);
1157  }
1158  }
1159 
1160  if (blend != data->drawstate.blend) {
1161  if (blend == SDL_BLENDMODE_NONE) {
1162  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, FALSE);
1163  } else {
1164  IDirect3DDevice9_SetRenderState(data->device, D3DRS_ALPHABLENDENABLE, TRUE);
1165  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLEND,
1166  GetBlendFunc(SDL_GetBlendModeSrcColorFactor(blend)));
1167  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLEND,
1168  GetBlendFunc(SDL_GetBlendModeDstColorFactor(blend)));
1169  if (data->enableSeparateAlphaBlend) {
1170  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SRCBLENDALPHA,
1171  GetBlendFunc(SDL_GetBlendModeSrcAlphaFactor(blend)));
1172  IDirect3DDevice9_SetRenderState(data->device, D3DRS_DESTBLENDALPHA,
1173  GetBlendFunc(SDL_GetBlendModeDstAlphaFactor(blend)));
1174  }
1175  }
1176 
1177  data->drawstate.blend = blend;
1178  }
1179 
1180  if (is_copy_ex != was_copy_ex) {
1181  if (!is_copy_ex) { /* SDL_RENDERCMD_COPY_EX will set this, we only want to reset it here if necessary. */
1182  const Float4X4 d3dmatrix = MatrixIdentity();
1183  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*) &d3dmatrix);
1184  }
1185  data->drawstate.is_copy_ex = is_copy_ex;
1186  }
1187 
1188  if (data->drawstate.viewport_dirty) {
1189  const SDL_Rect *viewport = &data->drawstate.viewport;
1190  const D3DVIEWPORT9 d3dviewport = { viewport->x, viewport->y, viewport->w, viewport->h, 0.0f, 1.0f };
1191  IDirect3DDevice9_SetViewport(data->device, &d3dviewport);
1192 
1193  /* Set an orthographic projection matrix */
1194  if (viewport->w && viewport->h) {
1195  D3DMATRIX d3dmatrix;
1196  SDL_zero(d3dmatrix);
1197  d3dmatrix.m[0][0] = 2.0f / viewport->w;
1198  d3dmatrix.m[1][1] = -2.0f / viewport->h;
1199  d3dmatrix.m[2][2] = 1.0f;
1200  d3dmatrix.m[3][0] = -1.0f;
1201  d3dmatrix.m[3][1] = 1.0f;
1202  d3dmatrix.m[3][3] = 1.0f;
1203  IDirect3DDevice9_SetTransform(data->device, D3DTS_PROJECTION, &d3dmatrix);
1204  }
1205 
1206  data->drawstate.viewport_dirty = SDL_FALSE;
1207  }
1208 
1209  if (data->drawstate.cliprect_enabled_dirty) {
1210  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, data->drawstate.cliprect_enabled ? TRUE : FALSE);
1211  data->drawstate.cliprect_enabled_dirty = SDL_FALSE;
1212  }
1213 
1214  if (data->drawstate.cliprect_dirty) {
1215  const SDL_Rect *viewport = &data->drawstate.viewport;
1216  const SDL_Rect *rect = &data->drawstate.cliprect;
1217  const RECT d3drect = { viewport->x + rect->x, viewport->y + rect->y, viewport->x + rect->x + rect->w, viewport->y + rect->y + rect->h };
1218  IDirect3DDevice9_SetScissorRect(data->device, &d3drect);
1219  data->drawstate.cliprect_dirty = SDL_FALSE;
1220  }
1221 
1222  return 0;
1223 }
1224 
1225 static int
1226 D3D_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
1227 {
1228  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1229  const int vboidx = data->currentVertexBuffer;
1230  IDirect3DVertexBuffer9 *vbo = NULL;
1231  const SDL_bool istarget = renderer->target != NULL;
1232  size_t i;
1233 
1234  if (D3D_ActivateRenderer(renderer) < 0) {
1235  return -1;
1236  }
1237 
1238  /* upload the new VBO data for this set of commands. */
1239  vbo = data->vertexBuffers[vboidx];
1240  if (data->vertexBufferSize[vboidx] < vertsize) {
1241  const DWORD usage = D3DUSAGE_DYNAMIC | D3DUSAGE_WRITEONLY;
1242  const DWORD fvf = D3DFVF_XYZ | D3DFVF_DIFFUSE | D3DFVF_TEX1;
1243  if (vbo) {
1244  IDirect3DVertexBuffer9_Release(vbo);
1245  }
1246 
1247  if (FAILED(IDirect3DDevice9_CreateVertexBuffer(data->device, (UINT) vertsize, usage, fvf, D3DPOOL_DEFAULT, &vbo, NULL))) {
1248  vbo = NULL;
1249  }
1250  data->vertexBuffers[vboidx] = vbo;
1251  data->vertexBufferSize[vboidx] = vbo ? vertsize : 0;
1252  }
1253 
1254  if (vbo) {
1255  void *ptr;
1256  if (FAILED(IDirect3DVertexBuffer9_Lock(vbo, 0, (UINT) vertsize, &ptr, D3DLOCK_DISCARD))) {
1257  vbo = NULL; /* oh well, we'll do immediate mode drawing. :( */
1258  } else {
1259  SDL_memcpy(ptr, vertices, vertsize);
1260  if (FAILED(IDirect3DVertexBuffer9_Unlock(vbo))) {
1261  vbo = NULL; /* oh well, we'll do immediate mode drawing. :( */
1262  }
1263  }
1264  }
1265 
1266  /* cycle through a few VBOs so D3D has some time with the data before we replace it. */
1267  if (vbo) {
1268  data->currentVertexBuffer++;
1269  if (data->currentVertexBuffer >= SDL_arraysize(data->vertexBuffers)) {
1270  data->currentVertexBuffer = 0;
1271  }
1272  } else if (!data->reportedVboProblem) {
1273  SDL_LogError(SDL_LOG_CATEGORY_RENDER, "SDL failed to get a vertex buffer for this Direct3D 9 rendering batch!");
1274  SDL_LogError(SDL_LOG_CATEGORY_RENDER, "Dropping back to a slower method.");
1275  SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This might be a brief hiccup, but if performance is bad, this is probably why.");
1276  SDL_LogError(SDL_LOG_CATEGORY_RENDER, "This error will not be logged again for this renderer.");
1277  data->reportedVboProblem = SDL_TRUE;
1278  }
1279 
1280  IDirect3DDevice9_SetStreamSource(data->device, 0, vbo, 0, sizeof (Vertex));
1281 
1282  while (cmd) {
1283  switch (cmd->command) {
1285  /* currently this is sent with each vertex, but if we move to
1286  shaders, we can put this in a uniform here and reduce vertex
1287  buffer bandwidth */
1288  break;
1289  }
1290 
1292  SDL_Rect *viewport = &data->drawstate.viewport;
1293  if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
1294  SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
1295  data->drawstate.viewport_dirty = SDL_TRUE;
1296  }
1297  break;
1298  }
1299 
1301  const SDL_Rect *rect = &cmd->data.cliprect.rect;
1302  if (data->drawstate.cliprect_enabled != cmd->data.cliprect.enabled) {
1303  data->drawstate.cliprect_enabled = cmd->data.cliprect.enabled;
1304  data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1305  }
1306 
1307  if (SDL_memcmp(&data->drawstate.cliprect, rect, sizeof (SDL_Rect)) != 0) {
1308  SDL_memcpy(&data->drawstate.cliprect, rect, sizeof (SDL_Rect));
1309  data->drawstate.cliprect_dirty = SDL_TRUE;
1310  }
1311  break;
1312  }
1313 
1314  case SDL_RENDERCMD_CLEAR: {
1315  const DWORD color = D3DCOLOR_ARGB(cmd->data.color.a, cmd->data.color.r, cmd->data.color.g, cmd->data.color.b);
1316  const SDL_Rect *viewport = &data->drawstate.viewport;
1317  const int backw = istarget ? renderer->target->w : data->pparams.BackBufferWidth;
1318  const int backh = istarget ? renderer->target->h : data->pparams.BackBufferHeight;
1319 
1320  if (data->drawstate.cliprect_enabled) {
1321  IDirect3DDevice9_SetRenderState(data->device, D3DRS_SCISSORTESTENABLE, FALSE);
1322  data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1323  }
1324 
1325  /* Don't reset the viewport if we don't have to! */
1326  if (!viewport->x && !viewport->y && (viewport->w == backw) && (viewport->h == backh)) {
1327  IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
1328  } else {
1329  /* Clear is defined to clear the entire render target */
1330  const D3DVIEWPORT9 wholeviewport = { 0, 0, backw, backh, 0.0f, 1.0f };
1331  IDirect3DDevice9_SetViewport(data->device, &wholeviewport);
1332  data->drawstate.viewport_dirty = SDL_TRUE;
1333  IDirect3DDevice9_Clear(data->device, 0, NULL, D3DCLEAR_TARGET, color, 0.0f, 0);
1334  }
1335 
1336  break;
1337  }
1338 
1340  const size_t count = cmd->data.draw.count;
1341  const size_t first = cmd->data.draw.first;
1342  SetDrawState(data, cmd);
1343  if (vbo) {
1344  IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) (first / sizeof (Vertex)), (UINT) count);
1345  } else {
1346  const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
1347  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, (UINT) count, verts, sizeof (Vertex));
1348  }
1349  break;
1350  }
1351 
1352  case SDL_RENDERCMD_DRAW_LINES: {
1353  const size_t count = cmd->data.draw.count;
1354  const size_t first = cmd->data.draw.first;
1355  const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
1356 
1357  /* DirectX 9 has the same line rasterization semantics as GDI,
1358  so we need to close the endpoint of the line with a second draw call. */
1359  const SDL_bool close_endpoint = ((count == 2) || (verts[0].x != verts[count-1].x) || (verts[0].y != verts[count-1].y));
1360 
1361  SetDrawState(data, cmd);
1362 
1363  if (vbo) {
1364  IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_LINESTRIP, (UINT) (first / sizeof (Vertex)), (UINT) (count - 1));
1365  if (close_endpoint) {
1366  IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_POINTLIST, (UINT) ((first / sizeof (Vertex)) + (count - 1)), 1);
1367  }
1368  } else {
1369  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_LINESTRIP, (UINT) (count - 1), verts, sizeof (Vertex));
1370  if (close_endpoint) {
1371  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_POINTLIST, 1, &verts[count-1], sizeof (Vertex));
1372  }
1373  }
1374  break;
1375  }
1376 
1377  case SDL_RENDERCMD_FILL_RECTS: {
1378  const size_t count = cmd->data.draw.count;
1379  const size_t first = cmd->data.draw.first;
1380  SetDrawState(data, cmd);
1381  if (vbo) {
1382  size_t offset = 0;
1383  for (i = 0; i < count; ++i, offset += 4) {
1384  IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (UINT) ((first / sizeof (Vertex)) + offset), 2);
1385  }
1386  } else {
1387  const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
1388  for (i = 0; i < count; ++i, verts += 4) {
1389  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
1390  }
1391  }
1392  break;
1393  }
1394 
1395  case SDL_RENDERCMD_COPY: {
1396  const size_t count = cmd->data.draw.count;
1397  const size_t first = cmd->data.draw.first;
1398  SetDrawState(data, cmd);
1399  if (vbo) {
1400  size_t offset = 0;
1401  for (i = 0; i < count; ++i, offset += 4) {
1402  IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (UINT) ((first / sizeof (Vertex)) + offset), 2);
1403  }
1404  } else {
1405  const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
1406  for (i = 0; i < count; ++i, verts += 4) {
1407  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
1408  }
1409  }
1410  break;
1411  }
1412 
1413  case SDL_RENDERCMD_COPY_EX: {
1414  const size_t first = cmd->data.draw.first;
1415  const Vertex *verts = (Vertex *) (((Uint8 *) vertices) + first);
1416  const Vertex *transvert = verts + 4;
1417  const float translatex = transvert->x;
1418  const float translatey = transvert->y;
1419  const float rotation = transvert->z;
1420  const Float4X4 d3dmatrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
1421  SetDrawState(data, cmd);
1422 
1423  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
1424 
1425  if (vbo) {
1426  IDirect3DDevice9_DrawPrimitive(data->device, D3DPT_TRIANGLEFAN, (UINT) (first / sizeof (Vertex)), 2);
1427  } else {
1428  IDirect3DDevice9_DrawPrimitiveUP(data->device, D3DPT_TRIANGLEFAN, 2, verts, sizeof (Vertex));
1429  }
1430  break;
1431  }
1432 
1433  case SDL_RENDERCMD_NO_OP:
1434  break;
1435  }
1436 
1437  cmd = cmd->next;
1438  }
1439 
1440  return 0;
1441 }
1442 
1443 
1444 static int
1445 D3D_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
1446  Uint32 format, void * pixels, int pitch)
1447 {
1448  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1449  D3DSURFACE_DESC desc;
1450  LPDIRECT3DSURFACE9 backBuffer;
1451  LPDIRECT3DSURFACE9 surface;
1452  RECT d3drect;
1453  D3DLOCKED_RECT locked;
1454  HRESULT result;
1455 
1456  if (data->currentRenderTarget) {
1457  backBuffer = data->currentRenderTarget;
1458  } else {
1459  backBuffer = data->defaultRenderTarget;
1460  }
1461 
1462  result = IDirect3DSurface9_GetDesc(backBuffer, &desc);
1463  if (FAILED(result)) {
1464  return D3D_SetError("GetDesc()", result);
1465  }
1466 
1467  result = IDirect3DDevice9_CreateOffscreenPlainSurface(data->device, desc.Width, desc.Height, desc.Format, D3DPOOL_SYSTEMMEM, &surface, NULL);
1468  if (FAILED(result)) {
1469  return D3D_SetError("CreateOffscreenPlainSurface()", result);
1470  }
1471 
1472  result = IDirect3DDevice9_GetRenderTargetData(data->device, backBuffer, surface);
1473  if (FAILED(result)) {
1474  IDirect3DSurface9_Release(surface);
1475  return D3D_SetError("GetRenderTargetData()", result);
1476  }
1477 
1478  d3drect.left = rect->x;
1479  d3drect.right = rect->x + rect->w;
1480  d3drect.top = rect->y;
1481  d3drect.bottom = rect->y + rect->h;
1482 
1483  result = IDirect3DSurface9_LockRect(surface, &locked, &d3drect, D3DLOCK_READONLY);
1484  if (FAILED(result)) {
1485  IDirect3DSurface9_Release(surface);
1486  return D3D_SetError("LockRect()", result);
1487  }
1488 
1490  D3DFMTToPixelFormat(desc.Format), locked.pBits, locked.Pitch,
1491  format, pixels, pitch);
1492 
1493  IDirect3DSurface9_UnlockRect(surface);
1494 
1495  IDirect3DSurface9_Release(surface);
1496 
1497  return 0;
1498 }
1499 
1500 static void
1501 D3D_RenderPresent(SDL_Renderer * renderer)
1502 {
1503  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1504  HRESULT result;
1505 
1506  if (!data->beginScene) {
1507  IDirect3DDevice9_EndScene(data->device);
1508  data->beginScene = SDL_TRUE;
1509  }
1510 
1511  result = IDirect3DDevice9_TestCooperativeLevel(data->device);
1512  if (result == D3DERR_DEVICELOST) {
1513  /* We'll reset later */
1514  return;
1515  }
1516  if (result == D3DERR_DEVICENOTRESET) {
1517  D3D_Reset(renderer);
1518  }
1519  result = IDirect3DDevice9_Present(data->device, NULL, NULL, NULL, NULL);
1520  if (FAILED(result)) {
1521  D3D_SetError("Present()", result);
1522  }
1523 }
1524 
1525 static void
1526 D3D_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1527 {
1528  D3D_RenderData *renderdata = (D3D_RenderData *) renderer->driverdata;
1529  D3D_TextureData *data = (D3D_TextureData *) texture->driverdata;
1530 
1531  if (renderdata->drawstate.texture == texture) {
1532  renderdata->drawstate.texture = NULL;
1533  renderdata->drawstate.shader = NULL;
1534  IDirect3DDevice9_SetPixelShader(renderdata->device, NULL);
1535  IDirect3DDevice9_SetTexture(renderdata->device, 0, NULL);
1536  if (data->yuv) {
1537  IDirect3DDevice9_SetTexture(renderdata->device, 1, NULL);
1538  IDirect3DDevice9_SetTexture(renderdata->device, 2, NULL);
1539  }
1540  }
1541 
1542  if (!data) {
1543  return;
1544  }
1545 
1546  D3D_DestroyTextureRep(&data->texture);
1547  D3D_DestroyTextureRep(&data->utexture);
1548  D3D_DestroyTextureRep(&data->vtexture);
1549  SDL_free(data->pixels);
1550  SDL_free(data);
1551  texture->driverdata = NULL;
1552 }
1553 
1554 static void
1555 D3D_DestroyRenderer(SDL_Renderer * renderer)
1556 {
1557  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1558 
1559  if (data) {
1560  int i;
1561 
1562  /* Release the render target */
1563  if (data->defaultRenderTarget) {
1564  IDirect3DSurface9_Release(data->defaultRenderTarget);
1565  data->defaultRenderTarget = NULL;
1566  }
1567  if (data->currentRenderTarget != NULL) {
1568  IDirect3DSurface9_Release(data->currentRenderTarget);
1569  data->currentRenderTarget = NULL;
1570  }
1571  for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
1572  if (data->shaders[i]) {
1573  IDirect3DPixelShader9_Release(data->shaders[i]);
1574  data->shaders[i] = NULL;
1575  }
1576  }
1577  /* Release all vertex buffers */
1578  for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
1579  if (data->vertexBuffers[i]) {
1580  IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
1581  }
1582  data->vertexBuffers[i] = NULL;
1583  }
1584  if (data->device) {
1585  IDirect3DDevice9_Release(data->device);
1586  data->device = NULL;
1587  }
1588  if (data->d3d) {
1589  IDirect3D9_Release(data->d3d);
1590  SDL_UnloadObject(data->d3dDLL);
1591  }
1592  SDL_free(data);
1593  }
1594  SDL_free(renderer);
1595 }
1596 
1597 static int
1598 D3D_Reset(SDL_Renderer * renderer)
1599 {
1600  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1601  const Float4X4 d3dmatrix = MatrixIdentity();
1602  HRESULT result;
1604  int i;
1605 
1606  /* Release the default render target before reset */
1607  if (data->defaultRenderTarget) {
1608  IDirect3DSurface9_Release(data->defaultRenderTarget);
1609  data->defaultRenderTarget = NULL;
1610  }
1611  if (data->currentRenderTarget != NULL) {
1612  IDirect3DSurface9_Release(data->currentRenderTarget);
1613  data->currentRenderTarget = NULL;
1614  }
1615 
1616  /* Release application render targets */
1618  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
1619  D3D_DestroyTexture(renderer, texture);
1620  } else {
1621  D3D_RecreateTexture(renderer, texture);
1622  }
1623  }
1624 
1625  /* Release all vertex buffers */
1626  for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
1627  if (data->vertexBuffers[i]) {
1628  IDirect3DVertexBuffer9_Release(data->vertexBuffers[i]);
1629  }
1630  data->vertexBuffers[i] = NULL;
1631  data->vertexBufferSize[i] = 0;
1632  }
1633 
1634  result = IDirect3DDevice9_Reset(data->device, &data->pparams);
1635  if (FAILED(result)) {
1636  if (result == D3DERR_DEVICELOST) {
1637  /* Don't worry about it, we'll reset later... */
1638  return 0;
1639  } else {
1640  return D3D_SetError("Reset()", result);
1641  }
1642  }
1643 
1644  /* Allocate application render targets */
1646  if (texture->access == SDL_TEXTUREACCESS_TARGET) {
1647  D3D_CreateTexture(renderer, texture);
1648  }
1649  }
1650 
1651  IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
1652  D3D_InitRenderState(data);
1653  D3D_SetRenderTargetInternal(renderer, renderer->target);
1654  data->drawstate.viewport_dirty = SDL_TRUE;
1655  data->drawstate.cliprect_dirty = SDL_TRUE;
1656  data->drawstate.cliprect_enabled_dirty = SDL_TRUE;
1657  data->drawstate.texture = NULL;
1658  data->drawstate.shader = NULL;
1659  data->drawstate.blend = SDL_BLENDMODE_INVALID;
1660  data->drawstate.is_copy_ex = SDL_FALSE;
1661  IDirect3DDevice9_SetTransform(data->device, D3DTS_VIEW, (D3DMATRIX*)&d3dmatrix);
1662 
1663  /* Let the application know that render targets were reset */
1664  {
1665  SDL_Event event;
1666  event.type = SDL_RENDER_TARGETS_RESET;
1667  SDL_PushEvent(&event);
1668  }
1669 
1670  return 0;
1671 }
1672 
1673 SDL_Renderer *
1674 D3D_CreateRenderer(SDL_Window * window, Uint32 flags)
1675 {
1677  D3D_RenderData *data;
1678  SDL_SysWMinfo windowinfo;
1679  HRESULT result;
1680  D3DPRESENT_PARAMETERS pparams;
1681  IDirect3DSwapChain9 *chain;
1682  D3DCAPS9 caps;
1683  DWORD device_flags;
1684  Uint32 window_flags;
1685  int w, h;
1686  SDL_DisplayMode fullscreen_mode;
1687  int displayIndex;
1688 
1689  renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
1690  if (!renderer) {
1691  SDL_OutOfMemory();
1692  return NULL;
1693  }
1694 
1695  data = (D3D_RenderData *) SDL_calloc(1, sizeof(*data));
1696  if (!data) {
1697  SDL_free(renderer);
1698  SDL_OutOfMemory();
1699  return NULL;
1700  }
1701 
1702  if (!D3D_LoadDLL(&data->d3dDLL, &data->d3d)) {
1703  SDL_free(renderer);
1704  SDL_free(data);
1705  SDL_SetError("Unable to create Direct3D interface");
1706  return NULL;
1707  }
1708 
1709  renderer->WindowEvent = D3D_WindowEvent;
1710  renderer->SupportsBlendMode = D3D_SupportsBlendMode;
1711  renderer->CreateTexture = D3D_CreateTexture;
1712  renderer->UpdateTexture = D3D_UpdateTexture;
1713  renderer->UpdateTextureYUV = D3D_UpdateTextureYUV;
1714  renderer->LockTexture = D3D_LockTexture;
1715  renderer->UnlockTexture = D3D_UnlockTexture;
1716  renderer->SetTextureScaleMode = D3D_SetTextureScaleMode;
1717  renderer->SetRenderTarget = D3D_SetRenderTarget;
1718  renderer->QueueSetViewport = D3D_QueueSetViewport;
1719  renderer->QueueSetDrawColor = D3D_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
1720  renderer->QueueDrawPoints = D3D_QueueDrawPoints;
1721  renderer->QueueDrawLines = D3D_QueueDrawPoints; /* lines and points queue vertices the same way. */
1722  renderer->QueueFillRects = D3D_QueueFillRects;
1723  renderer->QueueCopy = D3D_QueueCopy;
1724  renderer->QueueCopyEx = D3D_QueueCopyEx;
1725  renderer->RunCommandQueue = D3D_RunCommandQueue;
1726  renderer->RenderReadPixels = D3D_RenderReadPixels;
1727  renderer->RenderPresent = D3D_RenderPresent;
1728  renderer->DestroyTexture = D3D_DestroyTexture;
1729  renderer->DestroyRenderer = D3D_DestroyRenderer;
1733 
1734  SDL_VERSION(&windowinfo.version);
1735  SDL_GetWindowWMInfo(window, &windowinfo);
1736 
1737  window_flags = SDL_GetWindowFlags(window);
1738  SDL_GetWindowSize(window, &w, &h);
1739  SDL_GetWindowDisplayMode(window, &fullscreen_mode);
1740 
1741  SDL_zero(pparams);
1742  pparams.hDeviceWindow = windowinfo.info.win.window;
1743  pparams.BackBufferWidth = w;
1744  pparams.BackBufferHeight = h;
1745  pparams.BackBufferCount = 1;
1746  pparams.SwapEffect = D3DSWAPEFFECT_DISCARD;
1747 
1748  if (window_flags & SDL_WINDOW_FULLSCREEN && (window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) != SDL_WINDOW_FULLSCREEN_DESKTOP) {
1749  pparams.Windowed = FALSE;
1750  pparams.BackBufferFormat = PixelFormatToD3DFMT(fullscreen_mode.format);
1751  pparams.FullScreen_RefreshRateInHz = fullscreen_mode.refresh_rate;
1752  } else {
1753  pparams.Windowed = TRUE;
1754  pparams.BackBufferFormat = D3DFMT_UNKNOWN;
1755  pparams.FullScreen_RefreshRateInHz = 0;
1756  }
1758  pparams.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
1759  } else {
1760  pparams.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE;
1761  }
1762 
1763  /* Get the adapter for the display that the window is on */
1764  displayIndex = SDL_GetWindowDisplayIndex(window);
1765  data->adapter = SDL_Direct3D9GetAdapterIndex(displayIndex);
1766 
1767  IDirect3D9_GetDeviceCaps(data->d3d, data->adapter, D3DDEVTYPE_HAL, &caps);
1768 
1769  device_flags = D3DCREATE_FPU_PRESERVE;
1770  if (caps.DevCaps & D3DDEVCAPS_HWTRANSFORMANDLIGHT) {
1771  device_flags |= D3DCREATE_HARDWARE_VERTEXPROCESSING;
1772  } else {
1773  device_flags |= D3DCREATE_SOFTWARE_VERTEXPROCESSING;
1774  }
1775 
1777  device_flags |= D3DCREATE_MULTITHREADED;
1778  }
1779 
1780  result = IDirect3D9_CreateDevice(data->d3d, data->adapter,
1781  D3DDEVTYPE_HAL,
1782  pparams.hDeviceWindow,
1783  device_flags,
1784  &pparams, &data->device);
1785  if (FAILED(result)) {
1786  D3D_DestroyRenderer(renderer);
1787  D3D_SetError("CreateDevice()", result);
1788  return NULL;
1789  }
1790 
1791  /* Get presentation parameters to fill info */
1792  result = IDirect3DDevice9_GetSwapChain(data->device, 0, &chain);
1793  if (FAILED(result)) {
1794  D3D_DestroyRenderer(renderer);
1795  D3D_SetError("GetSwapChain()", result);
1796  return NULL;
1797  }
1798  result = IDirect3DSwapChain9_GetPresentParameters(chain, &pparams);
1799  if (FAILED(result)) {
1800  IDirect3DSwapChain9_Release(chain);
1801  D3D_DestroyRenderer(renderer);
1802  D3D_SetError("GetPresentParameters()", result);
1803  return NULL;
1804  }
1805  IDirect3DSwapChain9_Release(chain);
1806  if (pparams.PresentationInterval == D3DPRESENT_INTERVAL_ONE) {
1808  }
1809  data->pparams = pparams;
1810 
1811  IDirect3DDevice9_GetDeviceCaps(data->device, &caps);
1812  renderer->info.max_texture_width = caps.MaxTextureWidth;
1813  renderer->info.max_texture_height = caps.MaxTextureHeight;
1814  if (caps.NumSimultaneousRTs >= 2) {
1816  }
1817 
1818  if (caps.PrimitiveMiscCaps & D3DPMISCCAPS_SEPARATEALPHABLEND) {
1819  data->enableSeparateAlphaBlend = SDL_TRUE;
1820  }
1821 
1822  /* Store the default render target */
1823  IDirect3DDevice9_GetRenderTarget(data->device, 0, &data->defaultRenderTarget);
1824  data->currentRenderTarget = NULL;
1825 
1826  /* Set up parameters for rendering */
1827  D3D_InitRenderState(data);
1828 
1829  if (caps.MaxSimultaneousTextures >= 3) {
1830  int i;
1831  for (i = 0; i < SDL_arraysize(data->shaders); ++i) {
1832  result = D3D9_CreatePixelShader(data->device, (D3D9_Shader)i, &data->shaders[i]);
1833  if (FAILED(result)) {
1834  D3D_SetError("CreatePixelShader()", result);
1835  }
1836  }
1837  if (data->shaders[SHADER_YUV_JPEG] && data->shaders[SHADER_YUV_BT601] && data->shaders[SHADER_YUV_BT709]) {
1840  }
1841  }
1842 
1843  data->drawstate.blend = SDL_BLENDMODE_INVALID;
1844 
1845  return renderer;
1846 }
1847 
1849  D3D_CreateRenderer,
1850  {
1851  "direct3d",
1853  1,
1855  0,
1856  0}
1857 };
1858 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
1859 
1860 #ifdef __WIN32__
1861 /* This function needs to always exist on Windows, for the Dynamic API. */
1864 {
1866 
1867 #if SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED
1868  D3D_RenderData *data = (D3D_RenderData *) renderer->driverdata;
1869 
1870  /* Make sure that this is a D3D renderer */
1871  if (renderer->DestroyRenderer != D3D_DestroyRenderer) {
1872  SDL_SetError("Renderer is not a D3D renderer");
1873  return NULL;
1874  }
1875 
1876  device = data->device;
1877  if (device) {
1878  IDirect3DDevice9_AddRef(device);
1879  }
1880 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
1881 
1882  return device;
1883 }
1884 #endif /* __WIN32__ */
1885 
1886 /* vi: set ts=4 sw=4 expandtab: */
#define SDL_assert(condition)
Definition: SDL_assert.h:171
SDL_BlendOperation
The blend operation used when combining source and destination pixel components.
Definition: SDL_blendmode.h:66
@ SDL_BLENDOPERATION_ADD
Definition: SDL_blendmode.h:67
SDL_BlendFactor
The normalized factor used to multiply pixel components.
Definition: SDL_blendmode.h:79
@ SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR
Definition: SDL_blendmode.h:83
@ SDL_BLENDFACTOR_ZERO
Definition: SDL_blendmode.h:80
@ SDL_BLENDFACTOR_SRC_COLOR
Definition: SDL_blendmode.h:82
@ SDL_BLENDFACTOR_SRC_ALPHA
Definition: SDL_blendmode.h:84
@ SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR
Definition: SDL_blendmode.h:87
@ SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA
Definition: SDL_blendmode.h:89
@ SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA
Definition: SDL_blendmode.h:85
@ SDL_BLENDFACTOR_DST_ALPHA
Definition: SDL_blendmode.h:88
@ SDL_BLENDFACTOR_DST_COLOR
Definition: SDL_blendmode.h:86
@ SDL_BLENDFACTOR_ONE
Definition: SDL_blendmode.h:81
SDL_BlendMode
The blend mode used in SDL_RenderCopy() and drawing operations.
Definition: SDL_blendmode.h:41
@ SDL_BLENDMODE_NONE
Definition: SDL_blendmode.h:42
@ SDL_BLENDMODE_INVALID
Definition: SDL_blendmode.h:56
#define FAILED(x)
Definition: SDL_directx.h:54
#define SDL_SetError
#define SDL_memset
#define SDL_GetWindowSize
#define SDL_PushEvent
#define SDL_GetWindowFlags
#define SDL_GetYUVConversionModeForResolution
#define SDL_UnloadObject
#define SDL_malloc
#define SDL_LogError
#define SDL_free
#define SDL_memcmp
#define SDL_GetWindowDisplayIndex
#define SDL_GetWindowDisplayMode
#define SDL_GetHintBoolean
#define SDL_memcpy
#define SDL_calloc
#define SDL_ConvertPixels
#define SDL_GetWindowWMInfo
#define SDL_OutOfMemory()
Definition: SDL_error.h:88
@ SDL_RENDER_TARGETS_RESET
Definition: SDL_events.h:160
#define SDL_HINT_RENDER_DIRECT3D_THREADSAFE
A variable controlling whether the Direct3D device is initialized for thread-safe operations.
Definition: SDL_hints.h:107
@ SDL_LOG_CATEGORY_RENDER
Definition: SDL_log.h:72
GLint GLint GLint GLint GLint GLint y
Definition: SDL_opengl.h:1574
const GLdouble * v
Definition: SDL_opengl.h:2064
GLuint GLuint GLsizei count
Definition: SDL_opengl.h:1571
GLint GLint GLsizei GLsizei GLsizei GLint GLenum GLenum const GLvoid * pixels
Definition: SDL_opengl.h:1572
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: SDL_opengl.h:1974
GLint GLint GLint GLint GLint x
Definition: SDL_opengl.h:1574
GLint GLint GLsizei GLsizei GLsizei GLint GLenum format
Definition: SDL_opengl.h:1572
struct _cl_event * event
GLfixed GLfixed GLint GLint GLfixed points
GLenum src
GLuint64EXT * result
GLuint color
GLuint sampler
GLintptr offset
GLuint shader
GLuint index
GLuint GLenum matrix
GLenum GLenum dst
GLdouble GLdouble z
GLenum GLenum void * row
GLfloat angle
GLsizei GLsizei GLuint * shaders
GLbitfield flags
GLenum GLenum GLuint texture
GLuint GLsizei GLsizei * length
const GLint * first
GLfloat GLfloat GLfloat GLfloat h
GLubyte GLubyte GLubyte GLubyte w
GLsizeiptr const void GLenum usage
#define SDL_BYTESPERPIXEL(X)
Definition: SDL_pixels.h:128
@ SDL_PIXELFORMAT_YV12
Definition: SDL_pixels.h:286
@ SDL_PIXELFORMAT_RGB888
Definition: SDL_pixels.h:246
@ SDL_PIXELFORMAT_NV12
Definition: SDL_pixels.h:296
@ SDL_PIXELFORMAT_NV21
Definition: SDL_pixels.h:298
@ SDL_PIXELFORMAT_IYUV
Definition: SDL_pixels.h:288
@ SDL_PIXELFORMAT_ARGB8888
Definition: SDL_pixels.h:257
@ SDL_PIXELFORMAT_RGB565
Definition: SDL_pixels.h:231
@ SDL_PIXELFORMAT_UNKNOWN
Definition: SDL_pixels.h:173
SDL_BlendFactor SDL_GetBlendModeDstColorFactor(SDL_BlendMode blendMode)
Definition: SDL_render.c:3393
SDL_BlendFactor SDL_GetBlendModeSrcColorFactor(SDL_BlendMode blendMode)
Definition: SDL_render.c:3386
void * SDL_AllocateRenderVertices(SDL_Renderer *renderer, const size_t numbytes, const size_t alignment, size_t *offset)
Definition: SDL_render.c:262
SDL_BlendFactor SDL_GetBlendModeDstAlphaFactor(SDL_BlendMode blendMode)
Definition: SDL_render.c:3414
SDL_BlendFactor SDL_GetBlendModeSrcAlphaFactor(SDL_BlendMode blendMode)
Definition: SDL_render.c:3407
SDL_BlendOperation SDL_GetBlendModeAlphaOperation(SDL_BlendMode blendMode)
Definition: SDL_render.c:3421
SDL_BlendOperation SDL_GetBlendModeColorOperation(SDL_BlendMode blendMode)
Definition: SDL_render.c:3400
@ SDL_RENDERER_ACCELERATED
Definition: SDL_render.h:67
@ SDL_RENDERER_PRESENTVSYNC
Definition: SDL_render.h:69
@ SDL_RENDERER_TARGETTEXTURE
Definition: SDL_render.h:71
SDL_RendererFlip
Flip constants for SDL_RenderCopyEx.
Definition: SDL_render.h:122
@ SDL_FLIP_VERTICAL
Definition: SDL_render.h:125
@ SDL_FLIP_HORIZONTAL
Definition: SDL_render.h:124
@ SDL_TEXTUREACCESS_TARGET
Definition: SDL_render.h:105
SDL_ScaleMode
The scaling mode for a texture.
Definition: SDL_render.h:92
@ SDL_ScaleModeNearest
Definition: SDL_render.h:93
static void SetDrawState(SDL_Surface *surface, SW_DrawStateCache *drawstate)
HRESULT D3D9_CreatePixelShader(IDirect3DDevice9 *d3dDevice, D3D9_Shader shader, IDirect3DPixelShader9 **pixelShader)
D3D9_Shader
@ SHADER_YUV_JPEG
@ NUM_SHADERS
@ SHADER_YUV_BT601
@ SHADER_YUV_BT709
#define SDL_zero(x)
Definition: SDL_stdinc.h:426
SDL_bool
Definition: SDL_stdinc.h:168
@ SDL_TRUE
Definition: SDL_stdinc.h:170
@ SDL_FALSE
Definition: SDL_stdinc.h:169
#define SDL_arraysize(array)
Definition: SDL_stdinc.h:121
uint8_t Uint8
Definition: SDL_stdinc.h:185
uint32_t Uint32
Definition: SDL_stdinc.h:209
@ SDL_YUV_CONVERSION_BT601
Definition: SDL_surface.h:109
@ SDL_YUV_CONVERSION_JPEG
Definition: SDL_surface.h:108
@ SDL_YUV_CONVERSION_BT709
Definition: SDL_surface.h:110
SDL_RenderDriver D3D_RenderDriver
@ SDL_RENDERCMD_SETCLIPRECT
Definition: SDL_sysrender.h:70
@ SDL_RENDERCMD_DRAW_LINES
Definition: SDL_sysrender.h:74
@ SDL_RENDERCMD_SETVIEWPORT
Definition: SDL_sysrender.h:69
@ SDL_RENDERCMD_DRAW_POINTS
Definition: SDL_sysrender.h:73
@ SDL_RENDERCMD_NO_OP
Definition: SDL_sysrender.h:68
@ SDL_RENDERCMD_FILL_RECTS
Definition: SDL_sysrender.h:75
@ SDL_RENDERCMD_COPY
Definition: SDL_sysrender.h:76
@ SDL_RENDERCMD_CLEAR
Definition: SDL_sysrender.h:72
@ SDL_RENDERCMD_SETDRAWCOLOR
Definition: SDL_sysrender.h:71
@ SDL_RENDERCMD_COPY_EX
Definition: SDL_sysrender.h:77
int SDL_Direct3D9GetAdapterIndex(int displayIndex)
Returns the D3D9 adapter index that matches the specified display index.
struct IDirect3DDevice9 IDirect3DDevice9
Definition: SDL_system.h:60
IDirect3DDevice9 * SDL_RenderGetD3D9Device(SDL_Renderer *renderer)
Returns the D3D device associated with a renderer, or NULL if it's not a D3D renderer.
#define SDL_VERSION(x)
Macro to determine SDL version program was compiled against.
Definition: SDL_version.h:79
@ SDL_WINDOW_FULLSCREEN_DESKTOP
Definition: SDL_video.h:110
@ SDL_WINDOW_FULLSCREEN
Definition: SDL_video.h:99
@ SDL_WINDOWEVENT_SIZE_CHANGED
Definition: SDL_video.h:156
SDL_bool D3D_LoadDLL(void **pD3DDLL, IDirect3D9 **pDirect3D9Interface)
struct IDirect3D9 IDirect3D9
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
#define NULL
Definition: begin_code.h:163
#define TRUE
Definition: edid-parse.c:33
#define FALSE
Definition: edid-parse.c:34
EGLSurface surface
Definition: eglext.h:248
EGLSurface EGLNativeWindowType * window
Definition: eglext.h:1025
EGLSurface EGLint * rects
Definition: eglext.h:282
static SDL_AudioDeviceID device
Definition: loopwave.c:37
set set set set set set set macro pixldst1 abits if abits op else op endif endm macro pixldst2 abits if abits op else op endif endm macro pixldst4 abits if abits op else op endif endm macro pixldst0 abits op endm macro pixldst3 mem_operand op endm macro pixldst30 mem_operand op endm macro pixldst abits if abits elseif abits elseif abits elseif abits elseif abits pixldst0 abits else pixldst0 abits pixldst0 abits pixldst0 abits pixldst0 abits endif elseif abits else pixldst0 abits pixldst0 abits endif elseif abits else error unsupported bpp *numpix else pixst endif endm macro pixld1_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl mov asr adds SRC_WIDTH_FIXED bpl add asl else error unsupported endif endm macro pixld2_s mem_operand if mov asr add asl add asl mov asr sub UNIT_X add asl mov asr add asl add asl mov asr add UNIT_X add asl else pixld1_s mem_operand pixld1_s mem_operand endif endm macro pixld0_s mem_operand if asr adds SRC_WIDTH_FIXED bpl add asl elseif asr adds SRC_WIDTH_FIXED bpl add asl endif endm macro pixld_s_internal mem_operand if mem_operand pixld2_s mem_operand pixdeinterleave basereg elseif mem_operand elseif mem_operand elseif mem_operand elseif mem_operand pixld0_s mem_operand else pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else pixld0_s mem_operand pixld0_s mem_operand endif elseif mem_operand else error unsupported mem_operand if bpp mem_operand endif endm macro vuzp8 reg2 vuzp d d &reg2 endm macro vzip8 reg2 vzip d d &reg2 endm macro pixdeinterleave basereg basereg basereg basereg basereg endif endm macro pixinterleave basereg basereg basereg basereg basereg endif endm macro PF boost_increment endif if endif PF tst PF addne PF subne PF cmp ORIG_W if endif if endif if endif PF subge ORIG_W PF subges if endif if endif if endif endif endm macro cache_preload_simple endif if dst_r_bpp pld[DST_R, #(PREFETCH_DISTANCE_SIMPLE *dst_r_bpp/8)] endif if mask_bpp pld if[MASK, #(PREFETCH_DISTANCE_SIMPLE *mask_bpp/8)] endif endif endm macro fetch_mask_pixblock pixld mask_basereg pixblock_size MASK endm macro ensure_destination_ptr_alignment process_pixblock_tail_head if beq irp skip1(dst_w_bpp<=(lowbit *8)) &&((lowbit *8)<(pixblock_size *dst_w_bpp)) .if lowbit< 16 tst DST_R
set set set set set set set set set set set set set set set set set set set set *set set set macro pixldst op &r &cond WK op &r &cond WK op &r &cond WK else op &m &cond &ia op &r &cond WK else op &m &cond &ia elseif elseif else error unsupported base if elseif elseif else error unsupported unaligned pixldst unaligned endm macro pixst base base else pixldst base endif endm macro PF ptr
The structure that defines a display mode.
Definition: SDL_video.h:54
Uint32 format
Definition: SDL_video.h:55
The structure that defines a point (floating point)
Definition: SDL_rect.h:61
float x
Definition: SDL_rect.h:62
float y
Definition: SDL_rect.h:63
A rectangle, with the origin at the upper left (floating point).
Definition: SDL_rect.h:88
float h
Definition: SDL_rect.h:92
float x
Definition: SDL_rect.h:89
float w
Definition: SDL_rect.h:91
float y
Definition: SDL_rect.h:90
A rectangle, with the origin at the upper left (integer).
Definition: SDL_rect.h:78
int h
Definition: SDL_rect.h:80
int w
Definition: SDL_rect.h:80
int y
Definition: SDL_rect.h:79
int x
Definition: SDL_rect.h:79
struct SDL_RenderCommand::@38::@42 color
struct SDL_RenderCommand * next
struct SDL_RenderCommand::@38::@39 viewport
struct SDL_RenderCommand::@38::@41 draw
SDL_RenderCommandType command
Definition: SDL_sysrender.h:82
union SDL_RenderCommand::@38 data
struct SDL_RenderCommand::@38::@40 cliprect
SDL_RendererInfo info
int(* QueueCopy)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_Rect *srcrect, const SDL_FRect *dstrect)
int(* LockTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, void **pixels, int *pitch)
SDL_Window * window
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)
int(* QueueDrawLines)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
void(* SetTextureScaleMode)(SDL_Renderer *renderer, SDL_Texture *texture, SDL_ScaleMode scaleMode)
SDL_Texture * textures
void(* UnlockTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* UpdateTexture)(SDL_Renderer *renderer, SDL_Texture *texture, const SDL_Rect *rect, const void *pixels, int pitch)
int(* SetRenderTarget)(SDL_Renderer *renderer, SDL_Texture *texture)
void(* DestroyRenderer)(SDL_Renderer *renderer)
void(* DestroyTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
SDL_bool(* SupportsBlendMode)(SDL_Renderer *renderer, SDL_BlendMode blendMode)
void(* RenderPresent)(SDL_Renderer *renderer)
int(* RenderReadPixels)(SDL_Renderer *renderer, const SDL_Rect *rect, Uint32 format, void *pixels, int pitch)
int(* QueueDrawPoints)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FPoint *points, int count)
int(* QueueFillRects)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, const SDL_FRect *rects, int count)
void(* WindowEvent)(SDL_Renderer *renderer, const SDL_WindowEvent *event)
int(* RunCommandQueue)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
int(* QueueCopyEx)(SDL_Renderer *renderer, SDL_RenderCommand *cmd, SDL_Texture *texture, const SDL_Rect *srcquad, const SDL_FRect *dstrect, const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
int(* CreateTexture)(SDL_Renderer *renderer, SDL_Texture *texture)
int(* QueueSetViewport)(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
SDL_RendererInfo info
void * driverdata
SDL_Texture * target
int(* QueueSetDrawColor)(SDL_Renderer *renderer, SDL_RenderCommand *cmd)
int max_texture_height
Definition: SDL_render.h:85
Uint32 texture_formats[16]
Definition: SDL_render.h:83
Uint32 num_texture_formats
Definition: SDL_render.h:82
union SDL_SysWMinfo::@10 info
Window window
Definition: SDL_syswm.h:240
SDL_version version
Definition: SDL_syswm.h:218
SDL_Texture * next
Definition: SDL_sysrender.h:63
Window state change event data (event.window.*)
Definition: SDL_events.h:202
The type used to identify a window.
Definition: SDL_sysvideo.h:75
static SDL_Renderer * renderer
static SDL_BlendMode blendMode
Definition: testdraw2.c:34
SDL_Rect rect
Definition: testrelative.c:27
static SDL_Rect viewport
Definition: testviewport.c:28
General event structure.
Definition: SDL_events.h:592