From ab53c84dcf7fa791c778a868866dd006e5dfa50d Mon Sep 17 00:00:00 2001 From: NeoBrainX Date: Sun, 24 Oct 2010 19:52:52 +0000 Subject: [PATCH] Properly emulate the alpha read pixel engine register function (used for EFB peeks). git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6313 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/VideoCommon/Src/PixelEngine.cpp | 11 ---- Source/Core/VideoCommon/Src/PixelEngine.h | 11 ++++ .../Plugins/Plugin_VideoDX11/Src/Render.cpp | 54 +++++++++++-------- Source/Plugins/Plugin_VideoDX9/Src/Render.cpp | 27 ++++++++-- Source/Plugins/Plugin_VideoOGL/Src/Render.cpp | 22 +++++++- 5 files changed, 87 insertions(+), 38 deletions(-) diff --git a/Source/Core/VideoCommon/Src/PixelEngine.cpp b/Source/Core/VideoCommon/Src/PixelEngine.cpp index 2785d66826..580571b328 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.cpp +++ b/Source/Core/VideoCommon/Src/PixelEngine.cpp @@ -81,17 +81,6 @@ union UPEAlphaModeConfReg }; }; -// Not sure about this reg... -union UPEAlphaReadReg -{ - u16 Hex; - struct - { - u16 ReadMode : 3; - u16 : 13; - }; -}; - // fifo Control Register union UPECtrlReg { diff --git a/Source/Core/VideoCommon/Src/PixelEngine.h b/Source/Core/VideoCommon/Src/PixelEngine.h index 5b773c6c9b..84b30a1bb5 100644 --- a/Source/Core/VideoCommon/Src/PixelEngine.h +++ b/Source/Core/VideoCommon/Src/PixelEngine.h @@ -54,6 +54,17 @@ enum namespace PixelEngine { +// ReadMode specifies the returned alpha channel for EFB peeks +union UPEAlphaReadReg +{ + u16 Hex; + struct + { + u16 ReadMode : 3; + u16 : 13; + }; +}; + void Init(); void DoState(PointerWrap &p); diff --git a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp index 3f5025baa8..97055dedf4 100644 --- a/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX11/Src/Render.cpp @@ -28,6 +28,7 @@ #include "VideoConfig.h" #include "main.h" #include "VertexManager.h" +#include "PixelEngine.h" #include "Render.h" #include "OpcodeDecoding.h" #include "BPStructs.h" @@ -614,6 +615,20 @@ void Renderer::SetColorMask() D3D::gfxstate->SetRenderTargetWriteMask(color_mask); } +// This function allows the CPU to directly access the EFB. +// There are EFB peeks (which will read the color or depth of a pixel) +// and EFB pokes (which will change the color or depth of a pixel). +// +// The behavior of EFB peeks can only be modified by: +// - GX_PokeAlphaRead +// The behavior of EFB pokes can be modified by: +// - GX_PokeAlphaMode (TODO) +// - GX_PokeAlphaUpdate (TODO) +// - GX_PokeBlendMode (TODO) +// - GX_PokeColorUpdate (TODO) +// - GX_PokeDither (TODO) +// - GX_PokeDstAlpha (TODO) +// - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { D3D11_MAPPED_SUBRESOURCE map; @@ -704,36 +719,29 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) D3D::context->Map(read_tex, 0, D3D11_MAP_READ, 0, &map); u32 ret = *(u32*)map.pData; D3D::context->Unmap(read_tex, 0); - return ret; + + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode; + PixelEngine::Read16((u16&)alpha_read_mode, PE_DSTALPHACONF); + if(alpha_read_mode.ReadMode == 2) return ret; // GX_READ_NONE + else if(alpha_read_mode.ReadMode == 1) return (ret | 0xFF000000); // GX_READ_FF + else /*if(alpha_read_mode.ReadMode == 0)*/ return (ret & 0x00FFFFFF); // GX_READ_00 } else //if(type == POKE_COLOR) { - // 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) - { - 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 + // TODO: The first five PE registers may change behavior of EFB pokes, this isn't implemented, yet. + ResetAPIState(); - 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); + 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); - RestoreAPIState(); - return 0; - } + RestoreAPIState(); + return 0; } } diff --git a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp index 050bdfd7f1..96795e81fe 100644 --- a/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoDX9/Src/Render.cpp @@ -30,6 +30,7 @@ #include "VideoConfig.h" #include "main.h" #include "VertexManager.h" +#include "PixelEngine.h" #include "Render.h" #include "OpcodeDecoding.h" #include "BPStructs.h" @@ -691,6 +692,20 @@ void Renderer::SetColorMask() D3D::SetRenderState(D3DRS_COLORWRITEENABLE, color_mask); } +// This function allows the CPU to directly access the EFB. +// There are EFB peeks (which will read the color or depth of a pixel) +// and EFB pokes (which will change the color or depth of a pixel). +// +// The behavior of EFB peeks can only be modified by: +// - GX_PokeAlphaRead +// The behavior of EFB pokes can be modified by: +// - GX_PokeAlphaMode (TODO) +// - GX_PokeAlphaUpdate (TODO) +// - GX_PokeBlendMode (TODO) +// - GX_PokeColorUpdate (TODO) +// - GX_PokeDither (TODO) +// - GX_PokeDstAlpha (TODO) +// - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { if (!g_ActiveConfig.bEFBAccessEnable) @@ -738,7 +753,6 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) TargetRectangle targetPixelRc = ConvertEFBRectangle(efbPixelRc); - u32 z = 0; HRESULT hr; RECT RectToLock; RectToLock.bottom = targetPixelRc.bottom; @@ -813,6 +827,7 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) pSystemBuf->LockRect(&drect, &RectToLock, D3DLOCK_READONLY); float val = 0.0f; + u32 z = 0; switch (g_framebufferManager.GetEFBDepthReadSurfaceFormat()) { @@ -849,9 +864,15 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) D3DLOCKED_RECT drect; pSystemBuf->LockRect(&drect, &RectToLock, D3DLOCK_READONLY); - z = ((u32*)drect.pBits)[0]; + u32 ret = ((u32*)drect.pBits)[0]; pSystemBuf->UnlockRect(); - return z; + + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode; + PixelEngine::Read16((u16&)alpha_read_mode, PE_DSTALPHACONF); + if(alpha_read_mode.ReadMode == 2) return ret; // GX_READ_NONE + else if(alpha_read_mode.ReadMode == 1) return (ret | 0xFF000000); // GX_READ_FF + else /*if(alpha_read_mode.ReadMode == 0)*/ return (ret & 0x00FFFFFF); // GX_READ_00 } else //if(type == POKE_COLOR) { diff --git a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp index 3f51031597..d4dede65d7 100644 --- a/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp +++ b/Source/Plugins/Plugin_VideoOGL/Src/Render.cpp @@ -36,6 +36,7 @@ #include "Profiler.h" #include "Statistics.h" #include "ImageWrite.h" +#include "PixelEngine.h" #include "Render.h" #include "OpcodeDecoding.h" #include "BPStructs.h" @@ -854,6 +855,20 @@ void Renderer::SetColorMask() glColorMask(ColorMask, ColorMask, ColorMask, AlphaMask); } +// This function allows the CPU to directly access the EFB. +// There are EFB peeks (which will read the color or depth of a pixel) +// and EFB pokes (which will change the color or depth of a pixel). +// +// The behavior of EFB peeks can only be modified by: +// - GX_PokeAlphaRead +// The behavior of EFB pokes can be modified by: +// - GX_PokeAlphaMode (TODO) +// - GX_PokeAlphaUpdate (TODO) +// - GX_PokeBlendMode (TODO) +// - GX_PokeColorUpdate (TODO) +// - GX_PokeDither (TODO) +// - GX_PokeDstAlpha (TODO) +// - GX_PokeZMode (TODO) u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) { if (!g_ActiveConfig.bEFBAccessEnable) @@ -922,7 +937,12 @@ u32 Renderer::AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) glReadPixels(srcX, srcY, 1, 1, GL_BGRA, GL_UNSIGNED_INT_8_8_8_8_REV, &color); GL_REPORT_ERRORD(); - return color; + // check what to do with the alpha channel (GX_PokeAlphaRead) + PixelEngine::UPEAlphaReadReg alpha_read_mode; + PixelEngine::Read16((u16&)alpha_read_mode, PE_DSTALPHACONF); + if(alpha_read_mode.ReadMode == 2) return color; // GX_READ_NONE + else if(alpha_read_mode.ReadMode == 1) return (color | 0xFF000000); // GX_READ_FF + else /*if(alpha_read_mode.ReadMode == 0)*/ return (color & 0x00FFFFFF); // GX_READ_00 } case POKE_COLOR: