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