Etapa 3: conectar a cadeia de permuta do DirectX à interface do usuário

Applies to Windows only

Para acabar de configurar o DirectX para visualização em um modo de exibição, é hora de trazer o DirectX para o provedor de modo de exibição que você criou para o seu aplicativo da Windows Store usando DirectX em C++. NaEtapa 1: criar e iniciar um modo de exibição, você criou o provedor de modo de exibição e o alocador responsável por sua criação. Depois, na Etapa Step 2: configurar os manipuladores de eventos, você preparou os eventos necessários para lidar com mudanças nas entradas de PLM, modo de exibição e tamanho da janela. Agora, vamos adicionar os recursos gráficos que desenham e gerenciam o modo de exibição e que são atualizados em resposta aos eventos recebidos pela CoreWindow do aplicativo.

Instruções

Antes de iniciar esta etapa, vamos voltar um pouco e observar a abordagem geral sobre como lidar com os recursos do DirectX no aplicativo DirectX no Microsoft Visual Studio 2013. No modelo, todos os recursos do DirectX são definidos em uma classe denominada DeviceResources nos arquivos DeviceResources.h e DeviceResources.cpp. Uma instância global dessa classe, que contém referências ComPtr a todos os recursos gráficos do dispositivo, é criada no thread principal do aplicativo e pode ser chamada ou acessada por meio de métodos e acessadores públicos. Com as configurações e subdivisões dos recursos do DirectX contidas dessa maneira, fica mais conveniente manter e depurar o código.


// Controls all the DirectX device resources.
class DeviceResources
{
	public:
		DeviceResources();
		void CreateDeviceIndependentResources();
		void CreateDeviceResources();
		void CreateWindowSizeDependentResources();
		void SetWindow(Windows::UI::Core::CoreWindow^ window);
		void SetDpi(float dpi);
		void UpdateForWindowSizeChange();
		void ValidateDevice();
		void HandleDeviceLost();
		void RegisterDeviceNotify(IDeviceNotify* deviceNotify);
		void Trim();
		void Present();

		// Device Accessors.
		Windows::Foundation::Size GetOutputBounds() const               { return m_outputSize; }

		// D3D Accessors.											  
		ID3D11Device2*			GetD3DDevice() const					{ return m_d3dDevice.Get(); }
		ID3D11DeviceContext2*	GetD3DDeviceContext() const				{ return m_d3dContext.Get(); }
		IDXGISwapChain1*		GetSwapChain() const					{ return m_swapChain.Get(); }
		D3D_FEATURE_LEVEL		GetDeviceFeatureLevel() const			{ return m_d3dFeatureLevel; }
		ID3D11RenderTargetView*	GetBackBufferRenderTargetView() const	{ return m_d3dRenderTargetView.Get(); }
		ID3D11DepthStencilView* GetDepthStencilView() const				{ return m_d3dDepthStencilView.Get(); }
		D3D11_VIEWPORT			GetScreenViewport() const				{ return m_screenViewport; }
		DirectX::XMFLOAT4X4		GetOrientationTransform3D() const		{ return m_orientationTransform3D; }

		// D2D Accessors.											  
		ID2D1Factory2*			GetD2DFactory() const					{ return m_d2dFactory.Get(); }
		ID2D1Device1*			GetD2DDevice() const					{ return m_d2dDevice.Get(); }
		ID2D1DeviceContext1*	GetD2DDeviceContext() const				{ return m_d2dContext.Get(); }
		ID2D1Bitmap1*			GetD2DTargetBitmap() const				{ return m_d2dTargetBitmap.Get(); }
		IDWriteFactory2*		GetDWriteFactory() const				{ return m_dwriteFactory.Get();	 }
		IWICImagingFactory2*	GetWicImagingFactory() const			{ return m_wicFactory.Get(); }
		D2D1::Matrix3x2F		GetOrientationTransform2D() const		{ return m_orientationTransform2D; }

private:
		DXGI_MODE_ROTATION ComputeDisplayRotation();

