Uso de recursos dinámicos

API importantes

Crea y usa recursos dinámicos cuando la aplicación necesita cambiar los datos de esos recursos. Puede crear texturas y búferes para su uso dinámico.

Lo que necesita saber

Tecnologías

Requisitos previos

Suponemos que estás familiarizado con C++. También necesitas tener experiencia básica en los conceptos de programación de elementos gráficos.

Instrucciones

Paso 1: Especificar el uso dinámico

Si quieres que la aplicación pueda realizar cambios en los recursos, debes especificar esos recursos como dinámicos y grabables al crearlos.

Para especificar el uso dinámico

  1. Especifique el uso de recursos como dinámico. Por ejemplo, especifique el valor D3D11_USAGE_DYNAMIC en el miembro Usage de D3D11_BUFFER_DESC para un búfer de vértices o constantes y especifique el valor D3D11_USAGE_DYNAMIC en el miembro Usage de D3D11_TEXTURE2D_DESC para una textura 2D.
  2. Especifique el recurso como grabable. Por ejemplo, especifique el valor D3D11_CPU_ACCESS_WRITE en el miembro CPUAccessFlags de D3D11_BUFFER_DESC o D3D11_TEXTURE2D_DESC.
  3. Pase la descripción del recurso a la función de creación. Por ejemplo, pase la dirección de D3D11_BUFFER_DESC a ID3D11Device::CreateBuffer y pase la dirección de D3D11_TEXTURE2D_DESC a ID3D11Device::CreateTexture2D.

Este es un ejemplo de creación de un búfer de vértices dinámico:

    // Create a vertex buffer for a triangle.

    float2 triangleVertices[] =
    {
        float2(-0.5f, -0.5f),
        float2(0.0f, 0.5f),
        float2(0.5f, -0.5f),
    };

    D3D11_BUFFER_DESC vertexBufferDesc = { 0 };
    vertexBufferDesc.ByteWidth = sizeof(float2)* ARRAYSIZE(triangleVertices);
    vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    vertexBufferDesc.MiscFlags = 0;
    vertexBufferDesc.StructureByteStride = 0;

    D3D11_SUBRESOURCE_DATA vertexBufferData;
    vertexBufferData.pSysMem = triangleVertices;
    vertexBufferData.SysMemPitch = 0;
    vertexBufferData.SysMemSlicePitch = 0;

    DX::ThrowIfFailed(
        m_d3dDevice->CreateBuffer(
        &vertexBufferDesc,
        &vertexBufferData,
        &vertexBuffer2
        )
        );

Paso 2: Cambiar un recurso dinámico

Si especificó un recurso como dinámico y grabable al crearlo, más adelante puede realizar cambios en ese recurso.

Para cambiar los datos de un recurso dinámico

  1. Configure los nuevos datos del recurso. Declare una variable de tipo D3D11_MAPPED_SUBRESOURCE e inicialícela en cero. Usará esta variable para cambiar el recurso.
  2. Deshabilite el acceso de la unidad de procesamiento gráfico (GPU) a los datos que desea cambiar y obtenga un puntero a la memoria que contiene los datos. Para obtener este puntero, pase D3D11_MAP_WRITE_DISCARD al parámetro MapType cuando llame a ID3D11DeviceContext::Map. Establezca este puntero en la dirección de la variable D3D11_MAPPED_SUBRESOURCE del paso anterior.
  3. Escriba los nuevos datos en la memoria.
  4. Llame a ID3D11DeviceContext::Unmap para volver a habilitar el acceso de GPU a los datos cuando haya terminado de escribir los nuevos datos.

Este es un ejemplo de cambio de un búfer de vértices dinámico:

