From ff917cb0c93354deb08ffa32a37ffdf3b90610ff Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 11 Jul 2010 16:26:46 +0000 Subject: [PATCH] DX9/DX11: Workaround the viewpoint/EFB creation issues in e.g. SMG2 on NVIDIA hardware or when using HD. Will most likely cause glitches, but prevents crashing. Correct behavior can't be implemented in Direct3D, so this is the best option we have. Also two little changes which don't affect functionality or performance: Change an IUnknown* cast to a T* cast. Improve some error messages. git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5870 8ced0084-cf51-0410-be5f-012b33b47a6e --- .../Plugins/Plugin_VideoDX11/Src/D3DBase.cpp | 21 +++++++++++++++++++ Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h | 2 ++ .../Plugins/Plugin_VideoDX11/Src/GfxState.cpp | 2 +- .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 12 +++++++++++ .../Src/FramebufferManager.cpp | 4 ++-- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 13 ++++++++++++ 6 files changed, 51 insertions(+), 3 deletions(-) diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp index 8a04f454c6..cfbca35f65 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.cpp @@ -238,6 +238,27 @@ unsigned int GetBackBufferHeight() { return yres; } bool BGRATexturesSupported() { return bgra_textures_supported; } +// Returns the maximum width/height of a texture. This value only depends upon the feature level in DX11 +unsigned int GetMaxTextureSize() +{ + switch (featlevel) + { + case D3D_FEATURE_LEVEL_11_0: + return 16384; + + case D3D_FEATURE_LEVEL_10_1: + case D3D_FEATURE_LEVEL_10_0: + return 8192; + + case D3D_FEATURE_LEVEL_9_3: + return 4096; + + case D3D_FEATURE_LEVEL_9_2: + case D3D_FEATURE_LEVEL_9_1: + return 2048; + } +} + void Reset() { // release all back buffer references diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h index efcd7c1438..c1a70c803f 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DBase.h @@ -51,6 +51,8 @@ const char* PixelShaderVersionString(); const char* VertexShaderVersionString(); bool BGRATexturesSupported(); +unsigned int GetMaxTextureSize(); + // Ihis function will assign a name to the given resource. // The DirectX debug layer will make it easier to identify resources that way, // e.g. when listing up all resources who have unreleased references. diff --git a/Source/Plugins/Plugin_VideoDX11/Src/GfxState.cpp b/Source/Plugins/Plugin_VideoDX11/Src/GfxState.cpp index 218afd6c9f..8ce9d41255 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/GfxState.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/GfxState.cpp @@ -311,7 +311,7 @@ template AutoState::AutoState(const T* object) : state(object) template AutoState::AutoState(const AutoState &source) { state = source.GetPtr(); - ((IUnknown*)state)->AddRef(); + ((T*)state)->AddRef(); } template AutoState::~AutoState() diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index fd38ef53dd..1ab07b4130 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -700,6 +700,9 @@ void UpdateViewport() // [3] = xorig + width/2 + 342 // [4] = yorig + height/2 + 342 // [5] = 16777215 * farz + const int old_fulltarget_w = s_Fulltarget_width; + const int old_fulltarget_h = s_Fulltarget_height; + int scissorXOff = bpmem.scissorOffset.x * 2; int scissorYOff = bpmem.scissorOffset.y * 2; @@ -739,6 +742,15 @@ void UpdateViewport() } if (sizeChanged) { + // Make sure that the requested size is actually supported by the GFX driver + if (s_Fulltarget_width > (int)D3D::GetMaxTextureSize() || s_Fulltarget_height > (int)D3D::GetMaxTextureSize()) + { + // Skip EFB recreation and viewport setting. Most likely cause glitches in this case, but prevents crashes at least + ERROR_LOG(VIDEO, "Tried to set a viewport which is too wide to emulate with Direct3D11. Requested EFB size is %dx%d\n", s_Fulltarget_width, s_Fulltarget_height); + s_Fulltarget_width = old_fulltarget_w; + s_Fulltarget_height = old_fulltarget_h; + return; + } D3D::context->OMSetRenderTargets(1, &D3D::GetBackBuffer()->GetRTV(), NULL); FBManager.Destroy(); FBManager.Create(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp index 4ea68869bc..cebcd00211 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp @@ -97,7 +97,7 @@ void FramebufferManager::Create() { hr = s_efb_color_texture->GetSurfaceLevel(0, &s_efb_color_surface); } - CHECK(hr, "Create Color Texture (hr=%#x)", hr); + CHECK(hr, "Create Color Texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, s_efb_color_surface_Format, D3DPOOL_DEFAULT, &s_efb_colorRead_texture, NULL); CHECK(hr, "Create Color Read Texture (hr=%#x)", hr); @@ -128,7 +128,7 @@ void FramebufferManager::Create() if (!FAILED(hr)) break; } - CHECK(hr, "Depth Color Texture (hr=%#x)", hr); + CHECK(hr, "Depth Color Texture (size: %dx%d; hr=%#x)", target_width, target_height, hr); // Get the Surface if(s_efb_depth_texture) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index ad8ccfc62e..65fd01aa52 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -823,6 +823,9 @@ void UpdateViewport() // [3] = xorig + width/2 + 342 // [4] = yorig + height/2 + 342 // [5] = 16777215 * farz + const int old_fulltarget_w = s_Fulltarget_width; + const int old_fulltarget_h = s_Fulltarget_height; + int scissorXOff = bpmem.scissorOffset.x * 2; int scissorYOff = bpmem.scissorOffset.y * 2; @@ -877,6 +880,16 @@ void UpdateViewport() } if (sizeChanged) { + D3DCAPS9 caps = D3D::GetCaps(); + // Make sure that the requested size is actually supported by the GFX driver + if (s_Fulltarget_width > caps.MaxTextureWidth || s_Fulltarget_height > caps.MaxTextureHeight) + { + // Skip EFB recreation and viewport setting. Most likely cause 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\n", s_Fulltarget_width, s_Fulltarget_height); + s_Fulltarget_width = old_fulltarget_w; + s_Fulltarget_height = old_fulltarget_h; + return; + } D3D::dev->SetRenderTarget(0, D3D::GetBackBufferSurface()); D3D::dev->SetDepthStencilSurface(D3D::GetBackBufferDepthSurface()); FBManager.Destroy();