		// Direct3D objects.
		Microsoft::WRL::ComPtr<ID3D11Device2>			m_d3dDevice;
		Microsoft::WRL::ComPtr<ID3D11DeviceContext2>	m_d3dContext;
		Microsoft::WRL::ComPtr<IDXGISwapChain1>			m_swapChain;

		// Direct3D rendering objects. Required for 3D.
		Microsoft::WRL::ComPtr<ID3D11RenderTargetView>	m_d3dRenderTargetView;
		Microsoft::WRL::ComPtr<ID3D11DepthStencilView>	m_d3dDepthStencilView;
		D3D11_VIEWPORT									m_screenViewport;

		// Direct2D drawing components.
		Microsoft::WRL::ComPtr<ID2D1Factory2>		m_d2dFactory;
		Microsoft::WRL::ComPtr<ID2D1Device1>		m_d2dDevice;
		Microsoft::WRL::ComPtr<ID2D1DeviceContext1>	m_d2dContext;
		Microsoft::WRL::ComPtr<ID2D1Bitmap1>		m_d2dTargetBitmap;

		// DirectWrite drawing components.
		Microsoft::WRL::ComPtr<IDWriteFactory2>		m_dwriteFactory;
		Microsoft::WRL::ComPtr<IWICImagingFactory2>	m_wicFactory;

		// Cached reference to the Window.
		Platform::Agile<Windows::UI::Core::CoreWindow> m_window;

		// Cached device properties.
		D3D_FEATURE_LEVEL								m_d3dFeatureLevel;
		Windows::Foundation::Size						m_d3dRenderTargetSize;
		Windows::Foundation::Size                       m_outputSize;
		Windows::Graphics::Display::DisplayOrientations	m_orientation;
		float											m_dpi;

		// Transforms used for display orientation.
		D2D1::Matrix3x2F	m_orientationTransform2D;
		DirectX::XMFLOAT4X4	m_orientationTransform3D;
};

Aqui está uma lista resumida dos principais campos nesse tipo:

  • Microsoft::WRL::ComPtr<ID3D11Device2> m_d3dDevice; Esta é a referência a uma representação virtual do dispositivo gráfico. Você usa essa instância para obter e configurar recursos gráficos e modos de exibição individuais, como buffers constantes e memória para elementos gráficos em 3D ou saída de renderização.
  • Microsoft::WRL::ComPtr<ID3D11DeviceContext2> m_d3dContext; Esta é a referência ao contexto de desenho associado ao dispositivo 3D. Você usa essa instância para invocar efetivamente os programas de sombreador individuais e desenhar os resultados do pipeline gráfico em um destino de renderização.
  • Microsoft::WRL::ComPtr<IDXGISwapChain1> m_swapChain; Esta é a referência à cadeia de permuta que contém o buffer de fundo que recebe os resultados renderizados.
  • Platform::Agile<Windows::UI::Core::CoreWindow> m_window; Esta é a janela que hospeda a cadeia de permuta apresentada e exibe os resultados renderizados do contexto de desenho.

Basicamente, você cria (e recria) seus recursos gráficos com ID3D11Device2, bem como cria uma nova instância de IDXGISwapChain2, cada vez que a tela ou janela é criada (ou sofre alguma alteração). Esses recursos são usados pelo ID3D11DeviceContext2 quando cada quadro é renderizado. A saída é enfim gravada no buffer de fundo da cadeia de permuta. Quando a cadeia de permuta é apresentada, o buffer de fundo é desenhado no CoreWindow e o usuário vê os resultados da renderização na janela.

No modelo, dividimos o carregamento dos recursos do DirectX em dois métodos: CreateWindowSizeDependentResources e CreateDeviceResources, ambos encontrados na implementação da classe DeviceResources.

Esta é a parte crucial: configurar a cadeia de permuta para seu aplicativo. Como a cadeia de permuta é o buffer que contém a imagem que seu aplicativo apresentará para exibição, ela deverá corresponder as dimensões de pixel do dispositivo de saída (a tela). Isso significa que ele tem uma dependência nas dimensões do pixel atual da janela de tela inteira do seu aplicativo e, se essa janela mudar de dimensões, a cadeia de permuta deverá ser recriada.

