src/video/windowsrt/SDL_winrtrenderer.cpp
author David Ludwig <dludwig@pobox.com>
Tue, 08 Jan 2013 23:11:22 -0500
changeset 8384 bc7a52629e1e
parent 8375 e33eb49b7f42
child 8399 1fa9dcfbeac5
permissions -rw-r--r--
WinRT: converted tabs to spaces in src/video/windowsrt/*
dludwig@8322
     1
#include "SDLmain_WinRT_common.h"
dludwig@8342
     2
#include "SDL_winrtrenderer.h"
dludwig@8322
     3
dludwig@8322
     4
using namespace DirectX;
dludwig@8322
     5
using namespace Microsoft::WRL;
dludwig@8369
     6
using namespace Windows::UI::Core;
dludwig@8322
     7
using namespace Windows::Foundation;
dludwig@8369
     8
using namespace Windows::Graphics::Display;
dludwig@8322
     9
dludwig@8369
    10
// Constructor.
dludwig@8342
    11
SDL_winrtrenderer::SDL_winrtrenderer() :
dludwig@8375
    12
    m_mainTextureHelperSurface(NULL),
dludwig@8369
    13
    m_loadingComplete(false),
dludwig@8384
    14
    m_vertexCount(0)
dludwig@8322
    15
{
dludwig@8322
    16
}
dludwig@8322
    17
dludwig@8375
    18
SDL_winrtrenderer::~SDL_winrtrenderer()
dludwig@8375
    19
{
dludwig@8375
    20
    if (m_mainTextureHelperSurface) {
dludwig@8375
    21
        SDL_FreeSurface(m_mainTextureHelperSurface);
dludwig@8375
    22
        m_mainTextureHelperSurface = NULL;
dludwig@8375
    23
    }
dludwig@8375
    24
}
dludwig@8375
    25
dludwig@8369
    26
// Initialize the Direct3D resources required to run.
dludwig@8369
    27
void SDL_winrtrenderer::Initialize(CoreWindow^ window)
dludwig@8369
    28
{
dludwig@8384
    29
    m_window = window;
dludwig@8384
    30
    
dludwig@8384
    31
    CreateDeviceResources();
dludwig@8384
    32
    CreateWindowSizeDependentResources();
dludwig@8369
    33
}
dludwig@8369
    34
dludwig@8369
    35
// Recreate all device resources and set them back to the current state.
dludwig@8369
    36
void SDL_winrtrenderer::HandleDeviceLost()
dludwig@8369
    37
{
dludwig@8384
    38
    // Reset these member variables to ensure that UpdateForWindowSizeChange recreates all resources.
dludwig@8384
    39
    m_windowBounds.Width = 0;
dludwig@8384
    40
    m_windowBounds.Height = 0;
dludwig@8384
    41
    m_swapChain = nullptr;
dludwig@8369
    42
dludwig@8384
    43
    CreateDeviceResources();
dludwig@8384
    44
    UpdateForWindowSizeChange();
dludwig@8369
    45
}
dludwig@8369
    46
dludwig@8369
    47
// These are the resources that depend on the device.
dludwig@8342
    48
void SDL_winrtrenderer::CreateDeviceResources()
dludwig@8322
    49
{
dludwig@8384
    50
    // This flag adds support for surfaces with a different color channel ordering
dludwig@8384
    51
    // than the API default. It is required for compatibility with Direct2D.
dludwig@8384
    52
    UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;
dludwig@8322
    53
dludwig@8369
    54
#if defined(_DEBUG)
dludwig@8384
    55
    // If the project is in a debug build, enable debugging via SDK Layers with this flag.
dludwig@8384
    56
    creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
dludwig@8369
    57
#endif
dludwig@8369
    58
dludwig@8384
    59
    // This array defines the set of DirectX hardware feature levels this app will support.
dludwig@8384
    60
    // Note the ordering should be preserved.
dludwig@8384
    61
    // Don't forget to declare your application's minimum required feature level in its
dludwig@8384
    62
    // description.  All applications are assumed to support 9.1 unless otherwise stated.
dludwig@8384
    63
    D3D_FEATURE_LEVEL featureLevels[] = 
dludwig@8384
    64
    {
dludwig@8384
    65
        D3D_FEATURE_LEVEL_11_1,
dludwig@8384
    66
        D3D_FEATURE_LEVEL_11_0,
dludwig@8384
    67
        D3D_FEATURE_LEVEL_10_1,
dludwig@8384
    68
        D3D_FEATURE_LEVEL_10_0,
dludwig@8384
    69
        D3D_FEATURE_LEVEL_9_3,
dludwig@8384
    70
        D3D_FEATURE_LEVEL_9_2,
dludwig@8384
    71
        D3D_FEATURE_LEVEL_9_1
dludwig@8384
    72
    };
dludwig@8369
    73
dludwig@8384
    74
    // Create the Direct3D 11 API device object and a corresponding context.
dludwig@8384
    75
    ComPtr<ID3D11Device> device;
dludwig@8384
    76
    ComPtr<ID3D11DeviceContext> context;
dludwig@8384
    77
    DX::ThrowIfFailed(
dludwig@8384
    78
        D3D11CreateDevice(
dludwig@8384
    79
            nullptr, // Specify nullptr to use the default adapter.
dludwig@8384
    80
            D3D_DRIVER_TYPE_HARDWARE,
dludwig@8384
    81
            nullptr,
dludwig@8384
    82
            creationFlags, // Set set debug and Direct2D compatibility flags.
dludwig@8384
    83
            featureLevels, // List of feature levels this app can support.
dludwig@8384
    84
            ARRAYSIZE(featureLevels),
dludwig@8384
    85
            D3D11_SDK_VERSION, // Always set this to D3D11_SDK_VERSION for Windows Store apps.
dludwig@8384
    86
            &device, // Returns the Direct3D device created.
dludwig@8384
    87
            &m_featureLevel, // Returns feature level of device created.
dludwig@8384
    88
            &context // Returns the device immediate context.
dludwig@8384
    89
            )
dludwig@8384
    90
        );
dludwig@8369
    91
dludwig@8384
    92
    // Get the Direct3D 11.1 API device and context interfaces.
dludwig@8384
    93
    DX::ThrowIfFailed(
dludwig@8384
    94
        device.As(&m_d3dDevice)
dludwig@8384
    95
        );
dludwig@8369
    96
dludwig@8384
    97
    DX::ThrowIfFailed(
dludwig@8384
    98
        context.As(&m_d3dContext)
dludwig@8384
    99
        );
dludwig@8369
   100
dludwig@8369
   101
    auto loadVSTask = DX::ReadDataAsync("SDL_VS2012_WinRT\\SimpleVertexShader.cso");
dludwig@8384
   102
    auto loadPSTask = DX::ReadDataAsync("SDL_VS2012_WinRT\\SimplePixelShader.cso");
dludwig@8322
   103
dludwig@8384
   104
    auto createVSTask = loadVSTask.then([this](Platform::Array<byte>^ fileData) {
dludwig@8384
   105
        DX::ThrowIfFailed(
dludwig@8384
   106
            m_d3dDevice->CreateVertexShader(
dludwig@8384
   107
                fileData->Data,
dludwig@8384
   108
                fileData->Length,
dludwig@8384
   109
                nullptr,
dludwig@8384
   110
                &m_vertexShader
dludwig@8384
   111
                )
dludwig@8384
   112
            );
dludwig@8322
   113
dludwig@8384
   114
        const D3D11_INPUT_ELEMENT_DESC vertexDesc[] = 
dludwig@8384
   115
        {
dludwig@8384
   116
            { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0,  D3D11_INPUT_PER_VERTEX_DATA, 0 },
dludwig@8384
   117
            { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
dludwig@8384
   118
        };
dludwig@8322
   119
dludwig@8384
   120
        DX::ThrowIfFailed(
dludwig@8384
   121
            m_d3dDevice->CreateInputLayout(
dludwig@8384
   122
                vertexDesc,
dludwig@8384
   123
                ARRAYSIZE(vertexDesc),
dludwig@8384
   124
                fileData->Data,
dludwig@8384
   125
                fileData->Length,
dludwig@8384
   126
                &m_inputLayout
dludwig@8384
   127
                )
dludwig@8384
   128
            );
dludwig@8384
   129
    });
dludwig@8322
   130
dludwig@8384
   131
    auto createPSTask = loadPSTask.then([this](Platform::Array<byte>^ fileData) {
dludwig@8384
   132
        DX::ThrowIfFailed(
dludwig@8384
   133
            m_d3dDevice->CreatePixelShader(
dludwig@8384
   134
                fileData->Data,
dludwig@8384
   135
                fileData->Length,
dludwig@8384
   136
                nullptr,
dludwig@8384
   137
                &m_pixelShader
dludwig@8384
   138
                )
dludwig@8384
   139
            );
dludwig@8384
   140
    });
dludwig@8322
   141
dludwig@8384
   142
    auto createVertexBuffer = (createPSTask && createVSTask).then([this] () {
dludwig@8384
   143
        VertexPositionColor vertices[] = 
dludwig@8384
   144
        {
dludwig@8384
   145
            {XMFLOAT3(-1.0f, -1.0f, 0.0f),  XMFLOAT2(0.0f, 1.0f)},
dludwig@8384
   146
            {XMFLOAT3(-1.0f, 1.0f, 0.0f), XMFLOAT2(0.0f, 0.0f)},
dludwig@8384
   147
            {XMFLOAT3(1.0f, -1.0f, 0.0f), XMFLOAT2(1.0f, 1.0f)},
dludwig@8384
   148
            {XMFLOAT3(1.0f, 1.0f, 0.0f), XMFLOAT2(1.0f, 0.0f)},
dludwig@8384
   149
        };
dludwig@8322
   150
dludwig@8384
   151
        m_vertexCount = ARRAYSIZE(vertices);
dludwig@8342
   152
dludwig@8384
   153
        D3D11_SUBRESOURCE_DATA vertexBufferData = {0};
dludwig@8384
   154
        vertexBufferData.pSysMem = vertices;
dludwig@8384
   155
        vertexBufferData.SysMemPitch = 0;
dludwig@8384
   156
        vertexBufferData.SysMemSlicePitch = 0;
dludwig@8384
   157
        CD3D11_BUFFER_DESC vertexBufferDesc(sizeof(vertices), D3D11_BIND_VERTEX_BUFFER);
dludwig@8384
   158
        DX::ThrowIfFailed(
dludwig@8384
   159
            m_d3dDevice->CreateBuffer(
dludwig@8384
   160
                &vertexBufferDesc,
dludwig@8384
   161
                &vertexBufferData,
dludwig@8384
   162
                &m_vertexBuffer
dludwig@8384
   163
                )
dludwig@8384
   164
            );
dludwig@8384
   165
    });
dludwig@8322
   166
dludwig@8371
   167
    auto createMainSamplerTask = createVertexBuffer.then([this] () {
dludwig@8384
   168
        D3D11_SAMPLER_DESC samplerDesc;
dludwig@8384
   169
        samplerDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_POINT;
dludwig@8384
   170
        samplerDesc.AddressU = D3D11_TEXTURE_ADDRESS_CLAMP;
dludwig@8384
   171
        samplerDesc.AddressV = D3D11_TEXTURE_ADDRESS_CLAMP;
dludwig@8384
   172
        samplerDesc.AddressW = D3D11_TEXTURE_ADDRESS_CLAMP;
dludwig@8384
   173
        samplerDesc.MipLODBias = 0.0f;
dludwig@8384
   174
        samplerDesc.MaxAnisotropy = 1;
dludwig@8384
   175
        samplerDesc.ComparisonFunc = D3D11_COMPARISON_ALWAYS;
dludwig@8384
   176
        samplerDesc.BorderColor[0] = 0.0f;
dludwig@8384
   177
        samplerDesc.BorderColor[1] = 0.0f;
dludwig@8384
   178
        samplerDesc.BorderColor[2] = 0.0f;
dludwig@8384
   179
        samplerDesc.BorderColor[3] = 0.0f;
dludwig@8384
   180
        samplerDesc.MinLOD = 0.0f;
dludwig@8384
   181
        samplerDesc.MaxLOD = D3D11_FLOAT32_MAX;
dludwig@8384
   182
        DX::ThrowIfFailed(
dludwig@8384
   183
            m_d3dDevice->CreateSamplerState(
dludwig@8384
   184
                &samplerDesc,
dludwig@8384
   185
                &m_mainSampler
dludwig@8384
   186
                )
dludwig@8384
   187
            );
dludwig@8384
   188
    });
dludwig@8347
   189
dludwig@8384
   190
    createMainSamplerTask.then([this] () {
dludwig@8384
   191
        m_loadingComplete = true;
dludwig@8384
   192
    });
dludwig@8322
   193
}
dludwig@8322
   194
dludwig@8369
   195
// Allocate all memory resources that change on a window SizeChanged event.
dludwig@8369
   196
void SDL_winrtrenderer::CreateWindowSizeDependentResources()
dludwig@8369
   197
{ 
dludwig@8384
   198
    // Store the window bounds so the next time we get a SizeChanged event we can
dludwig@8384
   199
    // avoid rebuilding everything if the size is identical.
dludwig@8384
   200
    m_windowBounds = m_window->Bounds;
dludwig@8369
   201
dludwig@8384
   202
    // Calculate the necessary swap chain and render target size in pixels.
dludwig@8384
   203
    float windowWidth = ConvertDipsToPixels(m_windowBounds.Width);
dludwig@8384
   204
    float windowHeight = ConvertDipsToPixels(m_windowBounds.Height);
dludwig@8369
   205
dludwig@8384
   206
    // The width and height of the swap chain must be based on the window's
dludwig@8384
   207
    // landscape-oriented width and height. If the window is in a portrait
dludwig@8384
   208
    // orientation, the dimensions must be reversed.
dludwig@8384
   209
    m_orientation = DisplayProperties::CurrentOrientation;
dludwig@8384
   210
    bool swapDimensions =
dludwig@8384
   211
        m_orientation == DisplayOrientations::Portrait ||
dludwig@8384
   212
        m_orientation == DisplayOrientations::PortraitFlipped;
dludwig@8384
   213
    m_renderTargetSize.Width = swapDimensions ? windowHeight : windowWidth;
dludwig@8384
   214
    m_renderTargetSize.Height = swapDimensions ? windowWidth : windowHeight;
dludwig@8369
   215
dludwig@8384
   216
    if(m_swapChain != nullptr)
dludwig@8384
   217
    {
dludwig@8384
   218
        // If the swap chain already exists, resize it.
dludwig@8384
   219
        DX::ThrowIfFailed(
dludwig@8384
   220
            m_swapChain->ResizeBuffers(
dludwig@8384
   221
                2, // Double-buffered swap chain.
dludwig@8384
   222
                static_cast<UINT>(m_renderTargetSize.Width),
dludwig@8384
   223
                static_cast<UINT>(m_renderTargetSize.Height),
dludwig@8384
   224
                DXGI_FORMAT_B8G8R8A8_UNORM,
dludwig@8384
   225
                0
dludwig@8384
   226
                )
dludwig@8384
   227
            );
dludwig@8384
   228
    }
dludwig@8384
   229
    else
dludwig@8384
   230
    {
dludwig@8384
   231
        // Otherwise, create a new one using the same adapter as the existing Direct3D device.
dludwig@8384
   232
        DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};
dludwig@8384
   233
        swapChainDesc.Width = static_cast<UINT>(m_renderTargetSize.Width); // Match the size of the window.
dludwig@8384
   234
        swapChainDesc.Height = static_cast<UINT>(m_renderTargetSize.Height);
dludwig@8384
   235
        swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
dludwig@8384
   236
        swapChainDesc.Stereo = false;
dludwig@8384
   237
        swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
dludwig@8384
   238
        swapChainDesc.SampleDesc.Quality = 0;
dludwig@8384
   239
        swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
dludwig@8384
   240
        swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
dludwig@8384
   241
        swapChainDesc.Scaling = DXGI_SCALING_NONE;
dludwig@8384
   242
        swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
dludwig@8384
   243
        swapChainDesc.Flags = 0;
dludwig@8369
   244
dludwig@8384
   245
        ComPtr<IDXGIDevice1>  dxgiDevice;
dludwig@8384
   246
        DX::ThrowIfFailed(
dludwig@8384
   247
            m_d3dDevice.As(&dxgiDevice)
dludwig@8384
   248
            );
dludwig@8369
   249
dludwig@8384
   250
        ComPtr<IDXGIAdapter> dxgiAdapter;
dludwig@8384
   251
        DX::ThrowIfFailed(
dludwig@8384
   252
            dxgiDevice->GetAdapter(&dxgiAdapter)
dludwig@8384
   253
            );
dludwig@8369
   254
dludwig@8384
   255
        ComPtr<IDXGIFactory2> dxgiFactory;
dludwig@8384
   256
        DX::ThrowIfFailed(
dludwig@8384
   257
            dxgiAdapter->GetParent(
dludwig@8384
   258
                __uuidof(IDXGIFactory2), 
dludwig@8384
   259
                &dxgiFactory
dludwig@8384
   260
                )
dludwig@8384
   261
            );
dludwig@8369
   262
dludwig@8384
   263
        Windows::UI::Core::CoreWindow^ window = m_window.Get();
dludwig@8384
   264
        DX::ThrowIfFailed(
dludwig@8384
   265
            dxgiFactory->CreateSwapChainForCoreWindow(
dludwig@8384
   266
                m_d3dDevice.Get(),
dludwig@8384
   267
                reinterpret_cast<IUnknown*>(window),
dludwig@8384
   268
                &swapChainDesc,
dludwig@8384
   269
                nullptr, // Allow on all displays.
dludwig@8384
   270
                &m_swapChain
dludwig@8384
   271
                )
dludwig@8384
   272
            );
dludwig@8384
   273
            
dludwig@8384
   274
        // Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
dludwig@8384
   275
        // ensures that the application will only render after each VSync, minimizing power consumption.
dludwig@8384
   276
        DX::ThrowIfFailed(
dludwig@8384
   277
            dxgiDevice->SetMaximumFrameLatency(1)
dludwig@8384
   278
            );
dludwig@8384
   279
    }
dludwig@8384
   280
    
dludwig@8384
   281
    // Set the proper orientation for the swap chain, and generate the
dludwig@8384
   282
    // 3D matrix transformation for rendering to the rotated swap chain.
dludwig@8384
   283
    DXGI_MODE_ROTATION rotation = DXGI_MODE_ROTATION_UNSPECIFIED;
dludwig@8384
   284
    switch (m_orientation)
dludwig@8384
   285
    {
dludwig@8384
   286
        case DisplayOrientations::Landscape:
dludwig@8384
   287
            rotation = DXGI_MODE_ROTATION_IDENTITY;
dludwig@8384
   288
            m_orientationTransform3D = XMFLOAT4X4( // 0-degree Z-rotation
dludwig@8384
   289
                1.0f, 0.0f, 0.0f, 0.0f,
dludwig@8384
   290
                0.0f, 1.0f, 0.0f, 0.0f,
dludwig@8384
   291
                0.0f, 0.0f, 1.0f, 0.0f,
dludwig@8384
   292
                0.0f, 0.0f, 0.0f, 1.0f
dludwig@8384
   293
                );
dludwig@8384
   294
            break;
dludwig@8369
   295
dludwig@8384
   296
        case DisplayOrientations::Portrait:
dludwig@8384
   297
            rotation = DXGI_MODE_ROTATION_ROTATE270;
dludwig@8384
   298
            m_orientationTransform3D = XMFLOAT4X4( // 90-degree Z-rotation
dludwig@8384
   299
                0.0f, 1.0f, 0.0f, 0.0f,
dludwig@8384
   300
                -1.0f, 0.0f, 0.0f, 0.0f,
dludwig@8384
   301
                0.0f, 0.0f, 1.0f, 0.0f,
dludwig@8384
   302
                0.0f, 0.0f, 0.0f, 1.0f
dludwig@8384
   303
                );
dludwig@8384
   304
            break;
dludwig@8369
   305
dludwig@8384
   306
        case DisplayOrientations::LandscapeFlipped:
dludwig@8384
   307
            rotation = DXGI_MODE_ROTATION_ROTATE180;
dludwig@8384
   308
            m_orientationTransform3D = XMFLOAT4X4( // 180-degree Z-rotation
dludwig@8384
   309
                -1.0f, 0.0f, 0.0f, 0.0f,
dludwig@8384
   310
                0.0f, -1.0f, 0.0f, 0.0f,
dludwig@8384
   311
                0.0f, 0.0f, 1.0f, 0.0f,
dludwig@8384
   312
                0.0f, 0.0f, 0.0f, 1.0f
dludwig@8384
   313
                );
dludwig@8384
   314
            break;
dludwig@8369
   315
dludwig@8384
   316
        case DisplayOrientations::PortraitFlipped:
dludwig@8384
   317
            rotation = DXGI_MODE_ROTATION_ROTATE90;
dludwig@8384
   318
            m_orientationTransform3D = XMFLOAT4X4( // 270-degree Z-rotation
dludwig@8384
   319
                0.0f, -1.0f, 0.0f, 0.0f,
dludwig@8384
   320
                1.0f, 0.0f, 0.0f, 0.0f,
dludwig@8384
   321
                0.0f, 0.0f, 1.0f, 0.0f,
dludwig@8384
   322
                0.0f, 0.0f, 0.0f, 1.0f
dludwig@8384
   323
                );
dludwig@8384
   324
            break;
dludwig@8369
   325
dludwig@8384
   326
        default:
dludwig@8384
   327
            throw ref new Platform::FailureException();
dludwig@8384
   328
    }
dludwig@8369
   329
dludwig@8384
   330
    DX::ThrowIfFailed(
dludwig@8384
   331
        m_swapChain->SetRotation(rotation)
dludwig@8384
   332
        );
dludwig@8369
   333
dludwig@8384
   334
    // Create a render target view of the swap chain back buffer.
dludwig@8384
   335
    ComPtr<ID3D11Texture2D> backBuffer;
dludwig@8384
   336
    DX::ThrowIfFailed(
dludwig@8384
   337
        m_swapChain->GetBuffer(
dludwig@8384
   338
            0,
dludwig@8384
   339
            __uuidof(ID3D11Texture2D),
dludwig@8384
   340
            &backBuffer
dludwig@8384
   341
            )
dludwig@8384
   342
        );
dludwig@8369
   343
dludwig@8384
   344
    DX::ThrowIfFailed(
dludwig@8384
   345
        m_d3dDevice->CreateRenderTargetView(
dludwig@8384
   346
            backBuffer.Get(),
dludwig@8384
   347
            nullptr,
dludwig@8384
   348
            &m_renderTargetView
dludwig@8384
   349
            )
dludwig@8384
   350
        );
dludwig@8369
   351
dludwig@8384
   352
    // Create a depth stencil view.
dludwig@8384
   353
    CD3D11_TEXTURE2D_DESC depthStencilDesc(
dludwig@8384
   354
        DXGI_FORMAT_D24_UNORM_S8_UINT, 
dludwig@8384
   355
        static_cast<UINT>(m_renderTargetSize.Width),
dludwig@8384
   356
        static_cast<UINT>(m_renderTargetSize.Height),
dludwig@8384
   357
        1,
dludwig@8384
   358
        1,
dludwig@8384
   359
        D3D11_BIND_DEPTH_STENCIL
dludwig@8384
   360
        );
dludwig@8369
   361
dludwig@8384
   362
    ComPtr<ID3D11Texture2D> depthStencil;
dludwig@8384
   363
    DX::ThrowIfFailed(
dludwig@8384
   364
        m_d3dDevice->CreateTexture2D(
dludwig@8384
   365
            &depthStencilDesc,
dludwig@8384
   366
            nullptr,
dludwig@8384
   367
            &depthStencil
dludwig@8384
   368
            )
dludwig@8384
   369
        );
dludwig@8369
   370
dludwig@8384
   371
    // Set the rendering viewport to target the entire window.
dludwig@8384
   372
    CD3D11_VIEWPORT viewport(
dludwig@8384
   373
        0.0f,
dludwig@8384
   374
        0.0f,
dludwig@8384
   375
        m_renderTargetSize.Width,
dludwig@8384
   376
        m_renderTargetSize.Height
dludwig@8384
   377
        );
dludwig@8369
   378
dludwig@8384
   379
    m_d3dContext->RSSetViewports(1, &viewport);
dludwig@8369
   380
}
dludwig@8369
   381
dludwig@8367
   382
void SDL_winrtrenderer::ResizeMainTexture(int w, int h)
dludwig@8367
   383
{
dludwig@8375
   384
    const int pixelSizeInBytes = 4;
dludwig@8375
   385
dludwig@8367
   386
    D3D11_TEXTURE2D_DESC textureDesc = {0};
dludwig@8384
   387
    textureDesc.Width = w;
dludwig@8384
   388
    textureDesc.Height = h;
dludwig@8384
   389
    textureDesc.MipLevels = 1;
dludwig@8384
   390
    textureDesc.ArraySize = 1;
dludwig@8384
   391
    textureDesc.Format = DXGI_FORMAT_B8G8R8X8_UNORM;
dludwig@8384
   392
    textureDesc.SampleDesc.Count = 1;
dludwig@8384
   393
    textureDesc.SampleDesc.Quality = 0;
dludwig@8384
   394
    textureDesc.Usage = D3D11_USAGE_DYNAMIC;
dludwig@8384
   395
    textureDesc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
dludwig@8384
   396
    textureDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
dludwig@8384
   397
    textureDesc.MiscFlags = 0;
dludwig@8367
   398
dludwig@8375
   399
    const int numPixels = textureDesc.Width * textureDesc.Height;
dludwig@8375
   400
    std::vector<uint8> initialTexturePixels(numPixels * pixelSizeInBytes, 0x00);
dludwig@8375
   401
dludwig@8375
   402
    // Fill the texture with a non-black color, for debugging purposes:
dludwig@8375
   403
    //for (int i = 0; i < (numPixels * pixelSizeInBytes); i += pixelSizeInBytes) {
dludwig@8375
   404
    //    initialTexturePixels[i+0] = 0xff;
dludwig@8375
   405
    //    initialTexturePixels[i+1] = 0xff;
dludwig@8375
   406
    //    initialTexturePixels[i+2] = 0x00;
dludwig@8375
   407
    //    initialTexturePixels[i+3] = 0xff;
dludwig@8375
   408
    //}
dludwig@8375
   409
dludwig@8384
   410
    D3D11_SUBRESOURCE_DATA initialTextureData = {0};
dludwig@8384
   411
    initialTextureData.pSysMem = (void *)&(initialTexturePixels[0]);
dludwig@8384
   412
    initialTextureData.SysMemPitch = textureDesc.Width * pixelSizeInBytes;
dludwig@8384
   413
    initialTextureData.SysMemSlicePitch = numPixels * pixelSizeInBytes;
dludwig@8384
   414
    DX::ThrowIfFailed(
dludwig@8384
   415
        m_d3dDevice->CreateTexture2D(
dludwig@8384
   416
            &textureDesc,
dludwig@8384
   417
            &initialTextureData,
dludwig@8384
   418
            &m_mainTexture
dludwig@8384
   419
            )
dludwig@8384
   420
        );
dludwig@8367
   421
dludwig@8375
   422
    if (m_mainTextureHelperSurface) {
dludwig@8375
   423
        SDL_FreeSurface(m_mainTextureHelperSurface);
dludwig@8375
   424
        m_mainTextureHelperSurface = NULL;
dludwig@8375
   425
    }
dludwig@8375
   426
    m_mainTextureHelperSurface = SDL_CreateRGBSurfaceFrom(
dludwig@8375
   427
        NULL,
dludwig@8375
   428
        textureDesc.Width, textureDesc.Height,
dludwig@8375
   429
        (pixelSizeInBytes * 8),
dludwig@8375
   430
        0,      // Use an nil pitch for now.  This'll be filled in when updating the texture.
dludwig@8375
   431
        0x00ff0000, 0x0000ff00, 0x000000ff, 0x00000000);    // TODO, WinRT: calculate masks given the Direct3D-defined pixel format of the texture
dludwig@8375
   432
    if (m_mainTextureHelperSurface == NULL) {
dludwig@8375
   433
        DX::ThrowIfFailed(E_FAIL);  // TODO, WinRT: generate a better error here, taking into account who's calling this function.
dludwig@8375
   434
    }
dludwig@8375
   435
dludwig@8384
   436
    D3D11_SHADER_RESOURCE_VIEW_DESC resourceViewDesc;
dludwig@8384
   437
    resourceViewDesc.Format = textureDesc.Format;
dludwig@8384
   438
    resourceViewDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
dludwig@8384
   439
    resourceViewDesc.Texture2D.MostDetailedMip = 0;
dludwig@8384
   440
    resourceViewDesc.Texture2D.MipLevels = textureDesc.MipLevels;
dludwig@8384
   441
    DX::ThrowIfFailed(
dludwig@8384
   442
        m_d3dDevice->CreateShaderResourceView(
dludwig@8384
   443
            m_mainTexture.Get(),
dludwig@8384
   444
            &resourceViewDesc,
dludwig@8384
   445
            &m_mainTextureResourceView)
dludwig@8384
   446
        );
dludwig@8367
   447
}
dludwig@8367
   448
dludwig@8369
   449
// This method is called in the event handler for the SizeChanged event.
dludwig@8369
   450
void SDL_winrtrenderer::UpdateForWindowSizeChange()
dludwig@8369
   451
{
dludwig@8384
   452
    if (m_window->Bounds.Width  != m_windowBounds.Width ||
dludwig@8384
   453
        m_window->Bounds.Height != m_windowBounds.Height ||
dludwig@8384
   454
        m_orientation != DisplayProperties::CurrentOrientation)
dludwig@8384
   455
    {
dludwig@8384
   456
        ID3D11RenderTargetView* nullViews[] = {nullptr};
dludwig@8384
   457
        m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
dludwig@8384
   458
        m_renderTargetView = nullptr;
dludwig@8384
   459
        m_d3dContext->Flush();
dludwig@8384
   460
        CreateWindowSizeDependentResources();
dludwig@8384
   461
    }
dludwig@8369
   462
}
dludwig@8369
   463
dludwig@8350
   464
void SDL_winrtrenderer::Render(SDL_Surface * surface, SDL_Rect * rects, int numrects)
dludwig@8322
   465
{
dludwig@8384
   466
    const float blackColor[] = { 0.0f, 0.0f, 0.0f, 0.0f };
dludwig@8384
   467
    m_d3dContext->ClearRenderTargetView(
dludwig@8384
   468
        m_renderTargetView.Get(),
dludwig@8384
   469
        blackColor
dludwig@8384
   470
        );
dludwig@8322
   471
dludwig@8384
   472
    // Only draw the screen once it is loaded (some loading is asynchronous).
dludwig@8384
   473
    if (!m_loadingComplete)
dludwig@8384
   474
    {
dludwig@8384
   475
        return;
dludwig@8384
   476
    }
dludwig@8367
   477
    if (!m_mainTextureResourceView)
dludwig@8367
   478
    {
dludwig@8367
   479
        return;
dludwig@8367
   480
    }
dludwig@8322
   481
dludwig@8384
   482
    // Update the main texture (for SDL usage).  Start by mapping the SDL
dludwig@8375
   483
    // window's main texture to CPU-accessible memory:
dludwig@8384
   484
    D3D11_MAPPED_SUBRESOURCE textureMemory = {0};
dludwig@8384
   485
    DX::ThrowIfFailed(
dludwig@8384
   486
        m_d3dContext->Map(
dludwig@8384
   487
            m_mainTexture.Get(),
dludwig@8384
   488
            0,
dludwig@8384
   489
            D3D11_MAP_WRITE_DISCARD,
dludwig@8384
   490
            0,
dludwig@8384
   491
            &textureMemory)
dludwig@8384
   492
        );
dludwig@8349
   493
dludwig@8375
   494
    // Copy pixel data to the locked texture's memory:
dludwig@8375
   495
    m_mainTextureHelperSurface->pixels = textureMemory.pData;
dludwig@8375
   496
    m_mainTextureHelperSurface->pitch = textureMemory.RowPitch;
dludwig@8375
   497
    SDL_BlitSurface(surface, NULL, m_mainTextureHelperSurface, NULL);
dludwig@8384
   498
    // TODO, WinRT: only update the requested rects (passed to SDL_UpdateWindowSurface), rather than everything
dludwig@8349
   499
dludwig@8375
   500
    // Clean up a bit, then commit the texture's memory back to Direct3D:
dludwig@8375
   501
    m_mainTextureHelperSurface->pixels = NULL;
dludwig@8375
   502
    m_mainTextureHelperSurface->pitch = 0;
dludwig@8384
   503
    m_d3dContext->Unmap(
dludwig@8384
   504
        m_mainTexture.Get(),
dludwig@8384
   505
        0);
dludwig@8349
   506
dludwig@8384
   507
    m_d3dContext->OMSetRenderTargets(
dludwig@8384
   508
        1,
dludwig@8384
   509
        m_renderTargetView.GetAddressOf(),
dludwig@8384
   510
        nullptr
dludwig@8384
   511
        );
dludwig@8322
   512
dludwig@8384
   513
    UINT stride = sizeof(VertexPositionColor);
dludwig@8384
   514
    UINT offset = 0;
dludwig@8384
   515
    m_d3dContext->IASetVertexBuffers(
dludwig@8384
   516
        0,
dludwig@8384
   517
        1,
dludwig@8384
   518
        m_vertexBuffer.GetAddressOf(),
dludwig@8384
   519
        &stride,
dludwig@8384
   520
        &offset
dludwig@8384
   521
        );
dludwig@8322
   522
dludwig@8384
   523
    m_d3dContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
dludwig@8322
   524
dludwig@8384
   525
    m_d3dContext->IASetInputLayout(m_inputLayout.Get());
dludwig@8322
   526
dludwig@8384
   527
    m_d3dContext->VSSetShader(
dludwig@8384
   528
        m_vertexShader.Get(),
dludwig@8384
   529
        nullptr,
dludwig@8384
   530
        0
dludwig@8384
   531
        );
dludwig@8322
   532
dludwig@8384
   533
    m_d3dContext->PSSetShader(
dludwig@8384
   534
        m_pixelShader.Get(),
dludwig@8384
   535
        nullptr,
dludwig@8384
   536
        0
dludwig@8384
   537
        );
dludwig@8322
   538
dludwig@8384
   539
    m_d3dContext->PSSetShaderResources(0, 1, m_mainTextureResourceView.GetAddressOf());
dludwig@8347
   540
dludwig@8384
   541
    m_d3dContext->PSSetSamplers(0, 1, m_mainSampler.GetAddressOf());
dludwig@8347
   542
dludwig@8384
   543
    m_d3dContext->Draw(4, 0);
dludwig@8322
   544
}
dludwig@8369
   545
dludwig@8369
   546
// Method to deliver the final image to the display.
dludwig@8369
   547
void SDL_winrtrenderer::Present()
dludwig@8369
   548
{
dludwig@8384
   549
    // The application may optionally specify "dirty" or "scroll"
dludwig@8384
   550
    // rects to improve efficiency in certain scenarios.
dludwig@8384
   551
    DXGI_PRESENT_PARAMETERS parameters = {0};
dludwig@8384
   552
    parameters.DirtyRectsCount = 0;
dludwig@8384
   553
    parameters.pDirtyRects = nullptr;
dludwig@8384
   554
    parameters.pScrollRect = nullptr;
dludwig@8384
   555
    parameters.pScrollOffset = nullptr;
dludwig@8384
   556
    
dludwig@8384
   557
    // The first argument instructs DXGI to block until VSync, putting the application
dludwig@8384
   558
    // to sleep until the next VSync. This ensures we don't waste any cycles rendering
dludwig@8384
   559
    // frames that will never be displayed to the screen.
dludwig@8384
   560
    HRESULT hr = m_swapChain->Present1(1, 0, &parameters);
dludwig@8369
   561
dludwig@8384
   562
    // Discard the contents of the render target.
dludwig@8384
   563
    // This is a valid operation only when the existing contents will be entirely
dludwig@8384
   564
    // overwritten. If dirty or scroll rects are used, this call should be removed.
dludwig@8384
   565
    m_d3dContext->DiscardView(m_renderTargetView.Get());
dludwig@8369
   566
dludwig@8384
   567
    // If the device was removed either by a disconnect or a driver upgrade, we 
dludwig@8384
   568
    // must recreate all device resources.
dludwig@8384
   569
    if (hr == DXGI_ERROR_DEVICE_REMOVED)
dludwig@8384
   570
    {
dludwig@8384
   571
        HandleDeviceLost();
dludwig@8384
   572
    }
dludwig@8384
   573
    else
dludwig@8384
   574
    {
dludwig@8384
   575
        DX::ThrowIfFailed(hr);
dludwig@8384
   576
    }
dludwig@8369
   577
}
dludwig@8369
   578
dludwig@8369
   579
// Method to convert a length in device-independent pixels (DIPs) to a length in physical pixels.
dludwig@8369
   580
float SDL_winrtrenderer::ConvertDipsToPixels(float dips)
dludwig@8369
   581
{
dludwig@8384
   582
    static const float dipsPerInch = 96.0f;
dludwig@8384
   583
    return floor(dips * DisplayProperties::LogicalDpi / dipsPerInch + 0.5f); // Round to nearest integer.
dludwig@8369
   584
}