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 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
24
25 #define COBJMACROS
26 #include "../../core/windows/SDL_windows.h"
27 #include "SDL_hints.h"
28 #include "SDL_loadso.h"
29 #include "SDL_syswm.h"
30 #include "../SDL_sysrender.h"
31 #include "../SDL_d3dmath.h"
32
33 #include <d3d11_1.h>
34
35 #include "SDL_shaders_d3d11.h"
36
37 #ifdef __WINRT__
38
39 #if NTDDI_VERSION > NTDDI_WIN8
40 #include <DXGI1_3.h>
41 #endif
42
43 #include "SDL_render_winrt.h"
44
45 #if WINAPI_FAMILY == WINAPI_FAMILY_APP
46 #include <windows.ui.xaml.media.dxinterop.h>
47 /* TODO, WinRT, XAML: get the ISwapChainBackgroundPanelNative from something other than a global var */
48 extern ISwapChainBackgroundPanelNative * WINRT_GlobalSwapChainBackgroundPanelNative;
49 #endif /* WINAPI_FAMILY == WINAPI_FAMILY_APP */
50
51 #endif /* __WINRT__ */
52
53
54 #define SDL_COMPOSE_ERROR(str) SDL_STRINGIFY_ARG(__FUNCTION__) ", " str
55
56 #define SAFE_RELEASE(X) if ((X)) { IUnknown_Release(SDL_static_cast(IUnknown*, X)); X = NULL; }
57
58
59 /* !!! FIXME: vertex buffer bandwidth could be significantly lower; move color to a uniform, only use UV coords
60 !!! FIXME: when textures are needed, and don't ever pass Z, since it's always zero. */
61
62 /* Vertex shader, common values */
63 typedef struct
64 {
65 Float4X4 model;
66 Float4X4 projectionAndView;
67 } VertexShaderConstants;
68
69 /* Per-vertex data */
70 typedef struct
71 {
72 Float3 pos;
73 Float2 tex;
74 Float4 color;
75 } VertexPositionColor;
76
77 /* Per-texture data */
78 typedef struct
79 {
80 ID3D11Texture2D *mainTexture;
81 ID3D11ShaderResourceView *mainTextureResourceView;
82 ID3D11RenderTargetView *mainTextureRenderTargetView;
83 ID3D11Texture2D *stagingTexture;
84 int lockedTexturePositionX;
85 int lockedTexturePositionY;
86 D3D11_FILTER scaleMode;
87
88 /* YV12 texture support */
89 SDL_bool yuv;
90 ID3D11Texture2D *mainTextureU;
91 ID3D11ShaderResourceView *mainTextureResourceViewU;
92 ID3D11Texture2D *mainTextureV;
93 ID3D11ShaderResourceView *mainTextureResourceViewV;
94
95 /* NV12 texture support */
96 SDL_bool nv12;
97 ID3D11Texture2D *mainTextureNV;
98 ID3D11ShaderResourceView *mainTextureResourceViewNV;
99
100 Uint8 *pixels;
101 int pitch;
102 SDL_Rect locked_rect;
103 } D3D11_TextureData;
104
105 /* Blend mode data */
106 typedef struct
107 {
108 SDL_BlendMode blendMode;
109 ID3D11BlendState *blendState;
110 } D3D11_BlendMode;
111
112 /* Private renderer data */
113 typedef struct
114 {
115 void *hDXGIMod;
116 void *hD3D11Mod;
117 IDXGIFactory2 *dxgiFactory;
118 IDXGIAdapter *dxgiAdapter;
119 ID3D11Device1 *d3dDevice;
120 ID3D11DeviceContext1 *d3dContext;
121 IDXGISwapChain1 *swapChain;
122 DXGI_SWAP_EFFECT swapEffect;
123 ID3D11RenderTargetView *mainRenderTargetView;
124 ID3D11RenderTargetView *currentOffscreenRenderTargetView;
125 ID3D11InputLayout *inputLayout;
126 ID3D11Buffer *vertexBuffers[8];
127 size_t vertexBufferSizes[8];
128 ID3D11VertexShader *vertexShader;
129 ID3D11PixelShader *pixelShaders[NUM_SHADERS];
130 int blendModesCount;
131 D3D11_BlendMode *blendModes;
132 ID3D11SamplerState *nearestPixelSampler;
133 ID3D11SamplerState *linearSampler;
134 D3D_FEATURE_LEVEL featureLevel;
135
136 /* Rasterizers */
137 ID3D11RasterizerState *mainRasterizer;
138 ID3D11RasterizerState *clippedRasterizer;
139
140 /* Vertex buffer constants */
141 VertexShaderConstants vertexShaderConstantsData;
142 ID3D11Buffer *vertexShaderConstants;
143
144 /* Cached renderer properties */
145 DXGI_MODE_ROTATION rotation;
146 ID3D11RenderTargetView *currentRenderTargetView;
147 ID3D11RasterizerState *currentRasterizerState;
148 ID3D11BlendState *currentBlendState;
149 ID3D11PixelShader *currentShader;
150 ID3D11ShaderResourceView *currentShaderResource;
151 ID3D11SamplerState *currentSampler;
152 SDL_bool cliprectDirty;
153 SDL_bool currentCliprectEnabled;
154 SDL_Rect currentCliprect;
155 SDL_Rect currentViewport;
156 int currentViewportRotation;
157 SDL_bool viewportDirty;
158 Float4X4 identity;
159 int currentVertexBuffer;
160 } D3D11_RenderData;
161
162
163 /* Define D3D GUIDs here so we don't have to include uuid.lib.
164 *
165 * Fix for SDL bug https://bugzilla.libsdl.org/show_bug.cgi?id=3437:
166 * The extra 'SDL_' was added to the start of each IID's name, in order
167 * to prevent build errors on both MinGW-w64 and WinRT/UWP.
168 * (SDL bug https://bugzilla.libsdl.org/show_bug.cgi?id=3336 led to
169 * linker errors in WinRT/UWP builds.)
170 */
171
172 #ifdef __GNUC__
173 #pragma GCC diagnostic push
174 #pragma GCC diagnostic ignored "-Wunused-const-variable"
175 #endif
176
177 static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } };
178 static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } };
179 static const GUID SDL_IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } };
180 static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } };
181 static const GUID SDL_IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } };
182 static const GUID SDL_IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } };
183 static const GUID SDL_IID_ID3D11Debug = { 0x79cf2233, 0x7536, 0x4948, { 0x9d, 0x36, 0x1e, 0x46, 0x92, 0xdc, 0x57, 0x60 } };
184
185 #ifdef __GNUC__
186 #pragma GCC diagnostic pop
187 #endif
188
189
190
191 Uint32
D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)192 D3D11_DXGIFormatToSDLPixelFormat(DXGI_FORMAT dxgiFormat)
193 {
194 switch (dxgiFormat) {
195 case DXGI_FORMAT_B8G8R8A8_UNORM:
196 return SDL_PIXELFORMAT_ARGB8888;
197 case DXGI_FORMAT_B8G8R8X8_UNORM:
198 return SDL_PIXELFORMAT_RGB888;
199 default:
200 return SDL_PIXELFORMAT_UNKNOWN;
201 }
202 }
203
204 static DXGI_FORMAT
SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)205 SDLPixelFormatToDXGIFormat(Uint32 sdlFormat)
206 {
207 switch (sdlFormat) {
208 case SDL_PIXELFORMAT_ARGB8888:
209 return DXGI_FORMAT_B8G8R8A8_UNORM;
210 case SDL_PIXELFORMAT_RGB888:
211 return DXGI_FORMAT_B8G8R8X8_UNORM;
212 case SDL_PIXELFORMAT_YV12:
213 case SDL_PIXELFORMAT_IYUV:
214 case SDL_PIXELFORMAT_NV12: /* For the Y texture */
215 case SDL_PIXELFORMAT_NV21: /* For the Y texture */
216 return DXGI_FORMAT_R8_UNORM;
217 default:
218 return DXGI_FORMAT_UNKNOWN;
219 }
220 }
221
222 static void D3D11_DestroyTexture(SDL_Renderer * renderer, SDL_Texture * texture);
223
224 static void
D3D11_ReleaseAll(SDL_Renderer * renderer)225 D3D11_ReleaseAll(SDL_Renderer * renderer)
226 {
227 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
228 SDL_Texture *texture = NULL;
229
230 /* Release all textures */
231 for (texture = renderer->textures; texture; texture = texture->next) {
232 D3D11_DestroyTexture(renderer, texture);
233 }
234
235 /* Release/reset everything else */
236 if (data) {
237 int i;
238
239 SAFE_RELEASE(data->dxgiFactory);
240 SAFE_RELEASE(data->dxgiAdapter);
241 SAFE_RELEASE(data->d3dDevice);
242 SAFE_RELEASE(data->d3dContext);
243 SAFE_RELEASE(data->swapChain);
244 SAFE_RELEASE(data->mainRenderTargetView);
245 SAFE_RELEASE(data->currentOffscreenRenderTargetView);
246 SAFE_RELEASE(data->inputLayout);
247 for (i = 0; i < SDL_arraysize(data->vertexBuffers); ++i) {
248 SAFE_RELEASE(data->vertexBuffers[i]);
249 }
250 SAFE_RELEASE(data->vertexShader);
251 for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) {
252 SAFE_RELEASE(data->pixelShaders[i]);
253 }
254 if (data->blendModesCount > 0) {
255 for (i = 0; i < data->blendModesCount; ++i) {
256 SAFE_RELEASE(data->blendModes[i].blendState);
257 }
258 SDL_free(data->blendModes);
259
260 data->blendModesCount = 0;
261 }
262 SAFE_RELEASE(data->nearestPixelSampler);
263 SAFE_RELEASE(data->linearSampler);
264 SAFE_RELEASE(data->mainRasterizer);
265 SAFE_RELEASE(data->clippedRasterizer);
266 SAFE_RELEASE(data->vertexShaderConstants);
267
268 data->swapEffect = (DXGI_SWAP_EFFECT) 0;
269 data->rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
270 data->currentRenderTargetView = NULL;
271 data->currentRasterizerState = NULL;
272 data->currentBlendState = NULL;
273 data->currentShader = NULL;
274 data->currentShaderResource = NULL;
275 data->currentSampler = NULL;
276
277 /* Unload the D3D libraries. This should be done last, in order
278 * to prevent IUnknown::Release() calls from crashing.
279 */
280 if (data->hD3D11Mod) {
281 SDL_UnloadObject(data->hD3D11Mod);
282 data->hD3D11Mod = NULL;
283 }
284 if (data->hDXGIMod) {
285 SDL_UnloadObject(data->hDXGIMod);
286 data->hDXGIMod = NULL;
287 }
288 }
289 }
290
291 static void
D3D11_DestroyRenderer(SDL_Renderer * renderer)292 D3D11_DestroyRenderer(SDL_Renderer * renderer)
293 {
294 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
295 D3D11_ReleaseAll(renderer);
296 if (data) {
297 SDL_free(data);
298 }
299 SDL_free(renderer);
300 }
301
GetBlendFunc(SDL_BlendFactor factor)302 static D3D11_BLEND GetBlendFunc(SDL_BlendFactor factor)
303 {
304 switch (factor) {
305 case SDL_BLENDFACTOR_ZERO:
306 return D3D11_BLEND_ZERO;
307 case SDL_BLENDFACTOR_ONE:
308 return D3D11_BLEND_ONE;
309 case SDL_BLENDFACTOR_SRC_COLOR:
310 return D3D11_BLEND_SRC_COLOR;
311 case SDL_BLENDFACTOR_ONE_MINUS_SRC_COLOR:
312 return D3D11_BLEND_INV_SRC_COLOR;
313 case SDL_BLENDFACTOR_SRC_ALPHA:
314 return D3D11_BLEND_SRC_ALPHA;
315 case SDL_BLENDFACTOR_ONE_MINUS_SRC_ALPHA:
316 return D3D11_BLEND_INV_SRC_ALPHA;
317 case SDL_BLENDFACTOR_DST_COLOR:
318 return D3D11_BLEND_DEST_COLOR;
319 case SDL_BLENDFACTOR_ONE_MINUS_DST_COLOR:
320 return D3D11_BLEND_INV_DEST_COLOR;
321 case SDL_BLENDFACTOR_DST_ALPHA:
322 return D3D11_BLEND_DEST_ALPHA;
323 case SDL_BLENDFACTOR_ONE_MINUS_DST_ALPHA:
324 return D3D11_BLEND_INV_DEST_ALPHA;
325 default:
326 return (D3D11_BLEND)0;
327 }
328 }
329
GetBlendEquation(SDL_BlendOperation operation)330 static D3D11_BLEND_OP GetBlendEquation(SDL_BlendOperation operation)
331 {
332 switch (operation) {
333 case SDL_BLENDOPERATION_ADD:
334 return D3D11_BLEND_OP_ADD;
335 case SDL_BLENDOPERATION_SUBTRACT:
336 return D3D11_BLEND_OP_SUBTRACT;
337 case SDL_BLENDOPERATION_REV_SUBTRACT:
338 return D3D11_BLEND_OP_REV_SUBTRACT;
339 case SDL_BLENDOPERATION_MINIMUM:
340 return D3D11_BLEND_OP_MIN;
341 case SDL_BLENDOPERATION_MAXIMUM:
342 return D3D11_BLEND_OP_MAX;
343 default:
344 return (D3D11_BLEND_OP)0;
345 }
346 }
347
348 static ID3D11BlendState *
D3D11_CreateBlendState(SDL_Renderer * renderer,SDL_BlendMode blendMode)349 D3D11_CreateBlendState(SDL_Renderer * renderer, SDL_BlendMode blendMode)
350 {
351 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
352 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
353 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
354 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
355 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
356 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
357 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
358 ID3D11BlendState *blendState = NULL;
359 D3D11_BlendMode *blendModes;
360 HRESULT result = S_OK;
361
362 D3D11_BLEND_DESC blendDesc;
363 SDL_zero(blendDesc);
364 blendDesc.AlphaToCoverageEnable = FALSE;
365 blendDesc.IndependentBlendEnable = FALSE;
366 blendDesc.RenderTarget[0].BlendEnable = TRUE;
367 blendDesc.RenderTarget[0].SrcBlend = GetBlendFunc(srcColorFactor);
368 blendDesc.RenderTarget[0].DestBlend = GetBlendFunc(dstColorFactor);
369 blendDesc.RenderTarget[0].BlendOp = GetBlendEquation(colorOperation);
370 blendDesc.RenderTarget[0].SrcBlendAlpha = GetBlendFunc(srcAlphaFactor);
371 blendDesc.RenderTarget[0].DestBlendAlpha = GetBlendFunc(dstAlphaFactor);
372 blendDesc.RenderTarget[0].BlendOpAlpha = GetBlendEquation(alphaOperation);
373 blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
374 result = ID3D11Device_CreateBlendState(data->d3dDevice, &blendDesc, &blendState);
375 if (FAILED(result)) {
376 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBlendState"), result);
377 return NULL;
378 }
379
380 blendModes = (D3D11_BlendMode *)SDL_realloc(data->blendModes, (data->blendModesCount + 1) * sizeof(*blendModes));
381 if (!blendModes) {
382 SAFE_RELEASE(blendState);
383 SDL_OutOfMemory();
384 return NULL;
385 }
386 blendModes[data->blendModesCount].blendMode = blendMode;
387 blendModes[data->blendModesCount].blendState = blendState;
388 data->blendModes = blendModes;
389 ++data->blendModesCount;
390
391 return blendState;
392 }
393
394 /* Create resources that depend on the device. */
395 static HRESULT
D3D11_CreateDeviceResources(SDL_Renderer * renderer)396 D3D11_CreateDeviceResources(SDL_Renderer * renderer)
397 {
398 typedef HRESULT(WINAPI *PFN_CREATE_DXGI_FACTORY)(REFIID riid, void **ppFactory);
399 PFN_CREATE_DXGI_FACTORY CreateDXGIFactoryFunc;
400 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
401 PFN_D3D11_CREATE_DEVICE D3D11CreateDeviceFunc;
402 ID3D11Device *d3dDevice = NULL;
403 ID3D11DeviceContext *d3dContext = NULL;
404 IDXGIDevice1 *dxgiDevice = NULL;
405 HRESULT result = S_OK;
406 UINT creationFlags;
407 int i;
408
409 /* This array defines the set of DirectX hardware feature levels this app will support.
410 * Note the ordering should be preserved.
411 * Don't forget to declare your application's minimum required feature level in its
412 * description. All applications are assumed to support 9.1 unless otherwise stated.
413 */
414 D3D_FEATURE_LEVEL featureLevels[] =
415 {
416 D3D_FEATURE_LEVEL_11_1,
417 D3D_FEATURE_LEVEL_11_0,
418 D3D_FEATURE_LEVEL_10_1,
419 D3D_FEATURE_LEVEL_10_0,
420 D3D_FEATURE_LEVEL_9_3,
421 D3D_FEATURE_LEVEL_9_2,
422 D3D_FEATURE_LEVEL_9_1
423 };
424
425 D3D11_BUFFER_DESC constantBufferDesc;
426 D3D11_SAMPLER_DESC samplerDesc;
427 D3D11_RASTERIZER_DESC rasterDesc;
428
429 #ifdef __WINRT__
430 CreateDXGIFactoryFunc = CreateDXGIFactory1;
431 D3D11CreateDeviceFunc = D3D11CreateDevice;
432 #else
433 data->hDXGIMod = SDL_LoadObject("dxgi.dll");
434 if (!data->hDXGIMod) {
435 result = E_FAIL;
436 goto done;
437 }
438
439 CreateDXGIFactoryFunc = (PFN_CREATE_DXGI_FACTORY)SDL_LoadFunction(data->hDXGIMod, "CreateDXGIFactory");
440 if (!CreateDXGIFactoryFunc) {
441 result = E_FAIL;
442 goto done;
443 }
444
445 data->hD3D11Mod = SDL_LoadObject("d3d11.dll");
446 if (!data->hD3D11Mod) {
447 result = E_FAIL;
448 goto done;
449 }
450
451 D3D11CreateDeviceFunc = (PFN_D3D11_CREATE_DEVICE)SDL_LoadFunction(data->hD3D11Mod, "D3D11CreateDevice");
452 if (!D3D11CreateDeviceFunc) {
453 result = E_FAIL;
454 goto done;
455 }
456 #endif /* __WINRT__ */
457
458 result = CreateDXGIFactoryFunc(&SDL_IID_IDXGIFactory2, (void **)&data->dxgiFactory);
459 if (FAILED(result)) {
460 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("CreateDXGIFactory"), result);
461 goto done;
462 }
463
464 /* FIXME: Should we use the default adapter? */
465 result = IDXGIFactory2_EnumAdapters(data->dxgiFactory, 0, &data->dxgiAdapter);
466 if (FAILED(result)) {
467 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result);
468 goto done;
469 }
470
471 /* This flag adds support for surfaces with a different color channel ordering
472 * than the API default. It is required for compatibility with Direct2D.
473 */
474 creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
475
476 /* Make sure Direct3D's debugging feature gets used, if the app requests it. */
477 if (SDL_GetHintBoolean(SDL_HINT_RENDER_DIRECT3D11_DEBUG, SDL_FALSE)) {
478 creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
479 }
480
481 /* Create the Direct3D 11 API device object and a corresponding context. */
482 result = D3D11CreateDeviceFunc(
483 data->dxgiAdapter,
484 D3D_DRIVER_TYPE_UNKNOWN,
485 NULL,
486 creationFlags, /* Set set debug and Direct2D compatibility flags. */
487 featureLevels, /* List of feature levels this app can support. */
488 SDL_arraysize(featureLevels),
489 D3D11_SDK_VERSION, /* Always set this to D3D11_SDK_VERSION for Windows Store apps. */
490 &d3dDevice, /* Returns the Direct3D device created. */
491 &data->featureLevel, /* Returns feature level of device created. */
492 &d3dContext /* Returns the device immediate context. */
493 );
494 if (FAILED(result)) {
495 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("D3D11CreateDevice"), result);
496 goto done;
497 }
498
499 result = ID3D11Device_QueryInterface(d3dDevice, &SDL_IID_ID3D11Device1, (void **)&data->d3dDevice);
500 if (FAILED(result)) {
501 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device to ID3D11Device1"), result);
502 goto done;
503 }
504
505 result = ID3D11DeviceContext_QueryInterface(d3dContext, &SDL_IID_ID3D11DeviceContext1, (void **)&data->d3dContext);
506 if (FAILED(result)) {
507 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext to ID3D11DeviceContext1"), result);
508 goto done;
509 }
510
511 result = ID3D11Device_QueryInterface(d3dDevice, &SDL_IID_IDXGIDevice1, (void **)&dxgiDevice);
512 if (FAILED(result)) {
513 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device to IDXGIDevice1"), result);
514 goto done;
515 }
516
517 /* Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
518 * ensures that the application will only render after each VSync, minimizing power consumption.
519 */
520 result = IDXGIDevice1_SetMaximumFrameLatency(dxgiDevice, 1);
521 if (FAILED(result)) {
522 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIDevice1::SetMaximumFrameLatency"), result);
523 goto done;
524 }
525
526 /* Make note of the maximum texture size
527 * Max texture sizes are documented on MSDN, at:
528 * http://msdn.microsoft.com/en-us/library/windows/apps/ff476876.aspx
529 */
530 switch (data->featureLevel) {
531 case D3D_FEATURE_LEVEL_11_1:
532 case D3D_FEATURE_LEVEL_11_0:
533 renderer->info.max_texture_width = renderer->info.max_texture_height = 16384;
534 break;
535
536 case D3D_FEATURE_LEVEL_10_1:
537 case D3D_FEATURE_LEVEL_10_0:
538 renderer->info.max_texture_width = renderer->info.max_texture_height = 8192;
539 break;
540
541 case D3D_FEATURE_LEVEL_9_3:
542 renderer->info.max_texture_width = renderer->info.max_texture_height = 4096;
543 break;
544
545 case D3D_FEATURE_LEVEL_9_2:
546 case D3D_FEATURE_LEVEL_9_1:
547 renderer->info.max_texture_width = renderer->info.max_texture_height = 2048;
548 break;
549
550 default:
551 SDL_SetError("%s, Unexpected feature level: %d", __FUNCTION__, data->featureLevel);
552 result = E_FAIL;
553 goto done;
554 }
555
556 if (D3D11_CreateVertexShader(data->d3dDevice, &data->vertexShader, &data->inputLayout) < 0) {
557 goto done;
558 }
559
560 for (i = 0; i < SDL_arraysize(data->pixelShaders); ++i) {
561 if (D3D11_CreatePixelShader(data->d3dDevice, (D3D11_Shader)i, &data->pixelShaders[i]) < 0) {
562 goto done;
563 }
564 }
565
566 /* Setup space to hold vertex shader constants: */
567 SDL_zero(constantBufferDesc);
568 constantBufferDesc.ByteWidth = sizeof(VertexShaderConstants);
569 constantBufferDesc.Usage = D3D11_USAGE_DEFAULT;
570 constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
571 result = ID3D11Device_CreateBuffer(data->d3dDevice,
572 &constantBufferDesc,
573 NULL,
574 &data->vertexShaderConstants
575 );
576 if (FAILED(result)) {
577 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex shader constants]"), result);
578 goto done;
579 }
580
581 /* Create samplers to use when drawing textures: */
582 SDL_zero(samplerDesc);
583 samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
584 samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
585 samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
586 samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
587 samplerDesc.MipLODBias = 0.0f;
588 samplerDesc.MaxAnisotropy = 1;
589 samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
590 samplerDesc.MinLOD = 0.0f;
591 samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
592 result = ID3D11Device_CreateSamplerState(data->d3dDevice,
593 &samplerDesc,
594 &data->nearestPixelSampler
595 );
596 if (FAILED(result)) {
597 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [nearest-pixel filter]"), result);
598 goto done;
599 }
600
601 samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
602 result = ID3D11Device_CreateSamplerState(data->d3dDevice,
603 &samplerDesc,
604 &data->linearSampler
605 );
606 if (FAILED(result)) {
607 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateSamplerState [linear filter]"), result);
608 goto done;
609 }
610
611 /* Setup Direct3D rasterizer states */
612 SDL_zero(rasterDesc);
613 rasterDesc.AntialiasedLineEnable = FALSE;
614 rasterDesc.CullMode = D3D11_CULL_NONE;
615 rasterDesc.DepthBias = 0;
616 rasterDesc.DepthBiasClamp = 0.0f;
617 rasterDesc.DepthClipEnable = TRUE;
618 rasterDesc.FillMode = D3D11_FILL_SOLID;
619 rasterDesc.FrontCounterClockwise = FALSE;
620 rasterDesc.MultisampleEnable = FALSE;
621 rasterDesc.ScissorEnable = FALSE;
622 rasterDesc.SlopeScaledDepthBias = 0.0f;
623 result = ID3D11Device_CreateRasterizerState(data->d3dDevice, &rasterDesc, &data->mainRasterizer);
624 if (FAILED(result)) {
625 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRasterizerState [main rasterizer]"), result);
626 goto done;
627 }
628
629 rasterDesc.ScissorEnable = TRUE;
630 result = ID3D11Device_CreateRasterizerState(data->d3dDevice, &rasterDesc, &data->clippedRasterizer);
631 if (FAILED(result)) {
632 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRasterizerState [clipped rasterizer]"), result);
633 goto done;
634 }
635
636 /* Create blending states: */
637 if (!D3D11_CreateBlendState(renderer, SDL_BLENDMODE_BLEND) ||
638 !D3D11_CreateBlendState(renderer, SDL_BLENDMODE_ADD) ||
639 !D3D11_CreateBlendState(renderer, SDL_BLENDMODE_MOD) ||
640 !D3D11_CreateBlendState(renderer, SDL_BLENDMODE_MUL)) {
641 /* D3D11_CreateBlendMode will set the SDL error, if it fails */
642 goto done;
643 }
644
645 /* Setup render state that doesn't change */
646 ID3D11DeviceContext_IASetInputLayout(data->d3dContext, data->inputLayout);
647 ID3D11DeviceContext_VSSetShader(data->d3dContext, data->vertexShader, NULL, 0);
648 ID3D11DeviceContext_VSSetConstantBuffers(data->d3dContext, 0, 1, &data->vertexShaderConstants);
649
650 done:
651 SAFE_RELEASE(d3dDevice);
652 SAFE_RELEASE(d3dContext);
653 SAFE_RELEASE(dxgiDevice);
654 return result;
655 }
656
657 #ifdef __WIN32__
658
659 static DXGI_MODE_ROTATION
D3D11_GetCurrentRotation()660 D3D11_GetCurrentRotation()
661 {
662 /* FIXME */
663 return DXGI_MODE_ROTATION_IDENTITY;
664 }
665
666 #endif /* __WIN32__ */
667
668 static BOOL
D3D11_IsDisplayRotated90Degrees(DXGI_MODE_ROTATION rotation)669 D3D11_IsDisplayRotated90Degrees(DXGI_MODE_ROTATION rotation)
670 {
671 switch (rotation) {
672 case DXGI_MODE_ROTATION_ROTATE90:
673 case DXGI_MODE_ROTATION_ROTATE270:
674 return TRUE;
675 default:
676 return FALSE;
677 }
678 }
679
680 static int
D3D11_GetRotationForCurrentRenderTarget(SDL_Renderer * renderer)681 D3D11_GetRotationForCurrentRenderTarget(SDL_Renderer * renderer)
682 {
683 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
684 if (data->currentOffscreenRenderTargetView) {
685 return DXGI_MODE_ROTATION_IDENTITY;
686 } else {
687 return data->rotation;
688 }
689 }
690
691 static int
D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer,const SDL_Rect * sdlRect,D3D11_RECT * outRect,BOOL includeViewportOffset)692 D3D11_GetViewportAlignedD3DRect(SDL_Renderer * renderer, const SDL_Rect * sdlRect, D3D11_RECT * outRect, BOOL includeViewportOffset)
693 {
694 const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
695 switch (rotation) {
696 case DXGI_MODE_ROTATION_IDENTITY:
697 outRect->left = sdlRect->x;
698 outRect->right = sdlRect->x + sdlRect->w;
699 outRect->top = sdlRect->y;
700 outRect->bottom = sdlRect->y + sdlRect->h;
701 if (includeViewportOffset) {
702 outRect->left += renderer->viewport.x;
703 outRect->right += renderer->viewport.x;
704 outRect->top += renderer->viewport.y;
705 outRect->bottom += renderer->viewport.y;
706 }
707 break;
708 case DXGI_MODE_ROTATION_ROTATE270:
709 outRect->left = sdlRect->y;
710 outRect->right = sdlRect->y + sdlRect->h;
711 outRect->top = renderer->viewport.w - sdlRect->x - sdlRect->w;
712 outRect->bottom = renderer->viewport.w - sdlRect->x;
713 break;
714 case DXGI_MODE_ROTATION_ROTATE180:
715 outRect->left = renderer->viewport.w - sdlRect->x - sdlRect->w;
716 outRect->right = renderer->viewport.w - sdlRect->x;
717 outRect->top = renderer->viewport.h - sdlRect->y - sdlRect->h;
718 outRect->bottom = renderer->viewport.h - sdlRect->y;
719 break;
720 case DXGI_MODE_ROTATION_ROTATE90:
721 outRect->left = renderer->viewport.h - sdlRect->y - sdlRect->h;
722 outRect->right = renderer->viewport.h - sdlRect->y;
723 outRect->top = sdlRect->x;
724 outRect->bottom = sdlRect->x + sdlRect->h;
725 break;
726 default:
727 return SDL_SetError("The physical display is in an unknown or unsupported rotation");
728 }
729 return 0;
730 }
731
732 static HRESULT
D3D11_CreateSwapChain(SDL_Renderer * renderer,int w,int h)733 D3D11_CreateSwapChain(SDL_Renderer * renderer, int w, int h)
734 {
735 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
736 #ifdef __WINRT__
737 IUnknown *coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer);
738 const BOOL usingXAML = (coreWindow == NULL);
739 #else
740 IUnknown *coreWindow = NULL;
741 const BOOL usingXAML = FALSE;
742 #endif
743 HRESULT result = S_OK;
744
745 /* Create a swap chain using the same adapter as the existing Direct3D device. */
746 DXGI_SWAP_CHAIN_DESC1 swapChainDesc;
747 SDL_zero(swapChainDesc);
748 swapChainDesc.Width = w;
749 swapChainDesc.Height = h;
750 swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; /* This is the most common swap chain format. */
751 swapChainDesc.Stereo = FALSE;
752 swapChainDesc.SampleDesc.Count = 1; /* Don't use multi-sampling. */
753 swapChainDesc.SampleDesc.Quality = 0;
754 swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
755 swapChainDesc.BufferCount = 2; /* Use double-buffering to minimize latency. */
756 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
757 swapChainDesc.Scaling = DXGI_SCALING_STRETCH; /* On phone, only stretch and aspect-ratio stretch scaling are allowed. */
758 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; /* On phone, no swap effects are supported. */
759 /* TODO, WinRT: see if Win 8.x DXGI_SWAP_CHAIN_DESC1 settings are available on Windows Phone 8.1, and if there's any advantage to having them on */
760 #else
761 if (usingXAML) {
762 swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
763 } else {
764 swapChainDesc.Scaling = DXGI_SCALING_NONE;
765 }
766 swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; /* All Windows Store apps must use this SwapEffect. */
767 #endif
768 swapChainDesc.Flags = 0;
769
770 if (coreWindow) {
771 result = IDXGIFactory2_CreateSwapChainForCoreWindow(data->dxgiFactory,
772 (IUnknown *)data->d3dDevice,
773 coreWindow,
774 &swapChainDesc,
775 NULL, /* Allow on all displays. */
776 &data->swapChain
777 );
778 if (FAILED(result)) {
779 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForCoreWindow"), result);
780 goto done;
781 }
782 } else if (usingXAML) {
783 result = IDXGIFactory2_CreateSwapChainForComposition(data->dxgiFactory,
784 (IUnknown *)data->d3dDevice,
785 &swapChainDesc,
786 NULL,
787 &data->swapChain);
788 if (FAILED(result)) {
789 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForComposition"), result);
790 goto done;
791 }
792
793 #if WINAPI_FAMILY == WINAPI_FAMILY_APP
794 result = ISwapChainBackgroundPanelNative_SetSwapChain(WINRT_GlobalSwapChainBackgroundPanelNative, (IDXGISwapChain *) data->swapChain);
795 if (FAILED(result)) {
796 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ISwapChainBackgroundPanelNative::SetSwapChain"), result);
797 goto done;
798 }
799 #else
800 SDL_SetError(SDL_COMPOSE_ERROR("XAML support is not yet available for Windows Phone"));
801 result = E_FAIL;
802 goto done;
803 #endif
804 } else {
805 #ifdef __WIN32__
806 SDL_SysWMinfo windowinfo;
807 SDL_VERSION(&windowinfo.version);
808 SDL_GetWindowWMInfo(renderer->window, &windowinfo);
809
810 result = IDXGIFactory2_CreateSwapChainForHwnd(data->dxgiFactory,
811 (IUnknown *)data->d3dDevice,
812 windowinfo.info.win.window,
813 &swapChainDesc,
814 NULL,
815 NULL, /* Allow on all displays. */
816 &data->swapChain
817 );
818 if (FAILED(result)) {
819 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGIFactory2::CreateSwapChainForHwnd"), result);
820 goto done;
821 }
822
823 IDXGIFactory_MakeWindowAssociation(data->dxgiFactory, windowinfo.info.win.window, DXGI_MWA_NO_WINDOW_CHANGES);
824 #else
825 SDL_SetError(__FUNCTION__", Unable to find something to attach a swap chain to");
826 goto done;
827 #endif /* ifdef __WIN32__ / else */
828 }
829 data->swapEffect = swapChainDesc.SwapEffect;
830
831 done:
832 SAFE_RELEASE(coreWindow);
833 return result;
834 }
835
836 static void
D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer)837 D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer)
838 {
839 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
840 ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL);
841 SAFE_RELEASE(data->mainRenderTargetView);
842 }
843
844 static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
845
846
847 HRESULT
D3D11_HandleDeviceLost(SDL_Renderer * renderer)848 D3D11_HandleDeviceLost(SDL_Renderer * renderer)
849 {
850 HRESULT result = S_OK;
851
852 D3D11_ReleaseAll(renderer);
853
854 result = D3D11_CreateDeviceResources(renderer);
855 if (FAILED(result)) {
856 /* D3D11_CreateDeviceResources will set the SDL error */
857 return result;
858 }
859
860 result = D3D11_UpdateForWindowSizeChange(renderer);
861 if (FAILED(result)) {
862 /* D3D11_UpdateForWindowSizeChange will set the SDL error */
863 return result;
864 }
865
866 /* Let the application know that the device has been reset */
867 {
868 SDL_Event event;
869 event.type = SDL_RENDER_DEVICE_RESET;
870 SDL_PushEvent(&event);
871 }
872
873 return S_OK;
874 }
875
876 /* Initialize all resources that change when the window's size changes. */
877 static HRESULT
D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)878 D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
879 {
880 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
881 ID3D11Texture2D *backBuffer = NULL;
882 HRESULT result = S_OK;
883 int w, h;
884
885 /* Release the previous render target view */
886 D3D11_ReleaseMainRenderTargetView(renderer);
887
888 /* The width and height of the swap chain must be based on the display's
889 * non-rotated size.
890 */
891 SDL_GetWindowSize(renderer->window, &w, &h);
892 data->rotation = D3D11_GetCurrentRotation();
893 /* SDL_Log("%s: windowSize={%d,%d}, orientation=%d\n", __FUNCTION__, w, h, (int)data->rotation); */
894 if (D3D11_IsDisplayRotated90Degrees(data->rotation)) {
895 int tmp = w;
896 w = h;
897 h = tmp;
898 }
899
900 if (data->swapChain) {
901 /* IDXGISwapChain::ResizeBuffers is not available on Windows Phone 8. */
902 #if !defined(__WINRT__) || (WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP)
903 /* If the swap chain already exists, resize it. */
904 result = IDXGISwapChain_ResizeBuffers(data->swapChain,
905 0,
906 w, h,
907 DXGI_FORMAT_UNKNOWN,
908 0
909 );
910 if (result == DXGI_ERROR_DEVICE_REMOVED) {
911 /* If the device was removed for any reason, a new device and swap chain will need to be created. */
912 D3D11_HandleDeviceLost(renderer);
913
914 /* Everything is set up now. Do not continue execution of this method. HandleDeviceLost will reenter this method
915 * and correctly set up the new device.
916 */
917 goto done;
918 } else if (FAILED(result)) {
919 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::ResizeBuffers"), result);
920 goto done;
921 }
922 #endif
923 } else {
924 result = D3D11_CreateSwapChain(renderer, w, h);
925 if (FAILED(result)) {
926 goto done;
927 }
928 }
929
930 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
931 /* Set the proper rotation for the swap chain.
932 *
933 * To note, the call for this, IDXGISwapChain1::SetRotation, is not necessary
934 * on Windows Phone 8.0, nor is it supported there.
935 *
936 * IDXGISwapChain1::SetRotation does seem to be available on Windows Phone 8.1,
937 * however I've yet to find a way to make it work. It might have something to
938 * do with IDXGISwapChain::ResizeBuffers appearing to not being available on
939 * Windows Phone 8.1 (it wasn't on Windows Phone 8.0), but I'm not 100% sure of this.
940 * The call doesn't appear to be entirely necessary though, and is a performance-related
941 * call, at least according to the following page on MSDN:
942 * http://code.msdn.microsoft.com/windowsapps/DXGI-swap-chain-rotation-21d13d71
943 * -- David L.
944 *
945 * TODO, WinRT: reexamine the docs for IDXGISwapChain1::SetRotation, see if might be available, usable, and prudent-to-call on WinPhone 8.1
946 */
947 if (data->swapEffect == DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL) {
948 result = IDXGISwapChain1_SetRotation(data->swapChain, data->rotation);
949 if (FAILED(result)) {
950 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain1::SetRotation"), result);
951 goto done;
952 }
953 }
954 #endif
955
956 result = IDXGISwapChain_GetBuffer(data->swapChain,
957 0,
958 &SDL_IID_ID3D11Texture2D,
959 (void **)&backBuffer
960 );
961 if (FAILED(result)) {
962 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::GetBuffer [back-buffer]"), result);
963 goto done;
964 }
965
966 /* Create a render target view of the swap chain back buffer. */
967 result = ID3D11Device_CreateRenderTargetView(data->d3dDevice,
968 (ID3D11Resource *)backBuffer,
969 NULL,
970 &data->mainRenderTargetView
971 );
972 if (FAILED(result)) {
973 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device::CreateRenderTargetView"), result);
974 goto done;
975 }
976
977 data->viewportDirty = SDL_TRUE;
978
979 done:
980 SAFE_RELEASE(backBuffer);
981 return result;
982 }
983
984 /* This method is called when the window's size changes. */
985 static HRESULT
D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)986 D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
987 {
988 return D3D11_CreateWindowSizeDependentResources(renderer);
989 }
990
991 void
D3D11_Trim(SDL_Renderer * renderer)992 D3D11_Trim(SDL_Renderer * renderer)
993 {
994 #ifdef __WINRT__
995 #if NTDDI_VERSION > NTDDI_WIN8
996 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
997 HRESULT result = S_OK;
998 IDXGIDevice3 *dxgiDevice = NULL;
999
1000 result = ID3D11Device_QueryInterface(data->d3dDevice, &SDL_IID_IDXGIDevice3, &dxgiDevice);
1001 if (FAILED(result)) {
1002 //WIN_SetErrorFromHRESULT(__FUNCTION__ ", ID3D11Device to IDXGIDevice3", result);
1003 return;
1004 }
1005
1006 IDXGIDevice3_Trim(dxgiDevice);
1007 SAFE_RELEASE(dxgiDevice);
1008 #endif
1009 #endif
1010 }
1011
1012 static void
D3D11_WindowEvent(SDL_Renderer * renderer,const SDL_WindowEvent * event)1013 D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
1014 {
1015 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) {
1016 D3D11_UpdateForWindowSizeChange(renderer);
1017 }
1018 }
1019
1020 static SDL_bool
D3D11_SupportsBlendMode(SDL_Renderer * renderer,SDL_BlendMode blendMode)1021 D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode)
1022 {
1023 SDL_BlendFactor srcColorFactor = SDL_GetBlendModeSrcColorFactor(blendMode);
1024 SDL_BlendFactor srcAlphaFactor = SDL_GetBlendModeSrcAlphaFactor(blendMode);
1025 SDL_BlendOperation colorOperation = SDL_GetBlendModeColorOperation(blendMode);
1026 SDL_BlendFactor dstColorFactor = SDL_GetBlendModeDstColorFactor(blendMode);
1027 SDL_BlendFactor dstAlphaFactor = SDL_GetBlendModeDstAlphaFactor(blendMode);
1028 SDL_BlendOperation alphaOperation = SDL_GetBlendModeAlphaOperation(blendMode);
1029
1030 if (!GetBlendFunc(srcColorFactor) || !GetBlendFunc(srcAlphaFactor) ||
1031 !GetBlendEquation(colorOperation) ||
1032 !GetBlendFunc(dstColorFactor) || !GetBlendFunc(dstAlphaFactor) ||
1033 !GetBlendEquation(alphaOperation)) {
1034 return SDL_FALSE;
1035 }
1036 return SDL_TRUE;
1037 }
1038
1039 static int
D3D11_CreateTexture(SDL_Renderer * renderer,SDL_Texture * texture)1040 D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1041 {
1042 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
1043 D3D11_TextureData *textureData;
1044 HRESULT result;
1045 DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format);
1046 D3D11_TEXTURE2D_DESC textureDesc;
1047 D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
1048
1049 if (textureFormat == DXGI_FORMAT_UNKNOWN) {
1050 return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified",
1051 __FUNCTION__, texture->format);
1052 }
1053
1054 textureData = (D3D11_TextureData*) SDL_calloc(1, sizeof(*textureData));
1055 if (!textureData) {
1056 SDL_OutOfMemory();
1057 return -1;
1058 }
1059 textureData->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
1060
1061 texture->driverdata = textureData;
1062
1063 SDL_zero(textureDesc);
1064 textureDesc.Width = texture->w;
1065 textureDesc.Height = texture->h;
1066 textureDesc.MipLevels = 1;
1067 textureDesc.ArraySize = 1;
1068 textureDesc.Format = textureFormat;
1069 textureDesc.SampleDesc.Count = 1;
1070 textureDesc.SampleDesc.Quality = 0;
1071 textureDesc.MiscFlags = 0;
1072
1073 if (texture->access == SDL_TEXTUREACCESS_STREAMING) {
1074 textureDesc.Usage = D3D11_USAGE_DYNAMIC;
1075 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1076 } else {
1077 textureDesc.Usage = D3D11_USAGE_DEFAULT;
1078 textureDesc.CPUAccessFlags = 0;
1079 }
1080
1081 if (texture->access == SDL_TEXTUREACCESS_TARGET) {
1082 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET;
1083 } else {
1084 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
1085 }
1086
1087 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
1088 &textureDesc,
1089 NULL,
1090 &textureData->mainTexture
1091 );
1092 if (FAILED(result)) {
1093 D3D11_DestroyTexture(renderer, texture);
1094 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
1095 return -1;
1096 }
1097
1098 if (texture->format == SDL_PIXELFORMAT_YV12 ||
1099 texture->format == SDL_PIXELFORMAT_IYUV) {
1100 textureData->yuv = SDL_TRUE;
1101
1102 textureDesc.Width = (textureDesc.Width + 1) / 2;
1103 textureDesc.Height = (textureDesc.Height + 1) / 2;
1104
1105 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
1106 &textureDesc,
1107 NULL,
1108 &textureData->mainTextureU
1109 );
1110 if (FAILED(result)) {
1111 D3D11_DestroyTexture(renderer, texture);
1112 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
1113 return -1;
1114 }
1115
1116 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
1117 &textureDesc,
1118 NULL,
1119 &textureData->mainTextureV
1120 );
1121 if (FAILED(result)) {
1122 D3D11_DestroyTexture(renderer, texture);
1123 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
1124 return -1;
1125 }
1126 }
1127
1128 if (texture->format == SDL_PIXELFORMAT_NV12 ||
1129 texture->format == SDL_PIXELFORMAT_NV21) {
1130 D3D11_TEXTURE2D_DESC nvTextureDesc = textureDesc;
1131
1132 textureData->nv12 = SDL_TRUE;
1133
1134 nvTextureDesc.Format = DXGI_FORMAT_R8G8_UNORM;
1135 nvTextureDesc.Width = (textureDesc.Width + 1) / 2;
1136 nvTextureDesc.Height = (textureDesc.Height + 1) / 2;
1137
1138 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
1139 &nvTextureDesc,
1140 NULL,
1141 &textureData->mainTextureNV
1142 );
1143 if (FAILED(result)) {
1144 D3D11_DestroyTexture(renderer, texture);
1145 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result);
1146 return -1;
1147 }
1148 }
1149
1150 resourceViewDesc.Format = textureDesc.Format;
1151 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
1152 resourceViewDesc.Texture2D.MostDetailedMip = 0;
1153 resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
1154 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
1155 (ID3D11Resource *)textureData->mainTexture,
1156 &resourceViewDesc,
1157 &textureData->mainTextureResourceView
1158 );
1159 if (FAILED(result)) {
1160 D3D11_DestroyTexture(renderer, texture);
1161 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
1162 return -1;
1163 }
1164
1165 if (textureData->yuv) {
1166 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
1167 (ID3D11Resource *)textureData->mainTextureU,
1168 &resourceViewDesc,
1169 &textureData->mainTextureResourceViewU
1170 );
1171 if (FAILED(result)) {
1172 D3D11_DestroyTexture(renderer, texture);
1173 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
1174 return -1;
1175 }
1176 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
1177 (ID3D11Resource *)textureData->mainTextureV,
1178 &resourceViewDesc,
1179 &textureData->mainTextureResourceViewV
1180 );
1181 if (FAILED(result)) {
1182 D3D11_DestroyTexture(renderer, texture);
1183 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
1184 return -1;
1185 }
1186 }
1187
1188 if (textureData->nv12) {
1189 D3D11_SHADER_RESOURCE_VIEW_DESC nvResourceViewDesc = resourceViewDesc;
1190
1191 nvResourceViewDesc.Format = DXGI_FORMAT_R8G8_UNORM;
1192
1193 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice,
1194 (ID3D11Resource *)textureData->mainTextureNV,
1195 &nvResourceViewDesc,
1196 &textureData->mainTextureResourceViewNV
1197 );
1198 if (FAILED(result)) {
1199 D3D11_DestroyTexture(renderer, texture);
1200 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result);
1201 return -1;
1202 }
1203 }
1204
1205 if (texture->access & SDL_TEXTUREACCESS_TARGET) {
1206 D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc;
1207 renderTargetViewDesc.Format = textureDesc.Format;
1208 renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D;
1209 renderTargetViewDesc.Texture2D.MipSlice = 0;
1210
1211 result = ID3D11Device_CreateRenderTargetView(rendererData->d3dDevice,
1212 (ID3D11Resource *)textureData->mainTexture,
1213 &renderTargetViewDesc,
1214 &textureData->mainTextureRenderTargetView);
1215 if (FAILED(result)) {
1216 D3D11_DestroyTexture(renderer, texture);
1217 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRenderTargetView"), result);
1218 return -1;
1219 }
1220 }
1221
1222 return 0;
1223 }
1224
1225 static void
D3D11_DestroyTexture(SDL_Renderer * renderer,SDL_Texture * texture)1226 D3D11_DestroyTexture(SDL_Renderer * renderer,
1227 SDL_Texture * texture)
1228 {
1229 D3D11_TextureData *data = (D3D11_TextureData *)texture->driverdata;
1230
1231 if (!data) {
1232 return;
1233 }
1234
1235 SAFE_RELEASE(data->mainTexture);
1236 SAFE_RELEASE(data->mainTextureResourceView);
1237 SAFE_RELEASE(data->mainTextureRenderTargetView);
1238 SAFE_RELEASE(data->stagingTexture);
1239 SAFE_RELEASE(data->mainTextureU);
1240 SAFE_RELEASE(data->mainTextureResourceViewU);
1241 SAFE_RELEASE(data->mainTextureV);
1242 SAFE_RELEASE(data->mainTextureResourceViewV);
1243 SDL_free(data->pixels);
1244 SDL_free(data);
1245 texture->driverdata = NULL;
1246 }
1247
1248 static int
D3D11_UpdateTextureInternal(D3D11_RenderData * rendererData,ID3D11Texture2D * texture,int bpp,int x,int y,int w,int h,const void * pixels,int pitch)1249 D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch)
1250 {
1251 ID3D11Texture2D *stagingTexture;
1252 const Uint8 *src;
1253 Uint8 *dst;
1254 int row;
1255 UINT length;
1256 HRESULT result;
1257 D3D11_TEXTURE2D_DESC stagingTextureDesc;
1258 D3D11_MAPPED_SUBRESOURCE textureMemory;
1259
1260 /* Create a 'staging' texture, which will be used to write to a portion of the main texture. */
1261 ID3D11Texture2D_GetDesc(texture, &stagingTextureDesc);
1262 stagingTextureDesc.Width = w;
1263 stagingTextureDesc.Height = h;
1264 stagingTextureDesc.BindFlags = 0;
1265 stagingTextureDesc.MiscFlags = 0;
1266 stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1267 stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
1268 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
1269 &stagingTextureDesc,
1270 NULL,
1271 &stagingTexture);
1272 if (FAILED(result)) {
1273 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result);
1274 return -1;
1275 }
1276
1277 /* Get a write-only pointer to data in the staging texture: */
1278 result = ID3D11DeviceContext_Map(rendererData->d3dContext,
1279 (ID3D11Resource *)stagingTexture,
1280 0,
1281 D3D11_MAP_WRITE,
1282 0,
1283 &textureMemory
1284 );
1285 if (FAILED(result)) {
1286 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result);
1287 SAFE_RELEASE(stagingTexture);
1288 return -1;
1289 }
1290
1291 src = (const Uint8 *)pixels;
1292 dst = textureMemory.pData;
1293 length = w * bpp;
1294 if (length == pitch && length == textureMemory.RowPitch) {
1295 SDL_memcpy(dst, src, length*h);
1296 } else {
1297 if (length > (UINT)pitch) {
1298 length = pitch;
1299 }
1300 if (length > textureMemory.RowPitch) {
1301 length = textureMemory.RowPitch;
1302 }
1303 for (row = 0; row < h; ++row) {
1304 SDL_memcpy(dst, src, length);
1305 src += pitch;
1306 dst += textureMemory.RowPitch;
1307 }
1308 }
1309
1310 /* Commit the pixel buffer's changes back to the staging texture: */
1311 ID3D11DeviceContext_Unmap(rendererData->d3dContext,
1312 (ID3D11Resource *)stagingTexture,
1313 0);
1314
1315 /* Copy the staging texture's contents back to the texture: */
1316 ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext,
1317 (ID3D11Resource *)texture,
1318 0,
1319 x,
1320 y,
1321 0,
1322 (ID3D11Resource *)stagingTexture,
1323 0,
1324 NULL);
1325
1326 SAFE_RELEASE(stagingTexture);
1327
1328 return 0;
1329 }
1330
1331 static int
D3D11_UpdateTexture(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * rect,const void * srcPixels,int srcPitch)1332 D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1333 const SDL_Rect * rect, const void * srcPixels,
1334 int srcPitch)
1335 {
1336 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
1337 D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata;
1338
1339 if (!textureData) {
1340 SDL_SetError("Texture is not currently available");
1341 return -1;
1342 }
1343
1344 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch) < 0) {
1345 return -1;
1346 }
1347
1348 if (textureData->yuv) {
1349 /* Skip to the correct offset into the next texture */
1350 srcPixels = (const void*)((const Uint8*)srcPixels + rect->h * srcPitch);
1351
1352 if (D3D11_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureV : textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2) < 0) {
1353 return -1;
1354 }
1355
1356 /* Skip to the correct offset into the next texture */
1357 srcPixels = (const void*)((const Uint8*)srcPixels + ((rect->h + 1) / 2) * ((srcPitch + 1) / 2));
1358 if (D3D11_UpdateTextureInternal(rendererData, texture->format == SDL_PIXELFORMAT_YV12 ? textureData->mainTextureU : textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, (rect->w + 1) / 2, (rect->h + 1) / 2, srcPixels, (srcPitch + 1) / 2) < 0) {
1359 return -1;
1360 }
1361 }
1362
1363 if (textureData->nv12) {
1364 /* Skip to the correct offset into the next texture */
1365 srcPixels = (const void*)((const Uint8*)srcPixels + rect->h * srcPitch);
1366
1367 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureNV, 2, rect->x / 2, rect->y / 2, ((rect->w + 1) / 2), (rect->h + 1) / 2, srcPixels, 2*((srcPitch + 1) / 2)) < 0) {
1368 return -1;
1369 }
1370 }
1371 return 0;
1372 }
1373
1374 static int
D3D11_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)1375 D3D11_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture,
1376 const SDL_Rect * rect,
1377 const Uint8 *Yplane, int Ypitch,
1378 const Uint8 *Uplane, int Upitch,
1379 const Uint8 *Vplane, int Vpitch)
1380 {
1381 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
1382 D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata;
1383
1384 if (!textureData) {
1385 SDL_SetError("Texture is not currently available");
1386 return -1;
1387 }
1388
1389 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) {
1390 return -1;
1391 }
1392 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureU, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Uplane, Upitch) < 0) {
1393 return -1;
1394 }
1395 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTextureV, SDL_BYTESPERPIXEL(texture->format), rect->x / 2, rect->y / 2, rect->w / 2, rect->h / 2, Vplane, Vpitch) < 0) {
1396 return -1;
1397 }
1398 return 0;
1399 }
1400
1401 static int
D3D11_LockTexture(SDL_Renderer * renderer,SDL_Texture * texture,const SDL_Rect * rect,void ** pixels,int * pitch)1402 D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
1403 const SDL_Rect * rect, void **pixels, int *pitch)
1404 {
1405 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
1406 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
1407 HRESULT result = S_OK;
1408 D3D11_TEXTURE2D_DESC stagingTextureDesc;
1409 D3D11_MAPPED_SUBRESOURCE textureMemory;
1410
1411 if (!textureData) {
1412 SDL_SetError("Texture is not currently available");
1413 return -1;
1414 }
1415
1416 if (textureData->yuv || textureData->nv12) {
1417 /* It's more efficient to upload directly... */
1418 if (!textureData->pixels) {
1419 textureData->pitch = texture->w;
1420 textureData->pixels = (Uint8 *)SDL_malloc((texture->h * textureData->pitch * 3) / 2);
1421 if (!textureData->pixels) {
1422 return SDL_OutOfMemory();
1423 }
1424 }
1425 textureData->locked_rect = *rect;
1426 *pixels =
1427 (void *)((Uint8 *)textureData->pixels + rect->y * textureData->pitch +
1428 rect->x * SDL_BYTESPERPIXEL(texture->format));
1429 *pitch = textureData->pitch;
1430 return 0;
1431 }
1432
1433 if (textureData->stagingTexture) {
1434 return SDL_SetError("texture is already locked");
1435 }
1436
1437 /* Create a 'staging' texture, which will be used to write to a portion
1438 * of the main texture. This is necessary, as Direct3D 11.1 does not
1439 * have the ability to write a CPU-bound pixel buffer to a rectangular
1440 * subrect of a texture. Direct3D 11.1 can, however, write a pixel
1441 * buffer to an entire texture, hence the use of a staging texture.
1442 *
1443 * TODO, WinRT: consider avoiding the use of a staging texture in D3D11_LockTexture if/when the entire texture is being updated
1444 */
1445 ID3D11Texture2D_GetDesc(textureData->mainTexture, &stagingTextureDesc);
1446 stagingTextureDesc.Width = rect->w;
1447 stagingTextureDesc.Height = rect->h;
1448 stagingTextureDesc.BindFlags = 0;
1449 stagingTextureDesc.MiscFlags = 0;
1450 stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1451 stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
1452 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice,
1453 &stagingTextureDesc,
1454 NULL,
1455 &textureData->stagingTexture);
1456 if (FAILED(result)) {
1457 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result);
1458 return -1;
1459 }
1460
1461 /* Get a write-only pointer to data in the staging texture: */
1462 result = ID3D11DeviceContext_Map(rendererData->d3dContext,
1463 (ID3D11Resource *)textureData->stagingTexture,
1464 0,
1465 D3D11_MAP_WRITE,
1466 0,
1467 &textureMemory
1468 );
1469 if (FAILED(result)) {
1470 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result);
1471 SAFE_RELEASE(textureData->stagingTexture);
1472 return -1;
1473 }
1474
1475 /* Make note of where the staging texture will be written to
1476 * (on a call to SDL_UnlockTexture):
1477 */
1478 textureData->lockedTexturePositionX = rect->x;
1479 textureData->lockedTexturePositionY = rect->y;
1480
1481 /* Make sure the caller has information on the texture's pixel buffer,
1482 * then return:
1483 */
1484 *pixels = textureMemory.pData;
1485 *pitch = textureMemory.RowPitch;
1486 return 0;
1487 }
1488
1489 static void
D3D11_UnlockTexture(SDL_Renderer * renderer,SDL_Texture * texture)1490 D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture)
1491 {
1492 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
1493 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
1494
1495 if (!textureData) {
1496 return;
1497 }
1498
1499 if (textureData->yuv || textureData->nv12) {
1500 const SDL_Rect *rect = &textureData->locked_rect;
1501 void *pixels =
1502 (void *) ((Uint8 *) textureData->pixels + rect->y * textureData->pitch +
1503 rect->x * SDL_BYTESPERPIXEL(texture->format));
1504 D3D11_UpdateTexture(renderer, texture, rect, pixels, textureData->pitch);
1505 return;
1506 }
1507
1508 /* Commit the pixel buffer's changes back to the staging texture: */
1509 ID3D11DeviceContext_Unmap(rendererData->d3dContext,
1510 (ID3D11Resource *)textureData->stagingTexture,
1511 0);
1512
1513 /* Copy the staging texture's contents back to the main texture: */
1514 ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext,
1515 (ID3D11Resource *)textureData->mainTexture,
1516 0,
1517 textureData->lockedTexturePositionX,
1518 textureData->lockedTexturePositionY,
1519 0,
1520 (ID3D11Resource *)textureData->stagingTexture,
1521 0,
1522 NULL);
1523
1524 SAFE_RELEASE(textureData->stagingTexture);
1525 }
1526
1527 static void
D3D11_SetTextureScaleMode(SDL_Renderer * renderer,SDL_Texture * texture,SDL_ScaleMode scaleMode)1528 D3D11_SetTextureScaleMode(SDL_Renderer * renderer, SDL_Texture * texture, SDL_ScaleMode scaleMode)
1529 {
1530 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
1531
1532 if (!textureData) {
1533 return;
1534 }
1535
1536 textureData->scaleMode = (scaleMode == SDL_ScaleModeNearest) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR;
1537 }
1538
1539 static int
D3D11_SetRenderTarget(SDL_Renderer * renderer,SDL_Texture * texture)1540 D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture)
1541 {
1542 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
1543 D3D11_TextureData *textureData = NULL;
1544
1545 if (texture == NULL) {
1546 rendererData->currentOffscreenRenderTargetView = NULL;
1547 return 0;
1548 }
1549
1550 textureData = (D3D11_TextureData *) texture->driverdata;
1551
1552 if (!textureData->mainTextureRenderTargetView) {
1553 return SDL_SetError("specified texture is not a render target");
1554 }
1555
1556 rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView;
1557
1558 return 0;
1559 }
1560
1561 static int
D3D11_QueueSetViewport(SDL_Renderer * renderer,SDL_RenderCommand * cmd)1562 D3D11_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
1563 {
1564 return 0; /* nothing to do in this backend. */
1565 }
1566
1567 static int
D3D11_QueueDrawPoints(SDL_Renderer * renderer,SDL_RenderCommand * cmd,const SDL_FPoint * points,int count)1568 D3D11_QueueDrawPoints(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FPoint * points, int count)
1569 {
1570 VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, count * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
1571 const float r = (float)(cmd->data.draw.r / 255.0f);
1572 const float g = (float)(cmd->data.draw.g / 255.0f);
1573 const float b = (float)(cmd->data.draw.b / 255.0f);
1574 const float a = (float)(cmd->data.draw.a / 255.0f);
1575 int i;
1576
1577 if (!verts) {
1578 return -1;
1579 }
1580
1581 cmd->data.draw.count = count;
1582
1583 for (i = 0; i < count; i++) {
1584 verts->pos.x = points[i].x + 0.5f;
1585 verts->pos.y = points[i].y + 0.5f;
1586 verts->pos.z = 0.0f;
1587 verts->tex.x = 0.0f;
1588 verts->tex.y = 0.0f;
1589 verts->color.x = r;
1590 verts->color.y = g;
1591 verts->color.z = b;
1592 verts->color.w = a;
1593 verts++;
1594 }
1595
1596 return 0;
1597 }
1598
1599 static int
D3D11_QueueFillRects(SDL_Renderer * renderer,SDL_RenderCommand * cmd,const SDL_FRect * rects,int count)1600 D3D11_QueueFillRects(SDL_Renderer * renderer, SDL_RenderCommand *cmd, const SDL_FRect * rects, int count)
1601 {
1602 VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, count * 4 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
1603 const float r = (float)(cmd->data.draw.r / 255.0f);
1604 const float g = (float)(cmd->data.draw.g / 255.0f);
1605 const float b = (float)(cmd->data.draw.b / 255.0f);
1606 const float a = (float)(cmd->data.draw.a / 255.0f);
1607 int i;
1608
1609 if (!verts) {
1610 return -1;
1611 }
1612
1613 cmd->data.draw.count = count;
1614
1615 for (i = 0; i < count; i++) {
1616 verts->pos.x = rects[i].x;
1617 verts->pos.y = rects[i].y;
1618 verts->pos.z = 0.0f;
1619 verts->tex.x = 0.0f;
1620 verts->tex.y = 0.0f;
1621 verts->color.x = r;
1622 verts->color.y = g;
1623 verts->color.z = b;
1624 verts->color.w = a;
1625 verts++;
1626
1627 verts->pos.x = rects[i].x;
1628 verts->pos.y = rects[i].y + rects[i].h;
1629 verts->pos.z = 0.0f;
1630 verts->tex.x = 0.0f;
1631 verts->tex.y = 0.0f;
1632 verts->color.x = r;
1633 verts->color.y = g;
1634 verts->color.z = b;
1635 verts->color.w = a;
1636 verts++;
1637
1638 verts->pos.x = rects[i].x + rects[i].w;
1639 verts->pos.y = rects[i].y;
1640 verts->pos.z = 0.0f;
1641 verts->tex.x = 0.0f;
1642 verts->tex.y = 0.0f;
1643 verts->color.x = r;
1644 verts->color.y = g;
1645 verts->color.z = b;
1646 verts->color.w = a;
1647 verts++;
1648
1649 verts->pos.x = rects[i].x + rects[i].w;
1650 verts->pos.y = rects[i].y + rects[i].h;
1651 verts->pos.z = 0.0f;
1652 verts->tex.x = 0.0f;
1653 verts->tex.y = 0.0f;
1654 verts->color.x = r;
1655 verts->color.y = g;
1656 verts->color.z = b;
1657 verts->color.w = a;
1658 verts++;
1659 }
1660
1661 return 0;
1662 }
1663
1664 static int
D3D11_QueueCopy(SDL_Renderer * renderer,SDL_RenderCommand * cmd,SDL_Texture * texture,const SDL_Rect * srcrect,const SDL_FRect * dstrect)1665 D3D11_QueueCopy(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
1666 const SDL_Rect * srcrect, const SDL_FRect * dstrect)
1667 {
1668 VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, 4 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
1669 const float r = (float)(cmd->data.draw.r / 255.0f);
1670 const float g = (float)(cmd->data.draw.g / 255.0f);
1671 const float b = (float)(cmd->data.draw.b / 255.0f);
1672 const float a = (float)(cmd->data.draw.a / 255.0f);
1673 const float minu = (float) srcrect->x / texture->w;
1674 const float maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1675 const float minv = (float) srcrect->y / texture->h;
1676 const float maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1677
1678 if (!verts) {
1679 return -1;
1680 }
1681
1682 cmd->data.draw.count = 1;
1683
1684 verts->pos.x = dstrect->x;
1685 verts->pos.y = dstrect->y;
1686 verts->pos.z = 0.0f;
1687 verts->tex.x = minu;
1688 verts->tex.y = minv;
1689 verts->color.x = r;
1690 verts->color.y = g;
1691 verts->color.z = b;
1692 verts->color.w = a;
1693 verts++;
1694
1695 verts->pos.x = dstrect->x;
1696 verts->pos.y = dstrect->y + dstrect->h;
1697 verts->pos.z = 0.0f;
1698 verts->tex.x = minu;
1699 verts->tex.y = maxv;
1700 verts->color.x = r;
1701 verts->color.y = g;
1702 verts->color.z = b;
1703 verts->color.w = a;
1704 verts++;
1705
1706 verts->pos.x = dstrect->x + dstrect->w;
1707 verts->pos.y = dstrect->y;
1708 verts->pos.z = 0.0f;
1709 verts->tex.x = maxu;
1710 verts->tex.y = minv;
1711 verts->color.x = r;
1712 verts->color.y = g;
1713 verts->color.z = b;
1714 verts->color.w = a;
1715 verts++;
1716
1717 verts->pos.x = dstrect->x + dstrect->w;
1718 verts->pos.y = dstrect->y + dstrect->h;
1719 verts->pos.z = 0.0f;
1720 verts->tex.x = maxu;
1721 verts->tex.y = maxv;
1722 verts->color.x = r;
1723 verts->color.y = g;
1724 verts->color.z = b;
1725 verts->color.w = a;
1726 verts++;
1727
1728 return 0;
1729 }
1730
1731 static int
D3D11_QueueCopyEx(SDL_Renderer * renderer,SDL_RenderCommand * cmd,SDL_Texture * texture,const SDL_Rect * srcrect,const SDL_FRect * dstrect,const double angle,const SDL_FPoint * center,const SDL_RendererFlip flip)1732 D3D11_QueueCopyEx(SDL_Renderer * renderer, SDL_RenderCommand *cmd, SDL_Texture * texture,
1733 const SDL_Rect * srcrect, const SDL_FRect * dstrect,
1734 const double angle, const SDL_FPoint *center, const SDL_RendererFlip flip)
1735 {
1736 VertexPositionColor *verts = (VertexPositionColor *) SDL_AllocateRenderVertices(renderer, 5 * sizeof (VertexPositionColor), 0, &cmd->data.draw.first);
1737 const float r = (float)(cmd->data.draw.r / 255.0f);
1738 const float g = (float)(cmd->data.draw.g / 255.0f);
1739 const float b = (float)(cmd->data.draw.b / 255.0f);
1740 const float a = (float)(cmd->data.draw.a / 255.0f);
1741 float minx, miny, maxx, maxy;
1742 float minu, maxu, minv, maxv;
1743
1744 if (!verts) {
1745 return -1;
1746 }
1747
1748 cmd->data.draw.count = 1;
1749
1750 minx = -center->x;
1751 maxx = dstrect->w - center->x;
1752 miny = -center->y;
1753 maxy = dstrect->h - center->y;
1754
1755 if (flip & SDL_FLIP_HORIZONTAL) {
1756 minu = (float) (srcrect->x + srcrect->w) / texture->w;
1757 maxu = (float) srcrect->x / texture->w;
1758 } else {
1759 minu = (float) srcrect->x / texture->w;
1760 maxu = (float) (srcrect->x + srcrect->w) / texture->w;
1761 }
1762
1763 if (flip & SDL_FLIP_VERTICAL) {
1764 minv = (float) (srcrect->y + srcrect->h) / texture->h;
1765 maxv = (float) srcrect->y / texture->h;
1766 } else {
1767 minv = (float) srcrect->y / texture->h;
1768 maxv = (float) (srcrect->y + srcrect->h) / texture->h;
1769 }
1770
1771
1772
1773 verts->pos.x = minx;
1774 verts->pos.y = miny;
1775 verts->pos.z = 0.0f;
1776 verts->color.x = r;
1777 verts->color.y = g;
1778 verts->color.z = b;
1779 verts->color.w = a;
1780 verts->tex.x = minu;
1781 verts->tex.y = minv;
1782 verts++;
1783
1784 verts->pos.x = minx;
1785 verts->pos.y = maxy;
1786 verts->pos.z = 0.0f;
1787 verts->color.x = r;
1788 verts->color.y = g;
1789 verts->color.z = b;
1790 verts->color.w = a;
1791 verts->tex.x = minu;
1792 verts->tex.y = maxv;
1793 verts++;
1794
1795 verts->pos.x = maxx;
1796 verts->pos.y = miny;
1797 verts->pos.z = 0.0f;
1798 verts->color.x = r;
1799 verts->color.y = g;
1800 verts->color.z = b;
1801 verts->color.w = a;
1802 verts->tex.x = maxu;
1803 verts->tex.y = minv;
1804 verts++;
1805
1806 verts->pos.x = maxx;
1807 verts->pos.y = maxy;
1808 verts->pos.z = 0.0f;
1809 verts->color.x = r;
1810 verts->color.y = g;
1811 verts->color.z = b;
1812 verts->color.w = a;
1813 verts->tex.x = maxu;
1814 verts->tex.y = maxv;
1815 verts++;
1816
1817 verts->pos.x = dstrect->x + center->x; /* X translation */
1818 verts->pos.y = dstrect->y + center->y; /* Y translation */
1819 verts->pos.z = (float)(M_PI * (float) angle / 180.0f); /* rotation */
1820 verts->color.x = 0;
1821 verts->color.y = 0;
1822 verts->color.z = 0;
1823 verts->color.w = 0;
1824 verts->tex.x = 0.0f;
1825 verts->tex.y = 0.0f;
1826 verts++;
1827
1828 return 0;
1829 }
1830
1831
1832 static int
D3D11_UpdateVertexBuffer(SDL_Renderer * renderer,const void * vertexData,size_t dataSizeInBytes)1833 D3D11_UpdateVertexBuffer(SDL_Renderer *renderer,
1834 const void * vertexData, size_t dataSizeInBytes)
1835 {
1836 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
1837 HRESULT result = S_OK;
1838 const int vbidx = rendererData->currentVertexBuffer;
1839 const UINT stride = sizeof(VertexPositionColor);
1840 const UINT offset = 0;
1841
1842 if (dataSizeInBytes == 0) {
1843 return 0; /* nothing to do. */
1844 }
1845
1846 if (rendererData->vertexBuffers[vbidx] && rendererData->vertexBufferSizes[vbidx] >= dataSizeInBytes) {
1847 D3D11_MAPPED_SUBRESOURCE mappedResource;
1848 result = ID3D11DeviceContext_Map(rendererData->d3dContext,
1849 (ID3D11Resource *)rendererData->vertexBuffers[vbidx],
1850 0,
1851 D3D11_MAP_WRITE_DISCARD,
1852 0,
1853 &mappedResource
1854 );
1855 if (FAILED(result)) {
1856 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result);
1857 return -1;
1858 }
1859 SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes);
1860 ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffers[vbidx], 0);
1861 } else {
1862 D3D11_BUFFER_DESC vertexBufferDesc;
1863 D3D11_SUBRESOURCE_DATA vertexBufferData;
1864
1865 SAFE_RELEASE(rendererData->vertexBuffers[vbidx]);
1866
1867 SDL_zero(vertexBufferDesc);
1868 vertexBufferDesc.ByteWidth = (UINT) dataSizeInBytes;
1869 vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
1870 vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
1871 vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
1872
1873 SDL_zero(vertexBufferData);
1874 vertexBufferData.pSysMem = vertexData;
1875 vertexBufferData.SysMemPitch = 0;
1876 vertexBufferData.SysMemSlicePitch = 0;
1877
1878 result = ID3D11Device_CreateBuffer(rendererData->d3dDevice,
1879 &vertexBufferDesc,
1880 &vertexBufferData,
1881 &rendererData->vertexBuffers[vbidx]
1882 );
1883 if (FAILED(result)) {
1884 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result);
1885 return -1;
1886 }
1887
1888 rendererData->vertexBufferSizes[vbidx] = dataSizeInBytes;
1889 }
1890
1891 ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext,
1892 0,
1893 1,
1894 &rendererData->vertexBuffers[vbidx],
1895 &stride,
1896 &offset
1897 );
1898
1899 rendererData->currentVertexBuffer++;
1900 if (rendererData->currentVertexBuffer >= SDL_arraysize(rendererData->vertexBuffers)) {
1901 rendererData->currentVertexBuffer = 0;
1902 }
1903
1904 return 0;
1905 }
1906
1907 static int
D3D11_UpdateViewport(SDL_Renderer * renderer)1908 D3D11_UpdateViewport(SDL_Renderer * renderer)
1909 {
1910 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
1911 const SDL_Rect *viewport = &data->currentViewport;
1912 Float4X4 projection;
1913 Float4X4 view;
1914 SDL_FRect orientationAlignedViewport;
1915 BOOL swapDimensions;
1916 D3D11_VIEWPORT d3dviewport;
1917 const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
1918
1919 if (viewport->w == 0 || viewport->h == 0) {
1920 /* If the viewport is empty, assume that it is because
1921 * SDL_CreateRenderer is calling it, and will call it again later
1922 * with a non-empty viewport.
1923 */
1924 /* SDL_Log("%s, no viewport was set!\n", __FUNCTION__); */
1925 return -1;
1926 }
1927
1928 /* Make sure the SDL viewport gets rotated to that of the physical display's rotation.
1929 * Keep in mind here that the Y-axis will be been inverted (from Direct3D's
1930 * default coordinate system) so rotations will be done in the opposite
1931 * direction of the DXGI_MODE_ROTATION enumeration.
1932 */
1933 switch (rotation) {
1934 case DXGI_MODE_ROTATION_IDENTITY:
1935 projection = MatrixIdentity();
1936 break;
1937 case DXGI_MODE_ROTATION_ROTATE270:
1938 projection = MatrixRotationZ(SDL_static_cast(float, M_PI * 0.5f));
1939 break;
1940 case DXGI_MODE_ROTATION_ROTATE180:
1941 projection = MatrixRotationZ(SDL_static_cast(float, M_PI));
1942 break;
1943 case DXGI_MODE_ROTATION_ROTATE90:
1944 projection = MatrixRotationZ(SDL_static_cast(float, -M_PI * 0.5f));
1945 break;
1946 default:
1947 return SDL_SetError("An unknown DisplayOrientation is being used");
1948 }
1949
1950 /* Update the view matrix */
1951 SDL_zero(view);
1952 view.m[0][0] = 2.0f / viewport->w;
1953 view.m[1][1] = -2.0f / viewport->h;
1954 view.m[2][2] = 1.0f;
1955 view.m[3][0] = -1.0f;
1956 view.m[3][1] = 1.0f;
1957 view.m[3][3] = 1.0f;
1958
1959 /* Combine the projection + view matrix together now, as both only get
1960 * set here (as of this writing, on Dec 26, 2013). When done, store it
1961 * for eventual transfer to the GPU.
1962 */
1963 data->vertexShaderConstantsData.projectionAndView = MatrixMultiply(
1964 view,
1965 projection);
1966
1967 /* Update the Direct3D viewport, which seems to be aligned to the
1968 * swap buffer's coordinate space, which is always in either
1969 * a landscape mode, for all Windows 8/RT devices, or a portrait mode,
1970 * for Windows Phone devices.
1971 */
1972 swapDimensions = D3D11_IsDisplayRotated90Degrees(rotation);
1973 if (swapDimensions) {
1974 orientationAlignedViewport.x = (float) viewport->y;
1975 orientationAlignedViewport.y = (float) viewport->x;
1976 orientationAlignedViewport.w = (float) viewport->h;
1977 orientationAlignedViewport.h = (float) viewport->w;
1978 } else {
1979 orientationAlignedViewport.x = (float) viewport->x;
1980 orientationAlignedViewport.y = (float) viewport->y;
1981 orientationAlignedViewport.w = (float) viewport->w;
1982 orientationAlignedViewport.h = (float) viewport->h;
1983 }
1984 /* TODO, WinRT: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped) */
1985
1986 d3dviewport.TopLeftX = orientationAlignedViewport.x;
1987 d3dviewport.TopLeftY = orientationAlignedViewport.y;
1988 d3dviewport.Width = orientationAlignedViewport.w;
1989 d3dviewport.Height = orientationAlignedViewport.h;
1990 d3dviewport.MinDepth = 0.0f;
1991 d3dviewport.MaxDepth = 1.0f;
1992 /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, d3dviewport.TopLeftX, d3dviewport.TopLeftY, d3dviewport.Width, d3dviewport.Height); */
1993 ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &d3dviewport);
1994
1995 data->viewportDirty = SDL_FALSE;
1996
1997 return 0;
1998 }
1999
2000 static ID3D11RenderTargetView *
D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer)2001 D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer)
2002 {
2003 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata;
2004 if (data->currentOffscreenRenderTargetView) {
2005 return data->currentOffscreenRenderTargetView;
2006 }
2007 else {
2008 return data->mainRenderTargetView;
2009 }
2010 }
2011
2012 static int
D3D11_SetDrawState(SDL_Renderer * renderer,const SDL_RenderCommand * cmd,ID3D11PixelShader * shader,const int numShaderResources,ID3D11ShaderResourceView ** shaderResources,ID3D11SamplerState * sampler,const Float4X4 * matrix)2013 D3D11_SetDrawState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, ID3D11PixelShader * shader,
2014 const int numShaderResources, ID3D11ShaderResourceView ** shaderResources,
2015 ID3D11SamplerState * sampler, const Float4X4 *matrix)
2016
2017 {
2018 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata;
2019 const Float4X4 *newmatrix = matrix ? matrix : &rendererData->identity;
2020 ID3D11RasterizerState *rasterizerState;
2021 ID3D11RenderTargetView *renderTargetView = D3D11_GetCurrentRenderTargetView(renderer);
2022 ID3D11ShaderResourceView *shaderResource;
2023 const SDL_BlendMode blendMode = cmd->data.draw.blend;
2024 ID3D11BlendState *blendState = NULL;
2025 SDL_bool updateSubresource = SDL_FALSE;
2026
2027 if (renderTargetView != rendererData->currentRenderTargetView) {
2028 ID3D11DeviceContext_OMSetRenderTargets(rendererData->d3dContext,
2029 1,
2030 &renderTargetView,
2031 NULL
2032 );
2033 rendererData->currentRenderTargetView = renderTargetView;
2034 }
2035
2036 if (rendererData->viewportDirty) {
2037 if (D3D11_UpdateViewport(renderer) == 0) {
2038 /* vertexShaderConstantsData.projectionAndView has changed */
2039 updateSubresource = SDL_TRUE;
2040 }
2041 }
2042
2043 if (rendererData->cliprectDirty) {
2044 if (!rendererData->currentCliprectEnabled) {
2045 ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 0, NULL);
2046 } else {
2047 D3D11_RECT scissorRect;
2048 if (D3D11_GetViewportAlignedD3DRect(renderer, &rendererData->currentCliprect, &scissorRect, TRUE) != 0) {
2049 /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */
2050 return -1;
2051 }
2052 ID3D11DeviceContext_RSSetScissorRects(rendererData->d3dContext, 1, &scissorRect);
2053 }
2054 rendererData->cliprectDirty = SDL_FALSE;
2055 }
2056
2057 if (!rendererData->currentCliprectEnabled) {
2058 rasterizerState = rendererData->mainRasterizer;
2059 } else {
2060 rasterizerState = rendererData->clippedRasterizer;
2061 }
2062 if (rasterizerState != rendererData->currentRasterizerState) {
2063 ID3D11DeviceContext_RSSetState(rendererData->d3dContext, rasterizerState);
2064 rendererData->currentRasterizerState = rasterizerState;
2065 }
2066
2067 if (blendMode != SDL_BLENDMODE_NONE) {
2068 int i;
2069 for (i = 0; i < rendererData->blendModesCount; ++i) {
2070 if (blendMode == rendererData->blendModes[i].blendMode) {
2071 blendState = rendererData->blendModes[i].blendState;
2072 break;
2073 }
2074 }
2075 if (!blendState) {
2076 blendState = D3D11_CreateBlendState(renderer, blendMode);
2077 if (!blendState) {
2078 return -1;
2079 }
2080 }
2081 }
2082 if (blendState != rendererData->currentBlendState) {
2083 ID3D11DeviceContext_OMSetBlendState(rendererData->d3dContext, blendState, 0, 0xFFFFFFFF);
2084 rendererData->currentBlendState = blendState;
2085 }
2086
2087 if (shader != rendererData->currentShader) {
2088 ID3D11DeviceContext_PSSetShader(rendererData->d3dContext, shader, NULL, 0);
2089 rendererData->currentShader = shader;
2090 }
2091 if (numShaderResources > 0) {
2092 shaderResource = shaderResources[0];
2093 } else {
2094 shaderResource = NULL;
2095 }
2096 if (shaderResource != rendererData->currentShaderResource) {
2097 ID3D11DeviceContext_PSSetShaderResources(rendererData->d3dContext, 0, numShaderResources, shaderResources);
2098 rendererData->currentShaderResource = shaderResource;
2099 }
2100 if (sampler != rendererData->currentSampler) {
2101 ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, 1, &sampler);
2102 rendererData->currentSampler = sampler;
2103 }
2104
2105 if (updateSubresource == SDL_TRUE || SDL_memcmp(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof (*newmatrix)) != 0) {
2106 SDL_memcpy(&rendererData->vertexShaderConstantsData.model, newmatrix, sizeof (*newmatrix));
2107 ID3D11DeviceContext_UpdateSubresource(rendererData->d3dContext,
2108 (ID3D11Resource *)rendererData->vertexShaderConstants,
2109 0,
2110 NULL,
2111 &rendererData->vertexShaderConstantsData,
2112 0,
2113 0
2114 );
2115 }
2116
2117 return 0;
2118 }
2119
2120 static int
D3D11_SetCopyState(SDL_Renderer * renderer,const SDL_RenderCommand * cmd,const Float4X4 * matrix)2121 D3D11_SetCopyState(SDL_Renderer * renderer, const SDL_RenderCommand *cmd, const Float4X4 *matrix)
2122 {
2123 SDL_Texture *texture = cmd->data.draw.texture;
2124 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
2125 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
2126 ID3D11SamplerState *textureSampler;
2127
2128 switch (textureData->scaleMode) {
2129 case D3D11_FILTER_MIN_MAG_MIP_POINT:
2130 textureSampler = rendererData->nearestPixelSampler;
2131 break;
2132 case D3D11_FILTER_MIN_MAG_MIP_LINEAR:
2133 textureSampler = rendererData->linearSampler;
2134 break;
2135 default:
2136 return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode);
2137 }
2138
2139 if (textureData->yuv) {
2140 ID3D11ShaderResourceView *shaderResources[] = {
2141 textureData->mainTextureResourceView,
2142 textureData->mainTextureResourceViewU,
2143 textureData->mainTextureResourceViewV
2144 };
2145 D3D11_Shader shader;
2146
2147 switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
2148 case SDL_YUV_CONVERSION_JPEG:
2149 shader = SHADER_YUV_JPEG;
2150 break;
2151 case SDL_YUV_CONVERSION_BT601:
2152 shader = SHADER_YUV_BT601;
2153 break;
2154 case SDL_YUV_CONVERSION_BT709:
2155 shader = SHADER_YUV_BT709;
2156 break;
2157 default:
2158 return SDL_SetError("Unsupported YUV conversion mode");
2159 }
2160
2161 return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[shader],
2162 SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
2163
2164 } else if (textureData->nv12) {
2165 ID3D11ShaderResourceView *shaderResources[] = {
2166 textureData->mainTextureResourceView,
2167 textureData->mainTextureResourceViewNV,
2168 };
2169 D3D11_Shader shader;
2170
2171 switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) {
2172 case SDL_YUV_CONVERSION_JPEG:
2173 shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG;
2174 break;
2175 case SDL_YUV_CONVERSION_BT601:
2176 shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601;
2177 break;
2178 case SDL_YUV_CONVERSION_BT709:
2179 shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709;
2180 break;
2181 default:
2182 return SDL_SetError("Unsupported YUV conversion mode");
2183 }
2184
2185 return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[shader],
2186 SDL_arraysize(shaderResources), shaderResources, textureSampler, matrix);
2187
2188 }
2189
2190 return D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_RGB],
2191 1, &textureData->mainTextureResourceView, textureSampler, matrix);
2192 }
2193
2194 static void
D3D11_DrawPrimitives(SDL_Renderer * renderer,D3D11_PRIMITIVE_TOPOLOGY primitiveTopology,const size_t vertexStart,const size_t vertexCount)2195 D3D11_DrawPrimitives(SDL_Renderer * renderer, D3D11_PRIMITIVE_TOPOLOGY primitiveTopology, const size_t vertexStart, const size_t vertexCount)
2196 {
2197 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
2198 ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology);
2199 ID3D11DeviceContext_Draw(rendererData->d3dContext, (UINT) vertexCount, (UINT) vertexStart);
2200 }
2201
2202 static int
D3D11_RunCommandQueue(SDL_Renderer * renderer,SDL_RenderCommand * cmd,void * vertices,size_t vertsize)2203 D3D11_RunCommandQueue(SDL_Renderer * renderer, SDL_RenderCommand *cmd, void *vertices, size_t vertsize)
2204 {
2205 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
2206 const int viewportRotation = D3D11_GetRotationForCurrentRenderTarget(renderer);
2207 size_t i;
2208
2209 if (rendererData->currentViewportRotation != viewportRotation) {
2210 rendererData->currentViewportRotation = viewportRotation;
2211 rendererData->viewportDirty = SDL_TRUE;
2212 }
2213
2214 if (D3D11_UpdateVertexBuffer(renderer, vertices, vertsize) < 0) {
2215 return -1;
2216 }
2217
2218 while (cmd) {
2219 switch (cmd->command) {
2220 case SDL_RENDERCMD_SETDRAWCOLOR: {
2221 break; /* this isn't currently used in this render backend. */
2222 }
2223
2224 case SDL_RENDERCMD_SETVIEWPORT: {
2225 SDL_Rect *viewport = &rendererData->currentViewport;
2226 if (SDL_memcmp(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect)) != 0) {
2227 SDL_memcpy(viewport, &cmd->data.viewport.rect, sizeof (SDL_Rect));
2228 rendererData->viewportDirty = SDL_TRUE;
2229 }
2230 break;
2231 }
2232
2233 case SDL_RENDERCMD_SETCLIPRECT: {
2234 const SDL_Rect *rect = &cmd->data.cliprect.rect;
2235 if (rendererData->currentCliprectEnabled != cmd->data.cliprect.enabled) {
2236 rendererData->currentCliprectEnabled = cmd->data.cliprect.enabled;
2237 rendererData->cliprectDirty = SDL_TRUE;
2238 }
2239 if (SDL_memcmp(&rendererData->currentCliprect, rect, sizeof (SDL_Rect)) != 0) {
2240 SDL_memcpy(&rendererData->currentCliprect, rect, sizeof (SDL_Rect));
2241 rendererData->cliprectDirty = SDL_TRUE;
2242 }
2243 break;
2244 }
2245
2246 case SDL_RENDERCMD_CLEAR: {
2247 const float colorRGBA[] = {
2248 (cmd->data.color.r / 255.0f),
2249 (cmd->data.color.g / 255.0f),
2250 (cmd->data.color.b / 255.0f),
2251 (cmd->data.color.a / 255.0f)
2252 };
2253 ID3D11DeviceContext_ClearRenderTargetView(rendererData->d3dContext, D3D11_GetCurrentRenderTargetView(renderer), colorRGBA);
2254 break;
2255 }
2256
2257 case SDL_RENDERCMD_DRAW_POINTS: {
2258 const size_t count = cmd->data.draw.count;
2259 const size_t first = cmd->data.draw.first;
2260 const size_t start = first / sizeof (VertexPositionColor);
2261 D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
2262 D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start, count);
2263 break;
2264 }
2265
2266 case SDL_RENDERCMD_DRAW_LINES: {
2267 const size_t count = cmd->data.draw.count;
2268 const size_t first = cmd->data.draw.first;
2269 const size_t start = first / sizeof (VertexPositionColor);
2270 const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
2271 D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
2272 D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, start, count);
2273 if (verts[0].pos.x != verts[count - 1].pos.x || verts[0].pos.y != verts[count - 1].pos.y) {
2274 D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, start + (count-1), 1);
2275 }
2276 break;
2277 }
2278
2279 case SDL_RENDERCMD_FILL_RECTS: {
2280 const size_t count = cmd->data.draw.count;
2281 const size_t first = cmd->data.draw.first;
2282 const size_t start = first / sizeof (VertexPositionColor);
2283 size_t offset = 0;
2284 D3D11_SetDrawState(renderer, cmd, rendererData->pixelShaders[SHADER_SOLID], 0, NULL, NULL, NULL);
2285 for (i = 0; i < count; i++, offset += 4) {
2286 D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start + offset, 4);
2287 }
2288 break;
2289 }
2290
2291 case SDL_RENDERCMD_COPY: {
2292 const size_t first = cmd->data.draw.first;
2293 const size_t start = first / sizeof (VertexPositionColor);
2294 D3D11_SetCopyState(renderer, cmd, NULL);
2295 D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start, 4);
2296 break;
2297 }
2298
2299 case SDL_RENDERCMD_COPY_EX: {
2300 const size_t first = cmd->data.draw.first;
2301 const size_t start = first / sizeof (VertexPositionColor);
2302 const VertexPositionColor *verts = (VertexPositionColor *) (((Uint8 *) vertices) + first);
2303 const VertexPositionColor *transvert = verts + 4;
2304 const float translatex = transvert->pos.x;
2305 const float translatey = transvert->pos.y;
2306 const float rotation = transvert->pos.z;
2307 const Float4X4 matrix = MatrixMultiply(MatrixRotationZ(rotation), MatrixTranslation(translatex, translatey, 0));
2308 D3D11_SetCopyState(renderer, cmd, &matrix);
2309 D3D11_DrawPrimitives(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, start, 4);
2310 break;
2311 }
2312
2313 case SDL_RENDERCMD_NO_OP:
2314 break;
2315 }
2316
2317 cmd = cmd->next;
2318 }
2319
2320 return 0;
2321 }
2322
2323 static int
D3D11_RenderReadPixels(SDL_Renderer * renderer,const SDL_Rect * rect,Uint32 format,void * pixels,int pitch)2324 D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
2325 Uint32 format, void * pixels, int pitch)
2326 {
2327 D3D11_RenderData * data = (D3D11_RenderData *) renderer->driverdata;
2328 ID3D11RenderTargetView *renderTargetView = NULL;
2329 ID3D11Texture2D *backBuffer = NULL;
2330 ID3D11Texture2D *stagingTexture = NULL;
2331 HRESULT result;
2332 int status = -1;
2333 D3D11_TEXTURE2D_DESC stagingTextureDesc;
2334 D3D11_RECT srcRect = {0, 0, 0, 0};
2335 D3D11_BOX srcBox;
2336 D3D11_MAPPED_SUBRESOURCE textureMemory;
2337
2338 ID3D11DeviceContext_OMGetRenderTargets(data->d3dContext, 1, &renderTargetView, NULL);
2339 if (renderTargetView == NULL) {
2340 SDL_SetError("%s, ID3D11DeviceContext::OMGetRenderTargets failed", __FUNCTION__);
2341 goto done;
2342 }
2343
2344 ID3D11View_GetResource(renderTargetView, (ID3D11Resource**)&backBuffer);
2345 if (backBuffer == NULL) {
2346 SDL_SetError("%s, ID3D11View::GetResource failed", __FUNCTION__);
2347 goto done;
2348 }
2349
2350 /* Create a staging texture to copy the screen's data to: */
2351 ID3D11Texture2D_GetDesc(backBuffer, &stagingTextureDesc);
2352 stagingTextureDesc.Width = rect->w;
2353 stagingTextureDesc.Height = rect->h;
2354 stagingTextureDesc.BindFlags = 0;
2355 stagingTextureDesc.MiscFlags = 0;
2356 stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ;
2357 stagingTextureDesc.Usage = D3D11_USAGE_STAGING;
2358 result = ID3D11Device_CreateTexture2D(data->d3dDevice,
2359 &stagingTextureDesc,
2360 NULL,
2361 &stagingTexture);
2362 if (FAILED(result)) {
2363 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result);
2364 goto done;
2365 }
2366
2367 /* Copy the desired portion of the back buffer to the staging texture: */
2368 if (D3D11_GetViewportAlignedD3DRect(renderer, rect, &srcRect, FALSE) != 0) {
2369 /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */
2370 goto done;
2371 }
2372
2373 srcBox.left = srcRect.left;
2374 srcBox.right = srcRect.right;
2375 srcBox.top = srcRect.top;
2376 srcBox.bottom = srcRect.bottom;
2377 srcBox.front = 0;
2378 srcBox.back = 1;
2379 ID3D11DeviceContext_CopySubresourceRegion(data->d3dContext,
2380 (ID3D11Resource *)stagingTexture,
2381 0,
2382 0, 0, 0,
2383 (ID3D11Resource *)backBuffer,
2384 0,
2385 &srcBox);
2386
2387 /* Map the staging texture's data to CPU-accessible memory: */
2388 result = ID3D11DeviceContext_Map(data->d3dContext,
2389 (ID3D11Resource *)stagingTexture,
2390 0,
2391 D3D11_MAP_READ,
2392 0,
2393 &textureMemory);
2394 if (FAILED(result)) {
2395 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result);
2396 goto done;
2397 }
2398
2399 /* Copy the data into the desired buffer, converting pixels to the
2400 * desired format at the same time:
2401 */
2402 if (SDL_ConvertPixels(
2403 rect->w, rect->h,
2404 D3D11_DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format),
2405 textureMemory.pData,
2406 textureMemory.RowPitch,
2407 format,
2408 pixels,
2409 pitch) != 0) {
2410 /* When SDL_ConvertPixels fails, it'll have already set the format.
2411 * Get the error message, and attach some extra data to it.
2412 */
2413 char errorMessage[1024];
2414 SDL_snprintf(errorMessage, sizeof(errorMessage), "%s, Convert Pixels failed: %s", __FUNCTION__, SDL_GetError());
2415 SDL_SetError("%s", errorMessage);
2416 goto done;
2417 }
2418
2419 /* Unmap the texture: */
2420 ID3D11DeviceContext_Unmap(data->d3dContext,
2421 (ID3D11Resource *)stagingTexture,
2422 0);
2423
2424 status = 0;
2425
2426 done:
2427 SAFE_RELEASE(backBuffer);
2428 SAFE_RELEASE(stagingTexture);
2429 return status;
2430 }
2431
2432 static void
D3D11_RenderPresent(SDL_Renderer * renderer)2433 D3D11_RenderPresent(SDL_Renderer * renderer)
2434 {
2435 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
2436 UINT syncInterval;
2437 UINT presentFlags;
2438 HRESULT result;
2439 DXGI_PRESENT_PARAMETERS parameters;
2440
2441 SDL_zero(parameters);
2442
2443 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
2444 syncInterval = 1;
2445 presentFlags = 0;
2446 result = IDXGISwapChain_Present(data->swapChain, syncInterval, presentFlags);
2447 #else
2448 if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) {
2449 syncInterval = 1;
2450 presentFlags = 0;
2451 } else {
2452 syncInterval = 0;
2453 presentFlags = DXGI_PRESENT_DO_NOT_WAIT;
2454 }
2455
2456 /* The application may optionally specify "dirty" or "scroll"
2457 * rects to improve efficiency in certain scenarios.
2458 * This option is not available on Windows Phone 8, to note.
2459 */
2460 result = IDXGISwapChain1_Present1(data->swapChain, syncInterval, presentFlags, ¶meters);
2461 #endif
2462
2463 /* Discard the contents of the render target.
2464 * This is a valid operation only when the existing contents will be entirely
2465 * overwritten. If dirty or scroll rects are used, this call should be removed.
2466 */
2467 ID3D11DeviceContext1_DiscardView(data->d3dContext, (ID3D11View*)data->mainRenderTargetView);
2468
2469 /* When the present flips, it unbinds the current view, so bind it again on the next draw call */
2470 data->currentRenderTargetView = NULL;
2471
2472 if (FAILED(result) && result != DXGI_ERROR_WAS_STILL_DRAWING) {
2473 /* If the device was removed either by a disconnect or a driver upgrade, we
2474 * must recreate all device resources.
2475 *
2476 * TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvage debug info from users' machines
2477 */
2478 if ( result == DXGI_ERROR_DEVICE_REMOVED ) {
2479 D3D11_HandleDeviceLost(renderer);
2480 } else if (result == DXGI_ERROR_INVALID_CALL) {
2481 /* We probably went through a fullscreen <-> windowed transition */
2482 D3D11_CreateWindowSizeDependentResources(renderer);
2483 } else {
2484 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::Present"), result);
2485 }
2486 }
2487 }
2488
2489 SDL_Renderer *
D3D11_CreateRenderer(SDL_Window * window,Uint32 flags)2490 D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
2491 {
2492 SDL_Renderer *renderer;
2493 D3D11_RenderData *data;
2494
2495 renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
2496 if (!renderer) {
2497 SDL_OutOfMemory();
2498 return NULL;
2499 }
2500
2501 data = (D3D11_RenderData *) SDL_calloc(1, sizeof(*data));
2502 if (!data) {
2503 SDL_OutOfMemory();
2504 return NULL;
2505 }
2506
2507 data->identity = MatrixIdentity();
2508
2509 renderer->WindowEvent = D3D11_WindowEvent;
2510 renderer->SupportsBlendMode = D3D11_SupportsBlendMode;
2511 renderer->CreateTexture = D3D11_CreateTexture;
2512 renderer->UpdateTexture = D3D11_UpdateTexture;
2513 renderer->UpdateTextureYUV = D3D11_UpdateTextureYUV;
2514 renderer->LockTexture = D3D11_LockTexture;
2515 renderer->UnlockTexture = D3D11_UnlockTexture;
2516 renderer->SetTextureScaleMode = D3D11_SetTextureScaleMode;
2517 renderer->SetRenderTarget = D3D11_SetRenderTarget;
2518 renderer->QueueSetViewport = D3D11_QueueSetViewport;
2519 renderer->QueueSetDrawColor = D3D11_QueueSetViewport; /* SetViewport and SetDrawColor are (currently) no-ops. */
2520 renderer->QueueDrawPoints = D3D11_QueueDrawPoints;
2521 renderer->QueueDrawLines = D3D11_QueueDrawPoints; /* lines and points queue vertices the same way. */
2522 renderer->QueueFillRects = D3D11_QueueFillRects;
2523 renderer->QueueCopy = D3D11_QueueCopy;
2524 renderer->QueueCopyEx = D3D11_QueueCopyEx;
2525 renderer->RunCommandQueue = D3D11_RunCommandQueue;
2526 renderer->RenderReadPixels = D3D11_RenderReadPixels;
2527 renderer->RenderPresent = D3D11_RenderPresent;
2528 renderer->DestroyTexture = D3D11_DestroyTexture;
2529 renderer->DestroyRenderer = D3D11_DestroyRenderer;
2530 renderer->info = D3D11_RenderDriver.info;
2531 renderer->info.flags = (SDL_RENDERER_ACCELERATED | SDL_RENDERER_TARGETTEXTURE);
2532 renderer->driverdata = data;
2533
2534 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
2535 /* VSync is required in Windows Phone, at least for Win Phone 8.0 and 8.1.
2536 * Failure to use it seems to either result in:
2537 *
2538 * - with the D3D11 debug runtime turned OFF, vsync seemingly gets turned
2539 * off (framerate doesn't get capped), but nothing appears on-screen
2540 *
2541 * - with the D3D11 debug runtime turned ON, vsync gets automatically
2542 * turned back on, and the following gets output to the debug console:
2543 *
2544 * DXGI ERROR: IDXGISwapChain::Present: Interval 0 is not supported, changed to Interval 1. [ UNKNOWN ERROR #1024: ]
2545 */
2546 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
2547 #else
2548 if ((flags & SDL_RENDERER_PRESENTVSYNC)) {
2549 renderer->info.flags |= SDL_RENDERER_PRESENTVSYNC;
2550 }
2551 #endif
2552
2553 /* HACK: make sure the SDL_Renderer references the SDL_Window data now, in
2554 * order to give init functions access to the underlying window handle:
2555 */
2556 renderer->window = window;
2557
2558 /* Initialize Direct3D resources */
2559 if (FAILED(D3D11_CreateDeviceResources(renderer))) {
2560 D3D11_DestroyRenderer(renderer);
2561 return NULL;
2562 }
2563 if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
2564 D3D11_DestroyRenderer(renderer);
2565 return NULL;
2566 }
2567
2568 return renderer;
2569 }
2570
2571 SDL_RenderDriver D3D11_RenderDriver = {
2572 D3D11_CreateRenderer,
2573 {
2574 "direct3d11",
2575 (
2576 SDL_RENDERER_ACCELERATED |
2577 SDL_RENDERER_PRESENTVSYNC |
2578 SDL_RENDERER_TARGETTEXTURE
2579 ), /* flags. see SDL_RendererFlags */
2580 6, /* num_texture_formats */
2581 { /* texture_formats */
2582 SDL_PIXELFORMAT_ARGB8888,
2583 SDL_PIXELFORMAT_RGB888,
2584 SDL_PIXELFORMAT_YV12,
2585 SDL_PIXELFORMAT_IYUV,
2586 SDL_PIXELFORMAT_NV12,
2587 SDL_PIXELFORMAT_NV21
2588 },
2589 0, /* max_texture_width: will be filled in later */
2590 0 /* max_texture_height: will be filled in later */
2591 }
2592 };
2593
2594 #endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */
2595
2596 /* vi: set ts=4 sw=4 expandtab: */
2597