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