Observe que esse método não é chamado apenas quando você inicia o aplicativo pela primeira vez, mas também sempre que a janela é redimensionada ou ocorre alguma mudança na tela.

Aqui, focamos na criação dos recursos de elementos gráficos que ser alterados quando o tamanho da janela, a orientação da janela ou o dispositivo de saída é alterado. Esses recursos incluem o alocador de interface de dispositivo usado para criar a cadeia de permuta, e a cadeia de permuta em si.


// These resources need to be recreated every time the window size is changed.
void DeviceResources::CreateWindowSizeDependentResources() 
{
	// Clear our previous window size specific context
	ID3D11RenderTargetView* nullViews[] = {nullptr};
	m_d3dContext->OMSetRenderTargets(ARRAYSIZE(nullViews), nullViews, nullptr);
	m_d3dRenderTargetView = nullptr;
	m_d2dContext->SetTarget(nullptr);
	m_d2dTargetBitmap = nullptr;
	m_d3dDepthStencilView = nullptr;
	m_d3dContext->Flush();

	// Store the output bounds so the next time we get a SizeChanged event we can
	// avoid rebuilding everything if the size is identical.
	DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();
	m_outputSize.Width = m_swapChainPanel == nullptr ? m_window->Bounds.Width : static_cast<float>(m_swapChainPanel->ActualWidth);
    m_outputSize.Height = m_swapChainPanel == nullptr ? m_window->Bounds.Height : static_cast<float>(m_swapChainPanel->ActualHeight);

	// Prevent zero size DirectX content from being created
	m_outputSize.Width = m_outputSize.Width > 0 ? m_outputSize.Width : 1;
	m_outputSize.Height = m_outputSize.Height > 0 ? m_outputSize.Height : 1;

	// Calculate the necessary swap chain and render target size in pixels.
	float outputWidthInPixels;
	float outputHeightInPixels;

	if (m_swapChainPanel != nullptr)
	{
		outputWidthInPixels = m_outputSize.Width * m_swapChainPanel->CompositionScaleX;
		outputHeightInPixels = m_outputSize.Height * m_swapChainPanel->CompositionScaleY;
	}
	else
	{
		outputWidthInPixels = DX::ConvertDipsToPixels(m_outputSize.Width, currentDisplayInformation->LogicalDpi);
		outputHeightInPixels = DX::ConvertDipsToPixels(m_outputSize.Height, currentDisplayInformation->LogicalDpi);
	}


	// The width and height of the swap chain must be based on the window's
	// natively-oriented width and height. If the window is not in the native
	// orientation, the dimensions must be reversed.
	m_orientation = currentDisplayInformation->CurrentOrientation;

	DXGI_MODE_ROTATION displayRotation = ComputeDisplayRotation();

	bool swapDimensions = displayRotation == DXGI_MODE_ROTATION_ROTATE90 || displayRotation == DXGI_MODE_ROTATION_ROTATE270;
	m_d3dRenderTargetSize.Width = swapDimensions ? outputHeightInPixels : outputWidthInPixels;
	m_d3dRenderTargetSize.Height = swapDimensions ? outputWidthInPixels : outputHeightInPixels;

	if (m_swapChain)
	{
		// If the swap chain already exists, resize it.
		HRESULT hr = m_swapChain->ResizeBuffers(
			2, // Double-buffered swap chain.
			static_cast<UINT>(m_d3dRenderTargetSize.Width),
			static_cast<UINT>(m_d3dRenderTargetSize.Height),
			DXGI_FORMAT_B8G8R8A8_UNORM,
			0
			);

		if (hr == DXGI_ERROR_DEVICE_REMOVED || hr == DXGI_ERROR_DEVICE_RESET)
		{
			// If the device was removed for any reason, a new device and swap chain will need to be created.
			HandleDeviceLost();

			// Everything is set up now. Do not continue execution of this method. 
			return;
		}
		else
		{
			DX::ThrowIfFailed(hr);
		}
	}
	else
	{
		// Otherwise, create a new one using the same adapter as the existing Direct3D device.
		DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};

		swapChainDesc.Width = static_cast<UINT>(m_d3dRenderTargetSize.Width); // Match the size of the window.
		swapChainDesc.Height = static_cast<UINT>(m_d3dRenderTargetSize.Height);
		swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; // This is the most common swap chain format.
		swapChainDesc.Stereo = false;
		swapChainDesc.SampleDesc.Count = 1; // Don't use multi-sampling.
		swapChainDesc.SampleDesc.Quality = 0;
		swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
		swapChainDesc.BufferCount = 2; // Use double-buffering to minimize latency.
		swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL; // All Windows Store apps must use this SwapEffect.
		swapChainDesc.Flags = 0;

		// When using XAML interop, change the Scaling to DXGI_SCALING_STRETCH
		if (m_swapChainPanel == nullptr)
		{
			swapChainDesc.Scaling = DXGI_SCALING_NONE;
		}
		else
		{
			swapChainDesc.Scaling = DXGI_SCALING_STRETCH;
		}

		swapChainDesc.AlphaMode = DXGI_ALPHA_MODE_IGNORE;

		// This sequence obtains the DXGI factory that was used to create the Direct3D device above.
		ComPtr<IDXGIDevice3> dxgiDevice;
		DX::ThrowIfFailed(
			m_d3dDevice.As(&dxgiDevice)
			);

		ComPtr<IDXGIAdapter> dxgiAdapter;
		DX::ThrowIfFailed(
			dxgiDevice->GetAdapter(&dxgiAdapter)
			);

		ComPtr<IDXGIFactory2> dxgiFactory;
		DX::ThrowIfFailed(
			dxgiAdapter->GetParent(
				__uuidof(IDXGIFactory2), 
				&dxgiFactory
				)
			);

		DX::ThrowIfFailed(
				dxgiFactory->CreateSwapChainForCoreWindow(
					m_d3dDevice.Get(),
					reinterpret_cast<IUnknown*>(m_window.Get()),
					&swapChainDesc,
					nullptr,
					&m_swapChain
					)
				);;		
		}

		// Ensure that DXGI does not queue more than one frame at a time. This both reduces latency and
		// ensures that the application will only render after each VSync, minimizing power consumption.
		DX::ThrowIfFailed(
			dxgiDevice->SetMaximumFrameLatency(1)
			);
	}

	// Set the proper orientation for the swap chain, and generate 2D and
	// 3D matrix transformations for rendering to the rotated swap chain.
	// Note the rotation angle for the 2D and 3D transforms are different.
	// This is due to the difference in coordinate spaces.  Additionally,
	// the 3D matrix is specified explicitly to avoid rounding errors.

	switch (displayRotation)
	{
	case DXGI_MODE_ROTATION_IDENTITY:
		m_orientationTransform2D = Matrix3x2F::Identity();
		m_orientationTransform3D = ScreenRotation::Rotation0;
		break;

	case DXGI_MODE_ROTATION_ROTATE90:
		m_orientationTransform2D = 
			Matrix3x2F::Rotation(90.0f) *
            Matrix3x2F::Translation(m_outputSize.Height, 0.0f);
        m_orientationTransform3D = ScreenRotation::Rotation270;
		break;

	case DXGI_MODE_ROTATION_ROTATE180:
		m_orientationTransform2D = 
			Matrix3x2F::Rotation(180.0f) *
			Matrix3x2F::Translation(m_outputSize.Width, m_outputSize.Height);
		m_orientationTransform3D = ScreenRotation::Rotation180;
		break;

	case DXGI_MODE_ROTATION_ROTATE270:
		m_orientationTransform2D = 
			Matrix3x2F::Rotation(270.0f) *
            Matrix3x2F::Translation(0.0f, m_outputSize.Width);
        m_orientationTransform3D = ScreenRotation::Rotation90;
		break;

	default:
		throw ref new Platform::FailureException();
	}

	DX::ThrowIfFailed(
		m_swapChain->SetRotation(displayRotation)
		);
  
