diff --git a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp index fffde7b7b2..a64230bed6 100644 --- a/Source/Core/VideoCommon/Src/TextureCacheBase.cpp +++ b/Source/Core/VideoCommon/Src/TextureCacheBase.cpp @@ -27,15 +27,6 @@ TextureCache *g_texture_cache; u8 *TextureCache::temp; TextureCache::TexCache TextureCache::textures; -// returns the exponent of the smallest power of two which is greater than val -unsigned int GetPow2(unsigned int val) -{ - unsigned int ret = 0; - for (; val; val >>= 1) - ++ret; - return ret; -} - TextureCache::TCacheEntryBase::~TCacheEntryBase() { if (0 == addr) diff --git a/Source/Core/VideoCommon/Src/VideoCommon.h b/Source/Core/VideoCommon/Src/VideoCommon.h index ab79bdcbef..d22ba2eb17 100644 --- a/Source/Core/VideoCommon/Src/VideoCommon.h +++ b/Source/Core/VideoCommon/Src/VideoCommon.h @@ -181,4 +181,13 @@ inline u32 Z24ToZ16ToZ24(u32 src) return (src & 0xFFFF00) | (src >> 16); } +// returns the exponent of the smallest power of two which is greater than val +static unsigned int GetPow2(unsigned int val) +{ + unsigned int ret = 0; + for (; val; val >>= 1) + ++ret; + return ret; +} + #endif // _VIDEOCOMMON_H diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp index 0f0c84266a..7a007cb1d8 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.cpp @@ -20,6 +20,7 @@ #include "Render.h" #include "XFStructs.h" #include "StringUtil.h" +#include "VideoCommon.h" // D3DX HINSTANCE hD3DXDll = NULL; @@ -434,6 +435,29 @@ const D3DCAPS9 &GetCaps() return caps; } +// returns true if size was changed +bool FixTextureSize(int& width, int& height) +{ + int oldw = width, oldh = height; + + // conditional nonpow2 support should work fine for us + if ((caps.TextureCaps & D3DPTEXTURECAPS_POW2) && !(caps.TextureCaps & D3DPTEXTURECAPS_NONPOW2CONDITIONAL)) + { + // all texture dimensions need to be powers of two + width = GetPow2(width); + height = GetPow2(height); + } + if (caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) + { + width = height = max(width, height); + } + + width = min(width, (int)caps.MaxTextureWidth); + height = min(height, (int)caps.MaxTextureHeight); + + return (width != oldw) || (height != oldh); +} + const char *VertexShaderVersionString() { static const char *versions[5] = {"ERROR", "vs_1_4", "vs_2_0", "vs_3_0", "vs_4_0"}; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h index 533978a46c..f24f323bb8 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DBase.h @@ -71,6 +71,9 @@ const char *PixelShaderVersionString(); const char *VertexShaderVersionString(); void ShowD3DError(HRESULT err); +// returns true if size was changed +bool FixTextureSize(int& width, int& height); + // The following are "filtered" versions of the corresponding D3Ddev-> functions. void SetTexture(DWORD Stage, IDirect3DBaseTexture9 *pTexture); void SetRenderState(D3DRENDERSTATETYPE State, DWORD Value); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp index a9696591d2..5763989dc8 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp @@ -192,9 +192,6 @@ const int TS[6][2] = {D3DTSS_ALPHAARG2, D3DTA_DIFFUSE }, }; -static LPDIRECT3DPIXELSHADER9 ps_old = NULL; -static LPDIRECT3DVERTEXSHADER9 vs_old = NULL; - void RestoreShaders() { D3D::SetTexture(0, 0); @@ -339,22 +336,6 @@ int CD3DFont::DrawTextScaled(float x, float y, float fXScale, float fYScale, flo return S_OK; } -void quad2d(float x1, float y1, float x2, float y2, u32 color, float u1, float v1, float u2, float v2) -{ - struct Q2DVertex { float x,y,z,rhw;u32 color;float u,v,w,h; } coords[4] = { - {x1-0.5f, y1-0.5f, 0, 1, color, u1, v1}, - {x2-0.5f, y1-0.5f, 0, 1, color, u2, v1}, - {x2-0.5f, y2-0.5f, 0, 1, color, u2, v2}, - {x1-0.5f, y2-0.5f, 0, 1, color, u1, v2}, - }; - dev->SetPixelShader(0); - dev->SetVertexShader(0); - dev->SetVertexDeclaration(NULL); - dev->SetFVF(D3DFVF_XYZRHW | D3DFVF_DIFFUSE | D3DFVF_TEX1); - dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(Q2DVertex)); - RestoreShaders(); -} - /* Explanation of texture copying via drawShadedTexQuad and drawShadedTexSubQuad: From MSDN: "When rendering 2D output using pre-transformed vertices, care must be taken to ensure that each texel area correctly corresponds diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp index ccb7c9fc52..8b92944ea5 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp @@ -33,25 +33,6 @@ FramebufferManager::Efb FramebufferManager::s_efb; FramebufferManager::FramebufferManager() { - s_efb.color_texture = NULL; - s_efb.colorRead_texture = NULL; - s_efb.depth_texture = NULL; - s_efb.depthRead_texture = NULL; - - s_efb.depth_surface = NULL; - s_efb.color_surface = NULL; - s_efb.color_ReadBuffer = NULL; - s_efb.depth_ReadBuffer = NULL; - s_efb.color_OffScreenReadBuffer = NULL; - s_efb.depth_OffScreenReadBuffer = NULL; - - s_efb.color_reinterpret_texture = NULL; - s_efb.color_reinterpret_surface = NULL; - - s_efb.color_surface_Format = D3DFMT_FORCE_DWORD; - s_efb.depth_surface_Format = D3DFMT_FORCE_DWORD; - s_efb.depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD; - // Simplest possible setup to start with. int target_width = Renderer::GetFullTargetWidth(); int target_height = Renderer::GetFullTargetHeight(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h index 72c60d2911..7d83b78f4f 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h @@ -105,6 +105,13 @@ private: static struct Efb { + Efb() : color_texture(NULL), colorRead_texture(NULL), depth_texture(NULL), depthRead_texture(NULL), + color_reinterpret_texture(NULL), color_reinterpret_surface(NULL), + depth_surface(NULL), color_surface(NULL), color_ReadBuffer(NULL), depth_ReadBuffer(NULL), + color_OffScreenReadBuffer(NULL), depth_OffScreenReadBuffer(NULL), + color_surface_Format(D3DFMT_UNKNOWN), depth_surface_Format(D3DFMT_UNKNOWN), + depth_ReadBuffer_Format(D3DFMT_UNKNOWN) {} + LPDIRECT3DTEXTURE9 color_texture;//Texture thats contains the color data of the render target LPDIRECT3DTEXTURE9 colorRead_texture;//1 pixel texture for temporal data store LPDIRECT3DTEXTURE9 depth_texture;//Texture thats contains the depth data of the render target diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index dff22bb627..8001f93202 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -283,13 +283,16 @@ Renderer::Renderer() ComputeDrawRectangle(s_backbuffer_width, s_backbuffer_height, false, &dst_rect); CalculateXYScale(dst_rect); - + s_LastAA = g_ActiveConfig.iMultisampleMode; int SupersampleCoeficient = s_LastAA + 1; s_LastEFBScale = g_ActiveConfig.iEFBScale; CalculateTargetSize(SupersampleCoeficient); - + + // Make sure to use valid texture sizes + D3D::FixTextureSize(s_Fulltarget_width, s_Fulltarget_height); + s_bLastFrameDumped = false; s_bAVIDumping = false; @@ -317,8 +320,8 @@ Renderer::Renderer() D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface()); D3D::dev->SetDepthStencilSurface(FramebufferManager::GetEFBDepthRTSurface()); - vp.X = (s_Fulltarget_width - s_target_width) / 2; - vp.Y = (s_Fulltarget_height - s_target_height) / 2; + vp.X = TargetStrideX(); + vp.Y = TargetStrideY(); vp.Width = s_target_width; vp.Height = s_target_height; D3D::dev->SetViewport(&vp); @@ -766,18 +769,24 @@ void Renderer::UpdateViewport() } if (sizeChanged) { - D3DCAPS9 caps = D3D::GetCaps(); - // Make sure that the requested size is actually supported by the GFX driver - if (Renderer::GetFullTargetWidth() > (int)caps.MaxTextureWidth || Renderer::GetFullTargetHeight() > (int)caps.MaxTextureHeight) - { - // Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least - ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D9. Requested EFB size is %dx%d, keeping the %dx%d EFB now\n", Renderer::GetFullTargetWidth(), Renderer::GetFullTargetHeight(), old_fulltarget_w, old_fulltarget_h); + const int ideal_width = s_Fulltarget_width; + const int ideal_height = s_Fulltarget_height; - // Fix the viewport to fit to the old EFB size - X *= (old_fulltarget_w-1) / (Renderer::GetFullTargetWidth()-1); - Y *= (old_fulltarget_h-1) / (Renderer::GetFullTargetHeight()-1); - Width *= (old_fulltarget_w-1) / (Renderer::GetFullTargetWidth()-1); - Height *= (old_fulltarget_h-1) / (Renderer::GetFullTargetHeight()-1); + // Make sure that the requested size is actually supported by the GFX driver + D3D::FixTextureSize(s_Fulltarget_width, s_Fulltarget_height); + + // If the new EFB size is big enough for the requested viewport, we just recreate the internal buffer. + // Otherwise we use a hack to make the viewport fit into the smaller buffer by rendering at a lower resolution. + if (s_Fulltarget_width < ideal_width || s_Fulltarget_height < ideal_height) + { + // HACK: Skip EFB recreation and viewport setting. Most likely causes glitches in this case, but prevents crashes at least + ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D9. Requested EFB size is %dx%d, keeping the %dx%d EFB now\n", ideal_width, ideal_height, old_fulltarget_w, old_fulltarget_h); + + // Modify the viewport to fit to the old EFB size (effectively makes us render at a lower resolution) + X = X * old_fulltarget_w / ideal_width; + Y = Y * old_fulltarget_h / ideal_height; + Width = Width * old_fulltarget_w / ideal_width; + Height = Height * old_fulltarget_h / ideal_height; s_Fulltarget_width = old_fulltarget_w; s_Fulltarget_height = old_fulltarget_h; @@ -786,7 +795,7 @@ void Renderer::UpdateViewport() { D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); - + delete g_framebuffer_manager; g_framebuffer_manager = new FramebufferManager; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp index 627e6e0f4b..c5d7d13349 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp @@ -83,7 +83,7 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleB texture->GetSurfaceLevel(0, &Rendersurf); D3D::dev->SetDepthStencilSurface(NULL); D3D::dev->SetRenderTarget(0, Rendersurf); - + D3DVIEWPORT9 vp; // Stretch picture with increased internal resolution