diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index c99b4b6a2..e9ea4db1e 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -25,6 +25,8 @@ #include "../PSPLoaders.h" #include "../../Core/CoreTiming.h" #include "../../Core/System.h" +#include "../../GPU/GPUInterface.h" +#include "../../GPU/GPUState.h" #include "__sceAudio.h" @@ -187,6 +189,7 @@ void sceKernelGetGPI() // textures, and in the future display lists, in some cases though. void sceKernelDcacheInvalidateRange(u32 addr, int size) { + gpu->InvalidateCache(addr, size); } void sceKernelDcacheWritebackAll() { @@ -196,9 +199,11 @@ void sceKernelDcacheWritebackRange(u32 addr, int size) } void sceKernelDcacheWritebackInvalidateRange(u32 addr, int size) { + gpu->InvalidateCache(addr, size); } void sceKernelDcacheWritebackInvalidateAll() { + gpu->InvalidateCache(0, -1); } KernelObjectPool kernelObjects; diff --git a/GPU/GLES/DisplayListInterpreter.cpp b/GPU/GLES/DisplayListInterpreter.cpp index d516cfe9e..ba049038d 100644 --- a/GPU/GLES/DisplayListInterpreter.cpp +++ b/GPU/GLES/DisplayListInterpreter.cpp @@ -1259,7 +1259,7 @@ void GLES_GPU::DoBlockTransfer() { // TODO: This is used a lot to copy data around between render targets and textures, // and also to quickly load textures from RAM to VRAM. So we should do checks like the following: - // * Does dstBasePtr point to an existing texture? If so invalidate it and reload it immediately. + // * Does dstBasePtr point to an existing texture? If so maybe reload it immediately. // // * Does srcBasePtr point to a render target, and dstBasePtr to a texture? If so // either copy between rt and texture or reassign the texture to point to the render target @@ -1293,4 +1293,14 @@ void GLES_GPU::DoBlockTransfer() } // TODO: Notify all overlapping textures that it's time to die/reload. + + TextureCache_Invalidate(srcBasePtr + srcY * srcStride + srcX, height * srcStride + width * bpp); +} + +void GLES_GPU::InvalidateCache(u32 addr, int size) +{ + if (size > 0) + TextureCache_Invalidate(addr, size); + else + TextureCache_Clear(true); } diff --git a/GPU/GLES/DisplayListInterpreter.h b/GPU/GLES/DisplayListInterpreter.h index 690088e98..7ea8261ce 100644 --- a/GPU/GLES/DisplayListInterpreter.h +++ b/GPU/GLES/DisplayListInterpreter.h @@ -49,6 +49,7 @@ public: virtual void CopyDisplayToOutput(); virtual void BeginFrame(); virtual void UpdateStats(); + virtual void InvalidateCache(u32 addr, int size); private: // TransformPipeline.cpp diff --git a/GPU/GLES/TextureCache.cpp b/GPU/GLES/TextureCache.cpp index 9ad268565..05a9206f2 100644 --- a/GPU/GLES/TextureCache.cpp +++ b/GPU/GLES/TextureCache.cpp @@ -106,6 +106,26 @@ void TextureCache_Decimate() } } +void TextureCache_Invalidate(u32 addr, int size) +{ + u32 addr_end = addr + size; + + for (TexCache::iterator iter = cache.begin(); iter != cache.end(); ) + { + // Clear if either the addr or clutaddr is in the range. + bool invalidate = iter->second.addr >= addr && iter->second.addr < addr_end; + invalidate |= iter->second.clutaddr >= addr && iter->second.clutaddr < addr_end; + + if (invalidate) + { + glDeleteTextures(1, &iter->second.texture); + cache.erase(iter++); + } + else + ++iter; + } +} + int TextureCache_NumLoadedTextures() { return cache.size(); diff --git a/GPU/GLES/TextureCache.h b/GPU/GLES/TextureCache.h index 2579aa677..c895c569c 100644 --- a/GPU/GLES/TextureCache.h +++ b/GPU/GLES/TextureCache.h @@ -25,4 +25,5 @@ void TextureCache_Init(); void TextureCache_Shutdown(); void TextureCache_Clear(bool delete_them); void TextureCache_Decimate(); // Run this once per frame to get rid of old textures. +void TextureCache_Invalidate(u32 addr, int size); int TextureCache_NumLoadedTextures(); diff --git a/GPU/GPUInterface.h b/GPU/GPUInterface.h index f3fb0dad5..be31b0c02 100644 --- a/GPU/GPUInterface.h +++ b/GPU/GPUInterface.h @@ -45,6 +45,10 @@ public: // Tells the GPU to update the gpuStats structure. virtual void UpdateStats() = 0; + // Invalidate any cached content sourced from the specified range. + // If size = -1, invalidate everything. + virtual void InvalidateCache(u32 addr, int size) = 0; + // Internal hack to avoid interrupts from "PPGe" drawing (utility UI, etc) virtual void EnableInterrupts(bool enable) = 0; }; diff --git a/GPU/Null/NullGpu.cpp b/GPU/Null/NullGpu.cpp index c327266a0..3dd5228a0 100644 --- a/GPU/Null/NullGpu.cpp +++ b/GPU/Null/NullGpu.cpp @@ -838,3 +838,8 @@ void NullGPU::UpdateStats() gpuStats.numShaders = 0; gpuStats.numTextures = 0; } + +void NullGPU::InvalidateCache(u32 addr, int size) +{ + // Nothing to invalidate. +} diff --git a/GPU/Null/NullGpu.h b/GPU/Null/NullGpu.h index 4acbf6895..eacee1908 100644 --- a/GPU/Null/NullGpu.h +++ b/GPU/Null/NullGpu.h @@ -40,6 +40,7 @@ public: virtual void SetDisplayFramebuffer(u32 framebuf, u32 stride, int format) {} virtual void CopyDisplayToOutput() {} virtual void UpdateStats(); + virtual void InvalidateCache(u32 addr, int size); private: bool ProcessDLQueue();