// Create a render target view of the swap chain back buffer.
	ComPtr<ID3D11Texture2D> backBuffer;
	DX::ThrowIfFailed(
		m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
		);

	DX::ThrowIfFailed(
		m_d3dDevice->CreateRenderTargetView(
			backBuffer.Get(),
			nullptr,
			&m_d3dRenderTargetView
			)
		);

	// Create a depth stencil view for use with 3D rendering if needed.
	CD3D11_TEXTURE2D_DESC depthStencilDesc(
		DXGI_FORMAT_D24_UNORM_S8_UINT, 
		static_cast<UINT>(m_d3dRenderTargetSize.Width),
		static_cast<UINT>(m_d3dRenderTargetSize.Height),
		1, // This depth stencil view has only one texture.
		1, // Use a single mipmap level.
		D3D11_BIND_DEPTH_STENCIL
		);

	ComPtr<ID3D11Texture2D> depthStencil;
	DX::ThrowIfFailed(
		m_d3dDevice->CreateTexture2D(
			&depthStencilDesc,
			nullptr,
			&depthStencil
			)
		);

	CD3D11_DEPTH_STENCIL_VIEW_DESC depthStencilViewDesc(D3D11_DSV_DIMENSION_TEXTURE2D);
	DX::ThrowIfFailed(
		m_d3dDevice->CreateDepthStencilView(
			depthStencil.Get(),
			&depthStencilViewDesc,
			&m_d3dDepthStencilView
			)
		);
	
	// Set the 3D rendering viewport to target the entire window.
	m_screenViewport = CD3D11_VIEWPORT(
		0.0f,
		0.0f,
		m_d3dRenderTargetSize.Width,
		m_d3dRenderTargetSize.Height
		);

	m_d3dContext->RSSetViewports(1, &m_screenViewport);

}

