Configuración de recursos de DirectX y visualización de una imagenSet up DirectX resources and display an image

Aquí te mostramos cómo crear un dispositivo Direct3D, una cadena de intercambio y una vista de destino de representación, y cómo mostrar la imagen representada en la pantalla.Here, we show you how to create a Direct3D device, swap chain, and render-target view, and how to present the rendered image to the display.

Objetivo: configurar recursos de DirectX en una aplicación para la Plataforma universal de Windows (UWP) con C++ y mostrar un color sólido.Objective: To set up DirectX resources in a C++ Universal Windows Platform (UWP) app and to display a solid color.

Requisitos previosPrerequisites

Suponemos que estás familiarizado con C++.We assume that you are familiar with C++. También necesitas tener experiencia básica en los conceptos de programación de gráficos.You also need basic experience with graphics programming concepts.

Tiempo para completarlo: 20minutos.Time to complete: 20 minutes.

InstruccionesInstructions

1. Declarar variables de interfaz de Direct3D con ComPtr1. Declaring Direct3D interface variables with ComPtr

Declaramos variables de interfaz de Direct3D con la plantilla de puntero inteligente ComPtr de la Biblioteca de plantillas C++ de Windows en tiempo de ejecución (WRL), para poder administrar la vigencia de esas variables de manera segura.We declare Direct3D interface variables with the ComPtr smart pointer template from the Windows Runtime C++ Template Library (WRL), so we can manage the lifetime of those variables in an exception safe manner. Podemos usar esas variables para acceder a la clase ComPtr y a sus miembros.We can then use those variables to access the ComPtr class and its members. Por ejemplo:For example:

    ComPtr<ID3D11RenderTargetView> m_renderTargetView;
    m_d3dDeviceContext->OMSetRenderTargets(
        1,
        m_renderTargetView.GetAddressOf(),
        nullptr // Use no depth stencil.
        );

Si declaras ID3D11RenderTargetView con ComPtr, luego puedes usar el método GetAddressOf de ComPtr para obtener la dirección del puntero a ID3D11RenderTargetView (**ID3D11RenderTargetView) y pasar a ID3D11DeviceContext::OMSetRenderTargets.If you declare ID3D11RenderTargetView with ComPtr, you can then use ComPtr’s GetAddressOf method to get the address of the pointer to ID3D11RenderTargetView (**ID3D11RenderTargetView) to pass to ID3D11DeviceContext::OMSetRenderTargets. OMSetRenderTargets enlaza el destino de representación con la fase de combinación de salida para especificar el destino de representación como el destino de salida.OMSetRenderTargets binds the render target to the output-merger stage to specify the render target as the output target.

La aplicación de muestra primero se inicia, luego se inicializa y se carga, y luego está lista para ejecutarse.After the sample app is started, it initializes and loads, and is then ready to run.

2. Crear el dispositivo Direct3D2. Creating the Direct3D device

Para usar la API de Direct3D para representar una escena, primero debemos crear un dispositivo Direct3D que represente el adaptador de pantalla.To use the Direct3D API to render a scene, we must first create a Direct3D device that represents the display adapter. Para crear el dispositivo Direct3D, llamamos a la función D3D11CreateDevice.To create the Direct3D device, we call the D3D11CreateDevice function. Especificamos los niveles del 9.1 al 11.1 de la matriz de valores D3D_FEATURE_LEVEL.We specify levels 9.1 through 11.1 in the array of D3D_FEATURE_LEVEL values. Direct3D recorre la matriz en orden y devuelve el nivel de características más alto compatible.Direct3D walks the array in order and returns the highest supported feature level. Entonces, para obtener el nivel de características más alto, enumeramos las entradas de la matriz D3D_FEATURE_LEVEL en orden descendente.So, to get the highest feature level available, we list the D3D_FEATURE_LEVEL array entries from highest to lowest. Pasamos la marca D3D11_CREATE_DEVICE_BGRA_SUPPORT al parámetro Flags para que los recursos de Direct3D interoperen con Direct2D.We pass the D3D11_CREATE_DEVICE_BGRA_SUPPORT flag to the Flags parameter to make Direct3D resources interoperate with Direct2D. Si usamos la versión de depuración, también pasamos la marca D3D11_CREATE_DEVICE_DEBUG.If we use the debug build, we also pass the D3D11_CREATE_DEVICE_DEBUG flag. Para obtener más información acerca de la depuración de aplicaciones, consulta el tema sobre cómo usar la capa de depuración para depurar aplicaciones.For more info about debugging apps, see Using the debug layer to debug apps.

