Implement pixel data reinterpretation on EFB format change.
Whatever that means, it fixes that stupid Super Mario Sunshine glitch and possibly lots of other stuff, so test as many glitchy games as possible with this ;) git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@6669 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
6e8df50fff
commit
a271bb8182
|
@ -134,6 +134,63 @@ void ClearScreen(const BPCmd &bp, const EFBRectangle &rc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void OnPixelFormatChange(const BPCmd &bp)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* When changing the EFB format, the pixel data won't get converted to the new format but stays the same.
|
||||||
|
* Since we are always using an RGBA8 buffer though, this causes issues in some games.
|
||||||
|
* Thus, we reinterpret the old EFB data with the new format here.
|
||||||
|
*/
|
||||||
|
if (!g_ActiveConfig.bEFBEmulateFormatChanges ||
|
||||||
|
!g_ActiveConfig.backend_info.bSupportsFormatReinterpretation)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int new_format = bpmem.zcontrol.pixel_format;
|
||||||
|
int old_format = Renderer::GetPrevPixelFormat();
|
||||||
|
|
||||||
|
// no need to reinterpret pixel data in these cases
|
||||||
|
if (new_format == old_format || old_format == (unsigned int)-1)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
int convtype = -1;
|
||||||
|
switch (old_format)
|
||||||
|
{
|
||||||
|
case PIXELFMT_RGB8_Z24:
|
||||||
|
case PIXELFMT_Z24:
|
||||||
|
// Z24 and RGB8_Z24 are treated equal, so just return in this case
|
||||||
|
if (new_format == PIXELFMT_RGB565_Z16 || new_format == PIXELFMT_Z24)
|
||||||
|
goto skip;
|
||||||
|
|
||||||
|
if (new_format == PIXELFMT_RGBA6_Z24)
|
||||||
|
convtype = 0;
|
||||||
|
else if (new_format == PIXELFMT_RGB565_Z16)
|
||||||
|
convtype = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIXELFMT_RGBA6_Z24:
|
||||||
|
if (new_format == PIXELFMT_RGB8_Z24 ||
|
||||||
|
new_format == PIXELFMT_Z24)
|
||||||
|
convtype = 2;
|
||||||
|
else if (new_format == PIXELFMT_RGB565_Z16)
|
||||||
|
convtype = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case PIXELFMT_RGB565_Z16:
|
||||||
|
if (new_format == PIXELFMT_RGB8_Z24 ||
|
||||||
|
new_format == PIXELFMT_Z24)
|
||||||
|
convtype = 4;
|
||||||
|
else if (new_format == PIXELFMT_RGB565_Z16)
|
||||||
|
convtype = 5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
PanicAlert("Unhandled EFB format change: %d to %d\n", old_format, new_format);
|
||||||
|
goto skip;
|
||||||
|
}
|
||||||
|
g_renderer->ReinterpretPixelData(convtype);
|
||||||
|
skip:
|
||||||
|
Renderer::StorePixelFormat(new_format);
|
||||||
|
}
|
||||||
|
|
||||||
void RestoreRenderState(const BPCmd &bp)
|
void RestoreRenderState(const BPCmd &bp)
|
||||||
{
|
{
|
||||||
|
|
|
@ -47,6 +47,7 @@ void SetLogicOpMode(const BPCmd &bp);
|
||||||
void SetColorMask(const BPCmd &bp);
|
void SetColorMask(const BPCmd &bp);
|
||||||
void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const int &scaleByHalf);
|
void CopyEFB(const BPCmd &bp, const EFBRectangle &rc, const u32 &address, const bool &fromZBuffer, const bool &isIntensityFmt, const u32 ©fmt, const int &scaleByHalf);
|
||||||
void ClearScreen(const BPCmd &bp, const EFBRectangle &rc);
|
void ClearScreen(const BPCmd &bp, const EFBRectangle &rc);
|
||||||
|
void OnPixelFormatChange(const BPCmd &bp);
|
||||||
void RestoreRenderState(const BPCmd &bp);
|
void RestoreRenderState(const BPCmd &bp);
|
||||||
u8 *GetPointer(const u32 &address);
|
u8 *GetPointer(const u32 &address);
|
||||||
bool GetConfig(const int &type);
|
bool GetConfig(const int &type);
|
||||||
|
|
|
@ -422,7 +422,12 @@ void BPWritten(const BPCmd& bp)
|
||||||
break;
|
break;
|
||||||
case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow
|
case BPMEM_TEXINVALIDATE: // Used, if game has manual control the Texture Cache, which we don't allow
|
||||||
DEBUG_LOG(VIDEO, "BP Texture Invalid: %08x", bp.newvalue);
|
DEBUG_LOG(VIDEO, "BP Texture Invalid: %08x", bp.newvalue);
|
||||||
|
break;
|
||||||
|
|
||||||
case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
|
case BPMEM_ZCOMPARE: // Set the Z-Compare and EFB pixel format
|
||||||
|
OnPixelFormatChange(bp);
|
||||||
|
break;
|
||||||
|
|
||||||
case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel
|
case BPMEM_MIPMAP_STRIDE: // MipMap Stride Channel
|
||||||
case BPMEM_COPYYSCALE: // Display Copy Y Scale
|
case BPMEM_COPYYSCALE: // Display Copy Y Scale
|
||||||
case BPMEM_IREF: /* 24 RID
|
case BPMEM_IREF: /* 24 RID
|
||||||
|
|
|
@ -77,6 +77,8 @@ int Renderer::s_LastEFBScale;
|
||||||
bool Renderer::s_skipSwap;
|
bool Renderer::s_skipSwap;
|
||||||
bool Renderer::XFBWrited;
|
bool Renderer::XFBWrited;
|
||||||
|
|
||||||
|
unsigned int Renderer::prev_efb_format = (unsigned int)-1;
|
||||||
|
|
||||||
Renderer::Renderer()
|
Renderer::Renderer()
|
||||||
{
|
{
|
||||||
UpdateActiveConfig();
|
UpdateActiveConfig();
|
||||||
|
@ -84,7 +86,8 @@ Renderer::Renderer()
|
||||||
|
|
||||||
Renderer::~Renderer()
|
Renderer::~Renderer()
|
||||||
{
|
{
|
||||||
|
// invalidate previous efb format
|
||||||
|
prev_efb_format = (unsigned int)-1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
|
void Renderer::RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma)
|
||||||
|
|
|
@ -110,6 +110,7 @@ public:
|
||||||
virtual void RenderText(const char* pstr, int left, int top, u32 color) = 0;
|
virtual void RenderText(const char* pstr, int left, int top, u32 color) = 0;
|
||||||
|
|
||||||
virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0;
|
virtual void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z) = 0;
|
||||||
|
virtual void ReinterpretPixelData(unsigned int convtype) = 0;
|
||||||
static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma = 1.0f);
|
static void RenderToXFB(u32 xfbAddr, u32 fbWidth, u32 fbHeight, const EFBRectangle& sourceRc,float Gamma = 1.0f);
|
||||||
|
|
||||||
virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) = 0;
|
virtual u32 AccessEFB(EFBAccessType type, u32 x, u32 y, u32 poke_data) = 0;
|
||||||
|
@ -125,6 +126,9 @@ public:
|
||||||
|
|
||||||
virtual bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) = 0;
|
virtual bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc) = 0;
|
||||||
|
|
||||||
|
static unsigned int GetPrevPixelFormat() { return prev_efb_format; }
|
||||||
|
static void StorePixelFormat(unsigned int new_format) { prev_efb_format = new_format; }
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
static Common::CriticalSection s_criticalScreenshot;
|
static Common::CriticalSection s_criticalScreenshot;
|
||||||
|
@ -159,6 +163,9 @@ protected:
|
||||||
|
|
||||||
static bool s_skipSwap;
|
static bool s_skipSwap;
|
||||||
static bool XFBWrited;
|
static bool XFBWrited;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static unsigned int prev_efb_format;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern Renderer *g_renderer;
|
extern Renderer *g_renderer;
|
||||||
|
|
|
@ -109,6 +109,7 @@ void VideoConfig::Load(const char *ini_file)
|
||||||
iniFile.Get("Hacks", "EFBToTextureEnable", &bCopyEFBToTexture, false);
|
iniFile.Get("Hacks", "EFBToTextureEnable", &bCopyEFBToTexture, false);
|
||||||
iniFile.Get("Hacks", "EFBScaledCopy", &bCopyEFBScaled, true);
|
iniFile.Get("Hacks", "EFBScaledCopy", &bCopyEFBScaled, true);
|
||||||
iniFile.Get("Hacks", "EFBCopyCacheEnable", &bEFBCopyCacheEnable, false);
|
iniFile.Get("Hacks", "EFBCopyCacheEnable", &bEFBCopyCacheEnable, false);
|
||||||
|
iniFile.Get("Hacks", "EFBEmulateFormatChanges", &bEFBEmulateFormatChanges, true);
|
||||||
iniFile.Get("Hacks", "ProjectionHack", &iPhackvalue, 0);
|
iniFile.Get("Hacks", "ProjectionHack", &iPhackvalue, 0);
|
||||||
|
|
||||||
iniFile.Get("Hardware", "Adapter", &iAdapter, 0);
|
iniFile.Get("Hardware", "Adapter", &iAdapter, 0);
|
||||||
|
@ -226,6 +227,7 @@ void VideoConfig::Save(const char *ini_file)
|
||||||
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
|
iniFile.Set("Hacks", "EFBToTextureEnable", bCopyEFBToTexture);
|
||||||
iniFile.Set("Hacks", "EFBScaledCopy", bCopyEFBScaled);
|
iniFile.Set("Hacks", "EFBScaledCopy", bCopyEFBScaled);
|
||||||
iniFile.Set("Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
|
iniFile.Set("Hacks", "EFBCopyCacheEnable", bEFBCopyCacheEnable);
|
||||||
|
iniFile.Set("Hacks", "EFBEmulateFormatChanges", bEFBEmulateFormatChanges);
|
||||||
iniFile.Set("Hacks", "ProjectionHack", iPhackvalue);
|
iniFile.Set("Hacks", "ProjectionHack", iPhackvalue);
|
||||||
|
|
||||||
iniFile.Set("Hardware", "Adapter", iAdapter);
|
iniFile.Set("Hardware", "Adapter", iAdapter);
|
||||||
|
|
|
@ -119,6 +119,7 @@ struct VideoConfig
|
||||||
bool bDlistCachingEnable;
|
bool bDlistCachingEnable;
|
||||||
bool bEFBCopyEnable;
|
bool bEFBCopyEnable;
|
||||||
bool bEFBCopyCacheEnable;
|
bool bEFBCopyCacheEnable;
|
||||||
|
bool bEFBEmulateFormatChanges;
|
||||||
bool bOSDHotKey;
|
bool bOSDHotKey;
|
||||||
bool bHack;
|
bool bHack;
|
||||||
bool bCopyEFBToTexture;
|
bool bCopyEFBToTexture;
|
||||||
|
@ -159,6 +160,7 @@ struct VideoConfig
|
||||||
bool bSupports3DVision;
|
bool bSupports3DVision;
|
||||||
bool bAllowSignedBytes; // D3D9 doesn't support signed bytes (?)
|
bool bAllowSignedBytes; // D3D9 doesn't support signed bytes (?)
|
||||||
bool bSupportsDualSourceBlend; // only supported by D3D11 and OpenGL
|
bool bSupportsDualSourceBlend; // only supported by D3D11 and OpenGL
|
||||||
|
bool bSupportsFormatReinterpretation;
|
||||||
} backend_info;
|
} backend_info;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,7 @@ wxString force_filtering_tooltip = wxT("Forces bilinear texture filtering even i
|
||||||
wxString _3d_vision_tooltip = wxT("");
|
wxString _3d_vision_tooltip = wxT("");
|
||||||
wxString internal_res_tooltip = wxT("Specifies the resolution used to render at. A high resolution will improve visual quality but is also quite heavy on performance and might cause glitches in certain games.\nFractional: Uses your display resolution directly instead of the native resolution. The quality scales with your display/window size, as does the performance impact.\nIntegral: This is like Fractional, but rounds up to an integer multiple of the native resolution. Should give a more accurate look but is usually slower.\nThe other options are fixed resolutions for choosing a visual quality independent of your display size.");
|
wxString internal_res_tooltip = wxT("Specifies the resolution used to render at. A high resolution will improve visual quality but is also quite heavy on performance and might cause glitches in certain games.\nFractional: Uses your display resolution directly instead of the native resolution. The quality scales with your display/window size, as does the performance impact.\nIntegral: This is like Fractional, but rounds up to an integer multiple of the native resolution. Should give a more accurate look but is usually slower.\nThe other options are fixed resolutions for choosing a visual quality independent of your display size.");
|
||||||
wxString efb_access_tooltip = wxT("Allows the CPU to read or write to the EFB (render buffer).\nThis is needed for certain gameplay functionality (e.g. star pointer in Super Mario Galaxy) as well as for certain visual effects (e.g. Monster Hunter Tri),\nbut enabling this option can also have a huge negative impact on performance if the game uses this functionality heavily.");
|
wxString efb_access_tooltip = wxT("Allows the CPU to read or write to the EFB (render buffer).\nThis is needed for certain gameplay functionality (e.g. star pointer in Super Mario Galaxy) as well as for certain visual effects (e.g. Monster Hunter Tri),\nbut enabling this option can also have a huge negative impact on performance if the game uses this functionality heavily.");
|
||||||
|
wxString efb_emulate_format_changes_tooltip = wxT("Enables reinterpreting the data inside the EFB when the pixel format changes.\nSome games depend on this function for certain effects, so enable it if you're having glitches.\nDepending on how the game uses this function, the speed hits caused by this option range from none to critical.");
|
||||||
wxString efb_copy_tooltip = wxT("Enables emulation of Embedded Frame Buffer copies, if the game uses them.\nGames often need this for post-processing or other things, but if you can live without it, you can sometimes get a big speedup.");
|
wxString efb_copy_tooltip = wxT("Enables emulation of Embedded Frame Buffer copies, if the game uses them.\nGames often need this for post-processing or other things, but if you can live without it, you can sometimes get a big speedup.");
|
||||||
wxString efb_copy_texture_tooltip = wxT("Emulate frame buffer copies directly to textures.\nThis is not so accurate, but it's good enough for the way many games use framebuffer copies.");
|
wxString efb_copy_texture_tooltip = wxT("Emulate frame buffer copies directly to textures.\nThis is not so accurate, but it's good enough for the way many games use framebuffer copies.");
|
||||||
wxString efb_copy_ram_tooltip = wxT("Fully emulate embedded frame buffer copies.\nThis is more accurate than EFB Copy to Texture, and some games need this to work properly, but it can also be very slow.");
|
wxString efb_copy_ram_tooltip = wxT("Fully emulate embedded frame buffer copies.\nThis is more accurate than EFB Copy to Texture, and some games need this to work properly, but it can also be very slow.");
|
||||||
|
@ -243,6 +244,14 @@ VideoConfigDiag::VideoConfigDiag(wxWindow* parent, const std::string &title, con
|
||||||
}
|
}
|
||||||
|
|
||||||
group_efb->Add(new SettingCheckBox(page_general, wxT("Enable CPU Access"), efb_access_tooltip, vconfig.bEFBAccessEnable), 0, wxBOTTOM | wxLEFT, 5);
|
group_efb->Add(new SettingCheckBox(page_general, wxT("Enable CPU Access"), efb_access_tooltip, vconfig.bEFBAccessEnable), 0, wxBOTTOM | wxLEFT, 5);
|
||||||
|
SettingCheckBox *emulate_efb_format_changes = new SettingCheckBox(page_general, wxT("Emulate format changes"), efb_emulate_format_changes_tooltip, vconfig.bEFBEmulateFormatChanges);
|
||||||
|
group_efb->Add(emulate_efb_format_changes, 0, wxBOTTOM | wxLEFT, 5);
|
||||||
|
|
||||||
|
if (!vconfig.backend_info.bSupportsFormatReinterpretation)
|
||||||
|
{
|
||||||
|
emulate_efb_format_changes->SetValue(false);
|
||||||
|
emulate_efb_format_changes->Disable();
|
||||||
|
}
|
||||||
|
|
||||||
// EFB copy
|
// EFB copy
|
||||||
wxStaticBoxSizer* const group_efbcopy = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Copy"));
|
wxStaticBoxSizer* const group_efbcopy = new wxStaticBoxSizer(wxHORIZONTAL, page_general, wxT("Copy"));
|
||||||
|
|
|
@ -744,6 +744,11 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||||
RestoreAPIState();
|
RestoreAPIState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::SetBlendMode(bool forceUpdate)
|
void Renderer::SetBlendMode(bool forceUpdate)
|
||||||
{
|
{
|
||||||
if (bpmem.blendmode.logicopenable && !forceUpdate)
|
if (bpmem.blendmode.logicopenable && !forceUpdate)
|
||||||
|
|
|
@ -37,6 +37,8 @@ public:
|
||||||
|
|
||||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||||
|
|
||||||
|
void ReinterpretPixelData(unsigned int convtype);
|
||||||
|
|
||||||
void UpdateViewport();
|
void UpdateViewport();
|
||||||
|
|
||||||
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
||||||
|
|
|
@ -155,6 +155,7 @@ void InitBackendInfo()
|
||||||
g_Config.backend_info.bSupports3DVision = false;
|
g_Config.backend_info.bSupports3DVision = false;
|
||||||
g_Config.backend_info.bAllowSignedBytes = true;
|
g_Config.backend_info.bAllowSignedBytes = true;
|
||||||
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
g_Config.backend_info.bSupportsDualSourceBlend = true;
|
||||||
|
g_Config.backend_info.bSupportsFormatReinterpretation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DllConfig(void *_hParent)
|
void DllConfig(void *_hParent)
|
||||||
|
|
|
@ -397,7 +397,7 @@ void drawShadedTexQuad(IDirect3DTexture9 *texture,
|
||||||
float u2=((float)rSource->right) * sw;
|
float u2=((float)rSource->right) * sw;
|
||||||
float v1=((float)rSource->top) * sh;
|
float v1=((float)rSource->top) * sh;
|
||||||
float v2=((float)rSource->bottom) * sh;
|
float v2=((float)rSource->bottom) * sh;
|
||||||
float g = 1.0/Gamma;
|
float g = 1.0f/Gamma;
|
||||||
|
|
||||||
struct Q2DVertex { float x,y,z,rhw,u,v,w,h,G; } coords[4] = {
|
struct Q2DVertex { float x,y,z,rhw,u,v,w,h,G; } coords[4] = {
|
||||||
{-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, sw, sh, g},
|
{-1.0f - dw,-1.0f + dh, 0.0f,1.0f, u1, v2, sw, sh, g},
|
||||||
|
@ -432,7 +432,7 @@ void drawShadedTexSubQuad(IDirect3DTexture9 *texture,
|
||||||
float u2= rSource->right * sw;
|
float u2= rSource->right * sw;
|
||||||
float v1= rSource->top * sh;
|
float v1= rSource->top * sh;
|
||||||
float v2= rSource->bottom * sh;
|
float v2= rSource->bottom * sh;
|
||||||
float g = 1.0/Gamma;
|
float g = 1.0f/Gamma;
|
||||||
|
|
||||||
struct Q2DVertex { float x,y,z,rhw,u,v,w,h,G; } coords[4] = {
|
struct Q2DVertex { float x,y,z,rhw,u,v,w,h,G; } coords[4] = {
|
||||||
{ rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, sw, sh, g},
|
{ rDest->left - dw , rDest->top + dh, 1.0f,1.0f, u1, v2, sw, sh, g},
|
||||||
|
|
|
@ -45,6 +45,9 @@ FramebufferManager::FramebufferManager()
|
||||||
s_efb.color_OffScreenReadBuffer = NULL;
|
s_efb.color_OffScreenReadBuffer = NULL;
|
||||||
s_efb.depth_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.color_surface_Format = D3DFMT_FORCE_DWORD;
|
||||||
s_efb.depth_surface_Format = D3DFMT_FORCE_DWORD;
|
s_efb.depth_surface_Format = D3DFMT_FORCE_DWORD;
|
||||||
s_efb.depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD;
|
s_efb.depth_ReadBuffer_Format = D3DFMT_FORCE_DWORD;
|
||||||
|
@ -62,6 +65,7 @@ FramebufferManager::FramebufferManager()
|
||||||
hr = s_efb.color_texture->GetSurfaceLevel(0, &s_efb.color_surface);
|
hr = s_efb.color_texture->GetSurfaceLevel(0, &s_efb.color_surface);
|
||||||
}
|
}
|
||||||
CHECK(hr, "Create color texture (size: %dx%d; hr=%#x)", target_width, target_height, 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,
|
hr = D3D::dev->CreateTexture(1, 1, 1, D3DUSAGE_RENDERTARGET, s_efb.color_surface_Format,
|
||||||
D3DPOOL_DEFAULT, &s_efb.colorRead_texture, NULL);
|
D3DPOOL_DEFAULT, &s_efb.colorRead_texture, NULL);
|
||||||
CHECK(hr, "Create Color Read Texture (hr=%#x)", hr);
|
CHECK(hr, "Create Color Read Texture (hr=%#x)", hr);
|
||||||
|
@ -130,6 +134,15 @@ FramebufferManager::FramebufferManager()
|
||||||
// Create an offscreen surface that we can lock to retrieve the data
|
// Create an offscreen surface that we can lock to retrieve the data
|
||||||
hr = D3D::dev->CreateOffscreenPlainSurface(4, 4, s_efb.depth_ReadBuffer_Format, D3DPOOL_SYSTEMMEM, &s_efb.depth_OffScreenReadBuffer, NULL);
|
hr = D3D::dev->CreateOffscreenPlainSurface(4, 4, s_efb.depth_ReadBuffer_Format, D3DPOOL_SYSTEMMEM, &s_efb.depth_OffScreenReadBuffer, NULL);
|
||||||
CHECK(hr, "Create depth offscreen surface (hr=%#x)", hr);
|
CHECK(hr, "Create depth offscreen surface (hr=%#x)", hr);
|
||||||
|
|
||||||
|
// create resources for ReinterpretPixelData
|
||||||
|
hr = D3D::dev->CreateTexture(target_width, target_height, 1, D3DUSAGE_RENDERTARGET, s_efb.color_surface_Format,
|
||||||
|
D3DPOOL_DEFAULT, &s_efb.color_reinterpret_texture, NULL);
|
||||||
|
if (s_efb.color_reinterpret_texture)
|
||||||
|
{
|
||||||
|
hr = s_efb.color_reinterpret_texture->GetSurfaceLevel(0, &s_efb.color_reinterpret_surface);
|
||||||
|
}
|
||||||
|
CHECK(hr, "Create color reinterpret texture (size: %dx%d; hr=%#x)", target_width, target_height, hr);
|
||||||
}
|
}
|
||||||
|
|
||||||
FramebufferManager::~FramebufferManager()
|
FramebufferManager::~FramebufferManager()
|
||||||
|
@ -144,6 +157,8 @@ FramebufferManager::~FramebufferManager()
|
||||||
SAFE_RELEASE(s_efb.colorRead_texture);
|
SAFE_RELEASE(s_efb.colorRead_texture);
|
||||||
SAFE_RELEASE(s_efb.depth_texture);
|
SAFE_RELEASE(s_efb.depth_texture);
|
||||||
SAFE_RELEASE(s_efb.depthRead_texture);
|
SAFE_RELEASE(s_efb.depthRead_texture);
|
||||||
|
SAFE_RELEASE(s_efb.color_reinterpret_texture);
|
||||||
|
SAFE_RELEASE(s_efb.color_reinterpret_surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
XFBSourceBase* FramebufferManager::CreateXFBSource(unsigned int target_width, unsigned int target_height)
|
||||||
|
|
|
@ -85,6 +85,18 @@ public:
|
||||||
static LPDIRECT3DSURFACE9 GetEFBColorReadSurface() { return s_efb.color_ReadBuffer; }
|
static LPDIRECT3DSURFACE9 GetEFBColorReadSurface() { return s_efb.color_ReadBuffer; }
|
||||||
static LPDIRECT3DSURFACE9 GetEFBDepthReadSurface() { return s_efb.depth_ReadBuffer; }
|
static LPDIRECT3DSURFACE9 GetEFBDepthReadSurface() { return s_efb.depth_ReadBuffer; }
|
||||||
|
|
||||||
|
static LPDIRECT3DTEXTURE9 GetEFBColorReinterpretTexture() { return s_efb.color_reinterpret_texture; }
|
||||||
|
static LPDIRECT3DSURFACE9 GetEFBColorReinterpretSurface() { return s_efb.color_reinterpret_surface; }
|
||||||
|
static void SwapReinterpretTexture()
|
||||||
|
{
|
||||||
|
LPDIRECT3DSURFACE9 swapsurf = GetEFBColorReinterpretSurface();
|
||||||
|
LPDIRECT3DTEXTURE9 swaptex = GetEFBColorReinterpretTexture();
|
||||||
|
s_efb.color_reinterpret_surface = GetEFBColorRTSurface();
|
||||||
|
s_efb.color_reinterpret_texture = GetEFBColorTexture();
|
||||||
|
s_efb.color_surface = swapsurf;
|
||||||
|
s_efb.color_texture = swaptex;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
XFBSourceBase* CreateXFBSource(unsigned int target_width, unsigned int target_height);
|
||||||
void GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc);
|
void GetTargetSize(unsigned int *width, unsigned int *height, const EFBRectangle& sourceRc);
|
||||||
|
@ -98,6 +110,9 @@ private:
|
||||||
LPDIRECT3DTEXTURE9 depth_texture;//Texture thats contains the depth data of the render target
|
LPDIRECT3DTEXTURE9 depth_texture;//Texture thats contains the depth data of the render target
|
||||||
LPDIRECT3DTEXTURE9 depthRead_texture;//4 pixel texture for temporal data store
|
LPDIRECT3DTEXTURE9 depthRead_texture;//4 pixel texture for temporal data store
|
||||||
|
|
||||||
|
LPDIRECT3DTEXTURE9 color_reinterpret_texture;//buffer used for ReinterpretPixelData
|
||||||
|
LPDIRECT3DSURFACE9 color_reinterpret_surface;//corresponding surface
|
||||||
|
|
||||||
LPDIRECT3DSURFACE9 depth_surface;//Depth Surface
|
LPDIRECT3DSURFACE9 depth_surface;//Depth Surface
|
||||||
LPDIRECT3DSURFACE9 color_surface;//Color Surface
|
LPDIRECT3DSURFACE9 color_surface;//Color Surface
|
||||||
LPDIRECT3DSURFACE9 color_ReadBuffer;//Surface 0 of colorRead_texture
|
LPDIRECT3DSURFACE9 color_ReadBuffer;//Surface 0 of colorRead_texture
|
||||||
|
|
|
@ -52,7 +52,9 @@ enum
|
||||||
};
|
};
|
||||||
|
|
||||||
static LPDIRECT3DPIXELSHADER9 s_CopyProgram[NUM_COPY_TYPES][PixelShaderCache::NUM_DEPTH_CONVERSION_TYPES][MAX_SSAA_SHADERS];
|
static LPDIRECT3DPIXELSHADER9 s_CopyProgram[NUM_COPY_TYPES][PixelShaderCache::NUM_DEPTH_CONVERSION_TYPES][MAX_SSAA_SHADERS];
|
||||||
static LPDIRECT3DPIXELSHADER9 s_ClearProgram = 0;
|
static LPDIRECT3DPIXELSHADER9 s_ClearProgram = NULL;
|
||||||
|
static LPDIRECT3DPIXELSHADER9 s_rgba6_to_rgb8 = NULL;
|
||||||
|
static LPDIRECT3DPIXELSHADER9 s_rgb8_to_rgba6 = NULL;
|
||||||
|
|
||||||
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorMatrixProgram(int SSAAMode)
|
LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetColorMatrixProgram(int SSAAMode)
|
||||||
{
|
{
|
||||||
|
@ -74,6 +76,51 @@ LPDIRECT3DPIXELSHADER9 PixelShaderCache::GetClearProgram()
|
||||||
return s_ClearProgram;
|
return s_ClearProgram;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static LPDIRECT3DPIXELSHADER9 s_rgb8 = NULL;
|
||||||
|
static LPDIRECT3DPIXELSHADER9 s_rgba6 = NULL;
|
||||||
|
|
||||||
|
LPDIRECT3DPIXELSHADER9 PixelShaderCache::ReinterpRGBA6ToRGB8()
|
||||||
|
{
|
||||||
|
const char code[] =
|
||||||
|
{
|
||||||
|
"uniform sampler samp0 : register(s0);\n"
|
||||||
|
"void main(\n"
|
||||||
|
" out float4 ocol0 : COLOR0,\n"
|
||||||
|
" in float2 uv0 : TEXCOORD0){\n"
|
||||||
|
" ocol0 = tex2D(samp0,uv0);\n"
|
||||||
|
" float4 src6 = trunc(ocol0 * 63.f);\n"
|
||||||
|
" ocol0.r = src6.r*4.f + trunc(src6.g/16.f);\n" // dst8r = (src6r<<2)|(src6g>>4);
|
||||||
|
" ocol0.g = frac(src6.g/16.f)*16.f*16.f+trunc(src6.b/4.f);\n" // dst8g = ((src6g&0xF)<<4)|(src6b>>2);
|
||||||
|
" ocol0.b = frac(src6.b/4.f)*4.f*64.f+src6.a;\n" // dst8b = ((src6b&0x3)<<6)|src6a;
|
||||||
|
" ocol0.a = 255.f;\n"
|
||||||
|
" ocol0 /= 255.f;\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
if (!s_rgba6_to_rgb8) s_rgba6_to_rgb8 = D3D::CompileAndCreatePixelShader(code, (int)strlen(code));
|
||||||
|
return s_rgba6_to_rgb8;
|
||||||
|
}
|
||||||
|
|
||||||
|
LPDIRECT3DPIXELSHADER9 PixelShaderCache::ReinterpRGB8ToRGBA6()
|
||||||
|
{
|
||||||
|
const char code[] =
|
||||||
|
{
|
||||||
|
"uniform sampler samp0 : register(s0);\n"
|
||||||
|
"void main(\n"
|
||||||
|
" out float4 ocol0 : COLOR0,\n"
|
||||||
|
" in float2 uv0 : TEXCOORD0){\n"
|
||||||
|
" ocol0 = tex2D(samp0,uv0);\n"
|
||||||
|
" float4 src8 = trunc(ocol0*255.f);\n"
|
||||||
|
" ocol0.r = (src8.r/4.f);\n" // dst6r = src8r>>2;
|
||||||
|
" ocol0.g = frac(src8.r/4.f)*4.f*16.f + (src8.g/16.f);\n" // dst6g = ((src8r&0x3)<<4)|(src8g>>4);
|
||||||
|
" ocol0.b = frac(src8.g/16.f)*16.f*4.f + (src8.b/64.f);\n" // dst6b = ((src8g&0xF)<<2)|(src8b>>6);
|
||||||
|
" ocol0.a = frac(src8.b/64.f)*64.f;\n" // dst6a = src8b&0x3F;
|
||||||
|
" ocol0 /= 63.f;\n"
|
||||||
|
"}\n"
|
||||||
|
};
|
||||||
|
if (!s_rgb8_to_rgba6) s_rgb8_to_rgba6 = D3D::CompileAndCreatePixelShader(code, (int)strlen(code));
|
||||||
|
return s_rgb8_to_rgba6;
|
||||||
|
}
|
||||||
|
|
||||||
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
void SetPSConstant4f(unsigned int const_number, float f1, float f2, float f3, float f4)
|
||||||
{
|
{
|
||||||
float f[4] = { f1, f2, f3, f4 };
|
float f[4] = { f1, f2, f3, f4 };
|
||||||
|
@ -263,6 +310,10 @@ void PixelShaderCache::Shutdown()
|
||||||
|
|
||||||
if (s_ClearProgram) s_ClearProgram->Release();
|
if (s_ClearProgram) s_ClearProgram->Release();
|
||||||
s_ClearProgram = NULL;
|
s_ClearProgram = NULL;
|
||||||
|
if (s_rgb8_to_rgba6) s_rgb8_to_rgba6->Release();
|
||||||
|
s_rgb8_to_rgba6 = NULL;
|
||||||
|
if (s_rgba6_to_rgb8) s_rgba6_to_rgb8->Release();
|
||||||
|
s_rgba6_to_rgb8 = NULL;
|
||||||
|
|
||||||
Clear();
|
Clear();
|
||||||
g_ps_disk_cache.Sync();
|
g_ps_disk_cache.Sync();
|
||||||
|
|
|
@ -71,6 +71,8 @@ public:
|
||||||
};
|
};
|
||||||
static LPDIRECT3DPIXELSHADER9 GetDepthMatrixProgram(int SSAAMode, int depthConversionType);
|
static LPDIRECT3DPIXELSHADER9 GetDepthMatrixProgram(int SSAAMode, int depthConversionType);
|
||||||
static LPDIRECT3DPIXELSHADER9 GetClearProgram();
|
static LPDIRECT3DPIXELSHADER9 GetClearProgram();
|
||||||
|
static LPDIRECT3DPIXELSHADER9 ReinterpRGBA6ToRGB8();
|
||||||
|
static LPDIRECT3DPIXELSHADER9 ReinterpRGB8ToRGBA6();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -843,6 +843,29 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||||
RestoreAPIState();
|
RestoreAPIState();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||||
|
{
|
||||||
|
RECT source;
|
||||||
|
SetRect(&source, 0, 0, g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight());
|
||||||
|
|
||||||
|
LPDIRECT3DPIXELSHADER9 pixel_shader;
|
||||||
|
if (convtype == 0) pixel_shader = PixelShaderCache::ReinterpRGB8ToRGBA6();
|
||||||
|
else if (convtype == 2) pixel_shader = PixelShaderCache::ReinterpRGBA6ToRGB8();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
PanicAlert("Trying to reinterpret pixel data with unsupported conversion type %d", convtype);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// convert data and set the target texture as our new EFB
|
||||||
|
g_renderer->ResetAPIState();
|
||||||
|
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorReinterpretSurface());
|
||||||
|
D3D::drawShadedTexQuad(FramebufferManager::GetEFBColorTexture(), &source, g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight(), g_renderer->GetFullTargetWidth(), g_renderer->GetFullTargetHeight(), pixel_shader, VertexShaderCache::GetSimpleVertexShader(0));
|
||||||
|
FramebufferManager::SwapReinterpretTexture();
|
||||||
|
D3D::dev->SetRenderTarget(0, FramebufferManager::GetEFBColorRTSurface());
|
||||||
|
g_renderer->RestoreAPIState();
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::SetBlendMode(bool forceUpdate)
|
void Renderer::SetBlendMode(bool forceUpdate)
|
||||||
{
|
{
|
||||||
if (bpmem.blendmode.logicopenable && !forceUpdate)
|
if (bpmem.blendmode.logicopenable && !forceUpdate)
|
||||||
|
|
|
@ -37,6 +37,8 @@ public:
|
||||||
|
|
||||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||||
|
|
||||||
|
void ReinterpretPixelData(unsigned int convtype);
|
||||||
|
|
||||||
void UpdateViewport();
|
void UpdateViewport();
|
||||||
|
|
||||||
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
||||||
|
|
|
@ -158,6 +158,7 @@ void InitBackendInfo()
|
||||||
g_Config.backend_info.bSupports3DVision = true;
|
g_Config.backend_info.bSupports3DVision = true;
|
||||||
g_Config.backend_info.bAllowSignedBytes = false;
|
g_Config.backend_info.bAllowSignedBytes = false;
|
||||||
g_Config.backend_info.bSupportsDualSourceBlend = false;
|
g_Config.backend_info.bSupportsDualSourceBlend = false;
|
||||||
|
g_Config.backend_info.bSupportsFormatReinterpretation = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DllConfig(void *_hParent)
|
void DllConfig(void *_hParent)
|
||||||
|
|
|
@ -863,6 +863,11 @@ void Renderer::ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaE
|
||||||
SetScissorRect();
|
SetScissorRect();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Renderer::ReinterpretPixelData(unsigned int convtype)
|
||||||
|
{
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
void Renderer::SetBlendMode(bool forceUpdate)
|
void Renderer::SetBlendMode(bool forceUpdate)
|
||||||
{
|
{
|
||||||
// blend mode bit mask
|
// blend mode bit mask
|
||||||
|
|
|
@ -39,6 +39,8 @@ public:
|
||||||
|
|
||||||
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
void ClearScreen(const EFBRectangle& rc, bool colorEnable, bool alphaEnable, bool zEnable, u32 color, u32 z);
|
||||||
|
|
||||||
|
void ReinterpretPixelData(unsigned int convtype);
|
||||||
|
|
||||||
void UpdateViewport();
|
void UpdateViewport();
|
||||||
|
|
||||||
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
bool SaveScreenshot(const std::string &filename, const TargetRectangle &rc);
|
||||||
|
|
|
@ -198,6 +198,7 @@ void InitBackendInfo()
|
||||||
g_Config.backend_info.bSupports3DVision = false;
|
g_Config.backend_info.bSupports3DVision = false;
|
||||||
g_Config.backend_info.bAllowSignedBytes = true;
|
g_Config.backend_info.bAllowSignedBytes = true;
|
||||||
g_Config.backend_info.bSupportsDualSourceBlend = false; // supported, but broken
|
g_Config.backend_info.bSupportsDualSourceBlend = false; // supported, but broken
|
||||||
|
g_Config.backend_info.bSupportsFormatReinterpretation = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DllConfig(void *_hParent)
|
void DllConfig(void *_hParent)
|
||||||
|
|
Loading…
Reference in New Issue