Primeiro, verifique se o ponteiro para a cadeia de permuta não é uma referência nula. Se não for, significa que a chamada para esse método veio depois de um evento de redimensionamento de janela, e é preciso redimensionar os buffers.

Se o ponteiro de cadeia de permuta for uma referência nula, É hora de criar uma nova cadeia de permuta. Depois de criar o alocador de objetos gráficos DXGI, chame IDXGIFactory2::CreateSwapChainForCoreWindow nele para obter a cadeia de permuta como um recurso para a janela principal. Nesse caso, uma referência à CoreWindow do aplicativo é mantida em uma variável global (m_window) na instância DeviceResources e o IDXGIFactory2::CreateSwapChainForCoreWindow cria uma cadeia de permuta usando essa referência. Como resultado, qualquer atualização da cadeia de permuta, como chamadas ao IDXGISwapChain::Present, será associada à CoreWindow de seu aplicativo.

Agora você tem uma cadeia de permuta (nova ou redimensionada). É hora de anexar todos os recursos apropriados que exibirão os resultados do pipeline de renderização. Obtenha o buffer de fundo que será usado como destino de renderização do Direct3D e a interface do modo de exibição para mostrar esse destino quando apresentar a cadeia de permuta.

Este método também fornece algumas características básicas que podem melhorar a qualidade e o desempenho do renderizador: predefinição de matrizes de transformação para as alterações de orientação da tela, estênceis de profundidade e um modo de atualização padrão para melhorar o consumo de energia.

Você cria a fábrica de recursos no próximo método, CreateDeviceResources. Neste método são criados os recursos associados a um dispositivo Direct3D. Está tudo centralizado neste método, caso seja necessário recriar os recursos se um dispositivo Direct3D for perdido ou sofrer uma alteração. Isso costuma ocorrer se a tela for alterada ou se a placa de vídeo for removida.



