2013-03-10 2 views
2

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

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

  1. Получить указатель на renderTargetView в BackBuffer и получайте BackBuffer ресурсу
  2. Cast этот ресурс 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); 

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

+2

Как насчет рендеринга кадра в текстуру как RenderTarget и постобработки его с RGB в YUV шейдер? Это было бы намного быстрее, чем ручное преобразование из-за параллельных возможностей gpu. – Gnietschow

+0

Спасибо! На самом деле это отличная идея, я попробую. Рендеринг текстуры был альтернативой, которую я имел в виду (она исправляет проблему за счет другого прохода визуализации), но мне все еще интересно, почему я получаю эти результаты. – Glenn

+1

Он работал как шарм. Еще раз спасибо! – Glenn

ответ

1

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

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

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

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; 
} 
Смежные вопросы