Obtenemos el dispositivo Direct3D 11.1 (ID3D11Device1) y el contexto de dispositivo (ID3D11DeviceContext1) consultando el dispositivo Direct3D 11 y su contexto devueltos en D3D11CreateDevice.We obtain the Direct3D 11.1 device (ID3D11Device1) and device context (ID3D11DeviceContext1) by querying the Direct3D 11 device and device context that are returned from D3D11CreateDevice.

        // First, create the Direct3D device.

        // This flag is required in order to enable compatibility with Direct2D.
        UINT creationFlags = D3D11_CREATE_DEVICE_BGRA_SUPPORT;

#if defined(_DEBUG)
        // 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 ordering of feature levels that D3D should attempt to create.
        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_1
        };

        ComPtr<ID3D11Device> d3dDevice;
        ComPtr<ID3D11DeviceContext> d3dDeviceContext;
        DX::ThrowIfFailed(
            D3D11CreateDevice(
                nullptr,                    // Specify nullptr to use the default adapter.
                D3D_DRIVER_TYPE_HARDWARE,
                nullptr,                    // leave as nullptr if hardware is used
                creationFlags,              // optionally set debug and Direct2D compatibility flags
                featureLevels,
                ARRAYSIZE(featureLevels),
                D3D11_SDK_VERSION,          // always set this to D3D11_SDK_VERSION
                &d3dDevice,
                nullptr,
                &d3dDeviceContext
                )
            );

        // Retrieve the Direct3D 11.1 interfaces.
        DX::ThrowIfFailed(
            d3dDevice.As(&m_d3dDevice)
            );

        DX::ThrowIfFailed(
            d3dDeviceContext.As(&m_d3dDeviceContext)
            );

3. Crear la cadena de intercambio3. Creating the swap chain

A continuación, creamos una cadena de intercambio que el dispositivo usa para representar y mostrar en pantalla.Next, we create a swap chain that the device uses for rendering and display. Declaramos e inicializamos una estructura DXGI_SWAP_CHAIN_DESC1 para describir la cadena de intercambio.We declare and initialize a DXGI_SWAP_CHAIN_DESC1 structure to describe the swap chain. A continuación, configuramos la cadena de intercambio como modelo flip (es decir, una cadena de intercambio con el valor DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL establecido en el miembro SwapEffect) y establecemos el miembro Format en DXGI_FORMAT_B8G8R8A8_UNORM.Then, we set up the swap chain as flip-model (that is, a swap chain that has the DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL value set in the SwapEffect member) and set the Format member to DXGI_FORMAT_B8G8R8A8_UNORM. Establecemos el miembro Count de la estructura DXGI_SAMPLE_DESC que el miembro SampleDesc especifica en 1 y el miembro Quality de DXGI_SAMPLE_DESC en cero, porque el modelo flip no es compatible con el suavizado de contorno de varias muestras (MSAA).We set the Count member of the DXGI_SAMPLE_DESC structure that the SampleDesc member specifies to 1 and the Quality member of DXGI_SAMPLE_DESC to zero because flip-model doesn’t support multiple sample antialiasing (MSAA). Establecemos el miembro BufferCount en 2, de modo tal que la cadena de intercambio pueda usar un búfer frontal para presentar el dispositivo de pantalla y un búfer de reserva como el destino de representación.We set the BufferCount member to 2 so the swap chain can use a front buffer to present to the display device and a back buffer that serves as the render target.

Obtenemos el dispositivo DXGI subyacente consultando el dispositivo Direct3D 11.1.We obtain the underlying DXGI device by querying the Direct3D 11.1 device. Para reducir el consumo de energía; lo cual es muy importante en el caso de dispositivos a batería, como equipos portátiles y tabletas, llamamos al método IDXGIDevice1::SetMaximumFrameLatency con 1 como el número máximo de fotogramas del búfer de reserva que DXGI puede consultar.To minimize power consumption, which is important to do on battery-powered devices such as laptops and tablets, we call the IDXGIDevice1::SetMaximumFrameLatency method with 1 as the maximum number of back buffer frames that DXGI can queue. Esto asegura que la aplicación se represente solo después del espacio en blanco vertical.This ensures that the app is rendered only after the vertical blank.