// Configures the Direct3D device, and stores handles to it and the device context.
void DeviceResources::CreateDeviceResources() 
{
	// This flag adds support for surfaces with a different color channel ordering
	// than the API default. It is required for compatibility with Direct2D.
	UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

#if defined(_DEBUG)
	if (DX::SdkLayersAvailable())
	{
		// If the project is in a debug build, enable debugging via SDK Layers with this flag.
		creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
	}
#endif

	// This array defines the set of DirectX hardware feature levels this app will support.
	// Note the ordering should be preserved.
	// Don't forget to declare your application's minimum required feature level in its
	// description.  All applications are assumed to support 9.1 unless otherwise stated.
	D3D_FEATURE_LEVEL featureLevels[] = 
	{
		D3D_FEATURE_LEVEL_11_1,
		D3D_FEATURE_LEVEL_11_0,
		D3D_FEATURE_LEVEL_10_1,
		D3D_FEATURE_LEVEL_10_0,
		D3D_FEATURE_LEVEL_9_3,
		D3D_FEATURE_LEVEL_9_2,
		D3D_FEATURE_LEVEL_9_1
	};

	// Create the Direct3D 11 API device object and a corresponding context.
	ComPtr<ID3D11Device> device;
	ComPtr<ID3D11DeviceContext> context;

	HRESULT hr = D3D11CreateDevice(
		nullptr,					// Specify nullptr to use the default adapter.
		D3D_DRIVER_TYPE_HARDWARE,	// Create a device using the hardware graphics driver.
		0,							// Should be 0 unless the driver is D3D_DRIVER_TYPE_SOFTWARE.
		creationFlags,				// Set debug and Direct2D compatibility flags.
		featureLevels,				// List of feature levels this app can support.
		ARRAYSIZE(featureLevels),	// Size of the list above.
		D3D11_SDK_VERSION,			// Always set this to D3D11_SDK_VERSION for Windows Store apps.
		&device,					// Returns the Direct3D device created.
		&m_d3dFeatureLevel,			// Returns feature level of device created.
		&context					// Returns the device immediate context.
		);

	if (FAILED(hr))
	{
		// If the initialization fails, fall back to the WARP device.
		// For more information on WARP, see: 
		// http://go.microsoft.com/fwlink/?LinkId=286690
		DX::ThrowIfFailed(
			D3D11CreateDevice(
				nullptr,
				D3D_DRIVER_TYPE_WARP, // Create a WARP device instead of a hardware device.
				0,
				creationFlags,
				featureLevels,
				ARRAYSIZE(featureLevels),
				D3D11_SDK_VERSION,
				&device,
				&m_d3dFeatureLevel,
				&context
				)
			);
	}

	// Store pointers to the Direct3D 11.1 API device and immediate context.
	DX::ThrowIfFailed(
		device.As(&m_d3dDevice)
		);

	DX::ThrowIfFailed(
		context.As(&m_d3dContext)
		);

}

Agora, crie o dispositivo Direct3D 11 —uma representação abstrata da interface gráfica de hardware para uso com Direct3D— e obtenha um contexto para ele. Também é preciso testar se o dispositivo dá suporte aos recursos do Direct3D 11.1 e obter o dispositivo DXGI (esse dispositivo representa a interface gráfica de hardware em seu nível mais baixo e contém informações sobre o adaptador gráfico).

Lembre-se de que, se você estiver criando um aplicativo para a Windows Store (claro que está!), deverá definir o parâmetro SDKVersion na chamada D3D11CreateDevice a D3D11_SDK_VERSION.

Agora, vamos dar uma olhada em como nós usamos esses recursos. No tópico sobre como criar e inicializar um modo de exibição, você definiu a implementação do método IFrameworkView::SetWindow que o aplicativo chama quando cria a instância do provedor de modo de exibição. No modelo, essa implementação chama um método SetWindow separado, definido na classe DeviceResources em DeviceResources.cpp.


void DeviceResources::SetWindow(CoreWindow^ window)
{
	m_window = window;
	
	// SetDpi() will call CreateWindowSizeDependentResources()
	// if those resources have not been created yet.
	SetDpi(DisplayInformation::GetForCurrentView()->LogicalDpi);

	UpdateForWindowSizeChange();
}


