La façon dont je fais cela est la suivante.
IDirect3DDevice9 :: GetBackBuffer : Accédez à l'IDirect3DSurface9 représentant le tampon arrière, comme vous l'avez actuellement. N'oubliez pas de libérer cette surface une fois terminé car cet appel augmentera le nombre de références!
IDirect3DSurface :: GetDesc : Obtenez la description de la surface du tampon arrière, qui vous donnera sa largeur, sa hauteur et son format.
IDirect3DDevice9 :: CreateOffscreenPlainSurface : Créez un nouvel objet surface dans D3DPOOL_SCRATCH; vous voulez généralement utiliser la même largeur, la même hauteur et le même format (mais vous n'avez pas vraiment besoin de cette méthode). Encore une fois, relâchez lorsque vous avez terminé. Si vous effectuez cette opération à chaque image (dans ce cas, vous feriez mieux de chercher des alternatives telles qu'une approche basée sur des shaders pour ce que vous essayez de faire), vous pouvez simplement créer la surface lisse hors écran une fois au démarrage et réutiliser au lieu de le créer à chaque image.
D3DXLoadSurfaceFromSurface : Copie de la surface tampon arrière vers la surface lisse de l'écran. Cela fera automatiquement une conversion de redimensionnement et de formatage pour vous. Alternativement, si vous ne voulez pas ou ne devez pas redimensionner ou changer le format, vous pouvez utiliser IDirect3DDevice9 :: GetRenderTargetData , mais si c'est le cas, créez plutôt la surface unie hors écran dans D3DPOOL_SYSTEMMEM.
IDirect3DSurface9 :: LockRect : Accédez aux données dans la surface plate hors écran et ayez votre propre chemin mal avec elle; UnlockRect une fois terminé.
Cela ressemble à beaucoup plus de code, mais vous constaterez qu'il est tout aussi rapide que glReadPixels, et peut même être plus rapide si vous n'avez pas besoin de faire une conversion de format (ce que glReadPixels utilisant GL_RGB fait presque certainement).
Modifier pour ajouter: certaines fonctions d'assistance (rought 'n' ready) que j'ai également qui peuvent être utiles pour utiliser cette méthode pour les captures d'écran:
// 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);
}
}
}