From d924575b1e1391bf3f023fa0fa96fa22b5b920bf Mon Sep 17 00:00:00 2001 From: Randy Heit Date: Wed, 2 Dec 2009 05:02:40 +0000 Subject: [PATCH] - Fixed: After the previous screenwipe changes, the melt type no longer worked properly in letterboxed modes. - Added another surface to receive a copy of the top back buffer immediately before it is presented. This effectively produces a copy of the front buffer without the performance penalty of GetFrontBufferData, so fullscreen wipe preparation and screenshots are faster now. At lower resolutions, always copying the backbuffer does incur a slight FPS hit, but it's practically free at higher resolutions. SVN r2013 (trunk) --- docs/rh-log.txt | 8 ++ src/win32/fb_d3d9.cpp | 162 ++++++++++++++++--------------------- src/win32/fb_d3d9_wipe.cpp | 9 +-- src/win32/win32iface.h | 2 + 4 files changed, 82 insertions(+), 99 deletions(-) diff --git a/docs/rh-log.txt b/docs/rh-log.txt index d150ed707a..dc72ef8824 100644 --- a/docs/rh-log.txt +++ b/docs/rh-log.txt @@ -1,3 +1,11 @@ +December 1, 2009 +- Added another surface to receive a copy of the top back buffer immediately + before it is presented. This effectively produces a copy of the front + buffer without the performance penalty of GetFrontBufferData, so fullscreen + wipe preparation and screenshots are faster now. At lower resolutions, + always copying the backbuffer does incur a slight FPS hit, but it's + practically free at higher resolutions. + November 30, 2009 - The initial wipe screen is now kept in video memory. I had previously assumed that since the wipes only run at 35 FPS, the time spent DMA'ing diff --git a/src/win32/fb_d3d9.cpp b/src/win32/fb_d3d9.cpp index abcd952cbe..9c34db2bd8 100644 --- a/src/win32/fb_d3d9.cpp +++ b/src/win32/fb_d3d9.cpp @@ -253,6 +253,7 @@ D3DFB::D3DFB (int width, int height, bool fullscreen) FinalWipeScreen = NULL; PaletteTexture = NULL; GammaTexture = NULL; + FrontCopySurface = NULL; for (int i = 0; i < NUM_SHADERS; ++i) { Shaders[i] = NULL; @@ -637,6 +638,7 @@ void D3DFB::ReleaseDefaultPoolItems() SAFE_RELEASE( IndexBuffer ); SAFE_RELEASE( BlockSurface[0] ); SAFE_RELEASE( BlockSurface[1] ); + SAFE_RELEASE( FrontCopySurface ); } //========================================================================== @@ -748,14 +750,14 @@ void D3DFB::KillNativeTexs() bool D3DFB::CreateFBTexture () { - if (FAILED(D3DDevice->CreateTexture (Width, Height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &FBTexture, NULL))) + if (FAILED(D3DDevice->CreateTexture(Width, Height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &FBTexture, NULL))) { int pow2width, pow2height, i; for (i = 1; i < Width; i <<= 1) {} pow2width = i; for (i = 1; i < Height; i <<= 1) {} pow2height = i; - if (FAILED(D3DDevice->CreateTexture (pow2width, pow2height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &FBTexture, NULL))) + if (FAILED(D3DDevice->CreateTexture(pow2width, pow2height, 1, D3DUSAGE_DYNAMIC, D3DFMT_L8, D3DPOOL_DEFAULT, &FBTexture, NULL))) { return false; } @@ -770,7 +772,7 @@ bool D3DFB::CreateFBTexture () FBWidth = Width; FBHeight = Height; } - if (FAILED(D3DDevice->CreateTexture (FBWidth, FBHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &TempRenderTexture, NULL))) + if (FAILED(D3DDevice->CreateTexture(FBWidth, FBHeight, 1, D3DUSAGE_RENDERTARGET, D3DFMT_X8R8G8B8, D3DPOOL_DEFAULT, &TempRenderTexture, NULL))) { TempRenderTexture = NULL; } @@ -784,6 +786,10 @@ bool D3DFB::CreateFBTexture () surf->Release(); } } + if (FAILED(D3DDevice->CreateRenderTarget(Width, Height, D3DFMT_X8R8G8B8, D3DMULTISAMPLE_NONE, 0, FALSE, &FrontCopySurface, NULL))) + { + return false; + } return true; } @@ -1156,6 +1162,8 @@ void D3DFB::Flip() DoWindowedGamma(); D3DDevice->EndScene(); + CopyNextFrontBuffer(); + // Attempt to counter input lag. if (d3d_antilag && BlockSurface[0] != NULL) { @@ -1173,6 +1181,42 @@ void D3DFB::Flip() InScene = false; } +//========================================================================== +// +// D3DFB :: CopyNextFrontBuffer +// +// Duplicates the contents of the back buffer that will become the front +// buffer upon Present into FrontCopySurface so that we can get the +// contents of the display without wasting time in GetFrontBufferData(). +// +//========================================================================== + +void D3DFB::CopyNextFrontBuffer() +{ + IDirect3DSurface9 *backbuff; + + if (Windowed || PixelDoubling) + { + // Windowed mode or pixel doubling: TempRenderTexture has what we want + if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &backbuff))) + { + D3DDevice->StretchRect(backbuff, NULL, FrontCopySurface, NULL, D3DTEXF_NONE); + backbuff->Release(); + } + } + else + { + // Fullscreen, not pixel doubled: The back buffer has what we want, + // but it might be letter boxed. + if (SUCCEEDED(D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &backbuff))) + { + RECT srcrect = { 0, LBOffsetI, Width, LBOffsetI + Height }; + D3DDevice->StretchRect(backbuff, &srcrect, FrontCopySurface, NULL, D3DTEXF_NONE); + backbuff->Release(); + } + } +} + //========================================================================== // // D3DFB :: PaintToWindow @@ -1688,50 +1732,25 @@ void D3DFB::ReleaseScreenshotBuffer() IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool) { IDirect3DTexture9 *tex; - IDirect3DSurface9 *tsurf, *surf; + IDirect3DSurface9 *surf; D3DSURFACE_DESC desc; + HRESULT hr; assert(pool == D3DPOOL_SYSTEMMEM || pool == D3DPOOL_DEFAULT); - if (Windowed || PixelDoubling) + if (FAILED(FrontCopySurface->GetDesc(&desc))) { - // The texture we read into must have the same pixel format as - // the TempRenderTexture. - if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf))) - { - if (FAILED(tsurf->GetDesc(&desc))) - { - tsurf->Release(); - return NULL; - } - tsurf->Release(); - } - else - { - return NULL; - } + return NULL; + } + if (pool == D3DPOOL_SYSTEMMEM) + { + hr = D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0, desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL); } else { - if (SUCCEEDED(D3DDevice->GetBackBuffer(0, 0, D3DBACKBUFFER_TYPE_MONO, &tsurf))) - { - if (FAILED(tsurf->GetDesc(&desc))) - { - tsurf->Release(); - return NULL; - } - tsurf->Release(); - } - else - { - return NULL; - } - // GetFrontBufferData works only with this format - desc.Format = D3DFMT_A8R8G8B8; + hr = D3DDevice->CreateTexture(FBWidth, FBHeight, 1, D3DUSAGE_RENDERTARGET, desc.Format, D3DPOOL_DEFAULT, &tex, NULL); } - - // Read the image data into system memory. - if (FAILED(D3DDevice->CreateTexture(desc.Width, desc.Height, 1, 0, desc.Format, D3DPOOL_SYSTEMMEM, &tex, NULL))) + if (FAILED(hr)) { return NULL; } @@ -1740,68 +1759,23 @@ IDirect3DTexture9 *D3DFB::GetCurrentScreen(D3DPOOL pool) tex->Release(); return NULL; } - - if (!Windowed && !PixelDoubling) + if (pool == D3DPOOL_SYSTEMMEM) { - if (FAILED(D3DDevice->GetFrontBufferData(0, surf))) - { - surf->Release(); - tex->Release(); - return NULL; - } + // Video -> System memory : use GetRenderTargetData + hr = D3DDevice->GetRenderTargetData(FrontCopySurface, surf); } else { - if (SUCCEEDED(TempRenderTexture->GetSurfaceLevel(0, &tsurf))) - { - if (FAILED(D3DDevice->GetRenderTargetData(tsurf, surf))) - { - tsurf->Release(); - tex->Release(); - return NULL; - } - tsurf->Release(); - } - else - { - tex->Release(); - return NULL; - } - } - - // If the caller wants the screen in video memory, create a new texture, and copy back to that. - if (pool == D3DPOOL_DEFAULT) - { - IDirect3DTexture9 *vtex; - IDirect3DSurface9 *vsurf; - - if (FAILED(D3DDevice->CreateTexture(FBWidth, FBHeight, 1, 0, desc.Format, D3DPOOL_DEFAULT, &vtex, NULL))) - { - surf->Release(); - tex->Release(); - return NULL; - } - if (FAILED(vtex->GetSurfaceLevel(0, &vsurf))) - { - vtex->Release(); - surf->Release(); - tex->Release(); - return NULL; - } - if (FAILED(D3DDevice->UpdateSurface(surf, NULL, vsurf, NULL))) - { - vsurf->Release(); - vtex->Release(); - surf->Release(); - tex->Release(); - return NULL; - } - surf->Release(); - tex->Release(); - surf = vsurf; - tex = vtex; + // Video -> Video memory : use StretchRect + RECT destrect = { 0, 0, Width, Height }; + hr = D3DDevice->StretchRect(FrontCopySurface, NULL, surf, &destrect, D3DTEXF_POINT); } surf->Release(); + if (FAILED(hr)) + { + tex->Release(); + return NULL; + } return tex; } diff --git a/src/win32/fb_d3d9_wipe.cpp b/src/win32/fb_d3d9_wipe.cpp index 8783a2588e..798a950800 100644 --- a/src/win32/fb_d3d9_wipe.cpp +++ b/src/win32/fb_d3d9_wipe.cpp @@ -459,10 +459,9 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb) dpt.x = i * fbwidth / WIDTH; dpt.y = MAX(0, y[i] * fbheight / HEIGHT); rect.left = dpt.x; - rect.top = fb->LBOffsetI; + rect.top = 0; rect.right = (i + 1) * fbwidth / WIDTH; - rect.bottom = fbheight - dpt.y + fb->LBOffsetI; - dpt.y += fb->LBOffsetI; + rect.bottom = fbheight - dpt.y; if (rect.bottom > rect.top) { fb->CheckQuadBatch(); @@ -485,8 +484,8 @@ bool D3DFB::Wiper_Melt::Run(int ticks, D3DFB *fb) float x0 = float(rect.left) - 0.5f; float x1 = float(rect.right) - 0.5f; - float y0 = float(dpt.y) - 0.5f; - float y1 = float(fbheight) - 0.5f; + float y0 = float(dpt.y + fb->LBOffsetI) - 0.5f; + float y1 = float(fbheight + fb->LBOffsetI) - 0.5f; vert[0].x = x0; vert[0].y = y0; diff --git a/src/win32/win32iface.h b/src/win32/win32iface.h index 1684f9d827..e311049b7b 100644 --- a/src/win32/win32iface.h +++ b/src/win32/win32iface.h @@ -363,6 +363,7 @@ private: void BeginLineBatch(); void EndLineBatch(); void EndBatch(); + void CopyNextFrontBuffer(); D3DCAPS9 DeviceCaps; @@ -419,6 +420,7 @@ private: IDirect3DTexture9 *GammaTexture; IDirect3DTexture9 *ScreenshotTexture; IDirect3DSurface9 *ScreenshotSurface; + IDirect3DSurface9 *FrontCopySurface; IDirect3DVertexBuffer9 *VertexBuffer; FBVERTEX *VertexData;