forked from suyu/suyu
texture_cache uncompress-compress is untopological.
This makes conflicts between non compress and compress textures to be auto recycled. It also limits the amount of mipmaps a texture can have if it goes above it's limit.
This commit is contained in:
parent
9251354152
commit
228f516bb4
5 changed files with 53 additions and 19 deletions
|
@ -195,17 +195,17 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte
|
|||
|
||||
switch (params.target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
glTextureStorage1D(texture.handle, params.num_levels, internal_format, params.width);
|
||||
glTextureStorage1D(texture.handle, params.emulated_levels, internal_format, params.width);
|
||||
break;
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
glTextureStorage2D(texture.handle, params.num_levels, internal_format, params.width,
|
||||
glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, params.width,
|
||||
params.height);
|
||||
break;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
glTextureStorage3D(texture.handle, params.num_levels, internal_format, params.width,
|
||||
glTextureStorage3D(texture.handle, params.emulated_levels, internal_format, params.width,
|
||||
params.height, params.depth);
|
||||
break;
|
||||
default:
|
||||
|
@ -245,7 +245,7 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
|
|||
// TODO(Rodrigo): Optimize alignment
|
||||
SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); });
|
||||
|
||||
for (u32 level = 0; level < params.num_levels; ++level) {
|
||||
for (u32 level = 0; level < params.emulated_levels; ++level) {
|
||||
glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level)));
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.GetMipWidth(level)));
|
||||
const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level);
|
||||
|
@ -264,7 +264,7 @@ void CachedSurface::DownloadTexture(std::vector<u8>& staging_buffer) {
|
|||
void CachedSurface::UploadTexture(std::vector<u8>& staging_buffer) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Texture_Upload);
|
||||
SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); });
|
||||
for (u32 level = 0; level < params.num_levels; ++level) {
|
||||
for (u32 level = 0; level < params.emulated_levels; ++level) {
|
||||
UploadTextureMipmap(level, staging_buffer);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,12 @@ enum class MatchStructureResult : u32 {
|
|||
None = 2,
|
||||
};
|
||||
|
||||
enum class MatchTopologyResult : u32 {
|
||||
FullMatch = 0,
|
||||
CompressUnmatch = 1,
|
||||
None = 2,
|
||||
};
|
||||
|
||||
class StagingCache {
|
||||
public:
|
||||
StagingCache() {}
|
||||
|
@ -136,12 +142,20 @@ public:
|
|||
params.target == SurfaceTarget::Texture2D && params.num_levels == 1;
|
||||
}
|
||||
|
||||
bool MatchesTopology(const SurfaceParams& rhs) const {
|
||||
MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const {
|
||||
const u32 src_bpp{params.GetBytesPerPixel()};
|
||||
const u32 dst_bpp{rhs.GetBytesPerPixel()};
|
||||
const bool ib1 = params.IsBuffer();
|
||||
const bool ib2 = rhs.IsBuffer();
|
||||
return std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2);
|
||||
if (std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2)) {
|
||||
const bool cb1 = params.IsCompressed();
|
||||
const bool cb2 = rhs.IsCompressed();
|
||||
if (cb1 == cb2) {
|
||||
return MatchTopologyResult::FullMatch;
|
||||
}
|
||||
return MatchTopologyResult::CompressUnmatch;
|
||||
}
|
||||
return MatchTopologyResult::None;
|
||||
}
|
||||
|
||||
MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const {
|
||||
|
|
|
@ -85,6 +85,7 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
|
|||
}
|
||||
params.pitch = params.is_tiled ? 0 : config.tic.Pitch();
|
||||
params.num_levels = config.tic.max_mip_level + 1;
|
||||
params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
|
||||
params.is_layered = params.IsLayered();
|
||||
return params;
|
||||
}
|
||||
|
@ -109,6 +110,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(
|
|||
params.depth = 1;
|
||||
params.pitch = 0;
|
||||
params.num_levels = 1;
|
||||
params.emulated_levels = 1;
|
||||
params.is_layered = false;
|
||||
return params;
|
||||
}
|
||||
|
@ -139,6 +141,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
|
|||
params.depth = 1;
|
||||
params.target = SurfaceTarget::Texture2D;
|
||||
params.num_levels = 1;
|
||||
params.emulated_levels = 1;
|
||||
params.is_layered = false;
|
||||
return params;
|
||||
}
|
||||
|
@ -163,6 +166,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
|
|||
params.target = SurfaceTarget::Texture2D;
|
||||
params.depth = 1;
|
||||
params.num_levels = 1;
|
||||
params.emulated_levels = 1;
|
||||
params.is_layered = params.IsLayered();
|
||||
return params;
|
||||
}
|
||||
|
|
|
@ -160,6 +160,19 @@ public:
|
|||
return std::min(t_src_height, t_dst_height);
|
||||
}
|
||||
|
||||
u32 MaxPossibleMipmap() const {
|
||||
const u32 max_mipmap_w = Common::Log2Ceil32(width) + 1U;
|
||||
const u32 max_mipmap_h = Common::Log2Ceil32(height) + 1U;
|
||||
const u32 max_mipmap = std::max(max_mipmap_w, max_mipmap_h);
|
||||
if (target != VideoCore::Surface::SurfaceTarget::Texture3D)
|
||||
return max_mipmap;
|
||||
return std::max(max_mipmap, Common::Log2Ceil32(depth) + 1U);
|
||||
}
|
||||
|
||||
bool IsCompressed() const {
|
||||
return GetDefaultBlockHeight() > 1 || GetDefaultBlockWidth() > 1;
|
||||
}
|
||||
|
||||
/// Returns the default block width.
|
||||
u32 GetDefaultBlockWidth() const {
|
||||
return VideoCore::Surface::GetDefaultBlockWidth(pixel_format);
|
||||
|
@ -205,6 +218,7 @@ public:
|
|||
u32 depth;
|
||||
u32 pitch;
|
||||
u32 num_levels;
|
||||
u32 emulated_levels;
|
||||
VideoCore::Surface::PixelFormat pixel_format;
|
||||
VideoCore::Surface::ComponentType component_type;
|
||||
VideoCore::Surface::SurfaceType type;
|
||||
|
|
|
@ -305,7 +305,7 @@ private:
|
|||
* due to topological reasons.
|
||||
**/
|
||||
RecycleStrategy PickStrategy(std::vector<TSurface>& overlaps, const SurfaceParams& params,
|
||||
const GPUVAddr gpu_addr, const bool untopological) {
|
||||
const GPUVAddr gpu_addr, const MatchTopologyResult untopological) {
|
||||
if (Settings::values.use_accurate_gpu_emulation) {
|
||||
return RecycleStrategy::Flush;
|
||||
}
|
||||
|
@ -320,8 +320,8 @@ private:
|
|||
}
|
||||
}
|
||||
// Untopological decision
|
||||
if (untopological) {
|
||||
return RecycleStrategy::Ignore;
|
||||
if (untopological == MatchTopologyResult::CompressUnmatch) {
|
||||
return RecycleStrategy::Flush;
|
||||
}
|
||||
return RecycleStrategy::Ignore;
|
||||
}
|
||||
|
@ -341,7 +341,7 @@ private:
|
|||
std::pair<TSurface, TView> RecycleSurface(std::vector<TSurface>& overlaps,
|
||||
const SurfaceParams& params, const GPUVAddr gpu_addr,
|
||||
const bool preserve_contents,
|
||||
const bool untopological) {
|
||||
const MatchTopologyResult untopological) {
|
||||
const bool do_load = Settings::values.use_accurate_gpu_emulation && preserve_contents;
|
||||
for (auto surface : overlaps) {
|
||||
Unregister(surface);
|
||||
|
@ -502,9 +502,10 @@ private:
|
|||
// matches at certain level we are pretty much done.
|
||||
if (l1_cache.count(cache_addr) > 0) {
|
||||
TSurface current_surface = l1_cache[cache_addr];
|
||||
if (!current_surface->MatchesTopology(params)) {
|
||||
auto topological_result = current_surface->MatchesTopology(params);
|
||||
if (topological_result != MatchTopologyResult::FullMatch) {
|
||||
std::vector<TSurface> overlaps{current_surface};
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true);
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, topological_result);
|
||||
}
|
||||
MatchStructureResult s_result = current_surface->MatchesStructure(params);
|
||||
if (s_result != MatchStructureResult::None &&
|
||||
|
@ -534,8 +535,9 @@ private:
|
|||
// we do a topological test to ensure we can find some relationship. If it fails
|
||||
// inmediatly recycle the texture
|
||||
for (auto surface : overlaps) {
|
||||
if (!surface->MatchesTopology(params)) {
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true);
|
||||
auto topological_result = surface->MatchesTopology(params);
|
||||
if (topological_result != MatchTopologyResult::FullMatch) {
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, topological_result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -553,7 +555,7 @@ private:
|
|||
return *view;
|
||||
}
|
||||
}
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false);
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
|
||||
}
|
||||
// Now we check if the candidate is a mipmap/layer of the overlap
|
||||
std::optional<TView> view =
|
||||
|
@ -576,13 +578,13 @@ private:
|
|||
pair.first->EmplaceView(params, gpu_addr, candidate_size);
|
||||
if (mirage_view)
|
||||
return {pair.first, *mirage_view};
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false);
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
|
||||
}
|
||||
return {current_surface, *view};
|
||||
}
|
||||
// The next case is unsafe, so if we r in accurate GPU, just skip it
|
||||
if (Settings::values.use_accurate_gpu_emulation) {
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false);
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
|
||||
}
|
||||
// This is the case the texture is a part of the parent.
|
||||
if (current_surface->MatchesSubTexture(params, gpu_addr)) {
|
||||
|
@ -599,7 +601,7 @@ private:
|
|||
}
|
||||
}
|
||||
// We failed all the tests, recycle the overlaps into a new texture.
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false);
|
||||
return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch);
|
||||
}
|
||||
|
||||
std::pair<TSurface, TView> InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params,
|
||||
|
|
Loading…
Reference in a new issue