mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-09-27 11:36:29 -05:00
Latte+GX2: Improve GX2Invalidate and implement basic tex invalidation
This commit is contained in:
@@ -209,7 +209,7 @@ void LatteCP_skipWords(uint32 wordsToSkip)
|
||||
|
||||
LatteCMDPtr LatteCP_itSurfaceSync(LatteCMDPtr cmd)
|
||||
{
|
||||
uint32 invalidationFlags = LatteReadCMD();
|
||||
Latte::E_COHER_CNTL invalidationFlags = static_cast<Latte::E_COHER_CNTL>(LatteReadCMD());
|
||||
uint32 size = LatteReadCMD() << 8;
|
||||
MPTR addressPhys = LatteReadCMD() << 8;
|
||||
uint32 pollInterval = LatteReadCMD();
|
||||
@@ -217,11 +217,15 @@ LatteCMDPtr LatteCP_itSurfaceSync(LatteCMDPtr cmd)
|
||||
if (addressPhys == MPTR_NULL || size == 0xFFFFFFFF)
|
||||
return cmd; // block global invalidations because they are too expensive
|
||||
|
||||
if (invalidationFlags & 0x800000)
|
||||
// uniform invalidation needs both TC_ACTION_ENA and SH_ACTION_ENA?
|
||||
if (HAS_FLAG(invalidationFlags, Latte::E_COHER_CNTL::TC_ACTION_ENA))
|
||||
{
|
||||
// invalidate uniform or attribute buffer
|
||||
LatteBufferCache_invalidate(addressPhys, size);
|
||||
}
|
||||
// texture invalidation
|
||||
if (HAS_FLAG(invalidationFlags, Latte::E_COHER_CNTL::TC_ACTION_ENA))
|
||||
LatteTexture_Invalidate(addressPhys, size);
|
||||
return cmd;
|
||||
}
|
||||
|
||||
|
||||
@@ -169,6 +169,17 @@ void LatteTexture_UnregisterTextureMemoryOccupancy(LatteTexture* texture)
|
||||
}
|
||||
}
|
||||
|
||||
void LatteTexture_Invalidate(uint32 physAddr, uint32 size)
|
||||
{
|
||||
if (size == 0xFFFFFFFF)
|
||||
return; // full cache invalidation for all textures is too expensive, so for now lets ignore it. Most likely games don't use this anyway when they are modifying a single texture
|
||||
std::vector<LatteTexture*> textures;
|
||||
LatteTC_LookupTexturesByPhysAddr(physAddr, textures);
|
||||
uint32 invalidationVal = LatteGPUState.frameCounter - 1;
|
||||
for (LatteTexture* texture : textures)
|
||||
texture->lastDataUpdateFrameCounter = invalidationVal;
|
||||
}
|
||||
|
||||
// calculate the actually accessed data range
|
||||
// the resulting range is an estimate and may be smaller than the actual slice size (but not larger)
|
||||
void LatteTexture_EstimateMipSliceAccessedDataRange(LatteTexture* texture, sint32 sliceIndex, sint32 mipIndex, LatteTextureSliceMipInfo* sliceMipInfo)
|
||||
|
||||
@@ -348,6 +348,8 @@ void LatteTexture_InitSliceAndMipInfo(LatteTexture* texture);
|
||||
void LatteTexture_RegisterTextureMemoryOccupancy(LatteTexture* texture);
|
||||
void LatteTexture_UnregisterTextureMemoryOccupancy(LatteTexture* texture);
|
||||
|
||||
void LatteTexture_Invalidate(uint32 physAddr, uint32 size);
|
||||
|
||||
void LatteTexture_DeleteTextureRelations(LatteTexture* texture);
|
||||
void LatteTexture_DeleteDataOverlapTracking(LatteTexture* texture);
|
||||
|
||||
|
||||
@@ -350,6 +350,38 @@ namespace Latte
|
||||
return dim == E_DIM::DIM_2D_MSAA || dim == E_DIM::DIM_2D_ARRAY_MSAA;
|
||||
}
|
||||
|
||||
// PM4 packet field enums
|
||||
enum class E_COHER_CNTL : uint32 // for SURFACE_SYNC packet
|
||||
{
|
||||
DEST_BASE_0_ENA = (1<<0),
|
||||
DEST_BASE_1_ENA = (1<<1),
|
||||
SO0_DEST_BASE_ENA = (1<<2),
|
||||
SO1_DEST_BASE_ENA = (1<<3),
|
||||
SO2_DEST_BASE_ENA = (1<<4),
|
||||
SO3_DEST_BASE_ENA = (1<<5),
|
||||
CB0_DEST_BASE_ENA = (1<<6),
|
||||
CB1_DEST_BASE_ENA = (1<<7),
|
||||
CB2_DEST_BASE_ENA = (1<<8),
|
||||
CB3_DEST_BASE_ENA = (1<<9),
|
||||
CB4_DEST_BASE_ENA = (1<<10),
|
||||
CB5_DEST_BASE_ENA = (1<<11),
|
||||
CB6_DEST_BASE_ENA = (1<<12),
|
||||
CB7_DEST_BASE_ENA = (1<<13),
|
||||
DB_DEST_BASE_ENA = (1<<14),
|
||||
|
||||
FULL_CACHE_ENA = (1<<20),
|
||||
|
||||
TC_ACTION_ENA = (1<<23), // on Latte this bit seems to flush attribute buffer cache and texture cache
|
||||
VC_ACTION_ENA = (1<<24),
|
||||
CB_ACTION_ENA = (1<<25),
|
||||
DB_ACTION_ENA = (1<<26),
|
||||
SH_ACTION_ENA = (1<<27),
|
||||
SX_ACTION_ENA = (1<<28),
|
||||
|
||||
ENGINE_ME = (1u<<31)
|
||||
};
|
||||
DEFINE_ENUM_FLAG_OPERATORS(E_COHER_CNTL);
|
||||
|
||||
enum GPU_LIMITS
|
||||
{
|
||||
NUM_VERTEX_BUFFERS = 16,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#include "Cafe/HW/Latte/ISA/RegDefines.h"
|
||||
#include "Cafe/OS/common/OSCommon.h"
|
||||
#include "GX2.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
|
||||
#include "config/ActiveSettings.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Renderer.h"
|
||||
@@ -13,6 +12,8 @@
|
||||
#include "GX2_Memory.h"
|
||||
#include "GX2_Texture.h"
|
||||
|
||||
#include "Cafe/HW/Latte/ISA/LatteReg.h"
|
||||
|
||||
void gx2Export_GX2SetSwapInterval(PPCInterpreter_t* hCPU)
|
||||
{
|
||||
cemuLog_log(LogType::GX2, "GX2SetSwapInterval({})", hCPU->gpr[3]);
|
||||
@@ -270,37 +271,64 @@ namespace GX2
|
||||
return 1;
|
||||
}
|
||||
|
||||
void GX2Invalidate(uint32 invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize)
|
||||
void GX2Invalidate(GX2InvalidationFlag invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize)
|
||||
{
|
||||
uint32 surfaceSyncFlags = 0;
|
||||
Latte::E_COHER_CNTL coherCntl{};
|
||||
|
||||
if (invalidationFlags & 0x04)
|
||||
{
|
||||
// uniform block
|
||||
surfaceSyncFlags |= 0x8800000;
|
||||
}
|
||||
if (invalidationFlags & 0x01)
|
||||
{
|
||||
// attribute data
|
||||
surfaceSyncFlags |= 0x800000;
|
||||
}
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_ATTRIB) || HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_TEXTURE))
|
||||
coherCntl |= Latte::E_COHER_CNTL::TC_ACTION_ENA;
|
||||
|
||||
if (invalidationFlags & 0x40)
|
||||
{
|
||||
// CPU cache
|
||||
LatteBufferCache_notifyDCFlush(invalidationAddr, invalidationSize);
|
||||
}
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_UNIFORM_BLOCK))
|
||||
coherCntl |= Latte::E_COHER_CNTL::TC_ACTION_ENA | Latte::E_COHER_CNTL::SH_ACTION_ENA;
|
||||
|
||||
if (surfaceSyncFlags != 0)
|
||||
{
|
||||
GX2ReserveCmdSpace(5);
|
||||
// write PM4 command
|
||||
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SURFACE_SYNC, 4)); // IT_SURFACE_SYNC + 4 data dwords
|
||||
gx2WriteGather_submitU32AsBE(surfaceSyncFlags);
|
||||
gx2WriteGather_submitU32AsBE((invalidationSize + 0xFF) >> 8); // size
|
||||
gx2WriteGather_submitU32AsBE(memory_virtualToPhysical(invalidationAddr) >> 8); // base address (divided by 0x100)
|
||||
gx2WriteGather_submitU32AsBE(0x00000004); // poll interval
|
||||
}
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_SHADER))
|
||||
coherCntl |= Latte::E_COHER_CNTL::SH_ACTION_ENA;
|
||||
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_COLOR_BUFFER))
|
||||
{
|
||||
coherCntl |= Latte::E_COHER_CNTL::CB_ACTION_ENA
|
||||
| Latte::E_COHER_CNTL::CB0_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB1_DEST_BASE_ENA
|
||||
| Latte::E_COHER_CNTL::CB2_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB3_DEST_BASE_ENA
|
||||
| Latte::E_COHER_CNTL::CB4_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB5_DEST_BASE_ENA
|
||||
| Latte::E_COHER_CNTL::CB6_DEST_BASE_ENA | Latte::E_COHER_CNTL::CB7_DEST_BASE_ENA;
|
||||
}
|
||||
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_DEPTH_BUFFER))
|
||||
coherCntl |= Latte::E_COHER_CNTL::DB_ACTION_ENA | Latte::E_COHER_CNTL::DB_DEST_BASE_ENA;
|
||||
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_STREAM_OUT))
|
||||
{
|
||||
coherCntl |= Latte::E_COHER_CNTL::SX_ACTION_ENA
|
||||
| Latte::E_COHER_CNTL::SO0_DEST_BASE_ENA | Latte::E_COHER_CNTL::SO1_DEST_BASE_ENA
|
||||
| Latte::E_COHER_CNTL::SO2_DEST_BASE_ENA | Latte::E_COHER_CNTL::SO3_DEST_BASE_ENA;
|
||||
}
|
||||
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::GPU_EXPORT_BUFFER))
|
||||
{
|
||||
coherCntl |= Latte::E_COHER_CNTL::SX_ACTION_ENA
|
||||
| Latte::E_COHER_CNTL::DB_ACTION_ENA
|
||||
| Latte::E_COHER_CNTL::CB_ACTION_ENA
|
||||
| Latte::E_COHER_CNTL::TC_ACTION_ENA
|
||||
| Latte::E_COHER_CNTL::DEST_BASE_0_ENA;
|
||||
}
|
||||
|
||||
if (HAS_FLAG(invalidationFlags, GX2InvalidationFlag::CPU))
|
||||
LatteBufferCache_notifyDCFlush(invalidationAddr, invalidationSize);
|
||||
|
||||
if (coherCntl == static_cast<Latte::E_COHER_CNTL>(0))
|
||||
return; // no GPU-side invalidation
|
||||
|
||||
coherCntl |= Latte::E_COHER_CNTL::ENGINE_ME;
|
||||
|
||||
uint32 physicalAddr = memory_virtualToPhysical(invalidationAddr);
|
||||
uint32 sizeUnits = (invalidationSize == 0xFFFFFFFFu) ? 0x00FFFFFFu : ((invalidationSize + 0xFF) >> 8);
|
||||
|
||||
GX2ReserveCmdSpace(5);
|
||||
gx2WriteGather_submitU32AsBE(pm4HeaderType3(IT_SURFACE_SYNC, 4));
|
||||
gx2WriteGather_submitU32AsBE(static_cast<uint32>(coherCntl));
|
||||
gx2WriteGather_submitU32AsBE(sizeUnits);
|
||||
gx2WriteGather_submitU32AsBE(physicalAddr >> 8);
|
||||
gx2WriteGather_submitU32AsBE(4u);
|
||||
}
|
||||
|
||||
void GX2MiscInit()
|
||||
|
||||
@@ -14,12 +14,28 @@ namespace GX2
|
||||
DOUBLE_BUFFER = 2,
|
||||
};
|
||||
|
||||
enum class GX2InvalidationFlag : uint32
|
||||
{
|
||||
GPU_ATTRIB = (1<<0),
|
||||
GPU_TEXTURE = (1<<1),
|
||||
GPU_UNIFORM_BLOCK = (1<<2),
|
||||
GPU_SHADER = (1<<3),
|
||||
GPU_COLOR_BUFFER = (1<<4),
|
||||
GPU_DEPTH_BUFFER = (1<<5),
|
||||
CPU = (1<<6),
|
||||
GPU_STREAM_OUT = (1<<7),
|
||||
GPU_EXPORT_BUFFER = (1<<8)
|
||||
};
|
||||
|
||||
void _GX2DriverReset();
|
||||
|
||||
void GX2SetTVBuffer(void* imageBuffePtr, uint32 imageBufferSize, E_TVRES tvResolutionMode, uint32 surfaceFormat, E_TVBUFFERMODE bufferMode);
|
||||
void GX2SetTVGamma(float gamma);
|
||||
|
||||
void GX2Invalidate(uint32 invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize);
|
||||
void GX2Invalidate(GX2InvalidationFlag invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize);
|
||||
|
||||
void GX2MiscInit();
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
ENABLE_BITMASK_OPERATORS(GX2::GX2InvalidationFlag);
|
||||
|
||||
@@ -776,7 +776,7 @@ namespace proc_ui
|
||||
uint32be memBoundSize;
|
||||
OSGetMemBound(1, &memBound, &memBoundSize);
|
||||
OSBlockMove(memBound.GetPtr(), s_mem1StorageBasePtr, memBoundSize, true);
|
||||
GX2::GX2Invalidate(0x40, s_mem1StorageBasePtr.GetMPTR(), memBoundSize);
|
||||
GX2::GX2Invalidate(GX2::GX2InvalidationFlag::CPU, s_mem1StorageBasePtr.GetMPTR(), memBoundSize);
|
||||
}
|
||||
if (s_bucketStorageBasePtr)
|
||||
{
|
||||
@@ -784,7 +784,7 @@ namespace proc_ui
|
||||
uint32be memBoundSize;
|
||||
OSGetForegroundBucketFreeArea(&memBound, &memBoundSize);
|
||||
OSBlockMove(memBound.GetPtr(), s_bucketStorageBasePtr, memBoundSize, true);
|
||||
GX2::GX2Invalidate(0x40, memBound.GetMPTR(), memBoundSize);
|
||||
GX2::GX2Invalidate(GX2::GX2InvalidationFlag::CPU, memBound.GetMPTR(), memBoundSize);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user