Atlas - SDL_render_d3d11.c

Home / ext / SDL2 / src / render / direct3d11 Lines: 5 | Size: 92314 bytes [Download] [Show on GitHub] [Search similar files] [Raw] [Raw (proxy)]
[FILE BEGIN]
1/* 2 Simple DirectMedia Layer 3 Copyright (C) 1997-2018 Sam Lantinga <[email protected]> 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 */ 48extern 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 */ 60typedef struct 61{ 62 Float4X4 model; 63 Float4X4 projectionAndView; 64} VertexShaderConstants; 65 66/* Per-vertex data */ 67typedef struct 68{ 69 Float3 pos; 70 Float2 tex; 71 Float4 color; 72} VertexPositionColor; 73 74/* Per-texture data */ 75typedef 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 */ 103typedef struct 104{ 105 SDL_BlendMode blendMode; 106 ID3D11BlendState *blendState; 107} D3D11_BlendMode; 108 109/* Private renderer data */ 110typedef 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 165static const GUID SDL_IID_IDXGIFactory2 = { 0x50c83a1c, 0xe072, 0x4c48, { 0x87, 0xb0, 0x36, 0x30, 0xfa, 0x36, 0xa6, 0xd0 } }; 166static const GUID SDL_IID_IDXGIDevice1 = { 0x77db970f, 0x6276, 0x48ba, { 0xba, 0x28, 0x07, 0x01, 0x43, 0xb4, 0x39, 0x2c } }; 167static const GUID SDL_IID_IDXGIDevice3 = { 0x6007896c, 0x3244, 0x4afd, { 0xbf, 0x18, 0xa6, 0xd3, 0xbe, 0xda, 0x50, 0x23 } }; 168static const GUID SDL_IID_ID3D11Texture2D = { 0x6f15aaf2, 0xd208, 0x4e89, { 0x9a, 0xb4, 0x48, 0x95, 0x35, 0xd3, 0x4f, 0x9c } }; 169static const GUID SDL_IID_ID3D11Device1 = { 0xa04bfb29, 0x08ef, 0x43d6, { 0xa4, 0x9c, 0xa9, 0xbd, 0xbd, 0xcb, 0xe6, 0x86 } }; 170static const GUID SDL_IID_ID3D11DeviceContext1 = { 0xbb2c6faa, 0xb5fb, 0x4082, { 0x8e, 0x6b, 0x38, 0x8b, 0x8c, 0xfa, 0x90, 0xe1 } }; 171static 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 */ 179static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags); 180static void D3D11_WindowEvent(SDL_Renderer * renderer, 181 const SDL_WindowEvent *event); 182static SDL_bool D3D11_SupportsBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode); 183static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture); 184static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 185 const SDL_Rect * rect, const void *srcPixels, 186 int srcPitch); 187static 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); 192static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 193 const SDL_Rect * rect, void **pixels, int *pitch); 194static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture); 195static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture); 196static int D3D11_UpdateViewport(SDL_Renderer * renderer); 197static int D3D11_UpdateClipRect(SDL_Renderer * renderer); 198static int D3D11_RenderClear(SDL_Renderer * renderer); 199static int D3D11_RenderDrawPoints(SDL_Renderer * renderer, 200 const SDL_FPoint * points, int count); 201static int D3D11_RenderDrawLines(SDL_Renderer * renderer, 202 const SDL_FPoint * points, int count); 203static int D3D11_RenderFillRects(SDL_Renderer * renderer, 204 const SDL_FRect * rects, int count); 205static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 206 const SDL_Rect * srcrect, const SDL_FRect * dstrect); 207static 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); 210static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 211 Uint32 format, void * pixels, int pitch); 212static void D3D11_RenderPresent(SDL_Renderer * renderer); 213static void D3D11_DestroyTexture(SDL_Renderer * renderer, 214 SDL_Texture * texture); 215static void D3D11_DestroyRenderer(SDL_Renderer * renderer); 216 217/* Direct3D 11.1 Internal Functions */ 218static HRESULT D3D11_CreateDeviceResources(SDL_Renderer * renderer); 219static HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer); 220static HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer); 221static HRESULT D3D11_HandleDeviceLost(SDL_Renderer * renderer); 222static void D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer); 223 224SDL_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 248Uint32 249D3D11_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 261static DXGI_FORMAT 262SDLPixelFormatToDXGIFormat(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 279SDL_Renderer * 280D3D11_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 358static void 359D3D11_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 423static void 424D3D11_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 434static 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 462static 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 480static SDL_bool 481D3D11_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. */ 527static HRESULT 528D3D11_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 781done: 782 SAFE_RELEASE(d3dDevice); 783 SAFE_RELEASE(d3dContext); 784 SAFE_RELEASE(dxgiDevice); 785 return result; 786} 787 788#ifdef __WIN32__ 789 790static DXGI_MODE_ROTATION 791D3D11_GetCurrentRotation() 792{ 793 /* FIXME */ 794 return DXGI_MODE_ROTATION_IDENTITY; 795} 796 797#endif /* __WIN32__ */ 798 799static BOOL 800D3D11_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 811static int 812D3D11_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 822static int 823D3D11_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 863static HRESULT 864D3D11_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 962done: 963 SAFE_RELEASE(coreWindow); 964 return result; 965} 966 967 968/* Initialize all resources that change when the window's size changes. */ 969static HRESULT 970D3D11_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 1075done: 1076 SAFE_RELEASE(backBuffer); 1077 return result; 1078} 1079 1080/* This method is called when the window's size changes. */ 1081static HRESULT 1082D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer) 1083{ 1084 return D3D11_CreateWindowSizeDependentResources(renderer); 1085} 1086 1087HRESULT 1088D3D11_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 1116void 1117D3D11_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 1137static void 1138D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event) 1139{ 1140 if (event->event == SDL_WINDOWEVENT_SIZE_CHANGED) { 1141 D3D11_UpdateForWindowSizeChange(renderer); 1142 } 1143} 1144 1145static SDL_bool 1146D3D11_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 1164static int 1165D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture) 1166{ 1167 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 1168 D3D11_TextureData *textureData; 1169 HRESULT result; 1170 DXGI_FORMAT textureFormat = SDLPixelFormatToDXGIFormat(texture->format); 1171 D3D11_TEXTURE2D_DESC textureDesc; 1172 D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc; 1173 1174 if (textureFormat == DXGI_FORMAT_UNKNOWN) { 1175 return SDL_SetError("%s, An unsupported SDL pixel format (0x%x) was specified", 1176 __FUNCTION__, texture->format); 1177 } 1178 1179 textureData = (D3D11_TextureData*) SDL_calloc(1, sizeof(*textureData)); 1180 if (!textureData) { 1181 SDL_OutOfMemory(); 1182 return -1; 1183 } 1184 textureData->scaleMode = (texture->scaleMode == SDL_ScaleModeNearest) ? D3D11_FILTER_MIN_MAG_MIP_POINT : D3D11_FILTER_MIN_MAG_MIP_LINEAR; 1185 1186 texture->driverdata = textureData; 1187 1188 SDL_zero(textureDesc); 1189 textureDesc.Width = texture->w; 1190 textureDesc.Height = texture->h; 1191 textureDesc.MipLevels = 1; 1192 textureDesc.ArraySize = 1; 1193 textureDesc.Format = textureFormat; 1194 textureDesc.SampleDesc.Count = 1; 1195 textureDesc.SampleDesc.Quality = 0; 1196 textureDesc.MiscFlags = 0; 1197 1198 if (texture->access == SDL_TEXTUREACCESS_STREAMING) { 1199 textureDesc.Usage = D3D11_USAGE_DYNAMIC; 1200 textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 1201 } else { 1202 textureDesc.Usage = D3D11_USAGE_DEFAULT; 1203 textureDesc.CPUAccessFlags = 0; 1204 } 1205 1206 if (texture->access == SDL_TEXTUREACCESS_TARGET) { 1207 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET; 1208 } else { 1209 textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE; 1210 } 1211 1212 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, 1213 &textureDesc, 1214 NULL, 1215 &textureData->mainTexture 1216 ); 1217 if (FAILED(result)) { 1218 D3D11_DestroyTexture(renderer, texture); 1219 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); 1220 return -1; 1221 } 1222 1223 if (texture->format == SDL_PIXELFORMAT_YV12 || 1224 texture->format == SDL_PIXELFORMAT_IYUV) { 1225 textureData->yuv = SDL_TRUE; 1226 1227 textureDesc.Width = (textureDesc.Width + 1) / 2; 1228 textureDesc.Height = (textureDesc.Height + 1) / 2; 1229 1230 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, 1231 &textureDesc, 1232 NULL, 1233 &textureData->mainTextureU 1234 ); 1235 if (FAILED(result)) { 1236 D3D11_DestroyTexture(renderer, texture); 1237 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); 1238 return -1; 1239 } 1240 1241 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, 1242 &textureDesc, 1243 NULL, 1244 &textureData->mainTextureV 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 1253 if (texture->format == SDL_PIXELFORMAT_NV12 || 1254 texture->format == SDL_PIXELFORMAT_NV21) { 1255 D3D11_TEXTURE2D_DESC nvTextureDesc = textureDesc; 1256 1257 textureData->nv12 = SDL_TRUE; 1258 1259 nvTextureDesc.Format = DXGI_FORMAT_R8G8_UNORM; 1260 nvTextureDesc.Width = (textureDesc.Width + 1) / 2; 1261 nvTextureDesc.Height = (textureDesc.Height + 1) / 2; 1262 1263 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, 1264 &nvTextureDesc, 1265 NULL, 1266 &textureData->mainTextureNV 1267 ); 1268 if (FAILED(result)) { 1269 D3D11_DestroyTexture(renderer, texture); 1270 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D"), result); 1271 return -1; 1272 } 1273 } 1274 1275 resourceViewDesc.Format = textureDesc.Format; 1276 resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; 1277 resourceViewDesc.Texture2D.MostDetailedMip = 0; 1278 resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels; 1279 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, 1280 (ID3D11Resource *)textureData->mainTexture, 1281 &resourceViewDesc, 1282 &textureData->mainTextureResourceView 1283 ); 1284 if (FAILED(result)) { 1285 D3D11_DestroyTexture(renderer, texture); 1286 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); 1287 return -1; 1288 } 1289 1290 if (textureData->yuv) { 1291 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, 1292 (ID3D11Resource *)textureData->mainTextureU, 1293 &resourceViewDesc, 1294 &textureData->mainTextureResourceViewU 1295 ); 1296 if (FAILED(result)) { 1297 D3D11_DestroyTexture(renderer, texture); 1298 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); 1299 return -1; 1300 } 1301 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, 1302 (ID3D11Resource *)textureData->mainTextureV, 1303 &resourceViewDesc, 1304 &textureData->mainTextureResourceViewV 1305 ); 1306 if (FAILED(result)) { 1307 D3D11_DestroyTexture(renderer, texture); 1308 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); 1309 return -1; 1310 } 1311 } 1312 1313 if (textureData->nv12) { 1314 D3D11_SHADER_RESOURCE_VIEW_DESC nvResourceViewDesc = resourceViewDesc; 1315 1316 nvResourceViewDesc.Format = DXGI_FORMAT_R8G8_UNORM; 1317 1318 result = ID3D11Device_CreateShaderResourceView(rendererData->d3dDevice, 1319 (ID3D11Resource *)textureData->mainTextureNV, 1320 &nvResourceViewDesc, 1321 &textureData->mainTextureResourceViewNV 1322 ); 1323 if (FAILED(result)) { 1324 D3D11_DestroyTexture(renderer, texture); 1325 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateShaderResourceView"), result); 1326 return -1; 1327 } 1328 } 1329 1330 if (texture->access & SDL_TEXTUREACCESS_TARGET) { 1331 D3D11_RENDER_TARGET_VIEW_DESC renderTargetViewDesc; 1332 renderTargetViewDesc.Format = textureDesc.Format; 1333 renderTargetViewDesc.ViewDimension = D3D11_RTV_DIMENSION_TEXTURE2D; 1334 renderTargetViewDesc.Texture2D.MipSlice = 0; 1335 1336 result = ID3D11Device_CreateRenderTargetView(rendererData->d3dDevice, 1337 (ID3D11Resource *)textureData->mainTexture, 1338 &renderTargetViewDesc, 1339 &textureData->mainTextureRenderTargetView); 1340 if (FAILED(result)) { 1341 D3D11_DestroyTexture(renderer, texture); 1342 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateRenderTargetView"), result); 1343 return -1; 1344 } 1345 } 1346 1347 return 0; 1348} 1349 1350static void 1351D3D11_DestroyTexture(SDL_Renderer * renderer, 1352 SDL_Texture * texture) 1353{ 1354 D3D11_TextureData *data = (D3D11_TextureData *)texture->driverdata; 1355 1356 if (!data) { 1357 return; 1358 } 1359 1360 SAFE_RELEASE(data->mainTexture); 1361 SAFE_RELEASE(data->mainTextureResourceView); 1362 SAFE_RELEASE(data->mainTextureRenderTargetView); 1363 SAFE_RELEASE(data->stagingTexture); 1364 SAFE_RELEASE(data->mainTextureU); 1365 SAFE_RELEASE(data->mainTextureResourceViewU); 1366 SAFE_RELEASE(data->mainTextureV); 1367 SAFE_RELEASE(data->mainTextureResourceViewV); 1368 SDL_free(data->pixels); 1369 SDL_free(data); 1370 texture->driverdata = NULL; 1371} 1372 1373static int 1374D3D11_UpdateTextureInternal(D3D11_RenderData *rendererData, ID3D11Texture2D *texture, int bpp, int x, int y, int w, int h, const void *pixels, int pitch) 1375{ 1376 ID3D11Texture2D *stagingTexture; 1377 const Uint8 *src; 1378 Uint8 *dst; 1379 int row; 1380 UINT length; 1381 HRESULT result; 1382 D3D11_TEXTURE2D_DESC stagingTextureDesc; 1383 D3D11_MAPPED_SUBRESOURCE textureMemory; 1384 1385 /* Create a 'staging' texture, which will be used to write to a portion of the main texture. */ 1386 ID3D11Texture2D_GetDesc(texture, &stagingTextureDesc); 1387 stagingTextureDesc.Width = w; 1388 stagingTextureDesc.Height = h; 1389 stagingTextureDesc.BindFlags = 0; 1390 stagingTextureDesc.MiscFlags = 0; 1391 stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 1392 stagingTextureDesc.Usage = D3D11_USAGE_STAGING; 1393 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, 1394 &stagingTextureDesc, 1395 NULL, 1396 &stagingTexture); 1397 if (FAILED(result)) { 1398 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); 1399 return -1; 1400 } 1401 1402 /* Get a write-only pointer to data in the staging texture: */ 1403 result = ID3D11DeviceContext_Map(rendererData->d3dContext, 1404 (ID3D11Resource *)stagingTexture, 1405 0, 1406 D3D11_MAP_WRITE, 1407 0, 1408 &textureMemory 1409 ); 1410 if (FAILED(result)) { 1411 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); 1412 SAFE_RELEASE(stagingTexture); 1413 return -1; 1414 } 1415 1416 src = (const Uint8 *)pixels; 1417 dst = textureMemory.pData; 1418 length = w * bpp; 1419 if (length == pitch && length == textureMemory.RowPitch) { 1420 SDL_memcpy(dst, src, length*h); 1421 } else { 1422 if (length > (UINT)pitch) { 1423 length = pitch; 1424 } 1425 if (length > textureMemory.RowPitch) { 1426 length = textureMemory.RowPitch; 1427 } 1428 for (row = 0; row < h; ++row) { 1429 SDL_memcpy(dst, src, length); 1430 src += pitch; 1431 dst += textureMemory.RowPitch; 1432 } 1433 } 1434 1435 /* Commit the pixel buffer's changes back to the staging texture: */ 1436 ID3D11DeviceContext_Unmap(rendererData->d3dContext, 1437 (ID3D11Resource *)stagingTexture, 1438 0); 1439 1440 /* Copy the staging texture's contents back to the texture: */ 1441 ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext, 1442 (ID3D11Resource *)texture, 1443 0, 1444 x, 1445 y, 1446 0, 1447 (ID3D11Resource *)stagingTexture, 1448 0, 1449 NULL); 1450 1451 SAFE_RELEASE(stagingTexture); 1452 1453 return 0; 1454} 1455 1456static int 1457D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture, 1458 const SDL_Rect * rect, const void * srcPixels, 1459 int srcPitch) 1460{ 1461 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata; 1462 D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata; 1463 1464 if (!textureData) { 1465 SDL_SetError("Texture is not currently available"); 1466 return -1; 1467 } 1468 1469 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, srcPixels, srcPitch) < 0) { 1470 return -1; 1471 } 1472 1473 if (textureData->yuv) { 1474 /* Skip to the correct offset into the next texture */ 1475 srcPixels = (const void*)((const Uint8*)srcPixels + rect->h * srcPitch); 1476 1477 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) { 1478 return -1; 1479 } 1480 1481 /* Skip to the correct offset into the next texture */ 1482 srcPixels = (const void*)((const Uint8*)srcPixels + ((rect->h + 1) / 2) * ((srcPitch + 1) / 2)); 1483 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) { 1484 return -1; 1485 } 1486 } 1487 1488 if (textureData->nv12) { 1489 /* Skip to the correct offset into the next texture */ 1490 srcPixels = (const void*)((const Uint8*)srcPixels + rect->h * srcPitch); 1491 1492 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) { 1493 return -1; 1494 } 1495 } 1496 return 0; 1497} 1498 1499static int 1500D3D11_UpdateTextureYUV(SDL_Renderer * renderer, SDL_Texture * texture, 1501 const SDL_Rect * rect, 1502 const Uint8 *Yplane, int Ypitch, 1503 const Uint8 *Uplane, int Upitch, 1504 const Uint8 *Vplane, int Vpitch) 1505{ 1506 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata; 1507 D3D11_TextureData *textureData = (D3D11_TextureData *)texture->driverdata; 1508 1509 if (!textureData) { 1510 SDL_SetError("Texture is not currently available"); 1511 return -1; 1512 } 1513 1514 if (D3D11_UpdateTextureInternal(rendererData, textureData->mainTexture, SDL_BYTESPERPIXEL(texture->format), rect->x, rect->y, rect->w, rect->h, Yplane, Ypitch) < 0) { 1515 return -1; 1516 } 1517 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) { 1518 return -1; 1519 } 1520 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) { 1521 return -1; 1522 } 1523 return 0; 1524} 1525 1526static int 1527D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture, 1528 const SDL_Rect * rect, void **pixels, int *pitch) 1529{ 1530 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 1531 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; 1532 HRESULT result = S_OK; 1533 D3D11_TEXTURE2D_DESC stagingTextureDesc; 1534 D3D11_MAPPED_SUBRESOURCE textureMemory; 1535 1536 if (!textureData) { 1537 SDL_SetError("Texture is not currently available"); 1538 return -1; 1539 } 1540 1541 if (textureData->yuv || textureData->nv12) { 1542 /* It's more efficient to upload directly... */ 1543 if (!textureData->pixels) { 1544 textureData->pitch = texture->w; 1545 textureData->pixels = (Uint8 *)SDL_malloc((texture->h * textureData->pitch * 3) / 2); 1546 if (!textureData->pixels) { 1547 return SDL_OutOfMemory(); 1548 } 1549 } 1550 textureData->locked_rect = *rect; 1551 *pixels = 1552 (void *)((Uint8 *)textureData->pixels + rect->y * textureData->pitch + 1553 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1554 *pitch = textureData->pitch; 1555 return 0; 1556 } 1557 1558 if (textureData->stagingTexture) { 1559 return SDL_SetError("texture is already locked"); 1560 } 1561 1562 /* Create a 'staging' texture, which will be used to write to a portion 1563 * of the main texture. This is necessary, as Direct3D 11.1 does not 1564 * have the ability to write a CPU-bound pixel buffer to a rectangular 1565 * subrect of a texture. Direct3D 11.1 can, however, write a pixel 1566 * buffer to an entire texture, hence the use of a staging texture. 1567 * 1568 * TODO, WinRT: consider avoiding the use of a staging texture in D3D11_LockTexture if/when the entire texture is being updated 1569 */ 1570 ID3D11Texture2D_GetDesc(textureData->mainTexture, &stagingTextureDesc); 1571 stagingTextureDesc.Width = rect->w; 1572 stagingTextureDesc.Height = rect->h; 1573 stagingTextureDesc.BindFlags = 0; 1574 stagingTextureDesc.MiscFlags = 0; 1575 stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 1576 stagingTextureDesc.Usage = D3D11_USAGE_STAGING; 1577 result = ID3D11Device_CreateTexture2D(rendererData->d3dDevice, 1578 &stagingTextureDesc, 1579 NULL, 1580 &textureData->stagingTexture); 1581 if (FAILED(result)) { 1582 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); 1583 return -1; 1584 } 1585 1586 /* Get a write-only pointer to data in the staging texture: */ 1587 result = ID3D11DeviceContext_Map(rendererData->d3dContext, 1588 (ID3D11Resource *)textureData->stagingTexture, 1589 0, 1590 D3D11_MAP_WRITE, 1591 0, 1592 &textureMemory 1593 ); 1594 if (FAILED(result)) { 1595 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); 1596 SAFE_RELEASE(textureData->stagingTexture); 1597 return -1; 1598 } 1599 1600 /* Make note of where the staging texture will be written to 1601 * (on a call to SDL_UnlockTexture): 1602 */ 1603 textureData->lockedTexturePositionX = rect->x; 1604 textureData->lockedTexturePositionY = rect->y; 1605 1606 /* Make sure the caller has information on the texture's pixel buffer, 1607 * then return: 1608 */ 1609 *pixels = textureMemory.pData; 1610 *pitch = textureMemory.RowPitch; 1611 return 0; 1612} 1613 1614static void 1615D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture) 1616{ 1617 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 1618 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; 1619 1620 if (!textureData) { 1621 return; 1622 } 1623 1624 if (textureData->yuv || textureData->nv12) { 1625 const SDL_Rect *rect = &textureData->locked_rect; 1626 void *pixels = 1627 (void *) ((Uint8 *) textureData->pixels + rect->y * textureData->pitch + 1628 rect->x * SDL_BYTESPERPIXEL(texture->format)); 1629 D3D11_UpdateTexture(renderer, texture, rect, pixels, textureData->pitch); 1630 return; 1631 } 1632 1633 /* Commit the pixel buffer's changes back to the staging texture: */ 1634 ID3D11DeviceContext_Unmap(rendererData->d3dContext, 1635 (ID3D11Resource *)textureData->stagingTexture, 1636 0); 1637 1638 /* Copy the staging texture's contents back to the main texture: */ 1639 ID3D11DeviceContext_CopySubresourceRegion(rendererData->d3dContext, 1640 (ID3D11Resource *)textureData->mainTexture, 1641 0, 1642 textureData->lockedTexturePositionX, 1643 textureData->lockedTexturePositionY, 1644 0, 1645 (ID3D11Resource *)textureData->stagingTexture, 1646 0, 1647 NULL); 1648 1649 SAFE_RELEASE(textureData->stagingTexture); 1650} 1651 1652static int 1653D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture) 1654{ 1655 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 1656 D3D11_TextureData *textureData = NULL; 1657 1658 if (texture == NULL) { 1659 rendererData->currentOffscreenRenderTargetView = NULL; 1660 return 0; 1661 } 1662 1663 textureData = (D3D11_TextureData *) texture->driverdata; 1664 1665 if (!textureData->mainTextureRenderTargetView) { 1666 return SDL_SetError("specified texture is not a render target"); 1667 } 1668 1669 rendererData->currentOffscreenRenderTargetView = textureData->mainTextureRenderTargetView; 1670 1671 return 0; 1672} 1673 1674static void 1675D3D11_SetModelMatrix(SDL_Renderer *renderer, const Float4X4 *matrix) 1676{ 1677 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata; 1678 1679 if (matrix) { 1680 data->vertexShaderConstantsData.model = *matrix; 1681 } else { 1682 data->vertexShaderConstantsData.model = MatrixIdentity(); 1683 } 1684 1685 ID3D11DeviceContext_UpdateSubresource(data->d3dContext, 1686 (ID3D11Resource *)data->vertexShaderConstants, 1687 0, 1688 NULL, 1689 &data->vertexShaderConstantsData, 1690 0, 1691 0 1692 ); 1693} 1694 1695static int 1696D3D11_UpdateViewport(SDL_Renderer * renderer) 1697{ 1698 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; 1699 Float4X4 projection; 1700 Float4X4 view; 1701 SDL_FRect orientationAlignedViewport; 1702 BOOL swapDimensions; 1703 D3D11_VIEWPORT viewport; 1704 const int rotation = D3D11_GetRotationForCurrentRenderTarget(renderer); 1705 1706 if (renderer->viewport.w == 0 || renderer->viewport.h == 0) { 1707 /* If the viewport is empty, assume that it is because 1708 * SDL_CreateRenderer is calling it, and will call it again later 1709 * with a non-empty viewport. 1710 */ 1711 /* SDL_Log("%s, no viewport was set!\n", __FUNCTION__); */ 1712 return 0; 1713 } 1714 1715 /* Make sure the SDL viewport gets rotated to that of the physical display's rotation. 1716 * Keep in mind here that the Y-axis will be been inverted (from Direct3D's 1717 * default coordinate system) so rotations will be done in the opposite 1718 * direction of the DXGI_MODE_ROTATION enumeration. 1719 */ 1720 switch (rotation) { 1721 case DXGI_MODE_ROTATION_IDENTITY: 1722 projection = MatrixIdentity(); 1723 break; 1724 case DXGI_MODE_ROTATION_ROTATE270: 1725 projection = MatrixRotationZ(SDL_static_cast(float, M_PI * 0.5f)); 1726 break; 1727 case DXGI_MODE_ROTATION_ROTATE180: 1728 projection = MatrixRotationZ(SDL_static_cast(float, M_PI)); 1729 break; 1730 case DXGI_MODE_ROTATION_ROTATE90: 1731 projection = MatrixRotationZ(SDL_static_cast(float, -M_PI * 0.5f)); 1732 break; 1733 default: 1734 return SDL_SetError("An unknown DisplayOrientation is being used"); 1735 } 1736 1737 /* Update the view matrix */ 1738 view.m[0][0] = 2.0f / renderer->viewport.w; 1739 view.m[0][1] = 0.0f; 1740 view.m[0][2] = 0.0f; 1741 view.m[0][3] = 0.0f; 1742 view.m[1][0] = 0.0f; 1743 view.m[1][1] = -2.0f / renderer->viewport.h; 1744 view.m[1][2] = 0.0f; 1745 view.m[1][3] = 0.0f; 1746 view.m[2][0] = 0.0f; 1747 view.m[2][1] = 0.0f; 1748 view.m[2][2] = 1.0f; 1749 view.m[2][3] = 0.0f; 1750 view.m[3][0] = -1.0f; 1751 view.m[3][1] = 1.0f; 1752 view.m[3][2] = 0.0f; 1753 view.m[3][3] = 1.0f; 1754 1755 /* Combine the projection + view matrix together now, as both only get 1756 * set here (as of this writing, on Dec 26, 2013). When done, store it 1757 * for eventual transfer to the GPU. 1758 */ 1759 data->vertexShaderConstantsData.projectionAndView = MatrixMultiply( 1760 view, 1761 projection); 1762 1763 /* Reset the model matrix */ 1764 D3D11_SetModelMatrix(renderer, NULL); 1765 1766 /* Update the Direct3D viewport, which seems to be aligned to the 1767 * swap buffer's coordinate space, which is always in either 1768 * a landscape mode, for all Windows 8/RT devices, or a portrait mode, 1769 * for Windows Phone devices. 1770 */ 1771 swapDimensions = D3D11_IsDisplayRotated90Degrees(rotation); 1772 if (swapDimensions) { 1773 orientationAlignedViewport.x = (float) renderer->viewport.y; 1774 orientationAlignedViewport.y = (float) renderer->viewport.x; 1775 orientationAlignedViewport.w = (float) renderer->viewport.h; 1776 orientationAlignedViewport.h = (float) renderer->viewport.w; 1777 } else { 1778 orientationAlignedViewport.x = (float) renderer->viewport.x; 1779 orientationAlignedViewport.y = (float) renderer->viewport.y; 1780 orientationAlignedViewport.w = (float) renderer->viewport.w; 1781 orientationAlignedViewport.h = (float) renderer->viewport.h; 1782 } 1783 /* TODO, WinRT: get custom viewports working with non-Landscape modes (Portrait, PortraitFlipped, and LandscapeFlipped) */ 1784 1785 viewport.TopLeftX = orientationAlignedViewport.x; 1786 viewport.TopLeftY = orientationAlignedViewport.y; 1787 viewport.Width = orientationAlignedViewport.w; 1788 viewport.Height = orientationAlignedViewport.h; 1789 viewport.MinDepth = 0.0f; 1790 viewport.MaxDepth = 1.0f; 1791 /* SDL_Log("%s: D3D viewport = {%f,%f,%f,%f}\n", __FUNCTION__, viewport.TopLeftX, viewport.TopLeftY, viewport.Width, viewport.Height); */ 1792 ID3D11DeviceContext_RSSetViewports(data->d3dContext, 1, &viewport); 1793 1794 return 0; 1795} 1796 1797static int 1798D3D11_UpdateClipRect(SDL_Renderer * renderer) 1799{ 1800 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; 1801 1802 if (!renderer->clipping_enabled) { 1803 ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 0, NULL); 1804 } else { 1805 D3D11_RECT scissorRect; 1806 if (D3D11_GetViewportAlignedD3DRect(renderer, &renderer->clip_rect, &scissorRect, TRUE) != 0) { 1807 /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */ 1808 return -1; 1809 } 1810 ID3D11DeviceContext_RSSetScissorRects(data->d3dContext, 1, &scissorRect); 1811 } 1812 1813 return 0; 1814} 1815 1816static void 1817D3D11_ReleaseMainRenderTargetView(SDL_Renderer * renderer) 1818{ 1819 D3D11_RenderData *data = (D3D11_RenderData *)renderer->driverdata; 1820 ID3D11DeviceContext_OMSetRenderTargets(data->d3dContext, 0, NULL, NULL); 1821 SAFE_RELEASE(data->mainRenderTargetView); 1822} 1823 1824static ID3D11RenderTargetView * 1825D3D11_GetCurrentRenderTargetView(SDL_Renderer * renderer) 1826{ 1827 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; 1828 if (data->currentOffscreenRenderTargetView) { 1829 return data->currentOffscreenRenderTargetView; 1830 } else { 1831 return data->mainRenderTargetView; 1832 } 1833} 1834 1835static int 1836D3D11_RenderClear(SDL_Renderer * renderer) 1837{ 1838 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; 1839 const float colorRGBA[] = { 1840 (renderer->r / 255.0f), 1841 (renderer->g / 255.0f), 1842 (renderer->b / 255.0f), 1843 (renderer->a / 255.0f) 1844 }; 1845 ID3D11DeviceContext_ClearRenderTargetView(data->d3dContext, 1846 D3D11_GetCurrentRenderTargetView(renderer), 1847 colorRGBA 1848 ); 1849 return 0; 1850} 1851 1852static int 1853D3D11_UpdateVertexBuffer(SDL_Renderer *renderer, 1854 const void * vertexData, size_t dataSizeInBytes) 1855{ 1856 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 1857 D3D11_BUFFER_DESC vertexBufferDesc; 1858 HRESULT result = S_OK; 1859 D3D11_SUBRESOURCE_DATA vertexBufferData; 1860 const UINT stride = sizeof(VertexPositionColor); 1861 const UINT offset = 0; 1862 1863 if (rendererData->vertexBuffer) { 1864 ID3D11Buffer_GetDesc(rendererData->vertexBuffer, &vertexBufferDesc); 1865 } else { 1866 SDL_zero(vertexBufferDesc); 1867 } 1868 1869 if (rendererData->vertexBuffer && vertexBufferDesc.ByteWidth >= dataSizeInBytes) { 1870 D3D11_MAPPED_SUBRESOURCE mappedResource; 1871 result = ID3D11DeviceContext_Map(rendererData->d3dContext, 1872 (ID3D11Resource *)rendererData->vertexBuffer, 1873 0, 1874 D3D11_MAP_WRITE_DISCARD, 1875 0, 1876 &mappedResource 1877 ); 1878 if (FAILED(result)) { 1879 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [vertex buffer]"), result); 1880 return -1; 1881 } 1882 SDL_memcpy(mappedResource.pData, vertexData, dataSizeInBytes); 1883 ID3D11DeviceContext_Unmap(rendererData->d3dContext, (ID3D11Resource *)rendererData->vertexBuffer, 0); 1884 } else { 1885 SAFE_RELEASE(rendererData->vertexBuffer); 1886 1887 vertexBufferDesc.ByteWidth = (UINT) dataSizeInBytes; 1888 vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC; 1889 vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; 1890 vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; 1891 1892 SDL_zero(vertexBufferData); 1893 vertexBufferData.pSysMem = vertexData; 1894 vertexBufferData.SysMemPitch = 0; 1895 vertexBufferData.SysMemSlicePitch = 0; 1896 1897 result = ID3D11Device_CreateBuffer(rendererData->d3dDevice, 1898 &vertexBufferDesc, 1899 &vertexBufferData, 1900 &rendererData->vertexBuffer 1901 ); 1902 if (FAILED(result)) { 1903 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateBuffer [vertex buffer]"), result); 1904 return -1; 1905 } 1906 1907 ID3D11DeviceContext_IASetVertexBuffers(rendererData->d3dContext, 1908 0, 1909 1, 1910 &rendererData->vertexBuffer, 1911 &stride, 1912 &offset 1913 ); 1914 } 1915 1916 return 0; 1917} 1918 1919static void 1920D3D11_RenderStartDrawOp(SDL_Renderer * renderer) 1921{ 1922 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata; 1923 ID3D11RasterizerState *rasterizerState; 1924 ID3D11RenderTargetView *renderTargetView = D3D11_GetCurrentRenderTargetView(renderer); 1925 if (renderTargetView != rendererData->currentRenderTargetView) { 1926 ID3D11DeviceContext_OMSetRenderTargets(rendererData->d3dContext, 1927 1, 1928 &renderTargetView, 1929 NULL 1930 ); 1931 rendererData->currentRenderTargetView = renderTargetView; 1932 } 1933 1934 if (!renderer->clipping_enabled) { 1935 rasterizerState = rendererData->mainRasterizer; 1936 } else { 1937 rasterizerState = rendererData->clippedRasterizer; 1938 } 1939 if (rasterizerState != rendererData->currentRasterizerState) { 1940 ID3D11DeviceContext_RSSetState(rendererData->d3dContext, rasterizerState); 1941 rendererData->currentRasterizerState = rasterizerState; 1942 } 1943} 1944 1945static void 1946D3D11_RenderSetBlendMode(SDL_Renderer * renderer, SDL_BlendMode blendMode) 1947{ 1948 D3D11_RenderData *rendererData = (D3D11_RenderData *)renderer->driverdata; 1949 ID3D11BlendState *blendState = NULL; 1950 if (blendMode != SDL_BLENDMODE_NONE) { 1951 int i; 1952 for (i = 0; i < rendererData->blendModesCount; ++i) { 1953 if (blendMode == rendererData->blendModes[i].blendMode) { 1954 blendState = rendererData->blendModes[i].blendState; 1955 break; 1956 } 1957 } 1958 if (!blendState) { 1959 if (D3D11_CreateBlendState(renderer, blendMode)) { 1960 /* Successfully created the blend state, try again */ 1961 D3D11_RenderSetBlendMode(renderer, blendMode); 1962 } 1963 return; 1964 } 1965 } 1966 if (blendState != rendererData->currentBlendState) { 1967 ID3D11DeviceContext_OMSetBlendState(rendererData->d3dContext, blendState, 0, 0xFFFFFFFF); 1968 rendererData->currentBlendState = blendState; 1969 } 1970} 1971 1972static void 1973D3D11_SetPixelShader(SDL_Renderer * renderer, 1974 ID3D11PixelShader * shader, 1975 int numShaderResources, 1976 ID3D11ShaderResourceView ** shaderResources, 1977 ID3D11SamplerState * sampler) 1978{ 1979 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 1980 ID3D11ShaderResourceView *shaderResource; 1981 if (shader != rendererData->currentShader) { 1982 ID3D11DeviceContext_PSSetShader(rendererData->d3dContext, shader, NULL, 0); 1983 rendererData->currentShader = shader; 1984 } 1985 if (numShaderResources > 0) { 1986 shaderResource = shaderResources[0]; 1987 } else { 1988 shaderResource = NULL; 1989 } 1990 if (shaderResource != rendererData->currentShaderResource) { 1991 ID3D11DeviceContext_PSSetShaderResources(rendererData->d3dContext, 0, numShaderResources, shaderResources); 1992 rendererData->currentShaderResource = shaderResource; 1993 } 1994 if (sampler != rendererData->currentSampler) { 1995 ID3D11DeviceContext_PSSetSamplers(rendererData->d3dContext, 0, 1, &sampler); 1996 rendererData->currentSampler = sampler; 1997 } 1998} 1999 2000static void 2001D3D11_RenderFinishDrawOp(SDL_Renderer * renderer, 2002 D3D11_PRIMITIVE_TOPOLOGY primitiveTopology, 2003 UINT vertexCount) 2004{ 2005 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2006 2007 ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, primitiveTopology); 2008 ID3D11DeviceContext_Draw(rendererData->d3dContext, vertexCount, 0); 2009} 2010 2011static int 2012D3D11_RenderDrawPoints(SDL_Renderer * renderer, 2013 const SDL_FPoint * points, int count) 2014{ 2015 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2016 float r, g, b, a; 2017 VertexPositionColor *vertices; 2018 int i; 2019 2020 r = (float)(renderer->r / 255.0f); 2021 g = (float)(renderer->g / 255.0f); 2022 b = (float)(renderer->b / 255.0f); 2023 a = (float)(renderer->a / 255.0f); 2024 2025 vertices = SDL_stack_alloc(VertexPositionColor, count); 2026 for (i = 0; i < count; ++i) { 2027 const VertexPositionColor v = { { points[i].x + 0.5f, points[i].y + 0.5f, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } }; 2028 vertices[i] = v; 2029 } 2030 2031 D3D11_RenderStartDrawOp(renderer); 2032 D3D11_RenderSetBlendMode(renderer, renderer->blendMode); 2033 if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { 2034 SDL_stack_free(vertices); 2035 return -1; 2036 } 2037 2038 D3D11_SetPixelShader( 2039 renderer, 2040 rendererData->pixelShaders[SHADER_SOLID], 2041 0, 2042 NULL, 2043 NULL); 2044 2045 D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST, count); 2046 SDL_stack_free(vertices); 2047 return 0; 2048} 2049 2050static int 2051D3D11_RenderDrawLines(SDL_Renderer * renderer, 2052 const SDL_FPoint * points, int count) 2053{ 2054 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2055 float r, g, b, a; 2056 VertexPositionColor *vertices; 2057 int i; 2058 2059 r = (float)(renderer->r / 255.0f); 2060 g = (float)(renderer->g / 255.0f); 2061 b = (float)(renderer->b / 255.0f); 2062 a = (float)(renderer->a / 255.0f); 2063 2064 vertices = SDL_stack_alloc(VertexPositionColor, count); 2065 for (i = 0; i < count; ++i) { 2066 const VertexPositionColor v = { { points[i].x + 0.5f, points[i].y + 0.5f, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } }; 2067 vertices[i] = v; 2068 } 2069 2070 D3D11_RenderStartDrawOp(renderer); 2071 D3D11_RenderSetBlendMode(renderer, renderer->blendMode); 2072 if (D3D11_UpdateVertexBuffer(renderer, vertices, (unsigned int)count * sizeof(VertexPositionColor)) != 0) { 2073 SDL_stack_free(vertices); 2074 return -1; 2075 } 2076 2077 D3D11_SetPixelShader( 2078 renderer, 2079 rendererData->pixelShaders[SHADER_SOLID], 2080 0, 2081 NULL, 2082 NULL); 2083 2084 D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, count); 2085 2086 if (points[0].x != points[count - 1].x || points[0].y != points[count - 1].y) { 2087 ID3D11DeviceContext_IASetPrimitiveTopology(rendererData->d3dContext, D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); 2088 ID3D11DeviceContext_Draw(rendererData->d3dContext, 1, count - 1); 2089 } 2090 2091 SDL_stack_free(vertices); 2092 return 0; 2093} 2094 2095static int 2096D3D11_RenderFillRects(SDL_Renderer * renderer, 2097 const SDL_FRect * rects, int count) 2098{ 2099 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2100 float r, g, b, a; 2101 int i; 2102 2103 r = (float)(renderer->r / 255.0f); 2104 g = (float)(renderer->g / 255.0f); 2105 b = (float)(renderer->b / 255.0f); 2106 a = (float)(renderer->a / 255.0f); 2107 2108 for (i = 0; i < count; ++i) { 2109 VertexPositionColor vertices[] = { 2110 { { rects[i].x, rects[i].y, 0.0f }, { 0.0f, 0.0f}, {r, g, b, a} }, 2111 { { rects[i].x, rects[i].y + rects[i].h, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } }, 2112 { { rects[i].x + rects[i].w, rects[i].y, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } }, 2113 { { rects[i].x + rects[i].w, rects[i].y + rects[i].h, 0.0f }, { 0.0f, 0.0f }, { r, g, b, a } }, 2114 }; 2115 2116 D3D11_RenderStartDrawOp(renderer); 2117 D3D11_RenderSetBlendMode(renderer, renderer->blendMode); 2118 if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { 2119 return -1; 2120 } 2121 2122 D3D11_SetPixelShader( 2123 renderer, 2124 rendererData->pixelShaders[SHADER_SOLID], 2125 0, 2126 NULL, 2127 NULL); 2128 2129 D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, SDL_arraysize(vertices)); 2130 } 2131 2132 return 0; 2133} 2134 2135static int 2136D3D11_RenderSetupSampler(SDL_Renderer * renderer, SDL_Texture * texture) 2137{ 2138 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2139 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; 2140 ID3D11SamplerState *textureSampler; 2141 2142 switch (textureData->scaleMode) { 2143 case D3D11_FILTER_MIN_MAG_MIP_POINT: 2144 textureSampler = rendererData->nearestPixelSampler; 2145 break; 2146 case D3D11_FILTER_MIN_MAG_MIP_LINEAR: 2147 textureSampler = rendererData->linearSampler; 2148 break; 2149 default: 2150 return SDL_SetError("Unknown scale mode: %d\n", textureData->scaleMode); 2151 } 2152 2153 if (textureData->yuv) { 2154 ID3D11ShaderResourceView *shaderResources[] = { 2155 textureData->mainTextureResourceView, 2156 textureData->mainTextureResourceViewU, 2157 textureData->mainTextureResourceViewV 2158 }; 2159 D3D11_Shader shader; 2160 2161 switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) { 2162 case SDL_YUV_CONVERSION_JPEG: 2163 shader = SHADER_YUV_JPEG; 2164 break; 2165 case SDL_YUV_CONVERSION_BT601: 2166 shader = SHADER_YUV_BT601; 2167 break; 2168 case SDL_YUV_CONVERSION_BT709: 2169 shader = SHADER_YUV_BT709; 2170 break; 2171 default: 2172 return SDL_SetError("Unsupported YUV conversion mode"); 2173 } 2174 2175 D3D11_SetPixelShader( 2176 renderer, 2177 rendererData->pixelShaders[shader], 2178 SDL_arraysize(shaderResources), 2179 shaderResources, 2180 textureSampler); 2181 2182 } else if (textureData->nv12) { 2183 ID3D11ShaderResourceView *shaderResources[] = { 2184 textureData->mainTextureResourceView, 2185 textureData->mainTextureResourceViewNV, 2186 }; 2187 D3D11_Shader shader; 2188 2189 switch (SDL_GetYUVConversionModeForResolution(texture->w, texture->h)) { 2190 case SDL_YUV_CONVERSION_JPEG: 2191 shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_JPEG : SHADER_NV21_JPEG; 2192 break; 2193 case SDL_YUV_CONVERSION_BT601: 2194 shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT601 : SHADER_NV21_BT601; 2195 break; 2196 case SDL_YUV_CONVERSION_BT709: 2197 shader = texture->format == SDL_PIXELFORMAT_NV12 ? SHADER_NV12_BT709 : SHADER_NV21_BT709; 2198 break; 2199 default: 2200 return SDL_SetError("Unsupported YUV conversion mode"); 2201 } 2202 2203 D3D11_SetPixelShader( 2204 renderer, 2205 rendererData->pixelShaders[shader], 2206 SDL_arraysize(shaderResources), 2207 shaderResources, 2208 textureSampler); 2209 2210 } else { 2211 D3D11_SetPixelShader( 2212 renderer, 2213 rendererData->pixelShaders[SHADER_RGB], 2214 1, 2215 &textureData->mainTextureResourceView, 2216 textureSampler); 2217 } 2218 2219 return 0; 2220} 2221 2222static int 2223D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture, 2224 const SDL_Rect * srcrect, const SDL_FRect * dstrect) 2225{ 2226 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2227 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; 2228 float minu, maxu, minv, maxv; 2229 Float4 color; 2230 VertexPositionColor vertices[4]; 2231 2232 D3D11_RenderStartDrawOp(renderer); 2233 D3D11_RenderSetBlendMode(renderer, texture->blendMode); 2234 2235 minu = (float) srcrect->x / texture->w; 2236 maxu = (float) (srcrect->x + srcrect->w) / texture->w; 2237 minv = (float) srcrect->y / texture->h; 2238 maxv = (float) (srcrect->y + srcrect->h) / texture->h; 2239 2240 color.x = 1.0f; /* red */ 2241 color.y = 1.0f; /* green */ 2242 color.z = 1.0f; /* blue */ 2243 color.w = 1.0f; /* alpha */ 2244 if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) { 2245 color.x = (float)(texture->r / 255.0f); /* red */ 2246 color.y = (float)(texture->g / 255.0f); /* green */ 2247 color.z = (float)(texture->b / 255.0f); /* blue */ 2248 } 2249 if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) { 2250 color.w = (float)(texture->a / 255.0f); /* alpha */ 2251 } 2252 2253 vertices[0].pos.x = dstrect->x; 2254 vertices[0].pos.y = dstrect->y; 2255 vertices[0].pos.z = 0.0f; 2256 vertices[0].tex.x = minu; 2257 vertices[0].tex.y = minv; 2258 vertices[0].color = color; 2259 2260 vertices[1].pos.x = dstrect->x; 2261 vertices[1].pos.y = dstrect->y + dstrect->h; 2262 vertices[1].pos.z = 0.0f; 2263 vertices[1].tex.x = minu; 2264 vertices[1].tex.y = maxv; 2265 vertices[1].color = color; 2266 2267 vertices[2].pos.x = dstrect->x + dstrect->w; 2268 vertices[2].pos.y = dstrect->y; 2269 vertices[2].pos.z = 0.0f; 2270 vertices[2].tex.x = maxu; 2271 vertices[2].tex.y = minv; 2272 vertices[2].color = color; 2273 2274 vertices[3].pos.x = dstrect->x + dstrect->w; 2275 vertices[3].pos.y = dstrect->y + dstrect->h; 2276 vertices[3].pos.z = 0.0f; 2277 vertices[3].tex.x = maxu; 2278 vertices[3].tex.y = maxv; 2279 vertices[3].color = color; 2280 2281 if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { 2282 return -1; 2283 } 2284 2285 if (D3D11_RenderSetupSampler(renderer, texture) < 0) { 2286 return -1; 2287 } 2288 2289 D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); 2290 2291 return 0; 2292} 2293 2294static int 2295D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture, 2296 const SDL_Rect * srcrect, const SDL_FRect * dstrect, 2297 const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip) 2298{ 2299 D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata; 2300 D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata; 2301 float minu, maxu, minv, maxv; 2302 Float4 color; 2303 Float4X4 modelMatrix; 2304 float minx, maxx, miny, maxy; 2305 VertexPositionColor vertices[4]; 2306 2307 D3D11_RenderStartDrawOp(renderer); 2308 D3D11_RenderSetBlendMode(renderer, texture->blendMode); 2309 2310 minu = (float) srcrect->x / texture->w; 2311 maxu = (float) (srcrect->x + srcrect->w) / texture->w; 2312 minv = (float) srcrect->y / texture->h; 2313 maxv = (float) (srcrect->y + srcrect->h) / texture->h; 2314 2315 color.x = 1.0f; /* red */ 2316 color.y = 1.0f; /* green */ 2317 color.z = 1.0f; /* blue */ 2318 color.w = 1.0f; /* alpha */ 2319 if (texture->modMode & SDL_TEXTUREMODULATE_COLOR) { 2320 color.x = (float)(texture->r / 255.0f); /* red */ 2321 color.y = (float)(texture->g / 255.0f); /* green */ 2322 color.z = (float)(texture->b / 255.0f); /* blue */ 2323 } 2324 if (texture->modMode & SDL_TEXTUREMODULATE_ALPHA) { 2325 color.w = (float)(texture->a / 255.0f); /* alpha */ 2326 } 2327 2328 if (flip & SDL_FLIP_HORIZONTAL) { 2329 float tmp = maxu; 2330 maxu = minu; 2331 minu = tmp; 2332 } 2333 if (flip & SDL_FLIP_VERTICAL) { 2334 float tmp = maxv; 2335 maxv = minv; 2336 minv = tmp; 2337 } 2338 2339 modelMatrix = MatrixMultiply( 2340 MatrixRotationZ((float)(M_PI * (float) angle / 180.0f)), 2341 MatrixTranslation(dstrect->x + center->x, dstrect->y + center->y, 0) 2342 ); 2343 D3D11_SetModelMatrix(renderer, &modelMatrix); 2344 2345 minx = -center->x; 2346 maxx = dstrect->w - center->x; 2347 miny = -center->y; 2348 maxy = dstrect->h - center->y; 2349 2350 vertices[0].pos.x = minx; 2351 vertices[0].pos.y = miny; 2352 vertices[0].pos.z = 0.0f; 2353 vertices[0].tex.x = minu; 2354 vertices[0].tex.y = minv; 2355 vertices[0].color = color; 2356 2357 vertices[1].pos.x = minx; 2358 vertices[1].pos.y = maxy; 2359 vertices[1].pos.z = 0.0f; 2360 vertices[1].tex.x = minu; 2361 vertices[1].tex.y = maxv; 2362 vertices[1].color = color; 2363 2364 vertices[2].pos.x = maxx; 2365 vertices[2].pos.y = miny; 2366 vertices[2].pos.z = 0.0f; 2367 vertices[2].tex.x = maxu; 2368 vertices[2].tex.y = minv; 2369 vertices[2].color = color; 2370 2371 vertices[3].pos.x = maxx; 2372 vertices[3].pos.y = maxy; 2373 vertices[3].pos.z = 0.0f; 2374 vertices[3].tex.x = maxu; 2375 vertices[3].tex.y = maxv; 2376 vertices[3].color = color; 2377 2378 if (D3D11_UpdateVertexBuffer(renderer, vertices, sizeof(vertices)) != 0) { 2379 return -1; 2380 } 2381 2382 if (D3D11_RenderSetupSampler(renderer, texture) < 0) { 2383 return -1; 2384 } 2385 2386 D3D11_RenderFinishDrawOp(renderer, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP, sizeof(vertices) / sizeof(VertexPositionColor)); 2387 2388 D3D11_SetModelMatrix(renderer, NULL); 2389 2390 return 0; 2391} 2392 2393static int 2394D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect, 2395 Uint32 format, void * pixels, int pitch) 2396{ 2397 D3D11_RenderData * data = (D3D11_RenderData *) renderer->driverdata; 2398 ID3D11Texture2D *backBuffer = NULL; 2399 ID3D11Texture2D *stagingTexture = NULL; 2400 HRESULT result; 2401 int status = -1; 2402 D3D11_TEXTURE2D_DESC stagingTextureDesc; 2403 D3D11_RECT srcRect = {0, 0, 0, 0}; 2404 D3D11_BOX srcBox; 2405 D3D11_MAPPED_SUBRESOURCE textureMemory; 2406 2407 /* Retrieve a pointer to the back buffer: */ 2408 result = IDXGISwapChain_GetBuffer(data->swapChain, 2409 0, 2410 &SDL_IID_ID3D11Texture2D, 2411 (void **)&backBuffer 2412 ); 2413 if (FAILED(result)) { 2414 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain1::GetBuffer [get back buffer]"), result); 2415 goto done; 2416 } 2417 2418 /* Create a staging texture to copy the screen's data to: */ 2419 ID3D11Texture2D_GetDesc(backBuffer, &stagingTextureDesc); 2420 stagingTextureDesc.Width = rect->w; 2421 stagingTextureDesc.Height = rect->h; 2422 stagingTextureDesc.BindFlags = 0; 2423 stagingTextureDesc.MiscFlags = 0; 2424 stagingTextureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; 2425 stagingTextureDesc.Usage = D3D11_USAGE_STAGING; 2426 result = ID3D11Device_CreateTexture2D(data->d3dDevice, 2427 &stagingTextureDesc, 2428 NULL, 2429 &stagingTexture); 2430 if (FAILED(result)) { 2431 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11Device1::CreateTexture2D [create staging texture]"), result); 2432 goto done; 2433 } 2434 2435 /* Copy the desired portion of the back buffer to the staging texture: */ 2436 if (D3D11_GetViewportAlignedD3DRect(renderer, rect, &srcRect, FALSE) != 0) { 2437 /* D3D11_GetViewportAlignedD3DRect will have set the SDL error */ 2438 goto done; 2439 } 2440 2441 srcBox.left = srcRect.left; 2442 srcBox.right = srcRect.right; 2443 srcBox.top = srcRect.top; 2444 srcBox.bottom = srcRect.bottom; 2445 srcBox.front = 0; 2446 srcBox.back = 1; 2447 ID3D11DeviceContext_CopySubresourceRegion(data->d3dContext, 2448 (ID3D11Resource *)stagingTexture, 2449 0, 2450 0, 0, 0, 2451 (ID3D11Resource *)backBuffer, 2452 0, 2453 &srcBox); 2454 2455 /* Map the staging texture's data to CPU-accessible memory: */ 2456 result = ID3D11DeviceContext_Map(data->d3dContext, 2457 (ID3D11Resource *)stagingTexture, 2458 0, 2459 D3D11_MAP_READ, 2460 0, 2461 &textureMemory); 2462 if (FAILED(result)) { 2463 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("ID3D11DeviceContext1::Map [map staging texture]"), result); 2464 goto done; 2465 } 2466 2467 /* Copy the data into the desired buffer, converting pixels to the 2468 * desired format at the same time: 2469 */ 2470 if (SDL_ConvertPixels( 2471 rect->w, rect->h, 2472 D3D11_DXGIFormatToSDLPixelFormat(stagingTextureDesc.Format), 2473 textureMemory.pData, 2474 textureMemory.RowPitch, 2475 format, 2476 pixels, 2477 pitch) != 0) { 2478 /* When SDL_ConvertPixels fails, it'll have already set the format. 2479 * Get the error message, and attach some extra data to it. 2480 */ 2481 char errorMessage[1024]; 2482 SDL_snprintf(errorMessage, sizeof(errorMessage), "%s, Convert Pixels failed: %s", __FUNCTION__, SDL_GetError()); 2483 SDL_SetError("%s", errorMessage); 2484 goto done; 2485 } 2486 2487 /* Unmap the texture: */ 2488 ID3D11DeviceContext_Unmap(data->d3dContext, 2489 (ID3D11Resource *)stagingTexture, 2490 0); 2491 2492 status = 0; 2493 2494done: 2495 SAFE_RELEASE(backBuffer); 2496 SAFE_RELEASE(stagingTexture); 2497 return status; 2498} 2499 2500static void 2501D3D11_RenderPresent(SDL_Renderer * renderer) 2502{ 2503 D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata; 2504 UINT syncInterval; 2505 UINT presentFlags; 2506 HRESULT result; 2507 DXGI_PRESENT_PARAMETERS parameters; 2508 2509 SDL_zero(parameters); 2510 2511#if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP 2512 syncInterval = 1; 2513 presentFlags = 0; 2514 result = IDXGISwapChain_Present(data->swapChain, syncInterval, presentFlags); 2515#else 2516 if (renderer->info.flags & SDL_RENDERER_PRESENTVSYNC) { 2517 syncInterval = 1; 2518 presentFlags = 0; 2519 } else { 2520 syncInterval = 0; 2521 presentFlags = DXGI_PRESENT_DO_NOT_WAIT; 2522 } 2523 2524 /* The application may optionally specify "dirty" or "scroll" 2525 * rects to improve efficiency in certain scenarios. 2526 * This option is not available on Windows Phone 8, to note. 2527 */ 2528 result = IDXGISwapChain1_Present1(data->swapChain, syncInterval, presentFlags, &parameters); 2529#endif 2530 2531 /* Discard the contents of the render target. 2532 * This is a valid operation only when the existing contents will be entirely 2533 * overwritten. If dirty or scroll rects are used, this call should be removed. 2534 */ 2535 ID3D11DeviceContext1_DiscardView(data->d3dContext, (ID3D11View*)data->mainRenderTargetView); 2536 2537 /* When the present flips, it unbinds the current view, so bind it again on the next draw call */ 2538 data->currentRenderTargetView = NULL; 2539 2540 if (FAILED(result) && result != DXGI_ERROR_WAS_STILL_DRAWING) { 2541 /* If the device was removed either by a disconnect or a driver upgrade, we 2542 * must recreate all device resources. 2543 * 2544 * TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvage debug info from users' machines 2545 */ 2546 if ( result == DXGI_ERROR_DEVICE_REMOVED ) { 2547 D3D11_HandleDeviceLost(renderer); 2548 } else if (result == DXGI_ERROR_INVALID_CALL) { 2549 /* We probably went through a fullscreen <-> windowed transition */ 2550 D3D11_CreateWindowSizeDependentResources(renderer); 2551 } else { 2552 WIN_SetErrorFromHRESULT(SDL_COMPOSE_ERROR("IDXGISwapChain::Present"), result); 2553 } 2554 } 2555} 2556 2557#endif /* SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED */ 2558 2559/* vi: set ts=4 sw=4 expandtab: */ 2560
[FILE END]
(C) 2025 0x4248 (C) 2025 4248 Media and 4248 Systems, All part of 0x4248 See LICENCE files for more information. Not all files are by 0x4248 always check Licencing.