Je sais que dans OpenGL je peux faire quelque chose comme ça
glReadBuffer( GL_FRONT );
glReadPixels( 0, 0, _width, _height, GL_RGB, GL_UNSIGNED_BYTE, _buffer );
Et c'est assez rapide, j'obtiens le bitmap brut dans _buffer. Lorsque j'essaie de le faire dans DirectX. En supposant que j'ai un objet D3DDevice, je peux faire quelque chose comme ça
if (SUCCEEDED(D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &pBackbuffer))) {
HResult hr = D3DXSaveSurfaceToFileA(filename, D3DXIFF_BMP, pBackbuffer, NULL, NULL);
Mais D3DXSaveSurfaceToFile est assez lent, et je n'ai pas besoin d'écrire la capture sur le disque de toute façon, donc je me demandais s'il y avait un moyen plus rapide de le faire.
EDIT: Je cible uniquement les applications DirectX. En fait, les applications DX9. Je fais cela à travers un crochet pour présenter. (J'utilise Detours si cela est pertinent), et je le fais pour chaque image. Je n'ai pas besoin (ou ne veux pas) d'un format bitmap particulier comme BMP PNG JPEG, etc., et un espace colorimétrique de RGB24 est OK. L'obtenir en tant que YUV480p serait mieux mais certainement pas nécessaire. Merci à tous pour les réponses très utiles
la source
Réponses:
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:
la source
Je crois que vous devez LockRectangle sur le pBackBuffer puis lire les pixels de D3DLOCKED_RECT.pBits . Cela devrait être assez rapide. Si vous avez besoin de lire seulement quelques pixels, envisagez de copier tout le backbuffer dans un tampon plus petit via quelque chose comme DX11 CopySubresourceRegion (je suis sûr qu'il existe également une alternative dans DX9), ce qui se fait sur le GPU, puis diffusez ce petit tampon du GPU vers CPU via LockRectangle - vous enregistrez le transfert de gros backbuffer sur le bus.
la source
Vous ne pouvez pas capturer d'écran avec GetBackbuffer, cette fonction obtient uniquement un pointeur du tampon arrière, pas les données.
La bonne façon de penser est comme ci-dessous
la source
Un peu tard. Mais j'espère que cela aide quelqu'un.
création
capturer
Dans buf, vous aurez des données d'image brutes. N'oubliez pas de tout libérer.
la source