DirectX записывает данные резервного буфера в файл

Я пытаюсь преобразовать каждый кадр моей программы DirectX в YUV (для кодирования видео). Поэтому мне сначала нужны значения RGB (A) каждого пикселя в каждом кадре. Мне нужно получить их из бэкбуфера.

Поскольку в DirectX нет glReadPixels, я делаю следующее:

  1. Получить указатель на renderTargetView обратного буфера и получить ресурс обратного буфера
  2. Транслировать этот ресурс на ID3D10Texture2D
  3. Создайте промежуточную текстуру и CopyResource texture2D из предыдущего шага.

На этом этапе я могу использовать D3DX10SaveTextureToFile, и эта промежуточная текстура правильно сохранит задний буфер как изображение.

Однако я не хочу использовать диск в качестве обходного пути, я хочу сразу получить данные RGB, поэтому делаю следующее:

  1. Сопоставьте промежуточный ресурс
  2. Прочтите pData сопоставленной текстуры, чтобы получить значения RGB (A)

Проблема: значения RGB - мусор. Это пример для пикселя (1,1)

(1, 1) = (-170141183460469230000000000000000000000.000000, -170141183460469230000000000000000000000.000000, -170141183460469230000000000000000000000.000000)

Это особенно странно, потому что я использую тот же код для сопоставления другой промежуточной текстуры (из другой целевой рендеринга вне экрана), и этот код там отлично работает.

Это мой код:

// Get resource pointer to backbuffer
ID3D10Resource *backbufferRes;
m_D3D->GetRenderTargetView()->GetResource(&backbufferRes);

// Cast backbuffer resource to texture2D
ID3D10Texture2D* tempTexture = 0;
backbufferRes->QueryInterface(__uuidof(ID3D10Texture2D),(LPVOID*) &tempTexture);
backbufferRes->Release();

// Get the descriptor of this texture2D
D3D10_TEXTURE2D_DESC descDefault; 
tempTexture->GetDesc(&descDefault);

// Create a staging texture desc based on the texture of the backbuffer
D3D10_TEXTURE2D_DESC descStaging;
descStaging = descDefault;
descStaging.Usage = D3D10_USAGE_STAGING;
descStaging.CPUAccessFlags = D3D10_CPU_ACCESS_READ;  
descStaging.BindFlags = 0;

// Create the new empty staging texture
ID3D10Texture2D *texture = 0;
m_D3D->GetDevice()->CreateTexture2D( &descStaging, NULL, &texture);

// Copy the backbuffer texture data (tempTexture) to the staging texture (texture)
m_D3D->GetDevice()->CopyResource(texture, tempTexture);

// This call works perfectly, image is correct!
// D3DX10SaveTextureToFile(texture, D3DX10_IFF_BMP, L"D:\\img.bmp");

// We want to avoid disk access, so instead let's map the texture and read its RGB data
D3D10_MAPPED_TEXTURE2D mappedTexture;
hr = texture->Map(D3D10CalcSubresource(0, 0, 1), D3D10_MAP_READ, 0, &mappedTexture);
FLOAT* m_pBits = (FLOAT*) malloc(4 * descStaging.Width * descStaging.Height * sizeof(FLOAT));
if(!FAILED(hr)) {
    memcpy(m_pBits, mappedTexture.pData, 4 * descStaging.Width * descStaging.Height);
    texture->Unmap(D3D10CalcSubresource(0, 0, 1));
}
texture->Release();
tempTexture->Release();

fp = fopen("D:\\output.txt", "a");
for( UINT row = 0; row < descStaging.Height; row++ )
{
    UINT rowStart = row * mappedTexture.RowPitch / 4;
    for( UINT col = 0; col < descStaging.Width; col++ )
    {
        r = m_pBits[rowStart + col*4 + 0]; // Red (X)
        g = m_pBits[rowStart + col*4 + 1]; // Green (Y)
        b = m_pBits[rowStart + col*4 + 2]; // Blue (Z)
        a = m_pBits[rowStart + col*4 + 3]; // Alpha (W)

        // Save pixel values to disk
        fprintf(fp, "%d %d - %f %f %f\n",  col + 1, row + 1, r, g, b);
    }
}
fclose(fp);

Кто-нибудь знает, в чем может быть проблема? Любая помощь очень ценится.


person Glenn    schedule 10.03.2013    source источник
comment
Как насчет рендеринга вашего кадра в текстуру в качестве цели рендеринга и последующей обработки с помощью шейдера rgb в yuv? Это будет намного быстрее, чем ручное преобразование, из-за параллельных возможностей графического процессора.   -  person Gnietschow    schedule 10.03.2013
comment
Спасибо! На самом деле это отличная идея, попробую. Рендеринг в текстуру был альтернативой, которую я имел в виду (она решает проблему за счет еще одного прохода рендеринга), но мне все еще интересно, почему я получаю такие результаты.   -  person Glenn    schedule 11.03.2013
comment
Оно работало завораживающе. Спасибо еще раз!   -  person Glenn    schedule 11.03.2013


Ответы (1)


Старый вопрос, но я думаю, что это может быть проблемой:

После сопоставления текстуры с texture->Map() вы пытаетесь скопировать ее в m_pBits за один раз. Это не сработает, если RowPitch сопоставленной текстуры не совпадает с ее шириной (см. здесь).

Вместо этого вы должны скопировать изображение строка за строкой:

BYTE* source = static_cast<BYTE*>(mappedTexture.pData);
BYTE& dest = m_pBits;
for (int i = 0; i < IMAGE_HEIGHT; ++i) {
    memcpy(dest, source, IMAGE_WIDTH * 4); // for 4 bytes per pixel
    source += mappedTexture.RowPitch;
    dest += IMAGE_WIDTH * 4;
}
person errollw    schedule 01.04.2017