From ef75d9665548d1096f50e6a106a926e2f3994f5d Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Fri, 22 Oct 2010 19:40:05 +0000 Subject: [PATCH] Main change: Implemented EFB pokes in DX9/DX11. Games affected by this change: Mario Smash Football, Mario Strikers Charged Football, Monster Hunter Tri. Other games possibly affected: Shaun White Snowboarding, Resident Evil Code: Veronica, Baten Kaitos. This implementation will decrease performance if the game uses this feature, but the glitches will be gone. I'll add an option for this in a later commit. EFB pokes are somewhat slow in DX11 right now, speed should be okayish in DX9 though. Other changes: - SOMEWHAT cleaned up the EFB access code in DX9 - Fixed incompatible parameter list of AccessEFB and TVideo_AccessEFB. - Fixed a theoretical bug in ReplaceRGBATexture2D, add support for STAGING textures - Removed unused parameters in various DX9 functions git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6300 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/VideoCommon/Src/Render.h | 2 +- .../Plugin_VideoDX11/Src/D3DTexture.cpp | 4 +- .../Plugins/Plugin_VideoDX11/Src/D3DUtil.cpp | 57 ++++- Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.h | 3 +- .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 90 +++++--- Source/Plugins/Plugin_VideoDX11/Src/main.cpp | 2 +- .../Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp | 19 ++ Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h | 4 +- .../Src/FramebufferManager.cpp | 8 +- .../Plugin_VideoDX9/Src/FramebufferManager.h | 4 +- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 211 ++++++++---------- .../Plugin_VideoDX9/Src/TextureCache.cpp | 4 +- .../Plugin_VideoDX9/Src/TextureConverter.cpp | 2 +- Source/Plugins/Plugin_VideoDX9/Src/main.cpp | 2 +- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 2 +- Source/Plugins/Plugin_VideoOGL/Src/main.cpp | 2 +- 16 files changed, 248 insertions(+), 168 deletions(-) diff --git a/Source/Core/VideoCommon/Src/Render.h b/Source/Core/VideoCommon/Src/Render.h index 90184bc4ef..53ae09c4c6 100644 --- a/Source/Core/VideoCommon/Src/Render.h +++ b/Source/Core/VideoCommon/Src/Render.h @@ -79,7 +79,7 @@ public: static TargetRectangle ConvertEFBRectangle(const EFBRectangle& rc); - static u32 AccessEFB(EFBAccessType type, int x, int y); + static u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data); // Random utilities static void RenderText(const char* pstr, int left, int top, u32 color); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DTexture.cpp b/Source/Plugins/Plugin_VideoDX11/Src/D3DTexture.cpp index b666c1a599..38b9fe4431 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/D3DTexture.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DTexture.cpp @@ -24,7 +24,7 @@ namespace D3D void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned int width, unsigned int height, unsigned int pitch, unsigned int level, D3D11_USAGE usage) { - if (usage == D3D11_USAGE_DYNAMIC) + if (usage == D3D11_USAGE_DYNAMIC || usage == D3D11_USAGE_STAGING) { D3D11_MAPPED_SUBRESOURCE map; D3D::context->Map(pTexture, level, D3D11_MAP_WRITE_DISCARD, 0, &map); @@ -35,7 +35,7 @@ void ReplaceRGBATexture2D(ID3D11Texture2D* pTexture, const u8* buffer, unsigned else { for (unsigned int y = 0; y < height; ++y) - memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, map.RowPitch); + memcpy((u8*)map.pData + y * map.RowPitch, (u32*)buffer + y * pitch, 4 * pitch); } D3D::context->Unmap(pTexture, level); } diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.cpp b/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.cpp index 6ebc2e17bc..9aed9264ef 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.cpp @@ -429,11 +429,13 @@ ID3D11SamplerState* linear_copy_sampler = NULL; ID3D11SamplerState* point_copy_sampler = NULL; ID3D11Buffer* stqvb = NULL; ID3D11Buffer* stsqvb = NULL; +ID3D11Buffer* quadvb = NULL; ID3D11Buffer* clearvb = NULL; typedef struct { float x,y,z,u,v; } STQVertex; typedef struct { float x,y,z,u,v; } STSQVertex; typedef struct { float x,y,z; u32 col; } ClearVertex; +typedef struct { float x,y,z; u32 col; } ColVertex; struct { @@ -446,6 +448,12 @@ struct float u1, v1, u2, v2; } tex_sub_quad_data; +struct +{ + float x1, y1, x2, y2; + u32 col; +} draw_quad_data; + struct { u32 col; @@ -468,6 +476,7 @@ void InitUtils() // cached data used to avoid unnecessarily reloading the vertex buffers memset(&tex_quad_data, 0, sizeof(tex_quad_data)); memset(&tex_sub_quad_data, 0, sizeof(tex_sub_quad_data)); + memset(&draw_quad_data, 0, sizeof(draw_quad_data)); memset(&clear_quad_data, 0, sizeof(clear_quad_data)); STQVertex stqcoords[4] = { @@ -480,6 +489,9 @@ void InitUtils() STSQVertex stsqcoords[4]; memset(stsqcoords, 0, sizeof(stsqcoords)); + ColVertex colcoords[4]; + memset(colcoords, 0, sizeof(colcoords)); + ClearVertex cqcoords[4] = { {-1.0f, 1.0f, 0, 0}, { 1.0f, 1.0f, 0, 0}, @@ -495,6 +507,10 @@ void InitUtils() CHECK(stsqvb!=NULL, "Create vertex buffer of drawShadedTexSubQuad"); SetDebugObjectName((ID3D11DeviceChild*)stsqvb, "vertex buffer of drawShadedTexSubQuad"); + quadvb = CreateQuadVertexBuffer(4*sizeof(ColVertex), colcoords); + CHECK(quadvb!=NULL, "Create vertex buffer of drawColorQuad"); + SetDebugObjectName((ID3D11DeviceChild*)quadvb, "vertex buffer of drawColorQuad"); + clearvb = CreateQuadVertexBuffer(4*sizeof(ClearVertex), cqcoords); CHECK(clearvb!=NULL, "Create vertex buffer of drawClearQuad"); SetDebugObjectName((ID3D11DeviceChild*)clearvb, "vertex buffer of drawClearQuad"); @@ -509,6 +525,7 @@ void ShutdownUtils() SAFE_RELEASE(linear_copy_sampler); SAFE_RELEASE(stqvb); SAFE_RELEASE(stsqvb); + SAFE_RELEASE(quadvb); SAFE_RELEASE(clearvb); } @@ -627,6 +644,45 @@ void drawShadedTexSubQuad(ID3D11ShaderResourceView* texture, context->PSSetShaderResources(0, 1, &texres); // immediately unbind the texture } +// Fills a certain area of the current render target with the specified color +// destination coordinates normalized to (-1;1) +void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2) +{ + if(draw_quad_data.x1 != x1 || draw_quad_data.y1 != y1 || + draw_quad_data.x2 != x2 || draw_quad_data.y2 != y2 || + draw_quad_data.col != Color) + { + ColVertex coords[4] = { + { x1, y2, 0.f, Color }, + { x2, y2, 0.f, Color }, + { x1, y1, 0.f, Color }, + { x2, y1, 0.f, Color }, + }; + + D3D11_MAPPED_SUBRESOURCE map; + context->Map(quadvb, 0, D3D11_MAP_WRITE_DISCARD, 0, &map); + memcpy(map.pData, coords, sizeof(coords)); + context->Unmap(quadvb, 0); + + draw_quad_data.x1 = x1; + draw_quad_data.y1 = y1; + draw_quad_data.x2 = x2; + draw_quad_data.y2 = y2; + draw_quad_data.col = Color; + } + + context->VSSetShader(VertexShaderCache::GetClearVertexShader(), NULL, 0); + context->PSSetShader(PixelShaderCache::GetClearProgram(), NULL, 0); + context->IASetInputLayout(VertexShaderCache::GetClearInputLayout()); + + UINT stride = sizeof(ColVertex); + UINT offset = 0; + context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); + context->IASetVertexBuffers(0, 1, &quadvb, &stride, &offset); + + context->Draw(4, 0); +} + void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout) { if (clear_quad_data.col != Color || clear_quad_data.z != z) @@ -657,5 +713,4 @@ void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexS context->Draw(4, 0); } - } // namespace diff --git a/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.h b/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.h index 05b7f0c4d0..b8fa15a907 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.h +++ b/Source/Plugins/Plugin_VideoDX11/Src/D3DUtil.h @@ -80,6 +80,5 @@ namespace D3D ID3D11VertexShader* Vshader, ID3D11InputLayout* layout); void drawClearQuad(u32 Color, float z, ID3D11PixelShader* PShader, ID3D11VertexShader* Vshader, ID3D11InputLayout* layout); - void SaveRenderStates(); - void RestoreRenderStates(); + void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2); } diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index 4219536a15..55860052a4 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -594,19 +594,19 @@ void Renderer::SetColorMask() D3D::gfxstate->SetRenderTargetWriteMask(color_mask); } -u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) +u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { + D3D11_MAPPED_SUBRESOURCE map; ID3D11Texture2D* read_tex; - u32 ret = 0; if (!g_ActiveConfig.bEFBAccessEnable) return 0; - if (type == POKE_Z || type == POKE_COLOR) + if (type == POKE_Z) { static bool alert_only_once = true; if (!alert_only_once) return 0; - PanicAlert("Poke EFB not implemented"); + PanicAlert("EFB: Poke Z not implemented (tried to poke z value %#x at (%d,%d))", poke_data, x, y); alert_only_once = false; return 0; } @@ -619,12 +619,23 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) efbPixelRc.bottom = y + 1; TargetRectangle targetPixelRc = Renderer::ConvertEFBRectangle(efbPixelRc); - // Take the mean of the resulting dimensions; TODO: check whether this causes any bugs compared to taking the average color of the target area + // Take the mean of the resulting dimensions; TODO: Don't use the center pixel, compute the average color instead D3D11_RECT RectToLock; - RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2; - RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2; - RectToLock.right = RectToLock.left + 1; - RectToLock.bottom = RectToLock.top + 1; + if(type == PEEK_COLOR || type == PEEK_Z) + { + RectToLock.left = (targetPixelRc.left + targetPixelRc.right) / 2; + RectToLock.top = (targetPixelRc.top + targetPixelRc.bottom) / 2; + RectToLock.right = RectToLock.left + 1; + RectToLock.bottom = RectToLock.top + 1; + } + else + { + RectToLock.left = targetPixelRc.left; + RectToLock.right = targetPixelRc.right; + RectToLock.top = targetPixelRc.top; + RectToLock.bottom = targetPixelRc.bottom; + } + if (type == PEEK_Z) { ResetAPIState(); // Reset any game specific settings @@ -651,40 +662,59 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, g_framebufferManager.GetEFBDepthReadTexture()->GetTex(), 0, &box); RestoreAPIState(); // restore game state + + // read the data from system memory + D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map); + + float val = *(float*)map.pData; + u32 ret = ((u32)(val * 0xffffff)); + D3D::context->Unmap(read_tex, 0); + + // TODO: in RE0 this value is often off by one in Video_DX9 (where this code is derived from), which causes lighting to disappear + return ret; } - else + else if (type == PEEK_COLOR) { // we can directly copy to system memory here read_tex = g_framebufferManager.GetEFBColorStagingBuffer(); D3D11_BOX box = CD3D11_BOX(RectToLock.left, RectToLock.top, 0, RectToLock.right, RectToLock.bottom, 1); D3D::context->CopySubresourceRegion(read_tex, 0, 0, 0, 0, g_framebufferManager.GetEFBColorTexture()->GetTex(), 0, &box); + + // read the data from system memory + D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map); + u32 ret = *(u32*)map.pData; + D3D::context->Unmap(read_tex, 0); + return ret; } - - // read the data from system memory - D3D11_MAPPED_SUBRESOURCE map; - D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map); - - switch(type) + else //if(type == POKE_COLOR) { - case PEEK_Z: + // TODO: Speed this up by batching pokes? + // If we're only writing one pixel (native resolution), we can directly copy the data into the target. TODO: Check if this is faster than drawing quads + u32 rgbaColor = (poke_data & 0xFF00FF00) | ((poke_data >> 16) & 0xFF) | ((poke_data << 16) & 0xFF0000); + if(RectToLock.right <= RectToLock.left + 1 && RectToLock.bottom <= RectToLock.top + 1) { - float val = *(float*)map.pData; - ret = ((u32)(val * 0xffffff)); - break; + D3D::context->Map(g_framebufferManager.GetEFBColorStagingBuffer(), 0, D3D11_MAP_WRITE, 0, &map); + *(u32*)map.pData = rgbaColor; + D3D::context->Unmap(g_framebufferManager.GetEFBColorStagingBuffer(), 0); + + D3D11_BOX box = CD3D11_BOX(0, 0, 0, 1, 1, 1); + D3D::context->CopySubresourceRegion(g_framebufferManager.GetEFBColorTexture()->GetTex(), 0, RectToLock.left, RectToLock.top, 0, g_framebufferManager.GetEFBColorStagingBuffer(), 0, &box); + return 0; } + else + { + ResetAPIState(); // Reset any game specific settings - case PEEK_COLOR: - ret = *(u32*)map.pData; - break; + D3D::context->OMSetRenderTargets(1, &g_framebufferManager.GetEFBColorTexture()->GetRTV(), NULL); + D3D::drawColorQuad(rgbaColor, (float)RectToLock.left * 2.f / (float)Renderer::GetFullTargetWidth() - 1.f, + - (float)RectToLock.top * 2.f / (float)Renderer::GetFullTargetHeight() + 1.f, + (float)RectToLock.right * 2.f / (float)Renderer::GetFullTargetWidth() - 1.f, + - (float)RectToLock.bottom * 2.f / (float)Renderer::GetFullTargetHeight() + 1.f); - default: - // TODO: Implement POKE_Z and POKE_COLOR - break; + RestoreAPIState(); + return 0; + } } - - D3D::context->Unmap(read_tex, 0); - // TODO: in RE0 this value is often off by one in Video_DX9 (where this code is derived from), which causes lighting to disappear - return ret; } // Called from VertexShaderManager diff --git a/Source/Plugins/Plugin_VideoDX11/Src/main.cpp b/Source/Plugins/Plugin_VideoDX11/Src/main.cpp index b11940b2d9..ce8511dda2 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/main.cpp @@ -378,7 +378,7 @@ void VideoFifo_CheckEFBAccess() { if (Common::AtomicLoadAcquire(s_efbAccessRequested)) { - s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y); + s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y, s_accessEFBArgs.Data); Common::AtomicStoreRelease(s_efbAccessRequested, FALSE); } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp index 195a10166f..85234e5681 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.cpp @@ -21,6 +21,8 @@ #include "D3DBase.h" #include "D3DUtil.h" #include "Render.h" +#include "PixelShaderCache.h" +#include "VertexShaderCache.h" namespace D3D { @@ -423,6 +425,23 @@ void drawShadedTexSubQuad(IDirect3DTexture9 *texture, RestoreShaders(); } +// Fills a certain area of the current render target with the specified color +// Z buffer disabled; destination coordinates normalized to (-1;1) +void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2) +{ + struct CQVertex { float x, y, z, rhw; u32 col; } coords[4] = { + { x1, y2, 0.f, 1.f, Color }, + { x2, y2, 0.f, 1.f, Color }, + { x1, y1, 0.f, 1.f, Color }, + { x2, y1, 0.f, 1.f, Color }, + }; + dev->SetVertexShader(VertexShaderCache::GetClearVertexShader()); + dev->SetPixelShader(PixelShaderCache::GetClearProgram()); + dev->SetFVF(D3DFVF_XYZW | D3DFVF_DIFFUSE); + dev->DrawPrimitiveUP(D3DPT_TRIANGLEFAN, 2, coords, sizeof(CQVertex)); + 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 fe7adb214d..c71b7ab35e 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/D3DUtil.h @@ -77,7 +77,9 @@ namespace D3D int DestHeight, IDirect3DPixelShader9 *PShader, IDirect3DVertexShader9 *Vshader); - void drawClearQuad(u32 Color,float z,IDirect3DPixelShader9 *PShader,IDirect3DVertexShader9 *Vshader); + void drawClearQuad(u32 Color, float z, IDirect3DPixelShader9 *PShader, IDirect3DVertexShader9 *Vshader); + void drawColorQuad(u32 Color, float x1, float y1, float x2, float y2); + void SaveRenderStates(); void RestoreRenderStates(); } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp index ab83304b82..85b4b724f7 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.cpp @@ -73,12 +73,12 @@ D3DFORMAT FramebufferManager::GetEFBColorRTSurfaceFormat() return s_efb_color_surface_Format; } -LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture(const EFBRectangle& sourceRc) +LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBColorTexture() { return s_efb_color_texture; } -LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture(const EFBRectangle &sourceRc) +LPDIRECT3DTEXTURE9 FramebufferManager::GetEFBDepthTexture() { return s_efb_depth_texture; } @@ -305,7 +305,7 @@ void FramebufferManager::copyToRealXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, c } TargetRectangle targetRc = Renderer::ConvertEFBRectangle(sourceRc); - TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(sourceRc), targetRc, xfb_in_ram, fbWidth, fbHeight); + TextureConverter::EncodeToRamYUYV(GetEFBColorTexture(), targetRc, xfb_in_ram, fbWidth, fbHeight); } void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc) @@ -395,7 +395,7 @@ void FramebufferManager::copyToVirtualXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight // Copy EFB data to XFB and restore render target again if(!xfbTexture) return; - LPDIRECT3DTEXTURE9 read_texture = GetEFBColorTexture(sourceRc); + LPDIRECT3DTEXTURE9 read_texture = GetEFBColorTexture(); Renderer::ResetAPIState(); // Reset any game specific settings LPDIRECT3DSURFACE9 Rendersurf = NULL; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h index bed3c53acf..a3bcea3c09 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h +++ b/Source/Plugins/Plugin_VideoDX9/Src/FramebufferManager.h @@ -109,8 +109,8 @@ public: 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); + LPDIRECT3DTEXTURE9 GetEFBColorTexture(); + LPDIRECT3DTEXTURE9 GetEFBDepthTexture(); LPDIRECT3DSURFACE9 GetEFBColorRTSurface(); LPDIRECT3DSURFACE9 GetEFBDepthRTSurface(); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 8161d03315..050bdfd7f1 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -691,46 +691,45 @@ void Renderer::SetColorMask() D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask); } -u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) +u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { if (!g_ActiveConfig.bEFBAccessEnable) return 0; - if (type == POKE_Z || type == POKE_COLOR) + if (type == POKE_Z) { static bool alert_only_once = true; if (!alert_only_once) return 0; - PanicAlert("Poke EFB not implemented"); + PanicAlert("EFB: Poke Z not implemented (tried to poke z value %#x at (%d,%d))", poke_data, x, y); alert_only_once = false; return 0; } - // Get the working buffer - LPDIRECT3DSURFACE9 pBuffer = (type == PEEK_Z || type == POKE_Z) ? - g_framebufferManager.GetEFBDepthRTSurface() : g_framebufferManager.GetEFBColorRTSurface(); - // Get the temporal buffer to move 1pixel data - LPDIRECT3DSURFACE9 RBuffer = (type == PEEK_Z || type == POKE_Z) ? - g_framebufferManager.GetEFBDepthReadSurface() : g_framebufferManager.GetEFBColorReadSurface(); - // Get the memory buffer that can be locked - LPDIRECT3DSURFACE9 pOffScreenBuffer = (type == PEEK_Z || type == POKE_Z) ? - g_framebufferManager.GetEFBDepthOffScreenRTSurface() : g_framebufferManager.GetEFBColorOffScreenRTSurface(); - // Get the buffer format - D3DFORMAT BufferFormat = (type == PEEK_Z || type == POKE_Z) ? - g_framebufferManager.GetEFBDepthRTSurfaceFormat() : g_framebufferManager.GetEFBColorRTSurfaceFormat(); - D3DFORMAT ReadBufferFormat = (type == PEEK_Z || type == POKE_Z) ? - g_framebufferManager.GetEFBDepthReadSurfaceFormat() : BufferFormat; - - if (BufferFormat == D3DFMT_D24X8) - return 0; + // We're using three surfaces here: + // - pEFBSurf: EFB Surface. Source surface when peeking, destination surface when poking. + // - pBufferRT: A render target surface. When peeking, we render a textured quad to this surface. + // - pSystemBuf: An offscreen surface. Used to retrieve the pixel data from pBufferRT. + LPDIRECT3DSURFACE9 pEFBSurf, pBufferRT, pSystemBuf; + if(type == PEEK_Z || type == POKE_Z) + { + pEFBSurf = g_framebufferManager.GetEFBDepthRTSurface(); + pBufferRT = g_framebufferManager.GetEFBDepthReadSurface(); + pSystemBuf = g_framebufferManager.GetEFBDepthOffScreenRTSurface(); + } + else //if(type == PEEK_COLOR || type == POKE_COLOR) + { + pEFBSurf = g_framebufferManager.GetEFBColorRTSurface(); + pBufferRT = g_framebufferManager.GetEFBColorReadSurface(); + pSystemBuf = g_framebufferManager.GetEFBColorOffScreenRTSurface(); + } - D3DLOCKED_RECT drect; - // Buffer not found alert - if (!pBuffer) { + if (!pEFBSurf) { PanicAlert("No %s!", (type == PEEK_Z || type == POKE_Z) ? "Z-Buffer" : "Color EFB"); return 0; } - // Get the rectangular target region covered by the EFB pixel + + // Convert EFB dimensions to the ones of our render target EFBRectangle efbPixelRc; efbPixelRc.left = x; efbPixelRc.top = y; @@ -740,7 +739,6 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc); u32 z = 0; - float val = 0.0f; HRESULT hr; RECT RectToLock; RectToLock.bottom = targetPixelRc.bottom; @@ -749,6 +747,9 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) RectToLock.top = targetPixelRc.top; if (type == PEEK_Z) { + if (g_framebufferManager.GetEFBDepthRTSurfaceFormat() == D3DFMT_D24X8) + return 0; + RECT PixelRect; PixelRect.bottom = 4; PixelRect.left = 0; @@ -764,131 +765,105 @@ u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) RectToLock.left++; ResetAPIState(); // Reset any game specific settings - hr = D3D::dev->SetDepthStencilSurface(NULL); - hr = D3D::dev->SetRenderTarget(0, RBuffer); - if (FAILED(hr)) - { - PanicAlert("unable to set pixel render buffer"); - return 0; - } - D3DVIEWPORT9 vp; + D3D::dev->SetDepthStencilSurface(NULL); + D3D::dev->SetRenderTarget(0, pBufferRT); + // Stretch picture with increased internal resolution + D3DVIEWPORT9 vp; vp.X = 0; vp.Y = 0; vp.Width = 4; vp.Height = 4; vp.MinZ = 0.0f; vp.MaxZ = 1.0f; - hr = D3D::dev->SetViewport(&vp); - if (FAILED(hr)) - { - PanicAlert("unable to set pixel viewport"); - return 0; - } + D3D::dev->SetViewport(&vp); + float colmat[16] = {0.0f}; float fConstAdd[4] = {0.0f}; colmat[0] = colmat[5] = colmat[10] = 1.0f; PixelShaderManager::SetColorMatrix(colmat, fConstAdd); // set transformation - EFBRectangle source_rect; - LPDIRECT3DTEXTURE9 read_texture = g_framebufferManager.GetEFBDepthTexture(source_rect); + LPDIRECT3DTEXTURE9 read_texture = g_framebufferManager.GetEFBDepthTexture(); D3D::ChangeSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_POINT); D3D::drawShadedTexQuad( - read_texture, - &RectToLock, - Renderer::GetFullTargetWidth(), - Renderer::GetFullTargetHeight(), - 4, 4, - (BufferFormat == FOURCC_RAWZ) ? PixelShaderCache::GetColorMatrixProgram(0) : PixelShaderCache::GetDepthMatrixProgram(0), + read_texture, + &RectToLock, + Renderer::GetFullTargetWidth(), + Renderer::GetFullTargetHeight(), + 4, 4, + (g_framebufferManager.GetEFBDepthRTSurfaceFormat() == FOURCC_RAWZ) ? PixelShaderCache::GetColorMatrixProgram(0) : PixelShaderCache::GetDepthMatrixProgram(0), VertexShaderCache::GetSimpleVertexShader(0)); D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); - hr = D3D::dev->SetRenderTarget(0, g_framebufferManager.GetEFBColorRTSurface()); - hr = D3D::dev->SetDepthStencilSurface(g_framebufferManager.GetEFBDepthRTSurface()); + D3D::dev->SetRenderTarget(0, g_framebufferManager.GetEFBColorRTSurface()); + D3D::dev->SetDepthStencilSurface(g_framebufferManager.GetEFBDepthRTSurface()); RestoreAPIState(); + + // Retrieve the pixel data to the local memory buffer RectToLock.bottom = 4; RectToLock.left = 0; RectToLock.right = 4; RectToLock.top = 0; + D3D::dev->GetRenderTargetData(pBufferRT, pSystemBuf); + + // EFB data successfully retrieved, now get the pixel data + D3DLOCKED_RECT drect; + pSystemBuf->LockRect(&drect, &RectToLock, D3DLOCK_READONLY); + + float val = 0.0f; + + switch (g_framebufferManager.GetEFBDepthReadSurfaceFormat()) + { + case D3DFMT_R32F: + val = ((float*)drect.pBits)[6]; + break; + default: + float ffrac = 1.0f/255.0f; + z = ((u32*)drect.pBits)[6]; + val = ((float)((z>>16) & 0xFF)) * ffrac; + ffrac*= 1 / 255.0f; + val += ((float)((z>>8) & 0xFF)) * ffrac; + ffrac*= 1 / 255.0f; + val += ((float)(z & 0xFF)) * ffrac; + break; + }; + z = ((u32)(val * 0xffffff)); + + pSystemBuf->UnlockRect(); + // TODO: in RE0 this value is often off by one, which causes lighting to disappear + return z; } - else + else if(type == PEEK_COLOR) { - hr = D3D::dev->StretchRect(pBuffer, &RectToLock, RBuffer, NULL, D3DTEXF_NONE); - //change the rect to lock the entire one pixel buffer + // TODO: Can't we directly StretchRect to System buf? + hr = D3D::dev->StretchRect(pEFBSurf, &RectToLock, pBufferRT, NULL, D3DTEXF_NONE); + D3D::dev->GetRenderTargetData(pBufferRT, pSystemBuf); + + // EFB data successfully retrieved, now get the pixel data RectToLock.bottom = 1; RectToLock.left = 0; RectToLock.right = 1; RectToLock.top = 0; - } - if (FAILED(hr)) - { - PanicAlert("Unable to stretch data to buffer"); - return 0; - } - // Retrieve the pixel data to the local memory buffer - D3D::dev->GetRenderTargetData(RBuffer, pOffScreenBuffer); - if (FAILED(hr)) - { - PanicAlert("Unable to copy data to mem buffer"); - return 0; - } + D3DLOCKED_RECT drect; + pSystemBuf->LockRect(&drect, &RectToLock, D3DLOCK_READONLY); - - // The surface is good.. lock it - if ((hr = pOffScreenBuffer->LockRect(&drect, &RectToLock, D3DLOCK_READONLY)) != D3D_OK) - { - PanicAlert("ERROR: %s", hr == D3DERR_WASSTILLDRAWING ? "Still drawing" : hr == D3DERR_INVALIDCALL ? "Invalid call" : "w00t"); - return 0; - } - - switch (type) - { - case PEEK_Z: - { - switch (ReadBufferFormat) - { - case D3DFMT_R32F: - val = ((float*)drect.pBits)[6]; - break; - default: - float ffrac = 1.0f/255.0f; - z = ((u32*)drect.pBits)[6]; - val = ((float)((z>>16) & 0xFF)) * ffrac; - ffrac*= 1 / 255.0f; - val += ((float)((z>>8) & 0xFF)) * ffrac; - ffrac*= 1 / 255.0f; - val += ((float)(z & 0xFF)) * ffrac; - break; - }; - z = ((u32)(val * 0xffffff)); - } - break; - - case POKE_Z: - // TODO: Implement - break; - - case PEEK_COLOR: z = ((u32*)drect.pBits)[0]; - break; - - case POKE_COLOR: - // TODO: Implement. One way is to draw a tiny pixel-sized rectangle at - // the exact location. Note: EFB pokes are susceptible to Z-buffering - // and perhaps blending. - //WARN_LOG(VIDEOINTERFACE, "This is probably some kind of software rendering"); - break; - - // TODO: Implement POKE_Z and POKE_COLOR - default: - break; + pSystemBuf->UnlockRect(); + return z; + } + else //if(type == POKE_COLOR) + { + // TODO: Speed this up by batching pokes? + ResetAPIState(); + D3D::drawColorQuad(poke_data, (float)RectToLock.left * 2.f / (float)Renderer::GetFullTargetWidth() - 1.f, + - (float)RectToLock.top * 2.f / (float)Renderer::GetFullTargetHeight() + 1.f, + (float)RectToLock.right * 2.f / (float)Renderer::GetFullTargetWidth() - 1.f, + - (float)RectToLock.bottom * 2.f / (float)Renderer::GetFullTargetHeight() + 1.f); + RestoreAPIState(); + return 0; } - - pOffScreenBuffer->UnlockRect(); - // TODO: in RE0 this value is often off by one, which causes lighting to disappear - return z; } // Called from VertexShaderManager @@ -1190,7 +1165,7 @@ void Renderer::Swap(u32 xfbAddr, FieldType field, u32 fbWidth, u32 fbHeight,cons else { TargetRectangle targetRc = ConvertEFBRectangle(rc); - LPDIRECT3DTEXTURE9 read_texture = g_framebufferManager.GetEFBColorTexture(rc); + LPDIRECT3DTEXTURE9 read_texture = g_framebufferManager.GetEFBColorTexture(); D3D::drawShadedTexQuad(read_texture,targetRc.AsRECT(),Renderer::GetFullTargetWidth(),Renderer::GetFullTargetHeight(),Width,Height,PixelShaderCache::GetColorCopyProgram(g_Config.iMultisampleMode),VertexShaderCache::GetSimpleVertexShader(g_Config.iMultisampleMode)); } D3D::RefreshSamplerState(0, D3DSAMP_MINFILTER); diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp index 3b5133def7..5a289e1895 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureCache.cpp @@ -74,8 +74,8 @@ void TextureCache::TCacheEntry::FromRenderTarget(bool bFromZBuffer, bool bScaleB bool bIsIntensityFmt, u32 copyfmt) { const LPDIRECT3DTEXTURE9 read_texture = bFromZBuffer ? - g_framebufferManager.GetEFBDepthTexture(source_rect) : - g_framebufferManager.GetEFBColorTexture(source_rect); + g_framebufferManager.GetEFBDepthTexture() : + g_framebufferManager.GetEFBColorTexture(); if (!isDynamic || g_ActiveConfig.bCopyEFBToTexture) { diff --git a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp index e424edbf70..3e9d25c476 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/TextureConverter.cpp @@ -325,7 +325,7 @@ void EncodeToRam(u32 address, bool bFromZBuffer, bool bIsIntensityFmt, u32 copyf u8 *dest_ptr = Memory_GetPtr(address); - LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? g_framebufferManager.GetEFBDepthTexture(source) : g_framebufferManager.GetEFBColorTexture(source); + LPDIRECT3DTEXTURE9 source_texture = bFromZBuffer ? g_framebufferManager.GetEFBDepthTexture() : g_framebufferManager.GetEFBColorTexture(); int width = (source.right - source.left) >> bScaleByHalf; int height = (source.bottom - source.top) >> bScaleByHalf; diff --git a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp index a67d0853f5..bee4f86c7e 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/main.cpp @@ -400,7 +400,7 @@ void VideoFifo_CheckEFBAccess() { if (Common::AtomicLoadAcquire(s_efbAccessRequested)) { - s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y); + s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y, s_accessEFBArgs.Data); Common::AtomicStoreRelease(s_efbAccessRequested, FALSE); } diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 6d62777904..b9882f1087 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -854,7 +854,7 @@ void Renderer::SetColorMask() glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask); } -u32 Renderer::AccessEFB(EFBAccessType type, int x, int y) +u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { if (!g_ActiveConfig.bEFBAccessEnable) return 0; diff --git a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp index b25f1482b6..002b88458f 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/main.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/main.cpp @@ -430,7 +430,7 @@ void VideoFifo_CheckEFBAccess() { if (Common::AtomicLoadAcquire(s_efbAccessRequested)) { - s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y); + s_AccessEFBResult = Renderer::AccessEFB(s_accessEFBArgs.type, s_accessEFBArgs.x, s_accessEFBArgs.y, s_accessEFBArgs.Data); Common::AtomicStoreRelease(s_efbAccessRequested, FALSE); }