From: Toni Wilen Date: Sun, 24 Apr 2016 12:31:13 +0000 (+0300) Subject: Faster screenshot/avioutput capture in after filtering mode. X-Git-Tag: 3300~49 X-Git-Url: https://git.unchartedbackwaters.co.uk/w/?a=commitdiff_plain;h=0cf63a4bcc1f25c8416786991d4fba63b26c708c;p=francis%2Fwinuae.git Faster screenshot/avioutput capture in after filtering mode. --- diff --git a/od-win32/avioutput.cpp b/od-win32/avioutput.cpp index 76cbb80a..8676e41d 100644 --- a/od-win32/avioutput.cpp +++ b/od-win32/avioutput.cpp @@ -919,6 +919,57 @@ static void AVIOuput_WAVWriteAudio (uae_u8 *sndbuffer, int sndbufsize) fwrite (sndbuffer, 1, sndbufsize, wavfile); } +static int getFromRenderTarget(struct avientry *avie) +{ + int ok = 0; + int w, h, bits; + HRESULT hr; + D3DLOCKED_RECT l; + LPDIRECT3DSURFACE9 s = D3D_capture(&w, &h, &bits); + if (s) { + hr = s->LockRect(&l, NULL, D3DLOCK_READONLY); + if (SUCCEEDED(hr)) { + int dpitch = ((aviout_width_out * avioutput_bits + 31) & ~31) / 8; + if (bits == 32) { + for (int y = 0; y < h; y++) { + uae_u8 *d = (uae_u8*)avie->lpVideo + (h - y - 1) * dpitch; + uae_u32 *s = (uae_u32*)((uae_u8*)l.pBits + y * l.Pitch); + for (int x = 0; x < w; x++) { + uae_u32 v = *s++; + d[0] = v >> 0; + d[1] = v >> 8; + d[2] = v >> 16; + d += 3; + } + } + } else if (bits == 16 || bits == 15) { + for (int y = 0; y < h; y++) { + uae_u8 *d = (uae_u8*)avie->lpVideo + (h - y - 1) * dpitch; + uae_u16 *s = (uae_u16*)((uae_u8*)l.pBits + y * l.Pitch); + for (int x = 0; x < w; x++) { + uae_u16 v = s[x]; + uae_u16 v2 = v; + if (bits == 16) { + v2 = v & 31; + v2 |= ((v & (31 << 5)) << 1) | (((v >> 5) & 1) << 5); + v2 |= (v & (31 << 10)) << 1; + } else { + v2 = v & 31; + v2 |= (v >> 1) & (31 << 5); + v2 |= (v >> 1) & (31 << 10); + } + ((uae_u16*)d)[0] = v2; + d += 2; + } + } + } + s->UnlockRect(); + } + ok = 1; + } + return ok; +} + static int getFromDC (struct avientry *avie) { HDC hdc; @@ -1083,7 +1134,11 @@ void AVIOutput_WriteVideo (void) if (avioutput_originalsize || WIN32GFX_IsPicassoScreen ()) { v = getFromBuffer (ae, 1); } else { - v = getFromDC (ae); + if (D3D_isenabled()) { + v = getFromRenderTarget(ae); + } else { + v = getFromDC (ae); + } } if (v) queueavientry (ae); diff --git a/od-win32/direct3d.cpp b/od-win32/direct3d.cpp index 7ea2036e..b2fcbd06 100644 --- a/od-win32/direct3d.cpp +++ b/od-win32/direct3d.cpp @@ -2620,7 +2620,7 @@ static const TCHAR *D3D_init2 (HWND ahwnd, int w_w, int w_h, int depth, int *fre write_log (_T("%s: SetMaximumFrameLatency() failed: %s\n"), D3DHEAD, D3D_ErrorString (hr)); } - hr = d3ddev->CreateOffscreenPlainSurface(w_w, w_h, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &screenshotsurface, NULL); + hr = d3ddev->CreateOffscreenPlainSurface(w_w, w_h, tformat, D3DPOOL_SYSTEMMEM, &screenshotsurface, NULL); if (FAILED(hr)) { write_log(_T("%s: CreateOffscreenPlainSurface failed: %s\n"), D3DHEAD, D3D_ErrorString(hr)); } @@ -3470,6 +3470,31 @@ void D3D_guimode (bool guion) guimode = guion; } +LPDIRECT3DSURFACE9 D3D_capture(int *w, int *h, int *bits) +{ + LPDIRECT3DSURFACE9 rt; + HRESULT hr; + + waitfakemode(); + if (!isd3d()) + return NULL; + hr = d3ddev->GetRenderTarget(0, &rt); + if (FAILED(hr)) { + write_log(_T("%s: GetRenderTarget() failed: %s\n"), D3DHEAD, D3D_ErrorString(hr)); + return NULL; + } + hr = d3ddev->GetRenderTargetData(rt, screenshotsurface); + rt->Release(); + if (FAILED(hr)) { + write_log(_T("%s: GetRenderTargetData() failed: %s\n"), D3DHEAD, D3D_ErrorString(hr)); + return NULL; + } + *w = window_w; + *h = window_h; + *bits = t_depth; + return screenshotsurface; +} + HDC D3D_getDC (HDC hdc) { static LPDIRECT3DSURFACE9 bb; diff --git a/od-win32/direct3d.h b/od-win32/direct3d.h index 77a5555c..891189ba 100644 --- a/od-win32/direct3d.h +++ b/od-win32/direct3d.h @@ -22,6 +22,7 @@ extern double D3D_getrefreshrate (void); extern void D3D_vblank_reset (double freq); extern void D3D_restore (void); extern LPDIRECT3DTEXTURE9 cursorsurfaced3d; +extern LPDIRECT3DSURFACE9 D3D_capture(int*,int*,int*); #define CURSORMAXWIDTH 64 #define CURSORMAXHEIGHT 64 diff --git a/od-win32/screenshot.cpp b/od-win32/screenshot.cpp index 81f49ad4..2fa47a28 100644 --- a/od-win32/screenshot.cpp +++ b/od-win32/screenshot.cpp @@ -369,51 +369,119 @@ donormal: width = WIN32GFX_GetWidth (); height = WIN32GFX_GetHeight (); - surface_dc = gethdc (); - if (surface_dc == NULL) - goto oops; - - // need a HBITMAP to convert it to a DIB - if ((offscreen_bitmap = CreateCompatibleBitmap (surface_dc, width, height)) == NULL) - goto oops; // error - - // The bitmap is empty, so let's copy the contents of the surface to it. - // For that we need to select it into a device context. - if ((offscreen_dc = CreateCompatibleDC (surface_dc)) == NULL) - goto oops; // error - - // select offscreen_bitmap into offscreen_dc - hgdiobj = SelectObject (offscreen_dc, offscreen_bitmap); - - // now we can copy the contents of the surface to the offscreen bitmap - BitBlt (offscreen_dc, 0, 0, width, height, surface_dc, 0, 0, SRCCOPY); - - // de-select offscreen_bitmap - SelectObject (offscreen_dc, hgdiobj); - - ZeroMemory (bi, sizeof(bi)); - bi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); - bi->bmiHeader.biWidth = width; - bi->bmiHeader.biHeight = height; - bi->bmiHeader.biPlanes = 1; - bi->bmiHeader.biBitCount = 24; - bi->bmiHeader.biCompression = BI_RGB; - bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight; - bi->bmiHeader.biXPelsPerMeter = 0; - bi->bmiHeader.biYPelsPerMeter = 0; - bi->bmiHeader.biClrUsed = 0; - bi->bmiHeader.biClrImportant = 0; + if (D3D_isenabled()) { + int w, h, bits; + HRESULT hr; + D3DLOCKED_RECT l; + LPDIRECT3DSURFACE9 s = D3D_capture(&w, &h, &bits); + if (s) { + hr = s->LockRect(&l, NULL, D3DLOCK_READONLY); + if (SUCCEEDED(hr)) { + int dpitch = (((w * 24 + 31) & ~31) / 8); + lpvBits = xmalloc(uae_u8, dpitch * h); + + ZeroMemory(bi, sizeof(bi)); + bi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + bi->bmiHeader.biWidth = w; + bi->bmiHeader.biHeight = h; + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = 24; + bi->bmiHeader.biCompression = BI_RGB; + bi->bmiHeader.biSizeImage = dpitch * bi->bmiHeader.biHeight; + bi->bmiHeader.biXPelsPerMeter = 0; + bi->bmiHeader.biYPelsPerMeter = 0; + bi->bmiHeader.biClrUsed = 0; + bi->bmiHeader.biClrImportant = 0; + + if (lpvBits) { + if (bits == 32) { + for (int y = 0; y < h; y++) { + uae_u8 *d = (uae_u8*)lpvBits + (h - y - 1) * dpitch; + uae_u32 *s = (uae_u32*)((uae_u8*)l.pBits + y * l.Pitch); + for (int x = 0; x < w; x++) { + uae_u32 v = *s++; + d[0] = v >> 0; + d[1] = v >> 8; + d[2] = v >> 16; + d += 3; + } + } + } else if (bits == 16 || bits == 15) { + for (int y = 0; y < h; y++) { + uae_u8 *d = (uae_u8*)lpvBits + (h - y - 1) * dpitch; + uae_u16 *s = (uae_u16*)((uae_u8*)l.pBits + y * l.Pitch); + for (int x = 0; x < w; x++) { + uae_u16 v = s[x]; + uae_u16 v2 = v; + if (bits == 16) { + v2 = v & 31; + v2 |= ((v & (31 << 5)) << 1) | (((v >> 5) & 1) << 5); + v2 |= (v & (31 << 10)) << 1; + } else { + v2 = v & 31; + v2 |= (v >> 1) & (31 << 5); + v2 |= (v >> 1) & (31 << 10); + } + ((uae_u16*)d)[0] = v2; + d += 2; + } + } + } + } + s->UnlockRect(); + } + } - // Reserve memory for bitmap bits - if (!(lpvBits = xmalloc (uae_u8, bi->bmiHeader.biSizeImage))) - goto oops; // out of memory + } else { + surface_dc = gethdc (); + if (surface_dc == NULL) + goto oops; - // Have GetDIBits convert offscreen_bitmap to a DIB (device-independent bitmap): - if (!GetDIBits (offscreen_dc, offscreen_bitmap, 0, bi->bmiHeader.biHeight, lpvBits, bi, DIB_RGB_COLORS)) - goto oops; // GetDIBits FAILED + // need a HBITMAP to convert it to a DIB + if ((offscreen_bitmap = CreateCompatibleBitmap (surface_dc, width, height)) == NULL) + goto oops; // error + + // The bitmap is empty, so let's copy the contents of the surface to it. + // For that we need to select it into a device context. + if ((offscreen_dc = CreateCompatibleDC (surface_dc)) == NULL) + goto oops; // error + + // select offscreen_bitmap into offscreen_dc + hgdiobj = SelectObject (offscreen_dc, offscreen_bitmap); + + // now we can copy the contents of the surface to the offscreen bitmap + BitBlt (offscreen_dc, 0, 0, width, height, surface_dc, 0, 0, SRCCOPY); + + // de-select offscreen_bitmap + SelectObject (offscreen_dc, hgdiobj); + + ZeroMemory (bi, sizeof(bi)); + bi->bmiHeader.biSize = sizeof (BITMAPINFOHEADER); + bi->bmiHeader.biWidth = width; + bi->bmiHeader.biHeight = height; + bi->bmiHeader.biPlanes = 1; + bi->bmiHeader.biBitCount = 24; + bi->bmiHeader.biCompression = BI_RGB; + bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight; + bi->bmiHeader.biXPelsPerMeter = 0; + bi->bmiHeader.biYPelsPerMeter = 0; + bi->bmiHeader.biClrUsed = 0; + bi->bmiHeader.biClrImportant = 0; + + // Reserve memory for bitmap bits + if (!(lpvBits = xmalloc (uae_u8, bi->bmiHeader.biSizeImage))) + goto oops; // out of memory + + // Have GetDIBits convert offscreen_bitmap to a DIB (device-independent bitmap): + if (!GetDIBits (offscreen_dc, offscreen_bitmap, 0, bi->bmiHeader.biHeight, lpvBits, bi, DIB_RGB_COLORS)) + goto oops; // GetDIBits FAILED + + releasehdc (surface_dc); + surface_dc = NULL; + } - releasehdc (surface_dc); - surface_dc = NULL; + if (!lpvBits) + goto oops; } screenshot_prepared = TRUE; return 1;