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