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