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