void DeviceResources::UpdateForWindowSizeChange()
{
	DisplayInformation^ currentDisplayInformation = DisplayInformation::GetForCurrentView();

	if (m_swapChainPanel == nullptr && (
            m_window->Bounds.Width  != m_outputSize.Width ||
            m_window->Bounds.Height != m_outputSize.Height
        ) || m_orientation != currentDisplayInformation->CurrentOrientation)

	{
		CreateWindowSizeDependentResources();
	}
}

SetWindow, e por associação UpdateForWindowSizeChange, verificam os parâmetros CoreWindow e os dados Windows::Graphics::Display::DisplayInformation atuais para determinar se os recursos gráficos precisam ser recriados; especificamente a cadeia de permuta e os destinos de renderização que correspondem ao tamanho da janela atual. Se tiver ocorrido alguma mudança, então será necessário recriar os recursos usando o CreateWindowSizeDependentResources que você implementou.

CreateDeviceResources, por outro lado, é chamado quando o aplicativo é iniciado ou quando o adaptador gráfico é perdido (ou sofre alguma alteração). Para dar suporte a essa possibilidade, você deve criar métodos para lidar com a situação em que o usuário muda o dispositivo gráfico. O modelo fornece dois métodos:

  • ValidateDevice, que é chamado quando o evento DisplayInformation::DisplayContentsInvalidated é acionado. Esse evento ocorre quando a tela precisa ser redesenhada devido a um erro interno ou alteração.
  • HandleDeviceLost, que define o dispositivo para o estado anterior antes do erro de validação e notifica ao thread do aplicativo que o dispositivo foi perdido e que os recursos foram recriados.

// This method is called in the event handler for the DisplayContentsInvalidated event.
void DeviceResources::ValidateDevice()
{
	// The D3D Device is no longer valid if the default adapter changes or if 
	// the device has been removed. 
 
	// First, get the information for the adapter related to the current device. 

	ComPtr<IDXGIDevice3> dxgiDevice;
	DX::ThrowIfFailed(m_d3dDevice.As(&dxgiDevice));

	ComPtr<IDXGIAdapter> deviceAdapter;
	DX::ThrowIfFailed(dxgiDevice->GetAdapter(&deviceAdapter));

	DXGI_ADAPTER_DESC adapterDesc;
	DX::ThrowIfFailed(deviceAdapter->GetDesc(&adapterDesc));

	// Next, get the information for the default adapter. 

	ComPtr<IDXGIFactory2> dxgiFactory;
	DX::ThrowIfFailed(CreateDXGIFactory1(IID_PPV_ARGS(&dxgiFactory)));

	ComPtr<IDXGIAdapter1> currentAdapter;
	DX::ThrowIfFailed(dxgiFactory->EnumAdapters1(0, &currentAdapter));

	DXGI_ADAPTER_DESC currentDesc;
	DX::ThrowIfFailed(currentAdapter->GetDesc(&currentDesc));

	// If the adapter LUIDs don't match, or if the device reports that it has been removed, 
	// a new D3D device must be created. 

	if (adapterDesc.AdapterLuid.LowPart != currentDesc.AdapterLuid.LowPart ||
		adapterDesc.AdapterLuid.HighPart != currentDesc.AdapterLuid.HighPart ||
		FAILED(m_d3dDevice->GetDeviceRemovedReason()))
	{
		// Release references to resources related to the old device. 
		dxgiDevice = nullptr;
		deviceAdapter = nullptr;

		// Create a new device and swap chain. 
		HandleDeviceLost();
	}
}




// Recreate all device resources and set them back to the current state.
void DeviceResources::HandleDeviceLost()
{
		// Reset these member variables to ensure that SetDpi recreates all resources.
	float dpi = m_dpi;
	m_dpi = -1.0f;
	m_outputSize.Width = 0;
    m_outputSize.Height = 0;
	m_swapChain = nullptr;

	if (m_deviceNotify != nullptr)
	{
		m_deviceNotify->OnDeviceLost();
	}

	CreateDeviceResources();
	SetDpi(dpi);

	if (m_deviceNotify != nullptr)
	{
		m_deviceNotify->OnDeviceRecreated();
	}
}

