mirror of
https://github.com/yuzu-emu/yuzu-mainline.git
synced 2024-12-29 13:45:35 +00:00
rasterizer_cache_gl: Implement Partial Reinterpretation of Surfaces.
This commit is contained in:
parent
44ea2810e4
commit
8932001610
|
@ -1304,9 +1304,98 @@ Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool FindBestMipMap(std::size_t memory, const SurfaceParams params, u32 height, u32& mipmap) {
|
||||||
|
for (u32 i = 0; i < params.max_mip_level; i++)
|
||||||
|
if (memory == params.GetMipmapSingleSize(i) && params.MipHeight(i) == height) {
|
||||||
|
mipmap = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FindBestLayer(VAddr addr, const SurfaceParams params, u32 mipmap, u32& layer) {
|
||||||
|
std::size_t size = params.LayerMemorySize();
|
||||||
|
VAddr start = params.addr + params.GetMipmapLevelOffset(mipmap);
|
||||||
|
for (u32 i = 0; i < params.depth; i++) {
|
||||||
|
if (start == addr) {
|
||||||
|
layer = i;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
start += size;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool LayerFitReinterpretSurface(RasterizerCacheOpenGL& cache, const Surface render_surface,
|
||||||
|
const Surface blitted_surface) {
|
||||||
|
const auto dst_params = blitted_surface->GetSurfaceParams();
|
||||||
|
const auto src_params = render_surface->GetSurfaceParams();
|
||||||
|
u32 level = 0;
|
||||||
|
std::size_t src_memory_size = src_params.size_in_bytes;
|
||||||
|
if (FindBestMipMap(src_memory_size, dst_params, src_params.height, level)) {
|
||||||
|
if (src_params.width == dst_params.MipWidthGobAligned(level) &&
|
||||||
|
src_params.height == dst_params.MipHeight(level) &&
|
||||||
|
src_params.block_height >= dst_params.MipBlockHeight(level)) {
|
||||||
|
u32 slot = 0;
|
||||||
|
if (FindBestLayer(render_surface->GetAddr(), dst_params, level, slot)) {
|
||||||
|
glCopyImageSubData(
|
||||||
|
render_surface->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, 0,
|
||||||
|
0, blitted_surface->Texture().handle, SurfaceTargetToGL(dst_params.target),
|
||||||
|
level, 0, 0, slot, dst_params.MipWidth(level), dst_params.MipHeight(level), 1);
|
||||||
|
blitted_surface->MarkAsModified(true, cache);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsReinterpretInvalid(const Surface render_surface, const Surface blitted_surface) {
|
||||||
|
VAddr bound1 = blitted_surface->GetAddr() + blitted_surface->GetMemorySize();
|
||||||
|
VAddr bound2 = render_surface->GetAddr() + render_surface->GetMemorySize();
|
||||||
|
if (bound2 > bound1)
|
||||||
|
return true;
|
||||||
|
const auto dst_params = blitted_surface->GetSurfaceParams();
|
||||||
|
const auto src_params = render_surface->GetSurfaceParams();
|
||||||
|
if (dst_params.component_type != src_params.component_type)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool IsReinterpretInvalidSecond(const Surface render_surface, const Surface blitted_surface) {
|
||||||
|
const auto dst_params = blitted_surface->GetSurfaceParams();
|
||||||
|
const auto src_params = render_surface->GetSurfaceParams();
|
||||||
|
if (dst_params.height > src_params.height && dst_params.width > src_params.width)
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool RasterizerCacheOpenGL::PartialReinterpretSurface(Surface triggering_surface,
|
||||||
|
Surface intersect) {
|
||||||
|
if (IsReinterpretInvalid(triggering_surface, intersect)) {
|
||||||
|
Unregister(intersect);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!LayerFitReinterpretSurface(*this, triggering_surface, intersect)) {
|
||||||
|
if (IsReinterpretInvalidSecond(triggering_surface, intersect)) {
|
||||||
|
Unregister(intersect);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
FlushObject(intersect);
|
||||||
|
FlushObject(triggering_surface);
|
||||||
|
intersect->MarkForReload(true);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) {
|
void RasterizerCacheOpenGL::NotifyFrameBufferChange(Surface triggering_surface) {
|
||||||
if (triggering_surface == nullptr)
|
if (triggering_surface == nullptr)
|
||||||
return;
|
return;
|
||||||
|
Surface intersect = CollideOnReinterpretedSurface(triggering_surface->GetAddr());
|
||||||
|
if (intersect != nullptr) {
|
||||||
|
PartialReinterpretSurface(triggering_surface, intersect);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
|
@ -141,10 +141,18 @@ struct SurfaceParams {
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::size_t GetMipmapSingleSize(u32 mip_level) const {
|
||||||
|
return InnerMipmapMemorySize(mip_level, false, is_layered);
|
||||||
|
}
|
||||||
|
|
||||||
u32 MipWidth(u32 mip_level) const {
|
u32 MipWidth(u32 mip_level) const {
|
||||||
return std::max(1U, width >> mip_level);
|
return std::max(1U, width >> mip_level);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u32 MipWidthGobAligned(u32 mip_level) const {
|
||||||
|
return std::max(64U*8U / GetFormatBpp(), width >> mip_level);
|
||||||
|
}
|
||||||
|
|
||||||
u32 MipHeight(u32 mip_level) const {
|
u32 MipHeight(u32 mip_level) const {
|
||||||
return std::max(1U, height >> mip_level);
|
return std::max(1U, height >> mip_level);
|
||||||
}
|
}
|
||||||
|
@ -480,6 +488,9 @@ private:
|
||||||
/// When a render target is changed, this method is called with the previous render target
|
/// When a render target is changed, this method is called with the previous render target
|
||||||
void NotifyFrameBufferChange(Surface triggering_surface);
|
void NotifyFrameBufferChange(Surface triggering_surface);
|
||||||
|
|
||||||
|
// Partialy reinterpret a surface based on a triggering_surface that collides with it.
|
||||||
|
bool PartialReinterpretSurface(Surface triggering_surface, Surface intersect);
|
||||||
|
|
||||||
/// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
|
/// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data
|
||||||
void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
|
void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface);
|
||||||
void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
|
void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface);
|
||||||
|
|
Loading…
Reference in a new issue