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