Atlas - SDL_render_d3d11.c

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