diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp index 4df7e0165e..11f3bc624f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp @@ -20,7 +20,6 @@ #include "D3DBase.h" #include "D3DUtil.h" #include "Render.h" -#include namespace D3D { @@ -385,6 +384,35 @@ void drawShadedTexQuad(IDirect3DTexture9 *texture, RestoreShaders(); } +void drawShadedTexSubQuad(IDirect3DTexture9 *texture, + const MathUtil::Rectangle *rSource, + int SourceWidth, + int SourceHeight, + const MathUtil::Rectangle *rDest, + IDirect3DPixelShader9 *PShader, + IDirect3DVertexShader9 *Vshader) +{ + float sw = 1.0f /(float) SourceWidth; + float sh = 1.0f /(float) SourceHeight; + float u1= (rSource->left + 0.5f) * sw; + float u2= (rSource->right + 0.5f) * sw; + float v1= (rSource->top + 0.5f) * sh; + float v2= (rSource->bottom + 0.5f) * sh; + + struct Q2DVertex { float x,y,z,rhw,u,v,w,h,L,T,R,B; } coords[4] = { + { rDest->left , rDest->bottom, 0.0f,1.0f, u1, v1, sw, sh,u1,v1,u2,v2}, + { rDest->right, rDest->bottom, 0.0f,1.0f, u2, v1, sw, sh,u1,v1,u2,v2}, + { rDest->right, rDest->top , 0.0f,1.0f, u2, v2, sw, sh,u1,v1,u2,v2}, + { rDest->left , rDest->top , 0.0f,1.0f, u1, v2, sw, sh,u1,v1,u2,v2} + }; + dev->SetVertexShader(Vshader); + dev->SetPixelShader(PShader); + D3D::SetTexture(0, texture); + dev->SetFVF(D3DFVF_XYZW | D3DFVF_TEX3 | D3DFVF_TEXCOORDSIZE4(2)); + dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); + RestoreShaders(); +} + void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader) { struct Q2DVertex { float x,y,z,rhw;u32 color;} coords[4] = { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h index 90dd061d24..856743b5a6 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h @@ -18,6 +18,8 @@ #pragma once #include "D3DBase.h" +#include +#include namespace D3D { @@ -64,6 +66,13 @@ namespace D3D int SourceHeight, IDirect3DPixelShader9 *PShader, IDirect3DVertexShader9 *Vshader); + void drawShadedTexSubQuad(IDirect3DTexture9 *texture, + const MathUtil::Rectangle *rSource, + int SourceWidth, + int SourceHeight, + const MathUtil::Rectangle *rDest, + IDirect3DPixelShader9 *PShader, + IDirect3DVertexShader9 *Vshader); void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader); void SaveRenderStates(); void RestoreRenderStates(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Debugger/Debugger.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Debugger/Debugger.cpp index 8ed95c638d..6c146dbac1 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Debugger/Debugger.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Debugger/Debugger.cpp @@ -352,15 +352,15 @@ static void DX9DebuggerUpdateScreen() D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); D3D::dev->SetDepthStencilSurface(NULL); - D3D::dev->StretchRect(FBManager::GetEFBColorRTSurface(), NULL, + D3D::dev->StretchRect(FBManager.GetEFBColorRTSurface(), NULL, D3D::GetBackBufferSurface(), NULL, D3DTEXF_LINEAR); D3D::dev->EndScene(); D3D::dev->Present(NULL, NULL, NULL, NULL); - D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); D3D::dev->BeginScene(); } else diff --git a/Source/Plugins/Plugin_VideoDX9/Src/DlgSettings.cpp b/Source/Plugins/Plugin_VideoDX9/Src/DlgSettings.cpp index 9c38fe2b48..acf489ea44 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/DlgSettings.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/DlgSettings.cpp @@ -114,7 +114,7 @@ struct TabDirect3D : public W32Util::Tab Button_Enable(GetDlgItem(hDlg, IDC_SAFE_TEXTURE_CACHE_SAFE),g_Config.bSafeTextureCache); Button_Enable(GetDlgItem(hDlg, IDC_SAFE_TEXTURE_CACHE_NORMAL),g_Config.bSafeTextureCache); Button_Enable(GetDlgItem(hDlg, IDC_SAFE_TEXTURE_CACHE_FAST),g_Config.bSafeTextureCache); - + Button_SetCheck(GetDlgItem(hDlg, IDC_EFB_ACCESS_ENABLE), g_Config.bEFBAccessEnable); Button_GetCheck(GetDlgItem(hDlg,IDC_RENDER_TO_MAINWINDOW)) ? Button_Enable(GetDlgItem(hDlg,IDC_FULLSCREENENABLE), false) : Button_Enable(GetDlgItem(hDlg,IDC_FULLSCREENENABLE), true); } @@ -204,7 +204,9 @@ struct TabAdvanced : public W32Util::Tab Button_SetCheck(GetDlgItem(hDlg,IDC_SHOWSHADERERRORS), g_Config.bShowShaderErrors); Button_SetCheck(GetDlgItem(hDlg,IDC_DISABLEFOG), g_Config.bDisableFog); Button_SetCheck(GetDlgItem(hDlg,IDC_ENABLEEFBCOPY), !g_Config.bEFBCopyDisable); - + Button_SetCheck(GetDlgItem(hDlg,IDC_ENABLEXFB),g_Config.bUseXFB); + Button_SetCheck(GetDlgItem(hDlg,IDC_ENABLEREALXFB),g_Config.bUseRealXFB); + if(g_Config.bCopyEFBToTexture) Button_SetCheck(GetDlgItem(hDlg,IDC_EFBTOTEX), true); else @@ -221,6 +223,11 @@ struct TabAdvanced : public W32Util::Tab { switch (LOWORD(wParam)) { + case IDC_ENABLEXFB: + { + g_Config.bUseXFB = Button_GetCheck(GetDlgItem(hDlg, IDC_ENABLEXFB)) ? true : false; + } + break; case IDC_ENABLEEFBCOPY: { Button_GetCheck(GetDlgItem(hDlg,IDC_ENABLEEFBCOPY)) ? Button_Enable(GetDlgItem(hDlg,IDC_EFBTORAM), true) : Button_Enable(GetDlgItem(hDlg,IDC_EFBTORAM), false); @@ -252,7 +259,8 @@ struct TabAdvanced : public W32Util::Tab g_Config.bDisableFog = Button_GetCheck(GetDlgItem(hDlg,IDC_DISABLEFOG)) ? true : false; g_Config.bEFBCopyDisable = Button_GetCheck(GetDlgItem(hDlg,IDC_ENABLEEFBCOPY)) ? false : true; g_Config.bCopyEFBToTexture = Button_GetCheck(GetDlgItem(hDlg,IDC_EFBTORAM)) ? false : true; - + g_Config.bUseXFB = Button_GetCheck(GetDlgItem(hDlg, IDC_ENABLEXFB)) ? true : false; + g_Config.bUseRealXFB = Button_GetCheck(GetDlgItem(hDlg, IDC_ENABLEREALXFB)) ? true : false; g_Config.Save((std::string(File::GetUserPath(D_CONFIG_IDX)) + "gfx_dx9.ini").c_str()); if( D3D::dev != NULL ) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp index 7691be44b5..9e1ae5ebc9 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp @@ -19,79 +19,63 @@ #include "Render.h" #include "FramebufferManager.h" #include "VideoConfig.h" +#include "PixelShaderCache.h" +#include "VertexShaderCache.h" +#include "TextureConverter.h" -namespace FBManager -{ - -static LPDIRECT3DTEXTURE9 s_efb_color_texture;//Texture thats contains the color data of the render target -static LPDIRECT3DTEXTURE9 s_efb_colorRead_texture;//1 pixel texture for temporal data store -static LPDIRECT3DTEXTURE9 s_efb_depth_texture;//Texture thats contains the depth data of the render target -static LPDIRECT3DTEXTURE9 s_efb_depthRead_texture;//4 pixel texture for temporal data store - -static LPDIRECT3DSURFACE9 s_efb_depth_surface;//Depth Surface -static LPDIRECT3DSURFACE9 s_efb_color_surface;//Color Surface -static LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer;//Surface 0 of s_efb_colorRead_texture -static LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer;//Surface 0 of s_efb_depthRead_texture - -static LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data -static LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data - - -static D3DFORMAT s_efb_color_surface_Format;//Format of the color Surface -static D3DFORMAT s_efb_depth_surface_Format;//Format of the Depth Surface -static D3DFORMAT s_efb_depth_ReadBuffer_Format;//Format of the Depth color Read Surface #undef CHECK #define CHECK(hr,Message) if (FAILED(hr)) { PanicAlert(__FUNCTION__ " FAIL: %s" ,Message); } +FramebufferManager FBManager; - -LPDIRECT3DSURFACE9 GetEFBColorRTSurface() +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorRTSurface() { return s_efb_color_surface; } -LPDIRECT3DSURFACE9 GetEFBDepthRTSurface() + +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthRTSurface() { return s_efb_depth_surface; } -LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface() +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorOffScreenRTSurface() { return s_efb_color_OffScreenReadBuffer; } -LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface() +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthOffScreenRTSurface() { return s_efb_depth_OffScreenReadBuffer; } -LPDIRECT3DSURFACE9 GetEFBColorReadSurface() +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBColorReadSurface() { return s_efb_color_ReadBuffer; } -LPDIRECT3DSURFACE9 GetEFBDepthReadSurface() +LPDIRECT3DSURFACE9 FramebufferManager::GetEFBDepthReadSurface() { return s_efb_depth_ReadBuffer; } -D3DFORMAT GetEFBDepthRTSurfaceFormat(){return s_efb_depth_surface_Format;} -D3DFORMAT GetEFBDepthReadSurfaceFormat(){return s_efb_depth_ReadBuffer_Format;} -D3DFORMAT GetEFBColorRTSurfaceFormat(){return s_efb_color_surface_Format;} +D3DFORMAT FramebufferManager::GetEFBDepthRTSurfaceFormat(){return s_efb_depth_surface_Format;} +D3DFORMAT FramebufferManager::GetEFBDepthReadSurfaceFormat(){return s_efb_depth_ReadBuffer_Format;} +D3DFORMAT FramebufferManager::GetEFBColorRTSurfaceFormat(){return s_efb_color_surface_Format;} -LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc) +LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) { return s_efb_color_texture; } -LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle &sourceRc) +LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture(const EFBRectangle &sourceRc) { return s_efb_depth_texture; } -void Create() +void FramebufferManager::Create() { // Simplest possible setup to start with. int target_width = Renderer::GetFullTargetWidth(); @@ -180,49 +164,356 @@ void Create() } } -void Destroy() -{ - -if(s_efb_depth_surface) -s_efb_depth_surface->Release(); -s_efb_depth_surface=NULL; +void FramebufferManager::Destroy() +{ + if (s_efb_depth_surface) + s_efb_depth_surface->Release(); + s_efb_depth_surface=NULL; -if(s_efb_color_surface) -s_efb_color_surface->Release(); -s_efb_color_surface=NULL; + if (s_efb_color_surface) + s_efb_color_surface->Release(); + s_efb_color_surface=NULL; -if(s_efb_color_ReadBuffer) -s_efb_color_ReadBuffer->Release(); -s_efb_color_ReadBuffer=NULL; + if (s_efb_color_ReadBuffer) + s_efb_color_ReadBuffer->Release(); + s_efb_color_ReadBuffer=NULL; -if(s_efb_depth_ReadBuffer) -s_efb_depth_ReadBuffer->Release(); -s_efb_depth_ReadBuffer=NULL; + if (s_efb_depth_ReadBuffer) + s_efb_depth_ReadBuffer->Release(); + s_efb_depth_ReadBuffer=NULL; -if(s_efb_color_OffScreenReadBuffer) -s_efb_color_OffScreenReadBuffer->Release(); -s_efb_color_OffScreenReadBuffer=NULL; + if (s_efb_color_OffScreenReadBuffer) + s_efb_color_OffScreenReadBuffer->Release(); + s_efb_color_OffScreenReadBuffer=NULL; -if(s_efb_depth_OffScreenReadBuffer) -s_efb_depth_OffScreenReadBuffer->Release(); -s_efb_depth_OffScreenReadBuffer=NULL; + if (s_efb_depth_OffScreenReadBuffer) + s_efb_depth_OffScreenReadBuffer->Release(); + s_efb_depth_OffScreenReadBuffer=NULL; -if(s_efb_color_texture) - s_efb_color_texture->Release(); -s_efb_color_texture=NULL; + if (s_efb_color_texture) + s_efb_color_texture->Release(); + s_efb_color_texture=NULL; -if(s_efb_colorRead_texture) -s_efb_colorRead_texture->Release(); -s_efb_colorRead_texture=NULL; + if (s_efb_colorRead_texture) + s_efb_colorRead_texture->Release(); + s_efb_colorRead_texture=NULL; -if(s_efb_depth_texture) -s_efb_depth_texture->Release(); -s_efb_depth_texture=NULL; + if (s_efb_depth_texture) + s_efb_depth_texture->Release(); + s_efb_depth_texture=NULL; -if(s_efb_depthRead_texture) -s_efb_depthRead_texture->Release(); -s_efb_depthRead_texture=NULL; + if (s_efb_depthRead_texture) + s_efb_depthRead_texture->Release(); + s_efb_depthRead_texture=NULL; + + for (VirtualXFBListType::iterator it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it) + { + it->xfbSource.texture->Release(); + } + m_virtualXFBList.clear(); + if(m_realXFBSource.texture) + m_realXFBSource.texture->Release(); + m_realXFBSource.texture = NULL; } -} // namespace \ No newline at end of file +void FramebufferManager::CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + if (g_ActiveConfig.bUseRealXFB) + copyToRealXFB(xfbAddr, fbWidth, fbHeight, sourceRc); + else + copyToVirtualXFB(xfbAddr, fbWidth, fbHeight, sourceRc); +} + +const XFBSource** FramebufferManager::GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + if (g_ActiveConfig.bUseRealXFB) + return getRealXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); + else + return getVirtualXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); +} + +FramebufferManager::VirtualXFBListType::iterator FramebufferManager::findVirtualXFB(u32 xfbAddr, u32 width, u32 height) +{ + u32 srcLower = xfbAddr; + u32 srcUpper = xfbAddr + 2 * width * height; + + VirtualXFBListType::iterator it; + for (it = m_virtualXFBList.begin(); it != m_virtualXFBList.end(); ++it) + { + u32 dstLower = it->xfbAddr; + u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + + if (dstLower >= srcLower && dstUpper <= srcUpper) + return it; + } + + // That address is not in the Virtual XFB list. + return m_virtualXFBList.end(); +} + +void FramebufferManager::replaceVirtualXFB() +{ + VirtualXFBListType::iterator it = m_virtualXFBList.begin(); + + s32 srcLower = it->xfbAddr; + s32 srcUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + s32 lineSize = 2 * it->xfbWidth; + + it++; + + while (it != m_virtualXFBList.end()) + { + s32 dstLower = it->xfbAddr; + s32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + + if (dstLower >= srcLower && dstUpper <= srcUpper) + { + // invalidate the data + it->xfbAddr = 0; + it->xfbHeight = 0; + it->xfbWidth = 0; + } + else if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + s32 upperOverlap = (srcUpper - dstLower) / lineSize; + s32 lowerOverlap = (dstUpper - srcLower) / lineSize; + + if (upperOverlap > 0 && lowerOverlap < 0) + { + it->xfbAddr += lineSize * upperOverlap; + it->xfbHeight -= upperOverlap; + } + else if (lowerOverlap > 0) + { + it->xfbHeight -= lowerOverlap; + } + } + + it++; + } +} + +void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + u8* xfb_in_ram = Memory_GetPtr(xfbAddr); + if (!xfb_in_ram) + { + WARN_LOG(VIDEO, "Tried to copy to invalid XFB address"); + return; + } + + TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); + TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight); +} + +void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) +{ + LPDIRECT3DTEXTURE9 xfbTexture; + + VirtualXFBListType::iterator it = findVirtualXFB(xfbAddr, fbWidth, fbHeight); + + if (it == m_virtualXFBList.end() && (int)m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) + { + // replace the last virtual XFB + it--; + } + + float MultiSampleCompensation = 1.0f; + if(g_ActiveConfig.iMultisampleMode > 0 && g_ActiveConfig.iMultisampleMode < 4) + { + switch (g_ActiveConfig.iMultisampleMode) + { + case 1: + MultiSampleCompensation = 2.0f/3.0f; + break; + case 2: + MultiSampleCompensation = 0.5f; + break; + case 3: + MultiSampleCompensation = 1.0f/3.0f; + break; + default: + break; + }; + } + + float scaleX = Renderer::GetTargetScaleX() * MultiSampleCompensation ; + float scaleY = Renderer::GetTargetScaleY() * MultiSampleCompensation; + TargetRectangle targetSource,efbSource; + efbSource = Renderer::ConvertEFBRectangle(sourceRc); + targetSource.top = (sourceRc.top *scaleY); + targetSource.bottom = (sourceRc.bottom *scaleY); + targetSource.left = (sourceRc.left *scaleX); + targetSource.right = (sourceRc.right * scaleX); + int target_width = targetSource.right - targetSource.left; + int target_height = targetSource.bottom - targetSource.top; + if (it != m_virtualXFBList.end()) + { + // Overwrite an existing Virtual XFB. + + it->xfbAddr = xfbAddr; + it->xfbWidth = fbWidth; + it->xfbHeight = fbHeight; + + it->xfbSource.srcAddr = xfbAddr; + it->xfbSource.srcWidth = fbWidth; + it->xfbSource.srcHeight = fbHeight; + + if(it->xfbSource.texWidth != target_width || it->xfbSource.texHeight != target_height || !it->xfbSource.texture) + { + if(it->xfbSource.texture) + it->xfbSource.texture->Release(); + D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + D3DPOOL_DEFAULT, &it->xfbSource.texture, NULL); + } + + xfbTexture = it->xfbSource.texture; + + it->xfbSource.texWidth = target_width; + it->xfbSource.texHeight = target_height; + + // Move this Virtual XFB to the front of the list. + m_virtualXFBList.splice(m_virtualXFBList.begin(), m_virtualXFBList, it); + + // Keep stale XFB data from being used + replaceVirtualXFB(); + } + else + { + // Create a new Virtual XFB and place it at the front of the list. + + D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + D3DPOOL_DEFAULT, &xfbTexture, NULL); + VirtualXFB newVirt; + + newVirt.xfbAddr = xfbAddr; + newVirt.xfbWidth = fbWidth; + newVirt.xfbHeight = fbHeight; + + newVirt.xfbSource.texture = xfbTexture; + newVirt.xfbSource.texWidth = target_width; + newVirt.xfbSource.texHeight = target_height; + + // Add the new Virtual XFB to the list + + if ((int)m_virtualXFBList.size() >= MAX_VIRTUAL_XFB) + { + // List overflowed; delete the oldest. + m_virtualXFBList.back().xfbSource.texture->Release(); + m_virtualXFBList.pop_back(); + } + + m_virtualXFBList.push_front(newVirt); + } + + // Copy EFB to XFB texture + + if(!xfbTexture) + return; + // Make sure to resolve anything we need to read from. + LPDIRECT3DTEXTURE9 read_texture = GetEFBColorTexture(sourceRc); + + // We have to run a pixel shader, for color conversion. + Renderer::ResetAPIState(); // reset any game specific settings + LPDIRECT3DSURFACE9 Rendersurf = NULL; + + xfbTexture->GetSurfaceLevel(0,&Rendersurf); + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, Rendersurf); + + D3DVIEWPORT9 vp; + + // Stretch picture with increased internal resolution + vp.X = 0; + vp.Y = 0; + vp.Width = target_width; + vp.Height = target_height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + RECT sourcerect; + sourcerect.bottom = efbSource.bottom; + sourcerect.left = efbSource.left; + sourcerect.right = efbSource.right; + sourcerect.top = efbSource.top; + + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + + int SSAAMode = ( g_ActiveConfig.iMultisampleMode > 3 )? 0 : g_ActiveConfig.iMultisampleMode; + D3D::drawShadedTexQuad( + read_texture, + &sourcerect, + Renderer::GetFullTargetWidth() , + Renderer::GetFullTargetHeight(), + PixelShaderCache::GetColorCopyProgram(SSAAMode), + (SSAAMode != 0)? VertexShaderCache::GetFSAAVertexShader() : VertexShaderCache::GetSimpleVertexShader()); + + + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); + D3D::SetTexture(0,NULL); + D3D::dev->SetRenderTarget(0, GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(GetEFBDepthRTSurface()); + Renderer::RestoreAPIState(); + Rendersurf->Release(); + +} + +const XFBSource** FramebufferManager::getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + xfbCount = 1; + + m_realXFBSource.texWidth = fbWidth; + m_realXFBSource.texHeight = fbHeight; + + m_realXFBSource.srcAddr = xfbAddr; + m_realXFBSource.srcWidth = fbWidth; + m_realXFBSource.srcHeight = fbHeight; + + if (!m_realXFBSource.texture) + { + D3D::dev->CreateTexture(fbWidth, fbHeight, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, + D3DPOOL_DEFAULT, &m_realXFBSource.texture, NULL); + } + + // Decode YUYV data from GameCube RAM + TextureConverter::DecodeToTexture(xfbAddr, fbWidth, fbHeight, m_realXFBSource.texture); + + m_overlappingXFBArray[0] = &m_realXFBSource; + + return &m_overlappingXFBArray[0]; +} + +const XFBSource** FramebufferManager::getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount) +{ + xfbCount = 0; + + if (m_virtualXFBList.size() == 0) + { + // No Virtual XFBs available. + return NULL; + } + + u32 srcLower = xfbAddr; + u32 srcUpper = xfbAddr + 2 * fbWidth * fbHeight; + + VirtualXFBListType::iterator it; + for (it = m_virtualXFBList.end(); it != m_virtualXFBList.begin();) + { + --it; + + u32 dstLower = it->xfbAddr; + u32 dstUpper = it->xfbAddr + 2 * it->xfbWidth * it->xfbHeight; + + if (addrRangesOverlap(srcLower, srcUpper, dstLower, dstUpper)) + { + m_overlappingXFBArray[xfbCount] = &(it->xfbSource); + xfbCount++; + } + } + + return &m_overlappingXFBArray[0]; +} \ No newline at end of file diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h index 11f568fb49..85eded08de 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h @@ -21,50 +21,148 @@ #include #include "D3DBase.h" -namespace FBManager +// On the GameCube, the game sends a request for the graphics processor to +// transfer its internal EFB (Embedded Framebuffer) to an area in GameCube RAM +// called the XFB (External Framebuffer). The size and location of the XFB is +// decided at the time of the copy, and the format is always YUYV. The video +// interface is given a pointer to the XFB, which will be decoded and +// displayed on the TV. +// +// There are two ways for Dolphin to emulate this: +// +// Real XFB mode: +// +// Dolphin will behave like the GameCube and encode the EFB to +// a portion of GameCube RAM. The emulated video interface will decode the data +// for output to the screen. +// +// Advantages: Behaves exactly like the GameCube. +// Disadvantages: Resolution will be limited. +// +// Virtual XFB mode: +// +// When a request is made to copy the EFB to an XFB, Dolphin +// will remember the RAM location and size of the XFB in a Virtual XFB list. +// The video interface will look up the XFB in the list and use the enhanced +// data stored there, if available. +// +// Advantages: Enables high resolution graphics, better than real hardware. +// Disadvantages: If the GameCube CPU writes directly to the XFB (which is +// possible but uncommon), the Virtual XFB will not capture this information. + +// There may be multiple XFBs in GameCube RAM. This is the maximum number to +// virtualize. +const int MAX_VIRTUAL_XFB = 8; + +inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) { + return !((aLower >= bUpper) || (bLower >= aUpper)); +} -void Create(); -void Destroy(); +struct XFBSource +{ + XFBSource() : + texture(0) + {} -// To get the EFB in texture form, these functions may have to transfer -// the EFB to a resolved texture first. -LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc); -LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle& sourceRc); - -LPDIRECT3DSURFACE9 GetEFBColorRTSurface(); -LPDIRECT3DSURFACE9 GetEFBDepthRTSurface(); -LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface(); -LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface(); -D3DFORMAT GetEFBDepthRTSurfaceFormat(); -D3DFORMAT GetEFBColorRTSurfaceFormat(); -D3DFORMAT GetEFBDepthReadSurfaceFormat(); -LPDIRECT3DSURFACE9 GetEFBColorReadSurface(); -LPDIRECT3DSURFACE9 GetEFBDepthReadSurface(); - - - - - -/* -// Resolved framebuffer is only used in MSAA mode. -LPDIRECT3DTEXTURE9 GetResolvedFramebuffer() const { return m_resolvedFramebuffer; } - -TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc) const; - -void SetFramebuffer(LPDIRECT3DSURFACE9 surface); - -// If in MSAA mode, this will perform a resolve of the specified rectangle, and return the resolve target as a texture ID. -// Thus, this call may be expensive. Don't repeat it unnecessarily. -// If not in MSAA mode, will just return the render target texture ID. -// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. -LPDIRECT3DTEXTURE9 ResolveAndGetRenderTarget(const EFBRectangle &rect); - -// Same as above but for the depth Target. -// After calling this, before you render anything else, you MUST bind the framebuffer you want to draw to. -LPDIRECT3DTEXTURE9 ResolveAndGetDepthTarget(const EFBRectangle &rect); -*/ + u32 srcAddr; + u32 srcWidth; + u32 srcHeight; + LPDIRECT3DTEXTURE9 texture; + int texWidth; + int texHeight; }; +class FramebufferManager +{ +public: + FramebufferManager() + { + s_efb_color_texture = NULL; + LPDIRECT3DTEXTURE9 s_efb_colorRead_texture = NULL; + LPDIRECT3DTEXTURE9 s_efb_depth_texture = NULL; + LPDIRECT3DTEXTURE9 s_efb_depthRead_texture = NULL; + + LPDIRECT3DSURFACE9 s_efb_depth_surface = NULL; + LPDIRECT3DSURFACE9 s_efb_color_surface = NULL; + LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer = NULL; + LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer = NULL; + LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer = NULL; + LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer = NULL; + + D3DFORMAT s_efb_color_surface_Format = D3DFMT_FORCE_DWORD; + D3DFORMAT s_efb_depth_surface_Format = D3DFMT_FORCE_DWORD; + D3DFORMAT s_efb_depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD; + m_realXFBSource.texture = NULL; + } + + void Create(); + void Destroy(); + + void CopyToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + + const XFBSource** GetXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + + LPDIRECT3DTEXTURE9 GetEFBColorTexture(const EFBRectangle& sourceRc); + LPDIRECT3DTEXTURE9 GetEFBDepthTexture(const EFBRectangle& sourceRc); + + LPDIRECT3DSURFACE9 GetEFBColorRTSurface(); + LPDIRECT3DSURFACE9 GetEFBDepthRTSurface(); + LPDIRECT3DSURFACE9 GetEFBColorOffScreenRTSurface(); + LPDIRECT3DSURFACE9 GetEFBDepthOffScreenRTSurface(); + D3DFORMAT GetEFBDepthRTSurfaceFormat(); + D3DFORMAT GetEFBColorRTSurfaceFormat(); + D3DFORMAT GetEFBDepthReadSurfaceFormat(); + LPDIRECT3DSURFACE9 GetEFBColorReadSurface(); + LPDIRECT3DSURFACE9 GetEFBDepthReadSurface(); + +private: + + struct VirtualXFB + { + // Address and size in GameCube RAM + u32 xfbAddr; + u32 xfbWidth; + u32 xfbHeight; + + XFBSource xfbSource; + }; + + typedef std::list VirtualXFBListType; + + VirtualXFBListType::iterator findVirtualXFB(u32 xfbAddr, u32 width, u32 height); + + void replaceVirtualXFB(); + + void copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + void copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc); + const XFBSource** getRealXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + const XFBSource** getVirtualXFBSource(u32 xfbAddr, u32 fbWidth, u32 fbHeight, u32 &xfbCount); + + XFBSource m_realXFBSource; // Only used in Real XFB mode + VirtualXFBListType m_virtualXFBList; // Only used in Virtual XFB mode + + const XFBSource* m_overlappingXFBArray[MAX_VIRTUAL_XFB]; + + LPDIRECT3DTEXTURE9 s_efb_color_texture;//Texture thats contains the color data of the render target + LPDIRECT3DTEXTURE9 s_efb_colorRead_texture;//1 pixel texture for temporal data store + LPDIRECT3DTEXTURE9 s_efb_depth_texture;//Texture thats contains the depth data of the render target + LPDIRECT3DTEXTURE9 s_efb_depthRead_texture;//4 pixel texture for temporal data store + + LPDIRECT3DSURFACE9 s_efb_depth_surface;//Depth Surface + LPDIRECT3DSURFACE9 s_efb_color_surface;//Color Surface + LPDIRECT3DSURFACE9 s_efb_color_ReadBuffer;//Surface 0 of s_efb_colorRead_texture + LPDIRECT3DSURFACE9 s_efb_depth_ReadBuffer;//Surface 0 of s_efb_depthRead_texture + LPDIRECT3DSURFACE9 s_efb_color_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data + LPDIRECT3DSURFACE9 s_efb_depth_OffScreenReadBuffer;//System memory Surface that can be locked to retriebe the data + + + D3DFORMAT s_efb_color_surface_Format;//Format of the color Surface + D3DFORMAT s_efb_depth_surface_Format;//Format of the Depth Surface + D3DFORMAT s_efb_depth_ReadBuffer_Format;//Format of the Depth color Read Surface +}; + +extern FramebufferManager FBManager; + #endif diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 9c7708c9b1..101931f4e1 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -21,6 +21,7 @@ #include "StringUtil.h" #include "Common.h" +#include "Atomic.h" #include "FileUtil.h" #include "Thread.h" #include "Timer.h" @@ -52,6 +53,7 @@ int s_fps=0; +static bool WindowResized; static int s_target_width; static int s_target_height; @@ -61,6 +63,9 @@ static int s_Fulltarget_height; static int s_backbuffer_width; static int s_backbuffer_height; +static int s_XFB_width; +static int s_XFB_height; + static float xScale; static float yScale; @@ -73,7 +78,7 @@ static bool s_AVIDumping; static u32 s_blendMode; static u32 s_LastAA; static bool IS_AMD; - +static bool XFBWrited; char st[32768]; @@ -229,7 +234,7 @@ void SetupDeviceObjects() { D3D::font.Init(); VertexLoaderManager::Init(); - FBManager::Create(); + FBManager.Create(); VertexShaderManager::Dirty(); PixelShaderManager::Dirty(); @@ -246,7 +251,7 @@ void TeardownDeviceObjects() ScreenShootMEMSurface = NULL; D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - FBManager::Destroy(); + FBManager.Destroy(); D3D::font.Shutdown(); TextureCache::Invalidate(false); VertexManager::DestroyDeviceObjects(); @@ -282,31 +287,53 @@ bool Renderer::Init() s_backbuffer_width = D3D::GetBackBufferWidth(); s_backbuffer_height = D3D::GetBackBufferHeight(); - // TODO: Grab target width from configured resolution? - s_target_width = s_backbuffer_width; - s_target_height = s_backbuffer_height * ((float)EFB_HEIGHT / 480.0f); + s_XFB_width = MAX_XFB_WIDTH; + s_XFB_height = MAX_XFB_HEIGHT; + + TargetRectangle dst_rect; + ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); + + if(g_ActiveConfig.bUseRealXFB) + { + xScale = yScale = 1.0f; + } + else + { + xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width; + yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height; + } + + + s_target_width = EFB_WIDTH * xScale; + s_target_height = EFB_HEIGHT * yScale; + s_LastAA = (g_ActiveConfig.iMultisampleMode > 3)?0:g_ActiveConfig.iMultisampleMode; + float SupersampleCoeficient = 1.0f; switch (s_LastAA) { case 1: s_target_width = (s_target_width * 3) / 2; s_target_height = (s_target_height * 3) / 2; + SupersampleCoeficient = 3.0f/2.0f; break; case 2: s_target_width *= 2; s_target_height *= 2; + SupersampleCoeficient = 2.0f; break; case 3: s_target_width *= 3; s_target_height *= 3; + SupersampleCoeficient = 3.0f; break; default: break; }; - xScale = (float)s_target_width / (float)EFB_WIDTH; - yScale = (float)s_target_height / (float)EFB_HEIGHT; + xScale *= SupersampleCoeficient; + yScale *= SupersampleCoeficient; + s_Fulltarget_width = s_target_width; s_Fulltarget_height = s_target_height; @@ -335,8 +362,8 @@ bool Renderer::Init() D3D::dev->SetViewport(&vp); D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET, 0x0, 0, 0); - D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); vp.X = (s_Fulltarget_width - s_target_width) / 2; vp.Y = (s_Fulltarget_height - s_target_height) / 2; vp.Width = s_target_width; @@ -345,7 +372,7 @@ bool Renderer::Init() D3D::dev->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, 0x0, 1.0f, 0); D3D::BeginFrame(); D3D::SetRenderState(D3DRS_SCISSORTESTENABLE, true); - D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width,s_backbuffer_height, FBManager::GetEFBColorRTSurfaceFormat(), D3DPOOL_SYSTEMMEM, &ScreenShootMEMSurface, NULL ); + D3D::dev->CreateOffscreenPlainSurface(s_backbuffer_width,s_backbuffer_height, FBManager.GetEFBColorRTSurfaceFormat(), D3DPOOL_SYSTEMMEM, &ScreenShootMEMSurface, NULL ); return true; } @@ -369,6 +396,15 @@ int Renderer::GetFullTargetHeight() { return s_Fulltarget_height; } float Renderer::GetTargetScaleX() { return xScale; } float Renderer::GetTargetScaleY() { return yScale; } +int Renderer::GetFrameBufferWidth() +{ + return s_backbuffer_width; +} +int Renderer::GetFrameBufferHeight() +{ + return s_backbuffer_height; +} + // Create On-Screen-Messages void Renderer::DrawDebugText() { @@ -523,190 +559,33 @@ void CheckForResize() { TeardownDeviceObjects(); - D3D::Reset(); - - SetupDeviceObjects(); + D3D::Reset(); s_backbuffer_width = D3D::GetBackBufferWidth(); s_backbuffer_height = D3D::GetBackBufferHeight(); + WindowResized = true; } } -static void EFBTextureToD3DBackBuffer(const EFBRectangle& sourceRc) -{ - TargetRectangle src_rect, dst_rect; - src_rect = Renderer::ConvertEFBRectangle(sourceRc); - ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); - D3DVIEWPORT9 vp; - vp.X = 0; - vp.Y = 0; - vp.Width = s_backbuffer_width; - vp.Height = s_backbuffer_height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); - - D3D::dev->Clear(0,NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0); - int X = dst_rect.left; - int Y = dst_rect.top; - int Width = dst_rect.right - dst_rect.left; - int Height = dst_rect.bottom - dst_rect.top; - - if (X < 0) X = 0; - if (Y < 0) Y = 0; - if (X > s_backbuffer_width) X = s_backbuffer_width; - if (Y > s_backbuffer_height) Y = s_backbuffer_height; - if (Width < 0) Width = 0; - if (Height < 0) Height = 0; - if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X; - if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y; - vp.X = X; - vp.Y = Y; - vp.Width = Width; - vp.Height = Height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - - D3D::dev->SetViewport(&vp); - - EFBRectangle efbRect; - - LPDIRECT3DTEXTURE9 read_texture = FBManager::GetEFBColorTexture(efbRect); - RECT destinationrect; - destinationrect.bottom = dst_rect.bottom; - destinationrect.left = dst_rect.left; - destinationrect.right = dst_rect.right; - destinationrect.top = dst_rect.top; - RECT sourcerect; - sourcerect.bottom = src_rect.bottom; - sourcerect.left = src_rect.left; - sourcerect.right = src_rect.right; - sourcerect.top = src_rect.top; - - D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); - D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); - int SSAAMode = ( g_ActiveConfig.iMultisampleMode > 3 )? 0 : g_ActiveConfig.iMultisampleMode; - - D3D::drawShadedTexQuad(read_texture,&sourcerect,Renderer::GetFullTargetWidth(),Renderer::GetFullTargetHeight(),PixelShaderCache::GetColorCopyProgram(SSAAMode),(SSAAMode != 0)?VertexShaderCache::GetFSAAVertexShader():VertexShaderCache::GetSimpleVertexShader()); - - D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); - - vp.X = 0; - vp.Y = 0; - vp.Width = s_backbuffer_width; - vp.Height = s_backbuffer_height; - vp.MinZ = 0.0f; - vp.MaxZ = 1.0f; - D3D::dev->SetViewport(&vp); - if(s_bScreenshot) - { - s_criticalScreenshot.Enter(); - D3DXSaveSurfaceToFileA(s_sScreenshotName, D3DXIFF_BMP, D3D::GetBackBufferSurface(), NULL, &destinationrect); - s_bScreenshot = false; - s_criticalScreenshot.Leave(); - } - if (g_ActiveConfig.bDumpFrames) - { - D3D::dev->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface); - if (!s_LastFrameDumped) - { - s_recordWidth = destinationrect.right - destinationrect.left; - s_recordHeight = destinationrect.bottom - destinationrect.top; - s_AVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); - if (!s_AVIDumping) - { - PanicAlert("Error dumping frames to AVI."); - } - else - { - char msg [255]; - sprintf(msg, "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", File::GetUserPath(D_DUMPFRAMES_IDX), s_recordWidth, s_recordHeight); - OSD::AddMessage(msg, 2000); - } - } - if (s_AVIDumping) - { - D3DLOCKED_RECT rect; - if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, &destinationrect, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) - { - char *data = (char *)malloc(3 * s_recordWidth * s_recordHeight); - formatBufferDump((const char *)rect.pBits, data, s_recordWidth, s_recordHeight, rect.Pitch); - AVIDump::AddFrame(data); - free(data); - ScreenShootMEMSurface->UnlockRect(); - } - } - s_LastFrameDumped = true; - } - else - { - if (s_LastFrameDumped && s_AVIDumping) - { - AVIDump::Stop(); - s_AVIDumping = false; - } - s_LastFrameDumped = false; - } - - - // Finish up the current frame, print some stats - if (g_ActiveConfig.bShowFPS) - { - char fps[20]; - StringCchPrintfA(fps, 20, "FPS: %d\n", s_fps); - D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,fps,false); - } - Renderer::DrawDebugText(); - - if (g_ActiveConfig.bOverlayStats) - { - Statistics::ToString(st); - D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,st,false); - } - else if (g_ActiveConfig.bOverlayProjStats) - { - Statistics::ToStringProj(st); - D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,st,false); - } - - OSD::DrawMessages(); -} +extern volatile u32 s_swapRequested; void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) { - if (g_bSkipCurrentFrame) - { - g_VideoInitialize.pCopiedToXFB(false); - DEBUGGER_PAUSE_LOG_AT(NEXT_XFB_CMD,false,{printf("RenderToXFB - disabled");}); + VideoFifo_CheckEFBAccess(); + XFBWrited = true; + if(!fbWidth || !fbHeight) return; + // If we're about to write to a requested XFB, make sure the previous + // contents make it to the screen first. + VideoFifo_CheckSwapRequestAt(xfbAddr, fbWidth, fbHeight); + FBManager.CopyToXFB(xfbAddr, fbWidth, fbHeight, sourceRc); + + // XXX: Without the VI, how would we know what kind of field this is? So + // just use progressive. + if (!g_ActiveConfig.bUseXFB) + { + Renderer::Swap(xfbAddr, FIELD_PROGRESSIVE, fbWidth, fbHeight); + Common::AtomicStoreRelease(s_swapRequested, FALSE); } - - Renderer::ResetAPIState(); - // Set the backbuffer as the rendering target - D3D::dev->SetDepthStencilSurface(NULL); - D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); - - EFBTextureToD3DBackBuffer(sourceRc); - - D3D::EndFrame(); - - DEBUGGER_LOG_AT((NEXT_XFB_CMD|NEXT_EFB_CMD|NEXT_FRAME), - {printf("StretchRect, EFB->XFB\n");}); - DEBUGGER_PAUSE_LOG_AT( - (NEXT_XFB_CMD),false, - {printf("RenderToXFB: addr = %08X, %d x %d, sourceRc = (%d,%d,%d,%d)\n", - xfbAddr, fbWidth, fbHeight, - sourceRc.left, sourceRc.top, sourceRc.right, sourceRc.bottom);} - ); - - Swap(0,FIELD_PROGRESSIVE,0,0); // we used to swap the buffer here, now we will wait - // until the XFB pointer is updated by VI - D3D::BeginFrame(); - Renderer::RestoreAPIState(); - D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); - UpdateViewport(); - VertexShaderManager::SetViewportChanged(); } bool Renderer::SetScissorRect() @@ -789,18 +668,18 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) //Get the working buffer LPDIRECT3DSURFACE9 pBuffer = (type == PEEK_Z || type == POKE_Z) ? - FBManager::GetEFBDepthRTSurface() : FBManager::GetEFBColorRTSurface(); + FBManager.GetEFBDepthRTSurface() : FBManager.GetEFBColorRTSurface(); //get the temporal buffer to move 1pixel data LPDIRECT3DSURFACE9 RBuffer = (type == PEEK_Z || type == POKE_Z) ? - FBManager::GetEFBDepthReadSurface() : FBManager::GetEFBColorReadSurface(); + FBManager.GetEFBDepthReadSurface() : FBManager.GetEFBColorReadSurface(); //get the memory buffer that can be locked LPDIRECT3DSURFACE9 pOffScreenBuffer = (type == PEEK_Z || type == POKE_Z) ? - FBManager::GetEFBDepthOffScreenRTSurface() : FBManager::GetEFBColorOffScreenRTSurface(); + FBManager.GetEFBDepthOffScreenRTSurface() : FBManager.GetEFBColorOffScreenRTSurface(); //get the buffer format D3DFORMAT BufferFormat = (type == PEEK_Z || type == POKE_Z) ? - FBManager::GetEFBDepthRTSurfaceFormat() : FBManager::GetEFBColorRTSurfaceFormat(); + FBManager.GetEFBDepthRTSurfaceFormat() : FBManager.GetEFBColorRTSurfaceFormat(); D3DFORMAT ReadBufferFormat = (type == PEEK_Z || type == POKE_Z) ? - FBManager::GetEFBDepthReadSurfaceFormat() : BufferFormat; + FBManager.GetEFBDepthReadSurfaceFormat() : BufferFormat; if (BufferFormat == D3DFMT_D24X8) return 0; @@ -872,7 +751,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) colmat[0] = colmat[5] = colmat[10] = 1.0f; PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation EFBRectangle source_rect; - LPDIRECT3DTEXTURE9 read_texture = FBManager::GetEFBDepthTexture(source_rect); + LPDIRECT3DTEXTURE9 read_texture = FBManager.GetEFBDepthTexture(source_rect); D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); @@ -886,8 +765,8 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - hr = D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - hr = D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + hr = D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + hr = D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); RestoreAPIState(); RectToLock.bottom = 4; RectToLock.left = 0; @@ -1038,10 +917,10 @@ void UpdateViewport() { D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - FBManager::Destroy(); - FBManager::Create(); - D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + FBManager.Destroy(); + FBManager.Create(); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); } vp.X = X; vp.Y = Y; @@ -1131,55 +1010,279 @@ void Renderer::SetBlendMode(bool forceUpdate) void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) { + if(!fbWidth || !fbHeight) + return; // this function is called after the XFB field is changed, not after // EFB is copied to XFB. In this way, flickering is reduced in games - // and seems to also give more FPS in ZTP + // and seems to also give more FPS in ZTP + if(!XFBWrited) + return; + if (field == FIELD_LOWER) + xfbAddr -= fbWidth * 2; + + u32 xfbCount = 0; + const XFBSource** xfbSourceList = FBManager.GetXFBSource(xfbAddr, fbWidth, fbHeight, xfbCount); + if (!xfbSourceList || xfbCount == 0) + { + return; + } + + if (g_bSkipCurrentFrame) + { + g_VideoInitialize.pCopiedToXFB(false); + return; + } + + Renderer::ResetAPIState(); + // Set the backbuffer as the rendering target + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); + + TargetRectangle dst_rect; + ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); + D3DVIEWPORT9 vp; + vp.X = 0; + vp.Y = 0; + vp.Width = s_backbuffer_width; + vp.Height = s_backbuffer_height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + D3D::dev->Clear(0,NULL, D3DCLEAR_TARGET,D3DCOLOR_XRGB(0,0,0),1.0f,0); + + int X = dst_rect.left; + int Y = dst_rect.top; + int Width = dst_rect.right - dst_rect.left; + int Height = dst_rect.bottom - dst_rect.top; + + if (X < 0) X = 0; + if (Y < 0) Y = 0; + if (X > s_backbuffer_width) X = s_backbuffer_width; + if (Y > s_backbuffer_height) Y = s_backbuffer_height; + if (Width < 0) Width = 0; + if (Height < 0) Height = 0; + if (Width > (s_backbuffer_width - X)) Width = s_backbuffer_width - X; + if (Height > (s_backbuffer_height - Y)) Height = s_backbuffer_height - Y; + vp.X = X; + vp.Y = Y; + vp.Width = Width; + vp.Height = Height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + + D3D::dev->SetViewport(&vp); + + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + const XFBSource* xfbSource; + + // draw each xfb source + for (u32 i = 0; i < xfbCount; ++i) + { + xfbSource = xfbSourceList[i]; + MathUtil::Rectangle sourceRc; + + sourceRc.left = 0; + sourceRc.top = 0; + sourceRc.right = xfbSource->texWidth; + sourceRc.bottom = xfbSource->texHeight; + + MathUtil::Rectangle drawRc; + + if (g_ActiveConfig.bUseXFB && !g_ActiveConfig.bUseRealXFB) + { + // use virtual xfb with offset + int xfbHeight = xfbSource->srcHeight; + int xfbWidth = xfbSource->srcWidth; + int hOffset = ((s32)xfbSource->srcAddr - (s32)xfbAddr) / ((s32)fbWidth * 2); + + drawRc.bottom = 1.0f - 2.0f * ((hOffset) / (float)fbHeight); + drawRc.top = 1.0f - 2.0f * ((hOffset + xfbHeight) / (float)fbHeight); + drawRc.left = -(xfbWidth / (float)fbWidth); + drawRc.right = (xfbWidth / (float)fbWidth); + + + if (!g_ActiveConfig.bAutoScale) + { + // scale draw area for a 1 to 1 pixel mapping with the draw target + float vScale = (float)fbHeight / (float)s_backbuffer_height; + float hScale = (float)fbWidth / (float)s_backbuffer_width; + + drawRc.top *= vScale; + drawRc.bottom *= vScale; + drawRc.left *= hScale; + drawRc.right *= hScale; + } + } + else + { + drawRc.top = -1; + drawRc.bottom = 1; + drawRc.left = -1; + drawRc.right = 1; + } + + D3D::drawShadedTexSubQuad(xfbSource->texture,&sourceRc,xfbSource->texWidth,xfbSource->texHeight,&drawRc,PixelShaderCache::GetColorCopyProgram(0),VertexShaderCache::GetSimpleVertexShader()); + } + + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); + vp.X = 0; + vp.Y = 0; + vp.Width = s_backbuffer_width; + vp.Height = s_backbuffer_height; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + if(s_bScreenshot) + { + s_criticalScreenshot.Enter(); + D3DXSaveSurfaceToFileA(s_sScreenshotName, D3DXIFF_BMP, D3D::GetBackBufferSurface(), NULL, NULL); + s_bScreenshot = false; + s_criticalScreenshot.Leave(); + } + if (g_ActiveConfig.bDumpFrames) + { + D3D::dev->GetRenderTargetData(D3D::GetBackBufferSurface(),ScreenShootMEMSurface); + if (!s_LastFrameDumped) + { + s_recordWidth = s_backbuffer_width; + s_recordHeight = s_backbuffer_height; + s_AVIDumping = AVIDump::Start(EmuWindow::GetParentWnd(), s_recordWidth, s_recordHeight); + if (!s_AVIDumping) + { + PanicAlert("Error dumping frames to AVI."); + } + else + { + char msg [255]; + sprintf(msg, "Dumping Frames to \"%sframedump0.avi\" (%dx%d RGB24)", File::GetUserPath(D_DUMPFRAMES_IDX), s_recordWidth, s_recordHeight); + OSD::AddMessage(msg, 2000); + } + } + if (s_AVIDumping) + { + D3DLOCKED_RECT rect; + if (SUCCEEDED(ScreenShootMEMSurface->LockRect(&rect, NULL, D3DLOCK_NO_DIRTY_UPDATE | D3DLOCK_NOSYSLOCK | D3DLOCK_READONLY))) + { + char *data = (char *)malloc(3 * s_recordWidth * s_recordHeight); + formatBufferDump((const char *)rect.pBits, data, s_recordWidth, s_recordHeight, rect.Pitch); + AVIDump::AddFrame(data); + free(data); + ScreenShootMEMSurface->UnlockRect(); + } + } + s_LastFrameDumped = true; + } + else + { + if (s_LastFrameDumped && s_AVIDumping) + { + AVIDump::Stop(); + s_AVIDumping = false; + } + s_LastFrameDumped = false; + } + + + // Finish up the current frame, print some stats + if (g_ActiveConfig.bShowFPS) + { + char fps[20]; + StringCchPrintfA(fps, 20, "FPS: %d\n", s_fps); + D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,fps,false); + } + Renderer::DrawDebugText(); + + if (g_ActiveConfig.bOverlayStats) + { + Statistics::ToString(st); + D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,st,false); + } + else if (g_ActiveConfig.bOverlayProjStats) + { + Statistics::ToStringProj(st); + D3D::font.DrawTextScaled(0,30,20,20,0.0f,0xFF00FFFF,st,false); + } + + OSD::DrawMessages(); + + D3D::EndFrame(); - // D3D frame is now over - // Clean out old stuff from caches. frameCount++; TextureCache::Cleanup(); // Make any new configuration settings active. - UpdateActiveConfig(); - - g_VideoInitialize.pCopiedToXFB(false); - + UpdateActiveConfig(); + WindowResized = false; CheckForResize(); + + bool xfbchanged = false; + + if(s_XFB_width != fbWidth || s_XFB_height != fbHeight) + { + xfbchanged = true; + s_XFB_width = fbWidth; + s_XFB_height = fbHeight; + if(s_XFB_width < 1) s_XFB_width = MAX_XFB_WIDTH; + if(s_XFB_width > MAX_XFB_WIDTH) s_XFB_width = MAX_XFB_WIDTH; + if(s_XFB_height < 1) s_XFB_height = MAX_XFB_HEIGHT; + if(s_XFB_height > MAX_XFB_HEIGHT) s_XFB_height = MAX_XFB_HEIGHT; + + } u32 newAA = g_ActiveConfig.iMultisampleMode; - if(newAA != s_LastAA) + if(newAA != s_LastAA || xfbchanged || WindowResized) { - s_target_width = s_backbuffer_width; - s_target_height = s_backbuffer_height * ((float)EFB_HEIGHT / 480.0f); s_LastAA = newAA; + + ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); + + if(g_ActiveConfig.bUseRealXFB) + { + xScale = yScale = 1.0f; + } + else + { + xScale = (float)(dst_rect.right - dst_rect.left) / (float)s_XFB_width; + yScale = (float)(dst_rect.bottom - dst_rect.top) / (float)s_XFB_height; + } + + s_target_width = EFB_WIDTH * xScale; + s_target_height = EFB_HEIGHT * yScale; + + s_LastAA = (g_ActiveConfig.iMultisampleMode > 3)?0:g_ActiveConfig.iMultisampleMode; + + float SupersampleCoeficient = 1.0f; switch (s_LastAA) { case 1: s_target_width = (s_target_width * 3) / 2; s_target_height = (s_target_height * 3) / 2; + SupersampleCoeficient = 3.0f/2.0f; break; case 2: s_target_width *= 2; s_target_height *= 2; + SupersampleCoeficient = 2.0f; break; case 3: s_target_width *= 3; s_target_height *= 3; + SupersampleCoeficient = 3.0f; break; default: break; }; - xScale = (float)s_target_width / (float)EFB_WIDTH; - yScale = (float)s_target_height / (float)EFB_HEIGHT; - s_Fulltarget_width = s_target_width; - s_Fulltarget_height = s_target_height; + + xScale *= SupersampleCoeficient; + yScale *= SupersampleCoeficient; D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - FBManager::Destroy(); - FBManager::Create(); - D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + SetupDeviceObjects(); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); } // --------------------------------------------------------------------- @@ -1201,6 +1304,13 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) // Flip/present backbuffer to frontbuffer here D3D::Present(); + D3D::BeginFrame(); + Renderer::RestoreAPIState(); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); + UpdateViewport(); + VertexShaderManager::SetViewportChanged(); + XFBWrited = false; } void Renderer::ResetAPIState() diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp index b380546284..4b15d4dbae 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp @@ -330,7 +330,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo int tex_w = (abs(source_rect.GetWidth()) >> bScaleByHalf); int tex_h = (abs(source_rect.GetHeight()) >> bScaleByHalf); - //compensate the texture grow if multisample is enabled to conserve memory usage + //compensate the texture grow if supersampling is enabled to conserve memory usage float MultiSampleCompensation = 1.0f; if(g_ActiveConfig.iMultisampleMode > 0 && g_ActiveConfig.iMultisampleMode < 4) { @@ -353,16 +353,14 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo int Scaledtex_h = (g_ActiveConfig.bCopyEFBScaled)?((int)(Renderer::GetTargetScaleY() * MultiSampleCompensation * tex_h)):tex_h; TexCache::iterator iter; - LPDIRECT3DTEXTURE9 tex; + LPDIRECT3DTEXTURE9 tex = NULL; iter = textures.find(address); if (iter != textures.end()) { if (iter->second.isRenderTarget && iter->second.Scaledw == Scaledtex_w && iter->second.Scaledh == Scaledtex_h) - { - + { tex = iter->second.texture; iter->second.frameCount = frameCount; - goto have_texture; } else { @@ -374,6 +372,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo } } + if(!tex) { TCacheEntry entry; entry.isRenderTarget = true; @@ -390,7 +389,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 address, bool bFromZBuffer, boo tex = entry.texture; } -have_texture: + float colmat[16]= {0.0f}; float fConstAdd[4] = {0.0f}; @@ -499,7 +498,7 @@ have_texture: } } // Make sure to resolve anything we need to read from. - LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ? FBManager::GetEFBDepthTexture(source_rect) : FBManager::GetEFBColorTexture(source_rect); + LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ? FBManager.GetEFBDepthTexture(source_rect) : FBManager.GetEFBColorTexture(source_rect); // We have to run a pixel shader, for color conversion. Renderer::ResetAPIState(); // reset any game specific settings @@ -545,7 +544,7 @@ have_texture: } - D3DFORMAT bformat = FBManager::GetEFBDepthRTSurfaceFormat(); + D3DFORMAT bformat = FBManager.GetEFBDepthRTSurfaceFormat(); int SSAAMode = ( g_ActiveConfig.iMultisampleMode > 3 )? 0 : g_ActiveConfig.iMultisampleMode; D3D::drawShadedTexQuad( read_texture, @@ -559,8 +558,8 @@ have_texture: D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); D3D::SetTexture(0,NULL); - D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); Renderer::RestoreAPIState(); Rendersurf->Release(); } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp index 2bf0af72e8..5ea3735414 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp @@ -28,10 +28,6 @@ #include "VideoConfig.h" #include "ImageWrite.h" #include "Render.h" -#include "D3DBase.h" -#include "D3DTexture.h" -#include "D3DUtil.h" -#include "D3DShader.h" #include "TextureCache.h" #include "Math.h" #include "FileUtil.h" @@ -60,14 +56,16 @@ static LPDIRECT3DPIXELSHADER9 s_encodingPrograms[NUM_ENCODING_PROGRAMS]; void CreateRgbToYuyvProgram() { // Output is BGRA because that is slightly faster than RGBA. - const char *FProgram = + char* FProgram = new char[2048]; + sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n" + "uniform float4 textureDims : register(c%d);\n" "uniform sampler samp0 : register(s0);\n" "void main(\n" " out float4 ocol0 : COLOR0,\n" " in float2 uv0 : TEXCOORD0)\n" "{\n" - " float2 uv1 = float2(uv0.x + 1.0f, uv0.y);\n" - " float3 c0 = tex2D(samp0, uv0).rgb;\n" + " float2 uv1 = float2(uv0.x + (1.0f/blkDims.z), uv0.y);\n" + " float3 c0 = tex2D(samp0, uv0.xy).rgb;\n" " float3 c1 = tex2D(samp0, uv1).rgb;\n" " float3 y_const = float3(0.257f,0.504f,0.098f);\n" " float3 u_const = float3(-0.148f,-0.291f,0.439f);\n" @@ -75,16 +73,20 @@ void CreateRgbToYuyvProgram() " float4 const3 = float4(0.0625f,0.5f,0.0625f,0.5f);\n" " float3 c01 = (c0 + c1) * 0.5f;\n" " ocol0 = float4(dot(c1,y_const),dot(c01,u_const),dot(c0,y_const),dot(c01, v_const)) + const3;\n" - "}\n"; + "}\n",C_COLORMATRIX,C_COLORMATRIX+1); + s_rgbToYuyvProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram)); if (!s_rgbToYuyvProgram) { ERROR_LOG(VIDEO, "Failed to create RGB to YUYV fragment program"); } + delete [] FProgram; } void CreateYuyvToRgbProgram() { - const char *FProgram = + char* FProgram = new char[2048]; + sprintf(FProgram,"uniform float4 blkDims : register(c%d);\n" + "uniform float4 textureDims : register(c%d);\n" "uniform sampler samp0 : register(s0);\n" "void main(\n" " out float4 ocol0 : COLOR0,\n" @@ -92,7 +94,7 @@ void CreateYuyvToRgbProgram() "{\n" " float4 c0 = tex2D(samp0, uv0).rgba;\n" - " float f = step(0.5, frac(uv0.x));\n" + " float f = step(0.5, frac(uv0.x * blkDims.z));\n" " float y = lerp(c0.b, c0.r, f);\n" " float yComp = 1.164f * (y - 0.0625f);\n" " float uComp = c0.g - 0.5f;\n" @@ -102,11 +104,12 @@ void CreateYuyvToRgbProgram() " yComp - (0.813f * vComp) - (0.391f * uComp),\n" " yComp + (2.018f * uComp),\n" " 1.0f);\n" - "}\n"; + "}\n",C_COLORMATRIX,C_COLORMATRIX+1); s_yuyvToRgbProgram = D3D::CompileAndCreatePixelShader(FProgram, (int)strlen(FProgram)); if (!s_yuyvToRgbProgram) { ERROR_LOG(VIDEO, "Failed to create YUYV to RGB fragment program"); } + delete [] FProgram; } LPDIRECT3DPIXELSHADER9 GetOrCreateEncodingShader(u32 format) @@ -270,8 +273,8 @@ void EncodeToRamUsingShader(LPDIRECT3DPIXELSHADER9 shader, LPDIRECT3DTEXTURE9 sr // Draw... D3D::drawShadedTexQuad(srcTexture,&SrcRect,1,1,shader,VertexShaderCache::GetSimpleVertexShader()); - hr = D3D::dev->SetRenderTarget(0, FBManager::GetEFBColorRTSurface()); - hr = D3D::dev->SetDepthStencilSurface(FBManager::GetEFBDepthRTSurface()); + hr = D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + hr = D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); Renderer::RestoreAPIState(); D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); // .. and then readback the results. @@ -337,7 +340,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf u8 *dest_ptr = Memory_GetPtr(address); - LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? FBManager::GetEFBDepthTexture(source) : FBManager::GetEFBColorTexture(source); + LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? FBManager.GetEFBDepthTexture(source) : FBManager.GetEFBColorTexture(source); int width = (source.right - source.left) >> bScaleByHalf; int height = (source.bottom - source.top) >> bScaleByHalf; @@ -387,15 +390,23 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf EncodeToRamUsingShader(texconv_shader, source_texture, scaledSource, dest_ptr, expandedWidth / samples, expandedHeight,readStride, true, bScaleByHalf > 0); } -/*void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, - u8* destAddr, int dstWidth, int dstHeight) +void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc,u8* destAddr, int dstWidth, int dstHeight) { + TextureConversionShader::SetShaderParameters( + (float)dstWidth, + (float)dstHeight, + 0.0f , + 0.0f, + 1.0f, + 1.0f, + (float)Renderer::GetFullTargetWidth(), + (float)Renderer::GetFullTargetHeight()); EncodeToRamUsingShader(s_rgbToYuyvProgram, srcTexture, sourceRc, destAddr, dstWidth / 2, dstHeight, 0, false, false); } // Should be scale free. -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture) +void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture) { u8* srcAddr = Memory_GetPtr(xfbAddr); if (!srcAddr) @@ -404,64 +415,67 @@ void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTextur return; } - Renderer::ResetAPIState(); - float srcFormatFactor = 0.5f; float srcFmtWidth = srcWidth * srcFormatFactor; - - // swich to texture converter frame buffer - // attach destTexture as color destination - g_framebufferManager.SetFramebuffer(s_texConvFrameBuffer); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, destTexture); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, destTexture, 0); - - GL_REPORT_FBO_ERROR(); - - for (int i = 1; i < 8; ++i) - TextureMngr::DisableStage(i); - - // activate source texture - // set srcAddr as data for source texture - glActiveTexture(GL_TEXTURE0); - glEnable(GL_TEXTURE_RECTANGLE_ARB); - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, s_srcTexture); - - // TODO: make this less slow. (How?) - if(s_srcTextureWidth == (GLsizei)srcFmtWidth && s_srcTextureHeight == (GLsizei)srcHeight) - { - glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB, 0,0,0,s_srcTextureWidth, s_srcTextureHeight, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); - } - else - { - glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA8, (GLsizei)srcFmtWidth, (GLsizei)srcHeight, 0, GL_BGRA, GL_UNSIGNED_BYTE, srcAddr); - s_srcTextureWidth = (GLsizei)srcFmtWidth; - s_srcTextureHeight = (GLsizei)srcHeight; - } - - glViewport(0, 0, srcWidth, srcHeight); - - PixelShaderCache::EnableShader(s_yuyvToRgbProgram.glprogid); - GL_REPORT_ERRORD(); + Renderer::ResetAPIState(); // reset any game specific settings + LPDIRECT3DTEXTURE9 s_srcTexture = D3D::CreateTexture2D(srcAddr, srcFmtWidth, srcHeight, srcFmtWidth, D3DFMT_A8R8G8B8, false); + LPDIRECT3DSURFACE9 Rendersurf = NULL; + destTexture->GetSurfaceLevel(0,&Rendersurf); + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, Rendersurf); + + D3DVIEWPORT9 vp; - glBegin(GL_QUADS); - glTexCoord2f(srcFmtWidth, (float)srcHeight); glVertex2f(1,-1); - glTexCoord2f(srcFmtWidth, 0); glVertex2f(1,1); - glTexCoord2f(0, 0); glVertex2f(-1,1); - glTexCoord2f(0, (float)srcHeight); glVertex2f(-1,-1); - glEnd(); - - // reset state - glBindTexture(GL_TEXTURE_RECTANGLE_ARB, 0); - glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_RECTANGLE_ARB, 0, 0); - TextureMngr::DisableStage(0); - - VertexShaderManager::SetViewportChanged(); - - g_framebufferManager.SetFramebuffer(0); + // Stretch picture with increased internal resolution + vp.X = 0; + vp.Y = 0; + vp.Width = srcWidth; + vp.Height = srcHeight; + vp.MinZ = 0.0f; + vp.MaxZ = 1.0f; + D3D::dev->SetViewport(&vp); + RECT destrect; + destrect.bottom = srcHeight; + destrect.left = 0; + destrect.right = srcWidth; + destrect.top = 0; + + RECT sourcerect; + sourcerect.bottom = srcHeight; + sourcerect.left = 0; + sourcerect.right = srcFmtWidth; + sourcerect.top = 0; + D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR); + D3D::ChangeSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR); + + TextureConversionShader::SetShaderParameters( + (float)srcFmtWidth, + (float)srcHeight, + 0.0f , + 0.0f, + 1.0f, + 1.0f, + (float)srcFmtWidth, + (float)srcHeight); + D3D::drawShadedTexQuad( + s_srcTexture, + &sourcerect, + srcFmtWidth , + srcHeight, + s_yuyvToRgbProgram, + VertexShaderCache::GetSimpleVertexShader()); + + + D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); + D3D::RefreshSamplerState(0, D3DSAMP_MAGFILTER); + D3D::SetTexture(0,NULL); + D3D::dev->SetRenderTarget(0, FBManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(FBManager.GetEFBDepthRTSurface()); Renderer::RestoreAPIState(); - GL_REPORT_ERRORD(); + Rendersurf->Release(); + s_srcTexture->Release(); } -*/ + } // namespace diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h index cd2199607b..f0c8c44ed5 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.h @@ -19,6 +19,10 @@ #define _TEXTURECONVERTER_H_ #include "VideoCommon.h" +#include "D3DBase.h" +#include "D3DTexture.h" +#include "D3DUtil.h" +#include "D3DShader.h" // Converts textures between formats // TODO: support multiple texture formats @@ -31,10 +35,10 @@ void Shutdown(); void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyfmt, int bScaleByHalf, const EFBRectangle& source); -/*void EncodeToRamYUYV(GLuint srcTexture, const TargetRectangle& sourceRc, +void EncodeToRamYUYV(LPDIRECT3DTEXTURE9 srcTexture, const TargetRectangle& sourceRc, u8* destAddr, int dstWidth, int dstHeight); -void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, GLuint destTexture);*/ +void DecodeToTexture(u32 xfbAddr, int srcWidth, int srcHeight, LPDIRECT3DTEXTURE9 destTexture); } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index 9ffec68553..baf80d76ac 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -62,11 +62,12 @@ GFXDebuggerDX9 *m_DebuggerFrame = NULL; HINSTANCE g_hInstance = NULL; SVideoInitialize g_VideoInitialize; PLUGIN_GLOBALS* globals = NULL; -bool s_initialized; +static bool s_PluginInitialized = false; +volatile u32 s_swapRequested = FALSE; static u32 s_efbAccessRequested = FALSE; static volatile u32 s_FifoShuttingDown = FALSE; -static bool s_swapRequested = false; +static bool ForceSwap = true; static volatile struct { @@ -205,9 +206,9 @@ void DllAbout(HWND _hParent) void DllConfig(HWND _hParent) { // If not initialized, only init D3D so we can enumerate resolutions. - if (!s_initialized) D3D::Init(); + if (!s_PluginInitialized) D3D::Init(); DlgSettings_Show(g_hInstance, _hParent); - if (!s_initialized) D3D::Shutdown(); + if (!s_PluginInitialized) D3D::Shutdown(); } void Initialize(void *init) @@ -242,7 +243,7 @@ void Initialize(void *init) _pVideoInitialize->pWindowHandle = g_VideoInitialize.pWindowHandle; OSD::AddMessage("Dolphin Direct3D9 Video Plugin.", 5000); - s_initialized = true; + s_PluginInitialized = true; } void Video_Prepare() @@ -250,7 +251,8 @@ void Video_Prepare() // Better be safe... s_efbAccessRequested = FALSE; s_FifoShuttingDown = FALSE; - + s_swapRequested = FALSE; + ForceSwap = true; Renderer::Init(); TextureCache::Init(); BPInit(); @@ -270,7 +272,7 @@ void Shutdown() { s_efbAccessRequested = FALSE; s_FifoShuttingDown = FALSE; - + s_swapRequested = FALSE; Fifo_Shutdown(); VertexManager::Shutdown(); VertexLoaderManager::Shutdown(); @@ -283,7 +285,7 @@ void Shutdown() Renderer::Shutdown(); D3D::Shutdown(); EmuWindow::Close(); - s_initialized = false; + s_PluginInitialized = false; } void DoState(unsigned char **ptr, int mode) { @@ -318,52 +320,61 @@ void Video_SetRendering(bool bEnabled) { // Run from the graphics thread void VideoFifo_CheckSwapRequest() { - // swap unimplemented - return; - - if (s_swapRequested) + if (Common::AtomicLoadAcquire(s_swapRequested)) { - // Flip the backbuffer to front buffer now - s_swapRequested = false; - //if (s_beginFieldArgs.field == FIELD_PROGRESSIVE || s_beginFieldArgs.field == FIELD_LOWER) + if (ForceSwap || g_ActiveConfig.bUseXFB) { - Renderer::Swap(0,FIELD_PROGRESSIVE,0,0); // The swap function is not finished - // so it is ok to pass dummy parameters for now + Renderer::Swap(s_beginFieldArgs.xfbAddr, s_beginFieldArgs.field, s_beginFieldArgs.fbWidth, s_beginFieldArgs.fbHeight); } + + Common::AtomicStoreRelease(s_swapRequested, FALSE); } } +inline bool addrRangesOverlap(u32 aLower, u32 aUpper, u32 bLower, u32 bUpper) +{ + return !((aLower >= bUpper) || (bLower >= aUpper)); +} + // Run from the graphics thread void VideoFifo_CheckSwapRequestAt(u32 xfbAddr, u32 fbWidth, u32 fbHeight) { - // swap unimplemented + if (Common::AtomicLoadAcquire(s_swapRequested) && g_ActiveConfig.bUseXFB) + { + u32 aLower = xfbAddr; + u32 aUpper = xfbAddr + 2 * fbWidth * fbHeight; + u32 bLower = s_beginFieldArgs.xfbAddr; + u32 bUpper = s_beginFieldArgs.xfbAddr + 2 * s_beginFieldArgs.fbWidth * s_beginFieldArgs.fbHeight; + + if (addrRangesOverlap(aLower, aUpper, bLower, bUpper)) + VideoFifo_CheckSwapRequest(); + } + + ForceSwap = false; } // Run from the CPU thread (from VideoInterface.cpp) void Video_BeginField(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight) { - // swap unimplemented - return; - - s_beginFieldArgs.xfbAddr = xfbAddr; - s_beginFieldArgs.field = field; - s_beginFieldArgs.fbWidth = fbWidth; - s_beginFieldArgs.fbHeight = fbHeight; - s_swapRequested = true; - - if (s_initialized) + if (s_PluginInitialized) { // Make sure previous swap request has made it to the screen if (g_VideoInitialize.bOnThread) { - //while (Common::AtomicLoadAcquire(s_swapRequested)) - //Common::YieldCPU(); + while (Common::AtomicLoadAcquire(s_swapRequested) && !s_FifoShuttingDown) + //Common::SleepCurrentThread(1); + Common::YieldCPU(); } else VideoFifo_CheckSwapRequest(); + s_beginFieldArgs.xfbAddr = xfbAddr; + s_beginFieldArgs.field = field; + s_beginFieldArgs.fbWidth = fbWidth; + s_beginFieldArgs.fbHeight = fbHeight; + + Common::AtomicStoreRelease(s_swapRequested, TRUE); } - DEBUGGER_LOG_AT(NEXT_XFB_CMD,{printf("Begin Field: %08x, %d x %d\n",xfbAddr,fbWidth,fbHeight);}); } void Video_EndField() @@ -413,24 +424,27 @@ void VideoFifo_CheckEFBAccess() u32 Video_AccessEFB(EFBAccessType type, u32 x, u32 y) { - if (!g_ActiveConfig.bEFBAccessEnable) - return 0; - - s_accessEFBArgs.type = type; - s_accessEFBArgs.x = x; - s_accessEFBArgs.y = y; - - Common::AtomicStoreRelease(s_efbAccessRequested, TRUE); - - if (g_VideoInitialize.bOnThread) + if (s_PluginInitialized) { - while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown) - Common::YieldCPU(); - } - else - VideoFifo_CheckEFBAccess(); + s_accessEFBArgs.type = type; + s_accessEFBArgs.x = x; + s_accessEFBArgs.y = y; - return s_AccessEFBResult; + Common::AtomicStoreRelease(s_efbAccessRequested, TRUE); + + if (g_VideoInitialize.bOnThread) + { + while (Common::AtomicLoadAcquire(s_efbAccessRequested) && !s_FifoShuttingDown) + Common::SleepCurrentThread(1); + //Common::YieldCPU(); + } + else + VideoFifo_CheckEFBAccess(); + + return s_AccessEFBResult; + } + + return 0; } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/resource.h b/Source/Plugins/Plugin_VideoDX9/Src/resource.h index 9e0f268472..d1807ab7e3 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/resource.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/resource.h @@ -32,7 +32,10 @@ #define IDC_TEXFMT_OVERLAY 1024 #define IDC_TEXFMT_CENTER 1025 #define IDC_FORCEFILTERING 1026 +#define IDC_ENABLEXFB 1026 #define IDC_FORCEANISOTROPY 1027 +#define IDC_ENABLEXFB2 1027 +#define IDC_ENABLEREALXFB 1027 #define IDC_LOADHIRESTEXTURE 1028 #define IDC_EFBSCALEDCOPY 1029 #define IDC_OSDHOTKEY 1030 diff --git a/Source/Plugins/Plugin_VideoDX9/Src/resource.rc b/Source/Plugins/Plugin_VideoDX9/Src/resource.rc index de2f64fae3..286b1f313a 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/resource.rc +++ b/Source/Plugins/Plugin_VideoDX9/Src/resource.rc @@ -67,23 +67,25 @@ IDD_ADVANCED DIALOGEX 0, 0, 244, 200 STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD | WS_BORDER | WS_SYSMENU FONT 8, "MS Shell Dlg", 0, 0, 0x0 BEGIN - GROUPBOX "&Settings",IDC_STATIC,6,7,228,67 + GROUPBOX "&Settings",IDC_STATIC,6,7,228,89 CONTROL "Overlay FPS counter",IDC_OVERLAYFPS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,18,82,8 - CONTROL "&Overlay some statistics",IDC_OVERLAYSTATS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,137,90,8 + CONTROL "&Overlay some statistics",IDC_OVERLAYSTATS,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,155,90,8 CONTROL "Show s&hader compilation errors",IDC_SHOWSHADERERRORS, - "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,151,114,8 + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,169,114,8 CONTROL "Enable &Wireframe",IDC_WIREFRAME,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,48,87,8 CONTROL "Disable Fog",IDC_DISABLEFOG,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,18,78,8 CONTROL "Enable Hotkey",IDC_OSDHOTKEY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,33,87,8 CONTROL "Enable EFB copy",IDC_ENABLEEFBCOPY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,33,81,8 CONTROL "To RAM",IDC_EFBTORAM,"Button",BS_AUTORADIOBUTTON | WS_GROUP,29,44,59,10 CONTROL "To Texture",IDC_EFBTOTEX,"Button",BS_AUTORADIOBUTTON,29,57,60,10 - GROUPBOX "&Data dumping",IDC_STATIC,7,79,228,41 - CONTROL "Dump &textures",IDC_TEXDUMP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,92,70,9 - CONTROL "Dump Frames to User/Dump/Frames",IDC_DUMPFRAMES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,106,138,9 - GROUPBOX "Debugging Tools",IDC_STATIC,7,125,228,70 - CONTROL "Enable TexFmt Overlay",IDC_TEXFMT_OVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,164,92,10 - CONTROL "Centered",IDC_TEXFMT_CENTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,29,177,52,10 + GROUPBOX "&Data dumping",IDC_STATIC,7,100,228,41 + CONTROL "Dump &textures",IDC_TEXDUMP,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,111,70,9 + CONTROL "Dump Frames to User/Dump/Frames",IDC_DUMPFRAMES,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,125,138,9 + GROUPBOX "Debugging Tools",IDC_STATIC,7,143,228,51 + CONTROL "Enable TexFmt Overlay",IDC_TEXFMT_OVERLAY,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,182,92,10 + CONTROL "Centered",IDC_TEXFMT_CENTER,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,183,52,10 + CONTROL "Enable XFB",IDC_ENABLEXFB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,14,71,81,8 + CONTROL "Enable Real XFB",IDC_ENABLEREALXFB,"Button",BS_AUTOCHECKBOX | WS_TABSTOP,114,71,81,8 END IDD_ENHANCEMENTS DIALOGEX 0, 0, 224, 175