Imported Upstream version 2.0.14
[platform/upstream/SDL.git] / src / render / direct3d11 / SDL_render_d3d11.c
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
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
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
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
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
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
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 *
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
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
660 D3D11_GetCurrentRotation()
661 {
662     /* FIXME */
663     return DXGI_MODE_ROTATION_IDENTITY;
664 }
665
666 #endif /* __WIN32__ */
667
668 static BOOL
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
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
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
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
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
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
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
986 D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
987 {
988     return D3D11_CreateWindowSizeDependentResources(renderer);
989 }
990
991 void
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
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
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
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
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
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
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
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
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
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
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
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
1562 D3D11_QueueSetViewport(SDL_Renderer * renderer, SDL_RenderCommand *cmd)
1563 {
1564     return 0;  /* nothing to do in this backend. */
1565 }
1566
1567 static int
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
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
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
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
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
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 *
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
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
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
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
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
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
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, &parameters);
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 *
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: */