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