Para crear finalmente la cadena de intercambio, necesitamos obtener la fábrica primaria del dispositivo DXGI.To finally create the swap chain, we need to get the parent factory from the DXGI device. Llamamos a IDXGIDevice::GetAdapter para obtener el adaptador del dispositivo y, a continuación, llamamos a IDXGIObject::GetParent en el adaptador para obtener la fábrica primaria (IDXGIFactory2).We call IDXGIDevice::GetAdapter to get the adapter for the device, and then call IDXGIObject::GetParent on the adapter to get the parent factory (IDXGIFactory2). Para crear la cadena de intercambio, llamamos a IDXGIFactory2::CreateSwapChainForCoreWindow con el descriptor de cadena de intercambio y la ventana principal de la aplicación.To create the swap chain, we call IDXGIFactory2::CreateSwapChainForCoreWindow with the swap-chain descriptor and the app’s core window.

            // If the swap chain does not exist, create it.
            DXGI_SWAP_CHAIN_DESC1 swapChainDesc = {0};

            swapChainDesc.Stereo = false;
            swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
            swapChainDesc.Scaling = DXGI_SCALING_NONE;
            swapChainDesc.Flags = 0;

            // Use automatic sizing.
            swapChainDesc.Width = 0;
            swapChainDesc.Height = 0;

            // This is the most common swap chain format.
            swapChainDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;

            // Don't use multi-sampling.
            swapChainDesc.SampleDesc.Count = 1;
            swapChainDesc.SampleDesc.Quality = 0;

            // Use two buffers to enable the flip effect.
            swapChainDesc.BufferCount = 2;

            // We recommend using this swap effect for all applications.
            swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_SEQUENTIAL;


            // Once the swap chain description is configured, it must be
            // created on the same adapter as the existing D3D Device.

            // First, retrieve the underlying DXGI Device from the D3D Device.
            ComPtr<IDXGIDevice2> dxgiDevice;
            DX::ThrowIfFailed(
                m_d3dDevice.As(&dxgiDevice)
                );

            // 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)
                );

            // Next, get the parent factory from the DXGI Device.
            ComPtr<IDXGIAdapter> dxgiAdapter;
            DX::ThrowIfFailed(
                dxgiDevice->GetAdapter(&dxgiAdapter)
                );

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

            // Finally, create the swap chain.
            CoreWindow^ window = m_window.Get();
            DX::ThrowIfFailed(
                dxgiFactory->CreateSwapChainForCoreWindow(
                    m_d3dDevice.Get(),
                    reinterpret_cast<IUnknown*>(window),
                    &swapChainDesc,
                    nullptr, // Allow on all displays.
                    &m_swapChain
                    )
                );

4. Crear la vista del destino de representación4. Creating the render-target view

Para representar gráficos en la ventana, necesitamos crear una vista del destino de representación.To render graphics to the window, we need to create a render-target view. Llamamos a IDXGISwapChain::GetBuffer para obtener el búfer de reserva de la cadena de intercambio, al cual necesitaremos usar cuando creemos la vista del destino de representación.We call IDXGISwapChain::GetBuffer to get the swap chain’s back buffer to use when we create the render-target view. Especificamos el búfer de reserva como una textura 2D (ID3D11Texture2D).We specify the back buffer as a 2D texture (ID3D11Texture2D). Para crear la vista del destino de representación, llamamos a ID3D11Device::CreateRenderTargetView con el búfer de reserva de la cadena de intercambio.To create the render-target view, we call ID3D11Device::CreateRenderTargetView with the swap chain’s back buffer. Debemos especificar dibujar en toda la ventana principal determinando la ventanilla (D3D11_VIEWPORT) como el tamaño completo del búfer de reserva de la cadena de intercambio.We must specify to draw to the entire core window by specifying the view port (D3D11_VIEWPORT) as the full size of the swap chain's back buffer. Usamos la ventanilla en una llamada a ID3D11DeviceContext::RSSetViewports para enlazar la ventanilla a la fase de rasterización de la canalización.We use the view port in a call to ID3D11DeviceContext::RSSetViewports to bind the view port to the rasterizer stage of the pipeline. La fase de rasterización convierte la información de vector en una imagen rasterizada.The rasterizer stage converts vector information into a raster image. En este caso, no necesitamos la conversión porque solo estamos mostrando color sólido.In this case, we don't require a conversion because we are just displaying a solid color.

        // Once the swap chain is created, create a render target view.  This will
        // allow Direct3D to render graphics to the window.

        ComPtr<ID3D11Texture2D> backBuffer;
        DX::ThrowIfFailed(
            m_swapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer))
            );

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


        // After the render target view is created, specify that the viewport,
        // which describes what portion of the window to draw to, should cover
        // the entire window.

        D3D11_TEXTURE2D_DESC backBufferDesc = {0};
        backBuffer->GetDesc(&backBufferDesc);

        D3D11_VIEWPORT viewport;
        viewport.TopLeftX = 0.0f;
        viewport.TopLeftY = 0.0f;
        viewport.Width = static_cast<float>(backBufferDesc.Width);
        viewport.Height = static_cast<float>(backBufferDesc.Height);
        viewport.MinDepth = D3D11_MIN_DEPTH;
        viewport.MaxDepth = D3D11_MAX_DEPTH;

        m_d3dDeviceContext->RSSetViewports(1, &viewport);

