Merge pull request #2957 from phire/unify_efbcopy

Cleanup and unify efb copy implemtations into VideoCommon
This commit is contained in:
Scott Mansell
2015-09-07 00:10:42 +12:00
17 changed files with 180 additions and 285 deletions

View File

@ -9,7 +9,6 @@
#include "VideoCommon/BPFunctions.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/VertexManagerBase.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoConfig.h"
@ -85,15 +84,6 @@ void SetColorMask()
g_renderer->SetColorMask();
}
void CopyEFB(u32 dstAddr, const EFBRectangle& srcRect,
unsigned int dstFormat, PEControl::PixelFormat srcFormat,
bool isIntensity, bool scaleByHalf)
{
// bpmem.zcontrol.pixel_format to PEControl::Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format)
TextureCache::CopyRenderTargetToTexture(dstAddr, dstFormat, srcFormat,
srcRect, isIntensity, scaleByHalf);
}
/* Explanation of the magic behind ClearScreen:
There's numerous possible formats for the pixel data in the EFB.
However, in the HW accelerated backends we're always using RGBA8

View File

@ -23,9 +23,6 @@ void SetBlendMode();
void SetDitherMode();
void SetLogicOpMode();
void SetColorMask();
void CopyEFB(u32 dstAddr, const EFBRectangle& srcRect,
unsigned int dstFormat, PEControl::PixelFormat srcFormat,
bool isIntensity, bool scaleByHalf);
void ClearScreen(const EFBRectangle &rc);
void OnPixelFormatChange();
void SetInterlacingMode(const BPCmd &bp);

View File

@ -20,6 +20,7 @@
#include "VideoCommon/PixelShaderManager.h"
#include "VideoCommon/RenderBase.h"
#include "VideoCommon/Statistics.h"
#include "VideoCommon/TextureCacheBase.h"
#include "VideoCommon/TextureDecoder.h"
#include "VideoCommon/VertexShaderManager.h"
#include "VideoCommon/VideoCommon.h"
@ -205,6 +206,7 @@ static void BPWritten(const BPCmd& bp)
// The values in bpmem.copyTexSrcXY and bpmem.copyTexSrcWH are updated in case 0x49 and 0x4a in this function
u32 destAddr = bpmem.copyTexDest << 5;
u32 destStride = bpmem.copyMipMapStrideChannels << 5;
EFBRectangle srcRect;
srcRect.left = (int)bpmem.copyTexSrcXY.x;
@ -223,8 +225,9 @@ static void BPWritten(const BPCmd& bp)
if (g_ActiveConfig.bShowEFBCopyRegions)
stats.efb_regions.push_back(srcRect);
CopyEFB(destAddr, srcRect,
PE_copy.tp_realFormat(), bpmem.zcontrol.pixel_format,
// bpmem.zcontrol.pixel_format to PEControl::Z24 is when the game wants to copy from ZBuffer (Zbuffer uses 24-bit Format)
TextureCache::CopyRenderTargetToTexture(destAddr, PE_copy.tp_realFormat(), destStride,
bpmem.zcontrol.pixel_format, srcRect,
!!PE_copy.intensity_fmt, !!PE_copy.half_scale);
}
else
@ -251,10 +254,9 @@ static void BPWritten(const BPCmd& bp)
height = MAX_XFB_HEIGHT;
}
u32 stride = bpmem.copyMipMapStrideChannels << 5;
DEBUG_LOG(VIDEO, "RenderToXFB: destAddr: %08x | srcRect {%d %d %d %d} | fbWidth: %u | fbStride: %u | fbHeight: %u",
destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, bpmem.copyTexSrcWH.x + 1, stride, height);
Renderer::RenderToXFB(destAddr, srcRect, stride, height, s_gammaLUT[PE_copy.gamma]);
destAddr, srcRect.left, srcRect.top, srcRect.right, srcRect.bottom, bpmem.copyTexSrcWH.x + 1, destStride, height);
Renderer::RenderToXFB(destAddr, srcRect, destStride, height, s_gammaLUT[PE_copy.gamma]);
}
// Clear the rectangular region after copying it.

View File

@ -182,24 +182,6 @@ void TextureCache::Cleanup(int _frameCount)
}
}
void TextureCache::MakeRangeDynamic(u32 start_address, u32 size)
{
TexCache::iterator
iter = textures_by_address.begin();
while (iter != textures_by_address.end())
{
if (iter->second->OverlapsMemoryRange(start_address, size))
{
iter = FreeTexture(iter);
}
else
{
++iter;
}
}
}
bool TextureCache::TCacheEntryBase::OverlapsMemoryRange(u32 range_address, u32 range_size) const
{
if (addr + size_in_bytes <= range_address)
@ -243,7 +225,7 @@ TextureCache::TCacheEntryBase* TextureCache::DoPartialTextureUpdates(TexCache::i
&& entry_to_update->addr <= entry->addr
&& entry->addr + entry->size_in_bytes <= entry_to_update->addr + entry_to_update->size_in_bytes
&& entry->frameCount == FRAMECOUNT_INVALID
&& entry->copyMipMapStrideChannels * 32 == numBlocksX * block_size)
&& entry->memory_stride == numBlocksX * block_size)
{
u32 block_offset = (entry->addr - entry_to_update->addr) / block_size;
u32 block_x = block_offset % numBlocksX;
@ -372,11 +354,11 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
return nullptr;
// TexelSizeInNibbles(format) * width * height / 16;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat) - 1;
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat) - 1;
const unsigned int bsw = TexDecoder_GetBlockWidthInTexels(texformat);
const unsigned int bsh = TexDecoder_GetBlockHeightInTexels(texformat);
unsigned int expandedWidth = (width + bsw) & (~bsw);
unsigned int expandedHeight = (height + bsh) & (~bsh);
unsigned int expandedWidth = ROUND_UP(width, bsw);
unsigned int expandedHeight = ROUND_UP(height, bsh);
const unsigned int nativeW = width;
const unsigned int nativeH = height;
@ -668,8 +650,8 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
{
const u32 mip_width = CalculateLevelSize(width, level);
const u32 mip_height = CalculateLevelSize(height, level);
const u32 expanded_mip_width = (mip_width + bsw) & (~bsw);
const u32 expanded_mip_height = (mip_height + bsh) & (~bsh);
const u32 expanded_mip_width = ROUND_UP(mip_width, bsw);
const u32 expanded_mip_height = ROUND_UP(mip_height, bsh);
const u8*& mip_src_data = from_tmem
? ((level % 2) ? ptr_odd : ptr_even)
@ -693,7 +675,7 @@ TextureCache::TCacheEntryBase* TextureCache::Load(const u32 stage)
return ReturnEntry(stage, entry);
}
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, PEControl::PixelFormat srcFormat,
void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride, PEControl::PixelFormat srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf)
{
// Emulation methods:
@ -753,9 +735,11 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
case 0: // Z4
colmat[3] = colmat[7] = colmat[11] = colmat[15] = 1.0f;
cbufid = 0;
dstFormat |= _GX_TF_CTF;
break;
case 8: // Z8H
dstFormat |= _GX_TF_CTF;
case 1: // Z8
case 8: // Z8
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1.0f;
cbufid = 1;
break;
@ -768,6 +752,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
case 11: // Z16 (reverse order)
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
cbufid = 3;
dstFormat |= _GX_TF_CTF;
break;
case 6: // Z24X8
@ -778,11 +763,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
case 9: // Z8M
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
cbufid = 5;
dstFormat |= _GX_TF_CTF;
break;
case 10: // Z8L
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
cbufid = 6;
dstFormat |= _GX_TF_CTF;
break;
case 12: // Z16L - copy lower 16 depth bits
@ -790,6 +777,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
// Used e.g. in Zelda: Skyward Sword
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f;
cbufid = 7;
dstFormat |= _GX_TF_CTF;
break;
default:
@ -798,6 +786,8 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
cbufid = 8;
break;
}
dstFormat |= _GX_TF_ZTF;
}
else if (isIntensity)
{
@ -862,11 +852,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
ColorMask[0] = 15.0f;
ColorMask[4] = 1.0f / 15.0f;
cbufid = 14;
dstFormat |= _GX_TF_CTF;
break;
case 1: // R8
case 8: // R8
colmat[0] = colmat[4] = colmat[8] = colmat[12] = 1;
cbufid = 15;
dstFormat |= _GX_TF_CTF;
break;
case 2: // RA4
@ -881,6 +873,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
fConstAdd[3] = 1.0f;
cbufid = 17;
}
dstFormat |= _GX_TF_CTF;
break;
case 3: // RA8
colmat[0] = colmat[4] = colmat[8] = colmat[15] = 1.0f;
@ -892,6 +885,7 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
fConstAdd[3] = 1.0f;
cbufid = 19;
}
dstFormat |= _GX_TF_CTF;
break;
case 7: // A8
@ -907,25 +901,30 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
fConstAdd[3] = 1.0f;
cbufid = 21;
}
dstFormat |= _GX_TF_CTF;
break;
case 9: // G8
colmat[1] = colmat[5] = colmat[9] = colmat[13] = 1.0f;
cbufid = 22;
dstFormat |= _GX_TF_CTF;
break;
case 10: // B8
colmat[2] = colmat[6] = colmat[10] = colmat[14] = 1.0f;
cbufid = 23;
dstFormat |= _GX_TF_CTF;
break;
case 11: // RG8
colmat[0] = colmat[4] = colmat[8] = colmat[13] = 1.0f;
cbufid = 24;
dstFormat |= _GX_TF_CTF;
break;
case 12: // GB8
colmat[1] = colmat[5] = colmat[9] = colmat[14] = 1.0f;
cbufid = 25;
dstFormat |= _GX_TF_CTF;
break;
case 4: // RGB565
@ -973,6 +972,13 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
}
}
u8* dst = Memory::GetPointer(dstAddr);
if (dst == nullptr)
{
ERROR_LOG(VIDEO, "Trying to copy from EFB to invalid address 0x%8x", dstAddr);
return;
}
const unsigned int tex_w = scaleByHalf ? srcRect.GetWidth() / 2 : srcRect.GetWidth();
const unsigned int tex_h = scaleByHalf ? srcRect.GetHeight() / 2 : srcRect.GetHeight();
@ -996,17 +1002,36 @@ void TextureCache::CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat
TCacheEntryBase* entry = AllocateTexture(config);
// TODO: Using the wrong dstFormat, dumb...
entry->SetGeneralParameters(dstAddr, 0, dstFormat);
entry->SetDimensions(tex_w, tex_h, 1);
entry->SetHashes(TEXHASH_INVALID);
entry->frameCount = FRAMECOUNT_INVALID;
entry->is_efb_copy = true;
entry->SetEfbCopy(dstStride);
entry->is_custom_tex = false;
entry->copyMipMapStrideChannels = bpmem.copyMipMapStrideChannels;
entry->FromRenderTarget(dstAddr, dstFormat, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
entry->FromRenderTarget(dst, dstFormat, dstStride, srcFormat, srcRect, isIntensity, scaleByHalf, cbufid, colmat);
if (!g_ActiveConfig.bSkipEFBCopyToRam)
{
entry->hash = GetHash64(dst, (int)entry->size_in_bytes, g_ActiveConfig.iSafeTextureCache_ColorSamples);
// Invalidate all textures that overlap the range of our texture
TexCache::iterator
iter = textures_by_address.begin();
while (iter != textures_by_address.end())
{
if (iter->second->OverlapsMemoryRange(dstAddr, entry->size_in_bytes))
{
iter = FreeTexture(iter);
}
else
{
++iter;
}
}
}
if (g_ActiveConfig.bDumpEFBTarget)
{
@ -1052,3 +1077,36 @@ TextureCache::TexCache::iterator TextureCache::FreeTexture(TexCache::iterator it
return textures_by_address.erase(iter);
}
u32 TextureCache::TCacheEntryBase::CacheLinesPerRow() const
{
u32 blockW = TexDecoder_GetBlockWidthInTexels(format);
// Round up source height to multiple of block size
u32 actualWidth = ROUND_UP(native_width, blockW);
u32 numBlocksX = actualWidth / blockW;
// RGBA takes two cache lines per block; all others take one
if (format == GX_TF_RGBA8)
numBlocksX = numBlocksX * 2;
return numBlocksX;
}
u32 TextureCache::TCacheEntryBase::NumBlocksY() const
{
u32 blockH = TexDecoder_GetBlockHeightInTexels(format);
// Round up source height to multiple of block size
u32 actualHeight = ROUND_UP(native_height, blockH);
return actualHeight / blockH;
}
void TextureCache::TCacheEntryBase::SetEfbCopy(u32 stride)
{
is_efb_copy = true;
memory_stride = stride;
_assert_msg_(VIDEO, memory_stride >= CacheLinesPerRow(), "Memory stride is too small");
size_in_bytes = memory_stride * NumBlocksY();
}

View File

@ -53,7 +53,7 @@ public:
u32 format;
bool is_efb_copy;
bool is_custom_tex;
u32 copyMipMapStrideChannels;
u32 memory_stride;
unsigned int native_width, native_height; // Texture dimensions from the GameCube's point of view
unsigned int native_levels;
@ -76,6 +76,7 @@ public:
native_width = _native_width;
native_height = _native_height;
native_levels = _native_levels;
memory_stride = _native_width;
}
void SetHashes(u64 _hash)
@ -83,6 +84,8 @@ public:
hash = _hash;
}
void SetEfbCopy(u32 stride);
TCacheEntryBase(const TCacheEntryConfig& c) : config(c) {}
virtual ~TCacheEntryBase();
@ -96,7 +99,7 @@ public:
virtual void Load(unsigned int width, unsigned int height,
unsigned int expanded_width, unsigned int level) = 0;
virtual void FromRenderTarget(u32 dstAddr, unsigned int dstFormat,
virtual void FromRenderTarget(u8* dst, unsigned int dstFormat, u32 dstStride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect,
bool isIntensity, bool scaleByHalf, unsigned int cbufid,
const float *colmat) = 0;
@ -104,6 +107,11 @@ public:
bool OverlapsMemoryRange(u32 range_address, u32 range_size) const;
bool IsEfbCopy() const { return is_efb_copy; }
u32 NumBlocksY() const;
u32 CacheLinesPerRow() const;
void Memset(u8* ptr, u32 tag);
};
virtual ~TextureCache(); // needs virtual for DX11 dtor
@ -115,7 +123,6 @@ public:
static void Cleanup(int _frameCount);
static void Invalidate();
static void MakeRangeDynamic(u32 start_address, u32 size);
virtual TCacheEntryBase* CreateTexture(const TCacheEntryConfig& config) = 0;
@ -125,8 +132,8 @@ public:
static TCacheEntryBase* Load(const u32 stage);
static void UnbindTextures();
static void BindTextures();
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, PEControl::PixelFormat srcFormat,
const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
static void CopyRenderTargetToTexture(u32 dstAddr, unsigned int dstFormat, u32 dstStride,
PEControl::PixelFormat srcFormat, const EFBRectangle& srcRect, bool isIntensity, bool scaleByHalf);
static void RequestInvalidateTextureCache();

View File

@ -650,9 +650,11 @@ const char *GenerateEncodingShader(u32 format,API_TYPE ApiType)
case GX_CTF_GB8:
WriteCC8Encoder(p, "gb", ApiType);
break;
case GX_CTF_Z8H:
case GX_TF_Z8:
WriteC8Encoder(p, "r", ApiType);
break;
case GX_CTF_Z16R:
case GX_TF_Z16:
WriteZ16Encoder(p, ApiType);
break;

View File

@ -16,6 +16,7 @@ extern GC_ALIGNED16(u8 texMem[TMEM_SIZE]);
enum TextureFormat
{
// These are the texture formats that can be read by the texture mapper.
GX_TF_I4 = 0x0,
GX_TF_I8 = 0x1,
GX_TF_IA4 = 0x2,
@ -28,14 +29,21 @@ enum TextureFormat
GX_TF_C14X2 = 0xA,
GX_TF_CMPR = 0xE,
_GX_TF_CTF = 0x20, // copy-texture-format only (simply means linear?)
_GX_TF_ZTF = 0x10, // Z-texture-format
_GX_TF_ZTF = 0x10, // flag for Z texture formats (used internally by dolphin)
// these formats are also valid when copying targets
// Depth texture formats (which directly map to the equivalent colour format above.)
GX_TF_Z8 = 0x1 | _GX_TF_ZTF,
GX_TF_Z16 = 0x3 | _GX_TF_ZTF,
GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF,
_GX_TF_CTF = 0x20, // flag for copy-texture-format only (used internally by dolphin)
// These are extra formats that can be used when copying from efb,
// they use one of texel formats from above, but pack diffrent data into them.
GX_CTF_R4 = 0x0 | _GX_TF_CTF,
GX_CTF_RA4 = 0x2 | _GX_TF_CTF,
GX_CTF_RA8 = 0x3 | _GX_TF_CTF,
GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF,
GX_CTF_YUVA8 = 0x6 | _GX_TF_CTF, // YUV 4:4:4 - Dolphin doesn't implement this format as no commercial games use it
GX_CTF_A8 = 0x7 | _GX_TF_CTF,
GX_CTF_R8 = 0x8 | _GX_TF_CTF,
GX_CTF_G8 = 0x9 | _GX_TF_CTF,
@ -43,13 +51,12 @@ enum TextureFormat
GX_CTF_RG8 = 0xB | _GX_TF_CTF,
GX_CTF_GB8 = 0xC | _GX_TF_CTF,
GX_TF_Z8 = 0x1 | _GX_TF_ZTF,
GX_TF_Z16 = 0x3 | _GX_TF_ZTF,
GX_TF_Z24X8 = 0x6 | _GX_TF_ZTF,
// extra depth texture formats that can be used for efb copies.
GX_CTF_Z4 = 0x0 | _GX_TF_ZTF | _GX_TF_CTF,
GX_CTF_Z8H = 0x8 | _GX_TF_ZTF | _GX_TF_CTF, // This produces an identical result to to GX_TF_Z8
GX_CTF_Z8M = 0x9 | _GX_TF_ZTF | _GX_TF_CTF,
GX_CTF_Z8L = 0xA | _GX_TF_ZTF | _GX_TF_CTF,
GX_CTF_Z16R = 0xB | _GX_TF_ZTF | _GX_TF_CTF, // Reversed version of GX_TF_Z16
GX_CTF_Z16L = 0xC | _GX_TF_ZTF | _GX_TF_CTF,
};

View File

@ -35,7 +35,6 @@ int TexDecoder_GetTexelSizeInNibbles(int format)
case GX_CTF_R4: return 1;
case GX_CTF_RA4: return 2;
case GX_CTF_RA8: return 4;
case GX_CTF_YUVA8: return 8;
case GX_CTF_A8: return 2;
case GX_CTF_R8: return 2;
case GX_CTF_G8: return 2;
@ -48,10 +47,14 @@ int TexDecoder_GetTexelSizeInNibbles(int format)
case GX_TF_Z24X8: return 8;
case GX_CTF_Z4: return 1;
case GX_CTF_Z8H: return 2;
case GX_CTF_Z8M: return 2;
case GX_CTF_Z8L: return 2;
case GX_CTF_Z16R: return 4;
case GX_CTF_Z16L: return 4;
default: return 1;
default:
PanicAlert("Unsupported Texture Format (%08x)! (GetTexelSizeInNibbles)", format);
return 1;
}
}
@ -88,11 +91,13 @@ int TexDecoder_GetBlockWidthInTexels(u32 format)
case GX_TF_Z16: return 4;
case GX_TF_Z24X8: return 4;
case GX_CTF_Z4: return 8;
case GX_CTF_Z8H: return 8;
case GX_CTF_Z8M: return 8;
case GX_CTF_Z8L: return 8;
case GX_CTF_Z16R: return 4;
case GX_CTF_Z16L: return 4;
default:
ERROR_LOG(VIDEO, "Unsupported Texture Format (%08x)! (GetBlockWidthInTexels)", format);
PanicAlert("Unsupported Texture Format (%08x)! (GetBlockWidthInTexels)", format);
return 8;
}
}
@ -125,11 +130,13 @@ int TexDecoder_GetBlockHeightInTexels(u32 format)
case GX_TF_Z16: return 4;
case GX_TF_Z24X8: return 4;
case GX_CTF_Z4: return 8;
case GX_CTF_Z8H: return 4;
case GX_CTF_Z8M: return 4;
case GX_CTF_Z8L: return 4;
case GX_CTF_Z16R: return 4;
case GX_CTF_Z16L: return 4;
default:
ERROR_LOG(VIDEO, "Unsupported Texture Format (%08x)! (GetBlockHeightInTexels)", format);
PanicAlert("Unsupported Texture Format (%08x)! (GetBlockHeightInTexels)", format);
return 4;
}
}