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