// This might get called as the result of a click event to double the size of the triangle.
void TriangleRenderer::MapDoubleVertices()
{
    D3D11_MAPPED_SUBRESOURCE mappedResource;
    ZeroMemory(&mappedResource, sizeof(D3D11_MAPPED_SUBRESOURCE));
    float2 vertices[] =
    {
        float2(-1.0f, -1.0f),
        float2(0.0f, 1.0f),
        float2(1.0f, -1.0f),
    };
    //  Disable GPU access to the vertex buffer data.
    auto m_d3dContext = m_deviceResources->GetD3DDeviceContext();
    m_d3dContext->Map(vertexBuffer2.Get(), 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
    //  Update the vertex buffer here.
    memcpy(mappedResource.pData, vertices, sizeof(vertices));
    //  Reenable GPU access to the vertex buffer data.
    m_d3dContext->Unmap(vertexBuffer2.Get(), 0);
}

Observaciones

Uso de texturas dinámicas

Se recomienda crear solo una textura dinámica por formato y posiblemente por tamaño. No se recomienda crear mapas MIP dinámicos, cubos y volúmenes debido a la sobrecarga adicional en la asignación de cada nivel. En el caso de los mapas MIP, puede especificar D3D11_MAP_WRITE_DISCARD solo en el nivel superior. Todos los niveles se descartan mediante la asignación solo del nivel superior. Este comportamiento es el mismo para volúmenes y cubos. En el caso de los cubos, se asignan el nivel superior y la cara 0.

Uso de búferes dinámicos

Cuando se llama a Map en un búfer de vértices estático mientras la GPU usa el búfer, se obtiene una penalización significativa del rendimiento. En esta situación, Map debe esperar hasta que la GPU termine de leer los datos de vértices o índices del búfer antes de que Map pueda volver a la aplicación que realiza la llamada, lo que provoca un retraso significativo. Llamar a Map y, a continuación, representar desde un búfer estático varias veces por fotograma también impide que la GPU almacene en búfer los comandos de representación porque debe finalizar los comandos antes de devolver el puntero de mapa. Sin comandos almacenados en búfer, la GPU permanece inactiva hasta que la aplicación haya terminado de rellenar el búfer de vértices o el búfer de índice y emite un comando de representación.

Lo ideal es que los datos de vértices o índices nunca cambien, pero esto no siempre es posible. Hay muchas situaciones en las que la aplicación necesita cambiar los datos de vértices o índices de cada fotograma, quizás incluso varias veces por fotograma. En estas situaciones, se recomienda crear el búfer de vértices o índices con D3D11_USAGE_DYNAMIC. Esta marca de uso hace que el tiempo de ejecución se optimice para las operaciones de asignación frecuentes. D3D11_USAGE_DYNAMIC solo es útil cuando el búfer se asigna con frecuencia; Si los datos deben permanecer constantes, colóquelos en un búfer estático de vértices o índices.

Para recibir una mejora del rendimiento al usar búferes de vértices dinámicos, la aplicación debe llamar a Map con los valores de D3D11_MAP adecuados. D3D11_MAP_WRITE_DISCARD indica que la aplicación no necesita mantener los datos antiguos de vértices o índices en el búfer. Si la GPU sigue usando el búfer al llamar a Map con D3D11_MAP_WRITE_DISCARD, el tiempo de ejecución devuelve un puntero a una nueva región de memoria en lugar de los datos antiguos del búfer. Esto permite que la GPU siga usando los datos antiguos mientras la aplicación coloca los datos en el nuevo búfer. No se requiere ninguna administración de memoria adicional en la aplicación; el búfer antiguo se reutiliza o se destruye automáticamente cuando la GPU finaliza con él.

Nota

Al asignar un búfer con D3D11_MAP_WRITE_DISCARD, el tiempo de ejecución siempre descarta todo el búfer. No se puede conservar la información en áreas no asignadas del búfer especificando un campo de tamaño limitado o desplazamiento distinto de cero.

 

Hay casos en los que la cantidad de datos que la aplicación necesita almacenar por mapa es pequeña, como agregar cuatro vértices para representar un sprite. D3D11_MAP_WRITE_NO_OVERWRITE indica que la aplicación no sobrescribirá los datos que ya están en uso en el búfer dinámico. La llamada a Map devolverá un puntero a los datos antiguos, lo que permitirá a la aplicación agregar nuevos datos en regiones sin usar del búfer de vértices o índices. La aplicación no debe modificar los vértices ni los índices que se usan en una operación de dibujo, ya que podrían estar en uso por la GPU. Se recomienda que la aplicación use D3D11_MAP_WRITE_DISCARD después de que el búfer dinámico esté lleno para recibir una nueva región de memoria, que descarta los datos antiguos de vértices o índices una vez finalizada la GPU.

El mecanismo de consulta asincrónico es útil para determinar si los vértices todavía están en uso por la GPU. Emita una consulta de tipo D3D11_QUERY_EVENT después de la última llamada a draw que usa los vértices. Los vértices ya no se usan cuando ID3D11DeviceContext::GetData devuelve S_OK. Al asignar un búfer con D3D11_MAP_WRITE_DISCARD o sin valores de mapa, siempre se garantiza que los vértices se sincronizan correctamente con la GPU. Sin embargo, al asignar sin valores de mapa, incurrirá en la penalización de rendimiento descrita anteriormente.

Nota

El entorno de ejecución de Direct3D 11.1, que está disponible a partir de Windows 8, permite asignar búferes de constantes dinámicas y vistas de recursos de sombreador (SRV) de búferes dinámicos con D3D11_MAP_WRITE_NO_OVERWRITE. Los entornos de ejecución direct3D 11 y anteriores limitaron la asignación de actualizaciones parciales sin sobrescritura a búferes de vértices o índices. Para determinar si un dispositivo Direct3D admite estas características, llame a ID3D11Device::CheckFeatureSupport con D3D11_FEATURE_D3D11_OPTIONS. CheckFeatureSupport rellena los miembros de una estructura de D3D11_FEATURE_DATA_D3D11_OPTIONS con las características del dispositivo. Los miembros pertinentes aquí son MapNoOverwriteOnDynamicConstantBuffer y MapNoOverwriteOnDynamicBufferSRV.

 

Cómo usar Direct3D 11