Até agora, você criou e configurou a cadeia de permuta do Direct3D e manipulou eventos que exigem que uma nova cadeia de permuta seja criada. Você concluiu a configuração dos recursos gráficos e forneceu métodos para lidar com as alterações na tela. Agora, você pode criar seu próprio método de renderização para desenhar para o contexto Direct3D para apresentação pela cadeia de permuta.


void MyDirectXApp::Render()
{
    // Do some rendering to m_d3dContext!
}

Por fim, você apresenta o buffer de vídeo da cadeia de permuta com uma chamada para Present.


// Method to deliver the final image to the display.
void Direct3DBase::Present()
{
	// The application may optionally specify "dirty" or "scroll"
	// rects to improve efficiency in certain scenarios.
	DXGI_PRESENT_PARAMETERS parameters = {0};
	parameters.DirtyRectsCount = 0;
	parameters.pDirtyRects = nullptr;
	parameters.pScrollRect = nullptr;
	parameters.pScrollOffset = nullptr;
	
	// The first argument instructs DXGI to block until VSync, putting the application
	// to sleep until the next VSync. This ensures we don't waste any cycles rendering
	// frames that will never be displayed to the screen.
	HRESULT hr = m_swapChain->Present1(1, 0, &parameters);

	// Discard the contents of the render target.
	// This is a valid operation only when the existing contents will be entirely
	// overwritten. If dirty or scroll rects are used, remove this call.
	m_d3dContext->DiscardView(m_renderTargetView.Get());

	// Discard the contents of the depth stencil.
	m_d3dContext->DiscardView(m_depthStencilView.Get());

	// If the device was removed either by a disconnect or a driver upgrade, we 
	// must recreate all device resources.
	if (hr == DXGI_ERROR_DEVICE_REMOVED)
	{
		HandleDeviceLost();
	}
	else
	{
		DX::ThrowIfFailed(hr);
	}


Atualizações para o Windows 8.1

A partir do Windows 8.1, todos os aplicativos DirectX da Windows Store têm que chamar IDXGIDevice3::Trim no momento da suspensão. Essa chamada pede para o driver gráfico liberar todos os buffers temporários alocados no aplicativo, evitando que o aplicativo seja encerrado para recuperar recursos de memória durante o estado de suspensão. Esse é um requisito de certificação do Windows 8.1.

Adicione o código a seguir ao método do manipulador de eventos suspenso:

void App::OnSuspending(
    _In_ Platform::Object^ sender,
    _In_ Windows::ApplicationModel::SuspendingEventArgs^ args
    )
{
    Windows::ApplicationModel::SuspendingDeferral^ deferral = args->SuspendingOperation->GetDeferral();

   // Save application data

    m_exampleDxgiAdapter->Trim();
    deferral->Complete();
}

Nos modelos do Windows 8.1 DirectX fornecidos com o Visual Studio 2013, o adaptador DXGI é usado pelo objeto manipulador de recursos do dispositivo do modelo. Os modelos já incluem o código necessário que notifica o objeto de recursos do dispositivo para chamar IDXGIDevice3::Trim durante a suspensão.

Criando seu aplicativo

Se você tiver usado o modelo de Aplicativo Direct3D, deverá ver uma tela semelhante a seguinte quando compilar e executar seu projeto:

Um cubo renderizado com direct3d

Se você implementou o seu próprio código de renderização, verá o objeto que você definiu desenhado em uma linda tela inteira 3D!

Caso contrário, se não tiver implementado nenhum código no método Render e gravado no ID3D11DeviceContext1 (o campo m_d3dContext do Direct3DBase neste código), verá uma tela vazia. Isso é um pouco chato, mas é um ótimo começo!

Etapa anterior

Configurar o dispatcher de eventos

Tópicos relacionados

Como configurar o seu aplicativo DirectX da Windows Store para mostrar uma visualização
Código completo de um aplicativo DirectX da Windows Store

 

 

Mostrar:
© 2014 Microsoft