src/render/direct3d11/SDL_render_d3d11.cpp
author David Ludwig <dludwig@pobox.com>
Sun, 10 Feb 2013 17:35:38 -0500
changeset 8423 61f9a3eb6bc8
parent 8420 99dc85ad173c
child 8425 99448fee696f
permissions -rw-r--r--
WinRT: made SDL_RenderClear display the correct color via Direct3D 11.1
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2012 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 
    22 #include "SDL_config.h"
    23 
    24 #if SDL_VIDEO_RENDER_D3D11 && !SDL_RENDER_DISABLED
    25 
    26 extern "C" {
    27 #include "../../core/windows/SDL_windows.h"
    28 //#include "SDL_hints.h"
    29 //#include "SDL_loadso.h"
    30 #include "SDL_system.h"
    31 #include "SDL_syswm.h"
    32 #include "../SDL_sysrender.h"
    33 //#include "stdio.h"
    34 }
    35 
    36 #include <fstream>
    37 #include <string>
    38 #include <vector>
    39 
    40 #include "SDL_render_d3d11_cpp.h"
    41 
    42 using namespace DirectX;
    43 using namespace Microsoft::WRL;
    44 using namespace std;
    45 
    46 #ifdef __WINRT__
    47 using namespace Windows::Graphics::Display;
    48 using namespace Windows::UI::Core;
    49 #endif
    50 
    51 /* Direct3D 11.1 renderer implementation */
    52 
    53 static SDL_Renderer *D3D11_CreateRenderer(SDL_Window * window, Uint32 flags);
    54 static void D3D11_WindowEvent(SDL_Renderer * renderer,
    55                             const SDL_WindowEvent *event);
    56 static int D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    57 static int D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    58                              const SDL_Rect * rect, const void *pixels,
    59                              int pitch);
    60 //static int D3D11_LockTexture(SDL_Renderer * renderer, SDL_Texture * texture,
    61 //                           const SDL_Rect * rect, void **pixels, int *pitch);
    62 //static void D3D11_UnlockTexture(SDL_Renderer * renderer, SDL_Texture * texture);
    63 //static int D3D11_SetRenderTarget(SDL_Renderer * renderer, SDL_Texture * texture);
    64 static int D3D11_UpdateViewport(SDL_Renderer * renderer);
    65 static int D3D11_RenderClear(SDL_Renderer * renderer);
    66 //static int D3D11_RenderDrawPoints(SDL_Renderer * renderer,
    67 //                                const SDL_FPoint * points, int count);
    68 //static int D3D11_RenderDrawLines(SDL_Renderer * renderer,
    69 //                               const SDL_FPoint * points, int count);
    70 //static int D3D11_RenderFillRects(SDL_Renderer * renderer,
    71 //                               const SDL_FRect * rects, int count);
    72 static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
    73                             const SDL_Rect * srcrect, const SDL_FRect * dstrect);
    74 //static int D3D11_RenderCopyEx(SDL_Renderer * renderer, SDL_Texture * texture,
    75 //                          const SDL_Rect * srcrect, const SDL_FRect * dstrect,
    76 //                          const double angle, const SDL_FPoint * center, const SDL_RendererFlip flip);
    77 //static int D3D11_RenderReadPixels(SDL_Renderer * renderer, const SDL_Rect * rect,
    78 //                                Uint32 format, void * pixels, int pitch);
    79 static void D3D11_RenderPresent(SDL_Renderer * renderer);
    80 static void D3D11_DestroyTexture(SDL_Renderer * renderer,
    81                                  SDL_Texture * texture);
    82 static void D3D11_DestroyRenderer(SDL_Renderer * renderer);
    83 
    84 /* Direct3D 11.1 Internal Functions */
    85 HRESULT D3D11_CreateDeviceResources(SDL_Renderer * renderer);
    86 HRESULT D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer);
    87 HRESULT D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer);
    88 HRESULT D3D11_HandleDeviceLost(SDL_Renderer * renderer);
    89 
    90 extern "C" {
    91     SDL_RenderDriver D3D11_RenderDriver = {
    92     D3D11_CreateRenderer,
    93     {
    94      "direct3d 11.1",
    95      (SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_TARGETTEXTURE),
    96      1,
    97      {SDL_PIXELFORMAT_RGB888},
    98      0,
    99      0}
   100     };
   101 }
   102 
   103 //typedef struct
   104 //{
   105 //    float x, y, z;
   106 //    DWORD color;
   107 //    float u, v;
   108 //} Vertex;
   109 
   110 SDL_Renderer *
   111 D3D11_CreateRenderer(SDL_Window * window, Uint32 flags)
   112 {
   113     SDL_Renderer *renderer;
   114     D3D11_RenderData *data;
   115 
   116     renderer = (SDL_Renderer *) SDL_calloc(1, sizeof(*renderer));
   117     if (!renderer) {
   118         SDL_OutOfMemory();
   119         return NULL;
   120     }
   121     SDL_zerop(renderer);
   122 
   123     data = new D3D11_RenderData;    // Use the C++ 'new' operator to make sure the struct's members initialize using C++ rules
   124     if (!data) {
   125         SDL_OutOfMemory();
   126         return NULL;
   127     }
   128     data->featureLevel = (D3D_FEATURE_LEVEL) 0;
   129     data->vertexCount = 0;
   130     data->loadingComplete = false;
   131     data->windowSizeInDIPs = XMFLOAT2(0, 0);
   132     data->renderTargetSize = XMFLOAT2(0, 0);
   133 
   134     renderer->WindowEvent = D3D11_WindowEvent;
   135     renderer->CreateTexture = D3D11_CreateTexture;
   136     renderer->UpdateTexture = D3D11_UpdateTexture;
   137     //renderer->LockTexture = D3D11_LockTexture;
   138     //renderer->UnlockTexture = D3D11_UnlockTexture;
   139     //renderer->SetRenderTarget = D3D11_SetRenderTarget;
   140     renderer->UpdateViewport = D3D11_UpdateViewport;
   141     renderer->RenderClear = D3D11_RenderClear;
   142     //renderer->RenderDrawPoints = D3D11_RenderDrawPoints;
   143     //renderer->RenderDrawLines = D3D11_RenderDrawLines;
   144     //renderer->RenderFillRects = D3D11_RenderFillRects;
   145     renderer->RenderCopy = D3D11_RenderCopy;
   146     //renderer->RenderCopyEx = D3D11_RenderCopyEx;
   147     //renderer->RenderReadPixels = D3D11_RenderReadPixels;
   148     renderer->RenderPresent = D3D11_RenderPresent;
   149     renderer->DestroyTexture = D3D11_DestroyTexture;
   150     renderer->DestroyRenderer = D3D11_DestroyRenderer;
   151     renderer->info = D3D11_RenderDriver.info;
   152     renderer->info.flags = SDL_RENDERER_ACCELERATED;
   153     renderer->driverdata = data;
   154 
   155     // HACK: make sure the SDL_Renderer references the SDL_Window data now, in
   156     // order to give init functions access to the underlying window handle:
   157     renderer->window = window;
   158 
   159     /* Initialize Direct3D resources */
   160     if (FAILED(D3D11_CreateDeviceResources(renderer))) {
   161         D3D11_DestroyRenderer(renderer);
   162         return NULL;
   163     }
   164     if (FAILED(D3D11_CreateWindowSizeDependentResources(renderer))) {
   165         D3D11_DestroyRenderer(renderer);
   166         return NULL;
   167     }
   168 
   169     // TODO, WinRT: fill in renderer->info.texture_formats where appropriate
   170 
   171     return renderer;
   172 }
   173 
   174 static void
   175 D3D11_DestroyRenderer(SDL_Renderer * renderer)
   176 {
   177     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   178     if (data) {
   179         delete data;
   180         data = NULL;
   181     }
   182 }
   183 
   184 static bool
   185 D3D11_ReadFileContents(const wstring & fileName, vector<char> & out)
   186 {
   187     ifstream in(fileName, ios::in | ios::binary);
   188     if (!in) {
   189         return false;
   190     }
   191 
   192     in.seekg(0, ios::end);
   193     out.resize((size_t) in.tellg());
   194     in.seekg(0, ios::beg);
   195     in.read(&out[0], out.size());
   196     return in.good();
   197 }
   198 
   199 static bool
   200 D3D11_ReadShaderContents(const wstring & shaderName, vector<char> & out)
   201 {
   202     wstring fileName;
   203 
   204 #if WINAPI_FAMILY == WINAPI_FAMILY_APP
   205     fileName = SDL_WinRTGetFileSystemPath(SDL_WINRT_PATH_INSTALLED_LOCATION);
   206     fileName += L"\\SDL_VS2012_WinRT\\";
   207 #elif WINAPI_FAMILY == WINAPI_PHONE_APP
   208     fileName = SDL_WinRTGetFileSystemPath(SDL_WINRT_PATH_INSTALLED_LOCATION);
   209     fileName += L"\\";
   210 #endif
   211     // WinRT, TODO: test Direct3D 11.1 shader loading on Win32
   212     fileName += shaderName;
   213     return D3D11_ReadFileContents(fileName, out);
   214 }
   215 
   216 // Create resources that depend on the device.
   217 HRESULT
   218 D3D11_CreateDeviceResources(SDL_Renderer * renderer)
   219 {
   220     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   221 
   222     // This flag adds support for surfaces with a different color channel ordering
   223     // than the API default. It is required for compatibility with Direct2D.
   224     UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
   225 
   226 #if defined(_DEBUG)
   227     // If the project is in a debug build, enable debugging via SDK Layers with this flag.
   228     creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
   229 #endif
   230 
   231     // This array defines the set of DirectX hardware feature levels this app will support.
   232     // Note the ordering should be preserved.
   233     // Don't forget to declare your application's minimum required feature level in its
   234     // description.  All applications are assumed to support 9.1 unless otherwise stated.
   235     D3D_FEATURE_LEVEL featureLevels[] = 
   236     {
   237         D3D_FEATURE_LEVEL_11_1,
   238         D3D_FEATURE_LEVEL_11_0,
   239         D3D_FEATURE_LEVEL_10_1,
   240         D3D_FEATURE_LEVEL_10_0,
   241         D3D_FEATURE_LEVEL_9_3,
   242         D3D_FEATURE_LEVEL_9_2,
   243         D3D_FEATURE_LEVEL_9_1
   244     };
   245 
   246     // Create the Direct3D 11 API device object and a corresponding context.
   247     ComPtr<ID3D11Device> device;
   248     ComPtr<ID3D11DeviceContext> context;
   249     HRESULT result = S_OK;
   250     result = D3D11CreateDevice(
   251         nullptr, // Specify nullptr to use the default adapter.
   252         D3D_DRIVER_TYPE_HARDWARE,
   253         nullptr,
   254         creationFlags, // Set set debug and Direct2D compatibility flags.
   255         featureLevels, // List of feature levels this app can support.
   256         ARRAYSIZE(featureLevels),
   257         D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
   258         &device, // Returns the Direct3D device created.
   259         &data->featureLevel, // Returns feature level of device created.
   260         &context // Returns the device immediate context.
   261         );
   262     if (FAILED(result)) {
   263         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   264         return result;
   265     }
   266 
   267     // Get the Direct3D 11.1 API device and context interfaces.
   268     Microsoft::WRL::ComPtr<ID3D11Device1> d3dDevice1;
   269     result = device.As(&(data->d3dDevice));
   270     if (FAILED(result)) {
   271         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   272         return result;
   273     }
   274 
   275     result = context.As(&data->d3dContext);
   276     if (FAILED(result)) {
   277         return result;
   278     }
   279 
   280     // Start loading GPU shaders:
   281     vector<char> fileData;
   282 
   283     //
   284     // Load in SDL's one and only vertex shader:
   285     //
   286     if (!D3D11_ReadShaderContents(L"SimpleVertexShader.cso", fileData)) {
   287         SDL_SetError("Unable to open SDL's vertex shader file.");
   288         return E_FAIL;
   289     }
   290 
   291     result = data->d3dDevice->CreateVertexShader(
   292         &fileData[0],
   293         fileData.size(),
   294         nullptr,
   295         &data->vertexShader
   296         );
   297     if (FAILED(result)) {
   298         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   299         return result;
   300     }
   301 
   302     //
   303     // Create an input layout for SDL's vertex shader:
   304     //
   305     const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = 
   306     {
   307         { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
   308         { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
   309     };
   310 
   311     result = data->d3dDevice->CreateInputLayout(
   312         vertexDesc,
   313         ARRAYSIZE(vertexDesc),
   314         &fileData[0],
   315         fileData.size(),
   316         &data->inputLayout
   317         );
   318     if (FAILED(result)) {
   319         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   320         return result;
   321     }
   322 
   323     //
   324     // Load in SDL's one and only pixel shader (for now, more are likely to follow):
   325     //
   326     if (!D3D11_ReadShaderContents(L"SimplePixelShader.cso", fileData)) {
   327         SDL_SetError("Unable to open SDL's pixel shader file.");
   328         return E_FAIL;
   329     }
   330 
   331     result = data->d3dDevice->CreatePixelShader(
   332         &fileData[0],
   333         fileData.size(),
   334         nullptr,
   335         &data->pixelShader
   336         );
   337     if (FAILED(result)) {
   338         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   339         return result;
   340     }
   341 
   342     //
   343     // Setup space to hold vertex shader constants:
   344     //
   345     CD3D11_BUFFER_DESC constantBufferDesc(sizeof(SDL_VertexShaderConstants), D3D11_BIND_CONSTANT_BUFFER);
   346     result = data->d3dDevice->CreateBuffer(
   347 		&constantBufferDesc,
   348 		nullptr,
   349         &data->vertexShaderConstants
   350 		);
   351     if (FAILED(result)) {
   352         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   353         return result;
   354     }
   355 
   356     //
   357     // Create a vertex buffer:
   358     //
   359     VertexPositionColor vertices[] = 
   360     {
   361         {XMFLOAT3(-1.0f, -1.0f, 0.0f), XMFLOAT2(0.0f, 1.0f)},
   362         {XMFLOAT3(-1.0f, 1.0f, 0.0f), XMFLOAT2(0.0f, 0.0f)},
   363         {XMFLOAT3(1.0f, -1.0f, 0.0f), XMFLOAT2(1.0f, 1.0f)},
   364         {XMFLOAT3(1.0f, 1.0f, 0.0f), XMFLOAT2(1.0f, 0.0f)},
   365     };
   366 
   367     data->vertexCount = ARRAYSIZE(vertices);
   368 
   369     D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
   370     vertexBufferData.pSysMem = vertices;
   371     vertexBufferData.SysMemPitch = 0;
   372     vertexBufferData.SysMemSlicePitch = 0;
   373     CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
   374     result = data->d3dDevice->CreateBuffer(
   375         &vertexBufferDesc,
   376         &vertexBufferData,
   377         &data->vertexBuffer
   378         );
   379     if (FAILED(result)) {
   380         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   381         return result;
   382     }
   383 
   384     //
   385     // Create a sampler to use when drawing textures:
   386     //
   387     D3D11_SAMPLER_DESC samplerDesc;
   388     samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
   389     samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
   390     samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
   391     samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
   392     samplerDesc.MipLODBias = 0.0f;
   393     samplerDesc.MaxAnisotropy = 1;
   394     samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
   395     samplerDesc.BorderColor[0] = 0.0f;
   396     samplerDesc.BorderColor[1] = 0.0f;
   397     samplerDesc.BorderColor[2] = 0.0f;
   398     samplerDesc.BorderColor[3] = 0.0f;
   399     samplerDesc.MinLOD = 0.0f;
   400     samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
   401     result = data->d3dDevice->CreateSamplerState(
   402         &samplerDesc,
   403         &data->mainSampler
   404         );
   405     if (FAILED(result)) {
   406         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   407         return result;
   408     }
   409 
   410     //
   411     // All done!
   412     //
   413     data->loadingComplete = true;       // This variable can probably be factored-out
   414     return S_OK;
   415 }
   416 
   417 #ifdef __WINRT__
   418 
   419 static CoreWindow ^
   420 D3D11_GetCoreWindowFromSDLRenderer(SDL_Renderer * renderer)
   421 {
   422     SDL_Window * sdlWindow = renderer->window;
   423     if ( ! renderer->window ) {
   424         return nullptr;
   425     }
   426 
   427     SDL_SysWMinfo sdlWindowInfo;
   428     SDL_VERSION(&sdlWindowInfo.version);
   429     if ( ! SDL_GetWindowWMInfo(sdlWindow, &sdlWindowInfo) ) {
   430         return nullptr;
   431     }
   432 
   433     if (sdlWindowInfo.subsystem != SDL_SYSWM_WINDOWSRT) {
   434         return nullptr;
   435     }
   436 
   437     CoreWindow ^* coreWindowPointer = (CoreWindow ^*) sdlWindowInfo.info.winrt.window;
   438     if ( ! coreWindowPointer ) {
   439         return nullptr;
   440     }
   441 
   442     return *coreWindowPointer;
   443 }
   444 
   445 // Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
   446 static float
   447 D3D11_ConvertDipsToPixels(float dips)
   448 {
   449     static const float dipsPerInch = 96.0f;
   450     return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
   451 }
   452 #endif
   453 
   454 // Initialize all resources that change when the window's size changes.
   455 // WinRT, TODO: get D3D11_CreateWindowSizeDependentResources working on Win32
   456 HRESULT
   457 D3D11_CreateWindowSizeDependentResources(SDL_Renderer * renderer)
   458 {
   459     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   460     HRESULT result = S_OK;
   461     Windows::UI::Core::CoreWindow ^ coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer);
   462 
   463     // Store the window bounds so the next time we get a SizeChanged event we can
   464     // avoid rebuilding everything if the size is identical.
   465     data->windowSizeInDIPs.x = coreWindow->Bounds.Width;
   466     data->windowSizeInDIPs.y = coreWindow->Bounds.Height;
   467 
   468     // Calculate the necessary swap chain and render target size in pixels.
   469     float windowWidth = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.x);
   470     float windowHeight = D3D11_ConvertDipsToPixels(data->windowSizeInDIPs.y);
   471 
   472     // The width and height of the swap chain must be based on the window's
   473     // landscape-oriented width and height. If the window is in a portrait
   474     // orientation, the dimensions must be reversed.
   475     data->orientation = DisplayProperties::CurrentOrientation;
   476     bool swapDimensions =
   477         data->orientation == DisplayOrientations::Portrait ||
   478         data->orientation == DisplayOrientations::PortraitFlipped;
   479     data->renderTargetSize.x = swapDimensions ? windowHeight : windowWidth;
   480     data->renderTargetSize.y = swapDimensions ? windowWidth : windowHeight;
   481 
   482     if(data->swapChain != nullptr)
   483     {
   484         // If the swap chain already exists, resize it.
   485         result = data->swapChain->ResizeBuffers(
   486             2, // Double-buffered swap chain.
   487             static_cast<UINT>(data->renderTargetSize.x),
   488             static_cast<UINT>(data->renderTargetSize.y),
   489             DXGI_FORMAT_B8G8R8A8_UNORM,
   490             0
   491             );
   492         if (FAILED(result)) {
   493             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   494             return result;
   495         }
   496     }
   497     else
   498     {
   499         // Otherwise, create a new one using the same adapter as the existing Direct3D device.
   500         DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
   501         swapChainDesc.Width = static_cast<UINT>(data->renderTargetSize.x); // Match the size of the window.
   502         swapChainDesc.Height = static_cast<UINT>(data->renderTargetSize.y);
   503         swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
   504         swapChainDesc.Stereo = false;
   505         swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
   506         swapChainDesc.SampleDesc.Quality = 0;
   507         swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
   508         swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
   509 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
   510         swapChainDesc.Scaling = DXGI_SCALING_STRETCH; // On phone, only stretch and aspect-ratio stretch scaling are allowed.
   511         swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // On phone, no swap effects are supported.
   512 #else
   513         swapChainDesc.Scaling = DXGI_SCALING_NONE;
   514         swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
   515 #endif
   516         swapChainDesc.Flags = 0;
   517 
   518         ComPtr<IDXGIDevice1>  dxgiDevice;
   519         result = data->d3dDevice.As(&dxgiDevice);
   520         if (FAILED(result)) {
   521             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   522             return result;
   523         }
   524 
   525         ComPtr<IDXGIAdapter> dxgiAdapter;
   526         result = dxgiDevice->GetAdapter(&dxgiAdapter);
   527         if (FAILED(result)) {
   528             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   529             return result;
   530         }
   531 
   532         ComPtr<IDXGIFactory2> dxgiFactory;
   533         result = dxgiAdapter->GetParent(
   534             __uuidof(IDXGIFactory2), 
   535             &dxgiFactory
   536             );
   537         if (FAILED(result)) {
   538             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   539             return result;
   540         }
   541 
   542         result = dxgiFactory->CreateSwapChainForCoreWindow(
   543             data->d3dDevice.Get(),
   544             reinterpret_cast<IUnknown*>(coreWindow),
   545             &swapChainDesc,
   546             nullptr, // Allow on all displays.
   547             &data->swapChain
   548             );
   549         if (FAILED(result)) {
   550             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   551             return result;
   552         }
   553             
   554         // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
   555         // ensures that the application will only render after each VSync, minimizing power consumption.
   556         result = dxgiDevice->SetMaximumFrameLatency(1);
   557         if (FAILED(result)) {
   558             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   559             return result;
   560         }
   561     }
   562     
   563     // Set the proper orientation for the swap chain, and generate the
   564     // 3D matrix transformation for rendering to the rotated swap chain.
   565     DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
   566     switch (data->orientation)
   567     {
   568         case DisplayOrientations::Landscape:
   569             rotation = DXGI_MODE_ROTATION_IDENTITY;
   570             data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 0-degree Z-rotation
   571                 1.0f, 0.0f, 0.0f, 0.0f,
   572                 0.0f, 1.0f, 0.0f, 0.0f,
   573                 0.0f, 0.0f, 1.0f, 0.0f,
   574                 0.0f, 0.0f, 0.0f, 1.0f
   575                 );
   576             break;
   577 
   578         case DisplayOrientations::Portrait:
   579             rotation = DXGI_MODE_ROTATION_ROTATE270;
   580             data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 270-degree Z-rotation
   581                 0.0f, -1.0f, 0.0f, 0.0f,
   582                 1.0f, 0.0f, 0.0f, 0.0f,
   583                 0.0f, 0.0f, 1.0f, 0.0f,
   584                 0.0f, 0.0f, 0.0f, 1.0f
   585                 );
   586             break;
   587 
   588         case DisplayOrientations::LandscapeFlipped:
   589             rotation = DXGI_MODE_ROTATION_ROTATE180;
   590             data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 180-degree Z-rotation
   591                 -1.0f, 0.0f, 0.0f, 0.0f,
   592                 0.0f, -1.0f, 0.0f, 0.0f,
   593                 0.0f, 0.0f, 1.0f, 0.0f,
   594                 0.0f, 0.0f, 0.0f, 1.0f
   595                 );
   596             break;
   597 
   598         case DisplayOrientations::PortraitFlipped:
   599             rotation = DXGI_MODE_ROTATION_ROTATE90;
   600             data->vertexShaderConstantsData.projection = XMFLOAT4X4( // 90-degree Z-rotation
   601                 0.0f, 1.0f, 0.0f, 0.0f,
   602                 -1.0f, 0.0f, 0.0f, 0.0f,
   603                 0.0f, 0.0f, 1.0f, 0.0f,
   604                 0.0f, 0.0f, 0.0f, 1.0f
   605                 );
   606             break;
   607 
   608         default:
   609             throw ref new Platform::FailureException();
   610     }
   611 
   612 #if WINAPI_FAMILY != WINAPI_FAMILY_PHONE_APP
   613     // TODO, WinRT: Windows Phone does not have the IDXGISwapChain1::SetRotation method.  Check if an alternative is available, or needed.
   614     result = data->swapChain->SetRotation(rotation);
   615     if (FAILED(result)) {
   616         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   617         return result;
   618     }
   619 #endif
   620 
   621     // Create a render target view of the swap chain back buffer.
   622     ComPtr<ID3D11Texture2D> backBuffer;
   623     result = data->swapChain->GetBuffer(
   624         0,
   625         __uuidof(ID3D11Texture2D),
   626         &backBuffer
   627         );
   628     if (FAILED(result)) {
   629         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   630         return result;
   631     }
   632 
   633     result = data->d3dDevice->CreateRenderTargetView(
   634         backBuffer.Get(),
   635         nullptr,
   636         &data->renderTargetView
   637         );
   638     if (FAILED(result)) {
   639         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   640         return result;
   641     }
   642 
   643     // Create a depth stencil view.
   644     CD3D11_TEXTURE2D_DESC depthStencilDesc(
   645         DXGI_FORMAT_D24_UNORM_S8_UINT, 
   646         static_cast<UINT>(data->renderTargetSize.x),
   647         static_cast<UINT>(data->renderTargetSize.y),
   648         1,
   649         1,
   650         D3D11_BIND_DEPTH_STENCIL
   651         );
   652 
   653     ComPtr<ID3D11Texture2D> depthStencil;
   654     result = data->d3dDevice->CreateTexture2D(
   655         &depthStencilDesc,
   656         nullptr,
   657         &depthStencil
   658         );
   659     if (FAILED(result)) {
   660         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   661         return result;
   662     }
   663 
   664     // Set the rendering viewport to target the entire window.
   665     CD3D11_VIEWPORT viewport(
   666         0.0f,
   667         0.0f,
   668         data->renderTargetSize.x,
   669         data->renderTargetSize.y
   670         );
   671 
   672     data->d3dContext->RSSetViewports(1, &viewport);
   673 
   674     return S_OK;
   675 }
   676 
   677 // This method is called when the window's size changes.
   678 HRESULT
   679 D3D11_UpdateForWindowSizeChange(SDL_Renderer * renderer)
   680 {
   681     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   682     HRESULT result = S_OK;
   683     Windows::UI::Core::CoreWindow ^ coreWindow = D3D11_GetCoreWindowFromSDLRenderer(renderer);
   684 
   685     if (coreWindow->Bounds.Width  != data->windowSizeInDIPs.x ||
   686         coreWindow->Bounds.Height != data->windowSizeInDIPs.y ||
   687         data->orientation != DisplayProperties::CurrentOrientation)
   688     {
   689         ID3D11RenderTargetView* nullViews[] = {nullptr};
   690         data->d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
   691         data->renderTargetView = nullptr;
   692         data->d3dContext->Flush();
   693         result = D3D11_CreateWindowSizeDependentResources(renderer);
   694         if (FAILED(result)) {
   695             WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   696             return result;
   697         }
   698     }
   699 
   700     return S_OK;
   701 }
   702 
   703 HRESULT
   704 D3D11_HandleDeviceLost(SDL_Renderer * renderer)
   705 {
   706     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   707     HRESULT result = S_OK;
   708 
   709     // Reset these member variables to ensure that D3D11_UpdateForWindowSizeChange recreates all resources.
   710     data->windowSizeInDIPs.x = 0;
   711     data->windowSizeInDIPs.y = 0;
   712     data->swapChain = nullptr;
   713 
   714     result = D3D11_CreateDeviceResources(renderer);
   715     if (FAILED(result)) {
   716         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   717         return result;
   718     }
   719 
   720     result = D3D11_UpdateForWindowSizeChange(renderer);
   721     if (FAILED(result)) {
   722         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   723         return result;
   724     }
   725 
   726     return S_OK;
   727 }
   728 
   729 static void
   730 D3D11_WindowEvent(SDL_Renderer * renderer, const SDL_WindowEvent *event)
   731 {
   732     //D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   733 
   734     if (event->event == SDL_WINDOWEVENT_RESIZED) {
   735         D3D11_UpdateForWindowSizeChange(renderer);
   736     }
   737 }
   738 
   739 static int
   740 D3D11_CreateTexture(SDL_Renderer * renderer, SDL_Texture * texture)
   741 {
   742     D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
   743     D3D11_TextureData *textureData;
   744     HRESULT result;
   745 
   746     textureData = new D3D11_TextureData;
   747     if (!textureData) {
   748         SDL_OutOfMemory();
   749         return -1;
   750     }
   751     textureData->pixelFormat = SDL_AllocFormat(texture->format);
   752 
   753     texture->driverdata = textureData;
   754 
   755     const int pixelSizeInBytes = textureData->pixelFormat->BytesPerPixel;
   756 
   757     D3D11_TEXTURE2D_DESC textureDesc = {0};
   758     textureDesc.Width = texture->w;
   759     textureDesc.Height = texture->h;
   760     textureDesc.MipLevels = 1;
   761     textureDesc.ArraySize = 1;
   762     textureDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
   763     textureDesc.SampleDesc.Count = 1;
   764     textureDesc.SampleDesc.Quality = 0;
   765     textureDesc.Usage = D3D11_USAGE_DYNAMIC;
   766     textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
   767     textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
   768     textureDesc.MiscFlags = 0;
   769 
   770     const int numPixels = textureDesc.Width * textureDesc.Height;
   771     std::vector<uint8> initialTexturePixels(numPixels * pixelSizeInBytes, 0x00);
   772 
   773     // Fill the texture with a non-black color, for debugging purposes:
   774     //for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) {
   775     //    initialTexturePixels[i+0] = 0xff;
   776     //    initialTexturePixels[i+1] = 0xff;
   777     //    initialTexturePixels[i+2] = 0x00;
   778     //    initialTexturePixels[i+3] = 0xff;
   779     //}
   780 
   781     D3D11_SUBRESOURCE_DATA initialTextureData = {0};
   782     initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]);
   783     initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes;
   784     initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes;
   785     result = rendererData->d3dDevice->CreateTexture2D(
   786         &textureDesc,
   787         &initialTextureData,
   788         &textureData->mainTexture
   789         );
   790     if (FAILED(result)) {
   791         D3D11_DestroyTexture(renderer, texture);
   792         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   793         return -1;
   794     }
   795 
   796     D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
   797     resourceViewDesc.Format = textureDesc.Format;
   798     resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
   799     resourceViewDesc.Texture2D.MostDetailedMip = 0;
   800     resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
   801     result = rendererData->d3dDevice->CreateShaderResourceView(
   802         textureData->mainTexture.Get(),
   803         &resourceViewDesc,
   804         &textureData->mainTextureResourceView
   805         );
   806     if (FAILED(result)) {
   807         D3D11_DestroyTexture(renderer, texture);
   808         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   809         return -1;
   810     }
   811 
   812     return 0;
   813 }
   814 
   815 static void
   816 D3D11_DestroyTexture(SDL_Renderer * renderer,
   817                      SDL_Texture * texture)
   818 {
   819     D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
   820 
   821     if (textureData) {
   822         if (textureData->pixelFormat) {
   823             SDL_FreeFormat(textureData->pixelFormat);
   824             textureData->pixelFormat = NULL;
   825         }
   826 
   827         delete textureData;
   828         texture->driverdata = NULL;
   829     }
   830 }
   831 
   832 static int
   833 D3D11_UpdateTexture(SDL_Renderer * renderer, SDL_Texture * texture,
   834                     const SDL_Rect * rect, const void *pixels,
   835                     int pitch)
   836 {
   837     D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
   838     D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
   839     HRESULT result = S_OK;
   840 
   841     D3D11_MAPPED_SUBRESOURCE textureMemory = {0};
   842     result = rendererData->d3dContext->Map(
   843         textureData->mainTexture.Get(),
   844         0,
   845         D3D11_MAP_WRITE_DISCARD,
   846         0,
   847         &textureMemory
   848         );
   849     if (FAILED(result)) {
   850         WIN_SetErrorFromHRESULT(__FUNCTION__, result);
   851         return -1;
   852     }
   853 
   854     // Copy pixel data to the locked texture's memory:
   855     for (int y = 0; y < rect->h; ++y) {
   856         memcpy(
   857             ((Uint8 *)textureMemory.pData) + (textureMemory.RowPitch * y),
   858             ((Uint8 *)pixels) + (pitch * y),
   859             pitch
   860             );
   861     }
   862 
   863     // Clean up a bit, then commit the texture's memory back to Direct3D:
   864     rendererData->d3dContext->Unmap(
   865         textureData->mainTexture.Get(),
   866         0);
   867 
   868     return 0;
   869 }
   870 
   871 static int
   872 D3D11_UpdateViewport(SDL_Renderer * renderer)
   873 {
   874     return 0;
   875 }
   876 
   877 static int
   878 D3D11_RenderClear(SDL_Renderer * renderer)
   879 {
   880     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   881     const float colorRGBA[] = {
   882         (renderer->r / 255.0f),
   883         (renderer->g / 255.0f),
   884         (renderer->b / 255.0f),
   885         (renderer->a / 255.0f)
   886     };
   887     data->d3dContext->ClearRenderTargetView(
   888         data->renderTargetView.Get(),
   889         colorRGBA
   890         );
   891     return 0;
   892 }
   893 
   894 static int D3D11_RenderCopy(SDL_Renderer * renderer, SDL_Texture * texture,
   895                             const SDL_Rect * srcrect, const SDL_FRect * dstrect)
   896 {
   897     D3D11_RenderData *rendererData = (D3D11_RenderData *) renderer->driverdata;
   898     D3D11_TextureData *textureData = (D3D11_TextureData *) texture->driverdata;
   899     //HRESULT result = S_OK;
   900 
   901     rendererData->d3dContext->OMSetRenderTargets(
   902         1,
   903         rendererData->renderTargetView.GetAddressOf(),
   904         nullptr
   905         );
   906 
   907     rendererData->d3dContext->UpdateSubresource(
   908         rendererData->vertexShaderConstants.Get(),
   909 		0,
   910 		NULL,
   911 		&rendererData->vertexShaderConstantsData,
   912 		0,
   913 		0
   914 		);
   915 
   916     UINT stride = sizeof(VertexPositionColor);
   917     UINT offset = 0;
   918     rendererData->d3dContext->IASetVertexBuffers(
   919         0,
   920         1,
   921         rendererData->vertexBuffer.GetAddressOf(),
   922         &stride,
   923         &offset
   924         );
   925 
   926     rendererData->d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
   927 
   928     rendererData->d3dContext->IASetInputLayout(rendererData->inputLayout.Get());
   929 
   930     rendererData->d3dContext->VSSetShader(
   931         rendererData->vertexShader.Get(),
   932         nullptr,
   933         0
   934         );
   935 
   936     rendererData->d3dContext->VSSetConstantBuffers(
   937 		0,
   938 		1,
   939         rendererData->vertexShaderConstants.GetAddressOf()
   940 		);
   941 
   942     rendererData->d3dContext->PSSetShader(
   943         rendererData->pixelShader.Get(),
   944         nullptr,
   945         0
   946         );
   947 
   948     rendererData->d3dContext->PSSetShaderResources(0, 1, textureData->mainTextureResourceView.GetAddressOf());
   949 
   950     rendererData->d3dContext->PSSetSamplers(0, 1, rendererData->mainSampler.GetAddressOf());
   951 
   952     rendererData->d3dContext->Draw(4, 0);
   953 
   954     return 0;
   955 }
   956 
   957 static void
   958 D3D11_RenderPresent(SDL_Renderer * renderer)
   959 {
   960     D3D11_RenderData *data = (D3D11_RenderData *) renderer->driverdata;
   961 
   962 #if WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP
   963     // The first argument instructs DXGI to block until VSync, putting the application
   964     // to sleep until the next VSync. This ensures we don't waste any cycles rendering
   965     // frames that will never be displayed to the screen.
   966     HRESULT hr = data->swapChain->Present(1, 0);
   967 #else
   968     // The application may optionally specify "dirty" or "scroll"
   969     // rects to improve efficiency in certain scenarios.
   970     // This option is not available on Windows Phone 8, to note.
   971     DXGI_PRESENT_PARAMETERS parameters = {0};
   972     parameters.DirtyRectsCount = 0;
   973     parameters.pDirtyRects = nullptr;
   974     parameters.pScrollRect = nullptr;
   975     parameters.pScrollOffset = nullptr;
   976     
   977     // The first argument instructs DXGI to block until VSync, putting the application
   978     // to sleep until the next VSync. This ensures we don't waste any cycles rendering
   979     // frames that will never be displayed to the screen.
   980     HRESULT hr = data->swapChain->Present1(1, 0, &parameters);
   981 #endif
   982 
   983     // Discard the contents of the render target.
   984     // This is a valid operation only when the existing contents will be entirely
   985     // overwritten. If dirty or scroll rects are used, this call should be removed.
   986     data->d3dContext->DiscardView(data->renderTargetView.Get());
   987 
   988     // If the device was removed either by a disconnect or a driver upgrade, we 
   989     // must recreate all device resources.
   990     //
   991     // TODO, WinRT: consider throwing an exception if D3D11_RenderPresent fails, especially if there is a way to salvedge debug info from users' machines
   992     if (hr == DXGI_ERROR_DEVICE_REMOVED)
   993     {
   994         hr = D3D11_HandleDeviceLost(renderer);
   995         if (FAILED(hr)) {
   996             WIN_SetErrorFromHRESULT(__FUNCTION__, hr);
   997         }
   998     }
   999     else
  1000     {
  1001         WIN_SetErrorFromHRESULT(__FUNCTION__, hr);
  1002     }
  1003 }
  1004 
  1005 #endif /* SDL_VIDEO_RENDER_D3D && !SDL_RENDER_DISABLED */
  1006 
  1007 /* vi: set ts=4 sw=4 expandtab: */