5. Mostrar la imagen representada5. Presenting the rendered image

Entramos en un bucle sin fin para representar y mostrar continuamente la escena.We enter an endless loop to continually render and display the scene.

En este bucle, llamamos a:In this loop, we call:

  1. ID3D11DeviceContext::OMSetRenderTargets para especificar el destino de representación como el destino de salida.ID3D11DeviceContext::OMSetRenderTargets to specify the render target as the output target.
  2. ID3D11DeviceContext::ClearRenderTargetView para borrar el destino representado en un color sólido.ID3D11DeviceContext::ClearRenderTargetView to clear the render target to a solid color.
  3. IDXGISwapChain::Present para mostrar la imagen representada en la ventana.IDXGISwapChain::Present to present the rendered image to the window.

Como antes habíamos establecido la latencia de fotogramas en 1, Windows, por lo general, disminuye la velocidad del bucle de representación a la velocidad de actualización de pantalla, que es normalmente alrededor de 60 Hz.Because we previously set the maximum frame latency to 1, Windows generally slows down the render loop to the screen refresh rate, typically around 60 Hz. Windows disminuye el bucle sin fin poniendo a la aplicación en modo de suspensión cuando llama a Present.Windows slows down the render loop by making the app sleep when the app calls Present. Windows pone a la aplicación en modo de suspensión hasta que se actualiza la pantalla.Windows makes the app sleep until the screen is refreshed.

        // Enter the render loop.  Note that UWP apps should never exit.
        while (true)
        {
            // Process events incoming to the window.
            m_window->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent);

            // Specify the render target we created as the output target.
            m_d3dDeviceContext->OMSetRenderTargets(
                1,
                m_renderTargetView.GetAddressOf(),
                nullptr // Use no depth stencil.
                );

            // Clear the render target to a solid color.
            const float clearColor[4] = { 0.071f, 0.04f, 0.561f, 1.0f };
            m_d3dDeviceContext->ClearRenderTargetView(
                m_renderTargetView.Get(),
                clearColor
                );

            // Present the rendered image to the window.  Because the maximum frame latency is set to 1,
            // the render loop will generally be throttled to the screen refresh rate, typically around
            // 60 Hz, by sleeping the application on Present until the screen is refreshed.
            DX::ThrowIfFailed(
                m_swapChain->Present(1, 0)
                );
        }

6. Cambiar el tamaño de la ventana de la aplicación y el búfer de la cadena de intercambio6. Resizing the app window and the swap chain’s buffer

Si el tamaño de la ventana de la aplicación cambia, la aplicación debe cambiar el tamaño de los búferes de la cadena de intercambio, recrear la vista del destino de representación y luego mostrar la imagen representada en el nuevo tamaño.If the size of the app window changes, the app must resize the swap chain’s buffers, recreate the render-target view, and then present the resized rendered image. Para cambiar el tamaño de los búferes de la cadena de intercambio, llamamos a IDXGISwapChain::ResizeBuffers.To resize the swap chain’s buffers, we call IDXGISwapChain::ResizeBuffers. En esta llamada, dejamos la cantidad y el formato de los búferes sin modificar (el parámetro BufferCount en dos y el parámetro NewFormat en DXGI_FORMAT_B8G8R8A8_UNORM).In this call, we leave the number of buffers and the format of the buffers unchanged (the BufferCount parameter to two and the NewFormat parameter to DXGI_FORMAT_B8G8R8A8_UNORM). Hacemos que el tamaño del búfer de reserva de la cadena de intercambio sea el mismo que el de la ventana modificada.We make the size of the swap chain’s back buffer the same size as the resized window. Después de cambiar el tamaño de los búferes de la cadena de intercambio, creamos el nuevo destino de representación y mostramos la nueva imagen representada de forma similar a cuando inicializamos la aplicación.After we resize the swap chain’s buffers, we create the new render target and present the new rendered image similarly to when we initialized the app.

            // If the swap chain already exists, resize it.
            DX::ThrowIfFailed(
                m_swapChain->ResizeBuffers(
                    2,
                    0,
                    0,
                    DXGI_FORMAT_B8G8R8A8_UNORM,
                    0
                    )
                );

Resumen y pasos siguientesSummary and next steps

Hemos creado un dispositivo Direct3D, una cadena de intercambio y una vista de destino de representación, y mostramos la imagen representada en la pantalla.We created a Direct3D device, swap chain, and render-target view, and presented the rendered image to the display.

A continuación, también dibujaremos un triángulo en la pantalla.Next, we also draw a triangle on the display.

Crear sombreadores y dibujar primitivosCreating shaders and drawing primitives