Pregunta

Necesito averiguar cómo obtener los datos de D3D texturas y superficies de vuelta a la memoria del sistema.¿Cuál es la manera más rápida de hacer las cosas tal y cómo?

También si sólo necesito una subrect, ¿cómo se puede leer únicamente la parte sin tener que leer toda la cosa a la memoria del sistema?

En breve estoy buscando descripciones concisas de cómo copiar el siguiente la memoria del sistema:

  1. un la textura
  2. un subconjunto de un la textura
  3. un superficie
  4. un subconjunto de un superficie
  5. un D3DUSAGE_RENDERTARGET textura
  6. un subconjunto de un D3DUSAGE_RENDERTARGET textura

Este es Direct3D 9, pero las respuestas acerca de las versiones más recientes de D3D se agradecería demasiado.

¿Fue útil?

Solución

La mayoría de los implicados parte es la lectura de algunos de superficie que está en la memoria de video ("grupo predeterminado").Esto es más a menudo render targets.

Vamos a conseguir que las partes fáciles primero:

  1. la lectura de una textura es la misma que la lectura de 0 a nivel de superficie de esa textura.Ver a continuación.
  2. la misma para el subconjunto de una textura.
  3. la lectura de una superficie que está en la no-memoria predeterminada de la piscina ("sistema" o "administrado") es sólo que el bloqueo y la lectura de bytes.
  4. la misma para el subconjunto de la superficie.Simplemente bloquear pertinentes de la parte y la leyó.

Así que ahora que hemos dejado en las superficies que están en la memoria de video ("grupo predeterminado").Esto sería cualquier superficie/textura marcado como destino de representación, o cualquier superficie/textura que has creado en defecto de la piscina, o el backbuffer sí mismo.La parte compleja de aquí es que usted no puede bloquear.

Respuesta corta es: GetRenderTargetData método en D3D device.

Respuesta larga (un esbozo del código que será a continuación):

  1. rt = get destino de representación de la superficie (esto puede ser la superficie de la textura, o backbuffer, etc.)
  2. si rt es multisampled (GetDesc, compruebe D3DSURFACE_DESC.MultiSampleType), entonces:a) crear otro destino de representación de la superficie del mismo tamaño, el mismo formato pero sin multisampling;b) StretchRect de rt en esta nueva superficie;c) rt = esta nueva superficie (es decir,proceder en esta nueva superficie).
  3. off = crear fuera de la pantalla superficie plana (CreateOffscreenPlainSurface, D3DPOOL_SYSTEMMEM de la piscina)
  4. dispositivo->GetRenderTargetData( rt, off )
  5. ahora off contiene procesamiento de datos de destino.LockRect(), lectura de datos, UnlockRect() sobre él.
  6. limpieza

Incluso la respuesta larga (pegar en el código fuente en el que estoy trabajando) de la siguiente manera.Este no compilar fuera de la caja, porque utiliza algunas clases, funciones, macros y las utilidades del resto de codebase;pero se debe empezar.También he omitido la mayoría de comprobación de error (por ejemplo,si dada la anchura/altura está fuera de los límites).Yo también omite la parte en la que se lee píxeles reales y, posiblemente, los convierte en el destino adecuado de formato (que es muy fácil, pero puede conseguir mucho, dependiendo del número de conversiones de formato que desee de apoyo).

bool GfxDeviceD3D9::ReadbackImage( /* params */ )
{
    HRESULT hr;
    IDirect3DDevice9* dev = GetD3DDevice();
    SurfacePointer renderTarget;
    hr = dev->GetRenderTarget( 0, &renderTarget );
    if( !renderTarget || FAILED(hr) )
        return false;

    D3DSURFACE_DESC rtDesc;
    renderTarget->GetDesc( &rtDesc );

    SurfacePointer resolvedSurface;
    if( rtDesc.MultiSampleType != D3DMULTISAMPLE_NONE )
    {
        hr = dev->CreateRenderTarget( rtDesc.Width, rtDesc.Height, rtDesc.Format, D3DMULTISAMPLE_NONE, 0, FALSE, &resolvedSurface, NULL );
        if( FAILED(hr) )
            return false;
        hr = dev->StretchRect( renderTarget, NULL, resolvedSurface, NULL, D3DTEXF_NONE );
        if( FAILED(hr) )
            return false;
        renderTarget = resolvedSurface;
    }

    SurfacePointer offscreenSurface;
    hr = dev->CreateOffscreenPlainSurface( rtDesc.Width, rtDesc.Height, rtDesc.Format, D3DPOOL_SYSTEMMEM, &offscreenSurface, NULL );
    if( FAILED(hr) )
        return false;

    hr = dev->GetRenderTargetData( renderTarget, offscreenSurface );
    bool ok = SUCCEEDED(hr);
    if( ok )
    {
        // Here we have data in offscreenSurface.
        D3DLOCKED_RECT lr;
        RECT rect;
        rect.left = 0;
        rect.right = rtDesc.Width;
        rect.top = 0;
        rect.bottom = rtDesc.Height;
        // Lock the surface to read pixels
        hr = offscreenSurface->LockRect( &lr, &rect, D3DLOCK_READONLY );
        if( SUCCEEDED(hr) )
        {
            // Pointer to data is lt.pBits, each row is
            // lr.Pitch bytes apart (often it is the same as width*bpp, but
            // can be larger if driver uses padding)

            // Read the data here!
            offscreenSurface->UnlockRect();
        }
        else
        {
            ok = false;
        }
    }

    return ok;
}

SurfacePointer en el código anterior es un puntero inteligente a un objeto COM (libera el objeto de cesión o destructor).Simplifica el manejo de errores mucho.Esto es muy similar a _comptr_t las cosas en Visual C++.

El código de arriba lee toda la superficie.Si quieres leer solo una parte de ella de manera eficiente, entonces creo que la forma más rápida es aproximadamente:

  1. crear un valor predeterminado superficie de la piscina que es de el tamaño requerido.
  2. StretchRect de parte de la superficie original para que uno más pequeño.
  3. continuar de forma normal con el más pequeño.

De hecho, esto es bastante similar a lo que el código anterior no hace manejar multi-muestreados superficies.Si desea obtener sólo una parte de un multi-muestreados de la superficie, se puede hacer una multisample resolver y obtener parte de él en un StretchRect, creo.

Editar:retira la pieza de código que hace la lectura real de los píxeles y las conversiones de formato.No estaba directamente relacionada a la pregunta, y el código fue largo.

Editar:actualizado para que coincida editado pregunta.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top