Я делаю это следующим образом.
IDirect3DDevice9 :: GetBackBuffer : Получить доступ к IDirect3DSurface9, представляющему задний буфер, так же, как вы в настоящее время получили. Не забудьте освободить эту поверхность после завершения, так как этот вызов увеличит счетчик ссылок!
IDirect3DSurface :: GetDesc : Получить описание задней поверхности буфера, которая даст вам ее ширину, высоту и формат.
IDirect3DDevice9 :: CreateOffscreenPlainSurface : создать новый объект поверхности в D3DPOOL_SCRATCH; Вы обычно хотите использовать одинаковую ширину, высоту и формат (но на самом деле это не обязательно). Снова отпустите, когда закончите. Если вы выполняете эту операцию каждый кадр (в этом случае вам лучше смотреть на альтернативы, такие как шейдерный подход к тому, что вы пытаетесь сделать), вы можете просто создать закадровую плоскую поверхность один раз при запуске и повторно использовать это, вместо того, чтобы создавать его каждый кадр.
D3DXLoadSurfaceFromSurface : Копировать с задней поверхности буфера на невидимую плоскую поверхность. Это сделает изменение размера и форматирование автоматически для вас. В качестве альтернативы, если вы не хотите или не хотите изменять размер или изменять формат, вы можете использовать IDirect3DDevice9 :: GetRenderTargetData , но если это так, то вместо этого создайте плоскую поверхность вне экрана в D3DPOOL_SYSTEMMEM.
IDirect3DSurface9 :: LockRect : получите доступ к данным на простой экранной поверхности и используйте свой собственный злой путь; UnlockRect, когда закончите.
Это выглядит как гораздо больше кода, но вы обнаружите, что он такой же быстрый, как glReadPixels, и может быть даже быстрее, если вам не нужно выполнять преобразование формата (что почти наверняка делает glReadPixels, использующий GL_RGB).
Редактировать, чтобы добавить: некоторые (готовые и готовые) вспомогательные функции, которые у меня также есть, которые могут быть полезны для использования этого метода для снимков экрана:
// assumes pitch is measured in 32-bit texels, not bytes; use locked_rect.Pitch >> 2
void CollapseRowPitch (unsigned *data, int width, int height, int pitch)
{
if (width != pitch)
{
unsigned *out = data;
// as a minor optimization we can skip the first row
// since out and data point to the same this is OK
out += width;
data += pitch;
for (int h = 1; h < height; h++)
{
for (int w = 0; w < width; w++)
out[w] = data[w];
out += width;
data += pitch;
}
}
}
void Compress32To24 (byte *data, int width, int height)
{
byte *out = data;
for (int h = 0; h < height; h++)
{
for (int w = 0; w < width; w++, data += 4, out += 3)
{
out[0] = data[0];
out[1] = data[1];
out[2] = data[2];
}
}
}
// bpp is bits, not bytes
void WriteDataToTGA (char *name, void *data, int width, int height, int bpp)
{
if ((bpp == 24 || bpp == 8) && name && data && width > 0 && height > 0)
{
FILE *f = fopen (name, "wb");
if (f)
{
byte header[18];
memset (header, 0, 18);
header[2] = 2;
header[12] = width & 255;
header[13] = width >> 8;
header[14] = height & 255;
header[15] = height >> 8;
header[16] = bpp;
header[17] = 0x20;
fwrite (header, 18, 1, f);
fwrite (data, (width * height * bpp) >> 3, 1, f);
fclose (f);
}
}
}