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