gl_rasterizer_cache: Recycle host textures
Allocating new textures has fairly high driver overhead. We can avoid some of this by reusing the textures from destroyed surfaces since the game will probably create more textures with the same dimensions and format.
This commit is contained in:
parent
935e88a580
commit
85e9ba897d
|
@ -494,6 +494,10 @@ static bool FillSurface(const Surface& surface, const u8* fill_data,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CachedSurface::~CachedSurface() {
|
||||||
|
owner.host_texture_recycler.emplace(*this, std::move(texture));
|
||||||
|
}
|
||||||
|
|
||||||
bool CachedSurface::CanFill(const SurfaceParams& dest_surface,
|
bool CachedSurface::CanFill(const SurfaceParams& dest_surface,
|
||||||
SurfaceInterval fill_interval) const {
|
SurfaceInterval fill_interval) const {
|
||||||
if (type == SurfaceType::Fill && IsRegionValid(fill_interval) &&
|
if (type == SurfaceType::Fill && IsRegionValid(fill_interval) &&
|
||||||
|
@ -1893,12 +1897,17 @@ Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) {
|
||||||
Surface surface = std::make_shared<CachedSurface>(*this);
|
Surface surface = std::make_shared<CachedSurface>(*this);
|
||||||
static_cast<SurfaceParams&>(*surface) = params;
|
static_cast<SurfaceParams&>(*surface) = params;
|
||||||
|
|
||||||
surface->texture.Create();
|
|
||||||
|
|
||||||
surface->gl_buffer.resize(0);
|
|
||||||
surface->invalid_regions.insert(surface->GetInterval());
|
surface->invalid_regions.insert(surface->GetInterval());
|
||||||
AllocateSurfaceTexture(surface->texture.handle, GetFormatTuple(surface->pixel_format),
|
|
||||||
surface->GetScaledWidth(), surface->GetScaledHeight());
|
auto recycled_texture = host_texture_recycler.find(params);
|
||||||
|
if (recycled_texture == host_texture_recycler.end()) {
|
||||||
|
surface->texture.Create();
|
||||||
|
AllocateSurfaceTexture(surface->texture.handle, GetFormatTuple(surface->pixel_format),
|
||||||
|
surface->GetScaledWidth(), surface->GetScaledHeight());
|
||||||
|
} else {
|
||||||
|
surface->texture = std::move(recycled_texture->second);
|
||||||
|
host_texture_recycler.erase(recycled_texture);
|
||||||
|
}
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
|
|
@ -36,6 +36,36 @@ class RasterizerCacheOpenGL;
|
||||||
class TextureFilterer;
|
class TextureFilterer;
|
||||||
class FormatReinterpreterOpenGL;
|
class FormatReinterpreterOpenGL;
|
||||||
|
|
||||||
|
struct FormatTuple {
|
||||||
|
GLint internal_format;
|
||||||
|
GLenum format;
|
||||||
|
GLenum type;
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
|
||||||
|
|
||||||
|
const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format);
|
||||||
|
|
||||||
|
struct HostTextureTag {
|
||||||
|
GLint internal_format;
|
||||||
|
GLenum format;
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
HostTextureTag(const SurfaceParams& params) noexcept {
|
||||||
|
auto format_tuple = GetFormatTuple(params.pixel_format);
|
||||||
|
internal_format = format_tuple.internal_format;
|
||||||
|
format = format_tuple.format;
|
||||||
|
// The type in the format tuple is irrelevant for the tag since the type is only for
|
||||||
|
// interpreting data on upload/download
|
||||||
|
width = params.GetScaledWidth();
|
||||||
|
height = params.GetScaledHeight();
|
||||||
|
}
|
||||||
|
bool operator==(const HostTextureTag& rhs) const noexcept {
|
||||||
|
return std::tie(internal_format, format, width, height) ==
|
||||||
|
std::tie(rhs.internal_format, rhs.format, rhs.width, rhs.height);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
struct TextureCubeConfig {
|
struct TextureCubeConfig {
|
||||||
PAddr px;
|
PAddr px;
|
||||||
PAddr nx;
|
PAddr nx;
|
||||||
|
@ -59,6 +89,18 @@ struct TextureCubeConfig {
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
||||||
namespace std {
|
namespace std {
|
||||||
|
template <>
|
||||||
|
struct hash<OpenGL::HostTextureTag> {
|
||||||
|
std::size_t operator()(const OpenGL::HostTextureTag& tag) const noexcept {
|
||||||
|
std::size_t hash = 0;
|
||||||
|
boost::hash_combine(hash, tag.format);
|
||||||
|
boost::hash_combine(hash, tag.internal_format);
|
||||||
|
boost::hash_combine(hash, tag.width);
|
||||||
|
boost::hash_combine(hash, tag.height);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct hash<OpenGL::TextureCubeConfig> {
|
struct hash<OpenGL::TextureCubeConfig> {
|
||||||
std::size_t operator()(const OpenGL::TextureCubeConfig& config) const noexcept {
|
std::size_t operator()(const OpenGL::TextureCubeConfig& config) const noexcept {
|
||||||
|
@ -139,6 +181,7 @@ private:
|
||||||
|
|
||||||
struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface> {
|
struct CachedSurface : SurfaceParams, std::enable_shared_from_this<CachedSurface> {
|
||||||
CachedSurface(RasterizerCacheOpenGL& owner) : owner{owner} {}
|
CachedSurface(RasterizerCacheOpenGL& owner) : owner{owner} {}
|
||||||
|
~CachedSurface();
|
||||||
|
|
||||||
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
|
bool CanFill(const SurfaceParams& dest_surface, SurfaceInterval fill_interval) const;
|
||||||
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
|
bool CanCopy(const SurfaceParams& dest_surface, SurfaceInterval copy_interval) const;
|
||||||
|
@ -326,17 +369,12 @@ private:
|
||||||
std::unordered_map<TextureCubeConfig, CachedTextureCube> texture_cube_cache;
|
std::unordered_map<TextureCubeConfig, CachedTextureCube> texture_cube_cache;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
// Textures from destroyed surfaces are stored here to be recyled to reduce allocation overhead
|
||||||
|
// in the driver
|
||||||
|
std::unordered_multimap<HostTextureTag, OGLTexture> host_texture_recycler;
|
||||||
|
|
||||||
std::unique_ptr<TextureFilterer> texture_filterer;
|
std::unique_ptr<TextureFilterer> texture_filterer;
|
||||||
std::unique_ptr<FormatReinterpreterOpenGL> format_reinterpreter;
|
std::unique_ptr<FormatReinterpreterOpenGL> format_reinterpreter;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FormatTuple {
|
|
||||||
GLint internal_format;
|
|
||||||
GLenum format;
|
|
||||||
GLenum type;
|
|
||||||
};
|
|
||||||
|
|
||||||
constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
|
|
||||||
|
|
||||||
const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format);
|
|
||||||
} // namespace OpenGL
|
} // namespace OpenGL
|
||||||
|
|
Reference in New Issue