fix recycling custom textures

This commit is contained in:
BreadFish64 2021-02-08 15:38:30 -06:00
parent 00c798991c
commit ff56fdf37d
2 changed files with 41 additions and 45 deletions

View file

@ -311,13 +311,21 @@ static constexpr std::array<void (*)(u32, u32, u8*, PAddr, PAddr, PAddr), 18> gl
}; };
// Allocate an uninitialized texture of appropriate size and format for the surface // Allocate an uninitialized texture of appropriate size and format for the surface
static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tuple, u32 width, OGLTexture RasterizerCacheOpenGL::AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width,
u32 height) { u32 height) {
OpenGLState cur_state = OpenGLState::GetCurState(); auto recycled_tex = host_texture_recycler.find({format_tuple, width, height});
if (recycled_tex != host_texture_recycler.end()) {
OGLTexture texture = std::move(recycled_tex->second);
host_texture_recycler.erase(recycled_tex);
return texture;
}
OGLTexture texture;
texture.Create();
OpenGLState cur_state = OpenGLState::GetCurState();
// Keep track of previous texture bindings // Keep track of previous texture bindings
GLuint old_tex = cur_state.texture_units[0].texture_2d; GLuint old_tex = cur_state.texture_units[0].texture_2d;
cur_state.texture_units[0].texture_2d = texture; cur_state.texture_units[0].texture_2d = texture.handle;
cur_state.Apply(); cur_state.Apply();
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
@ -332,6 +340,8 @@ static void AllocateSurfaceTexture(GLuint texture, const FormatTuple& format_tup
// Restore previous texture bindings // Restore previous texture bindings
cur_state.texture_units[0].texture_2d = old_tex; cur_state.texture_units[0].texture_2d = old_tex;
cur_state.Apply(); cur_state.Apply();
return texture;
} }
static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple, u32 width) { static void AllocateTextureCube(GLuint texture, const FormatTuple& format_tuple, u32 width) {
@ -496,7 +506,12 @@ static bool FillSurface(const Surface& surface, const u8* fill_data,
CachedSurface::~CachedSurface() { CachedSurface::~CachedSurface() {
if (texture.handle) { if (texture.handle) {
owner.host_texture_recycler.emplace(*this, std::move(texture)); auto tag = is_custom ? HostTextureTag{GetFormatTuple(PixelFormat::RGBA8),
custom_tex_info.width, custom_tex_info.height}
: HostTextureTag{GetFormatTuple(pixel_format), GetScaledWidth(),
GetScaledHeight()};
owner.host_texture_recycler.emplace(tag, std::move(texture));
} }
} }
@ -819,12 +834,11 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
x0 = 0; x0 = 0;
y0 = 0; y0 = 0;
unscaled_tex.Create();
if (is_custom) { if (is_custom) {
AllocateSurfaceTexture(unscaled_tex.handle, GetFormatTuple(PixelFormat::RGBA8), unscaled_tex = owner.AllocateSurfaceTexture(
custom_tex_info.width, custom_tex_info.height); GetFormatTuple(PixelFormat::RGBA8), custom_tex_info.width, custom_tex_info.height);
} else { } else {
AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); unscaled_tex = owner.AllocateSurfaceTexture(tuple, rect.GetWidth(), rect.GetHeight());
} }
target_tex = unscaled_tex.handle; target_tex = unscaled_tex.handle;
} }
@ -839,7 +853,7 @@ void CachedSurface::UploadGLTexture(Common::Rectangle<u32> rect, GLuint read_fb_
ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0); ASSERT(stride * GetGLBytesPerPixel(pixel_format) % 4 == 0);
if (is_custom) { if (is_custom) {
if (res_scale == 1) { if (res_scale == 1) {
AllocateSurfaceTexture(texture.handle, GetFormatTuple(PixelFormat::RGBA8), texture = owner.AllocateSurfaceTexture(GetFormatTuple(PixelFormat::RGBA8),
custom_tex_info.width, custom_tex_info.height); custom_tex_info.width, custom_tex_info.height);
cur_state.texture_units[0].texture_2d = texture.handle; cur_state.texture_units[0].texture_2d = texture.handle;
cur_state.Apply(); cur_state.Apply();
@ -917,11 +931,9 @@ void CachedSurface::DownloadGLTexture(const Common::Rectangle<u32>& rect, GLuint
scaled_rect.right *= res_scale; scaled_rect.right *= res_scale;
scaled_rect.bottom *= res_scale; scaled_rect.bottom *= res_scale;
OGLTexture unscaled_tex;
unscaled_tex.Create();
Common::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0}; Common::Rectangle<u32> unscaled_tex_rect{0, rect.GetHeight(), rect.GetWidth(), 0};
AllocateSurfaceTexture(unscaled_tex.handle, tuple, rect.GetWidth(), rect.GetHeight()); OGLTexture unscaled_tex =
owner.AllocateSurfaceTexture(tuple, rect.GetWidth(), rect.GetHeight());
BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type, BlitTextures(texture.handle, scaled_rect, unscaled_tex.handle, unscaled_tex_rect, type,
read_fb_handle, draw_fb_handle); read_fb_handle, draw_fb_handle);
@ -1741,15 +1753,12 @@ bool RasterizerCacheOpenGL::ValidateByReinterpretation(const Surface& surface,
if (!texture_filterer->IsNull() && reinterpret_surface->res_scale == 1 && if (!texture_filterer->IsNull() && reinterpret_surface->res_scale == 1 &&
surface->res_scale == resolution_scale_factor) { surface->res_scale == resolution_scale_factor) {
// The destination surface is either a framebuffer, or a filtered texture. // The destination surface is either a framebuffer, or a filtered texture.
OGLTexture tmp_tex;
tmp_tex.Create();
// Create an intermediate surface to convert to before blitting to the // Create an intermediate surface to convert to before blitting to the
// destination. // destination.
Common::Rectangle<u32> tmp_rect{0, dest_rect.GetHeight() / resolution_scale_factor, Common::Rectangle<u32> tmp_rect{0, dest_rect.GetHeight() / resolution_scale_factor,
dest_rect.GetWidth() / resolution_scale_factor, 0}; dest_rect.GetWidth() / resolution_scale_factor, 0};
AllocateSurfaceTexture(tmp_tex.handle, OGLTexture tmp_tex = AllocateSurfaceTexture(
GetFormatTuple(reinterpreter->first.dst_format), GetFormatTuple(reinterpreter->first.dst_format), tmp_rect.right, tmp_rect.top);
tmp_rect.right, tmp_rect.top);
reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect, reinterpreter->second->Reinterpret(reinterpret_surface->texture.handle, src_rect,
read_framebuffer.handle, tmp_tex.handle, read_framebuffer.handle, tmp_tex.handle,
tmp_rect, draw_framebuffer.handle); tmp_rect, draw_framebuffer.handle);
@ -1901,15 +1910,9 @@ Surface RasterizerCacheOpenGL::CreateSurface(const SurfaceParams& params) {
surface->invalid_regions.insert(surface->GetInterval()); surface->invalid_regions.insert(surface->GetInterval());
auto recycled_texture = host_texture_recycler.find(params); surface->texture =
if (recycled_texture == host_texture_recycler.end()) { AllocateSurfaceTexture(GetFormatTuple(surface->pixel_format), surface->GetScaledWidth(),
surface->texture.Create(); surface->GetScaledHeight());
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;
} }

View file

@ -47,23 +47,14 @@ constexpr FormatTuple tex_tuple = {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE};
const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format); const FormatTuple& GetFormatTuple(SurfaceParams::PixelFormat pixel_format);
struct HostTextureTag { struct HostTextureTag {
GLint internal_format; FormatTuple format_tuple;
GLenum format;
u32 width; u32 width;
u32 height; 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 { bool operator==(const HostTextureTag& rhs) const noexcept {
return std::tie(internal_format, format, width, height) == return std::tie(format_tuple.format, format_tuple.internal_format, width, height) ==
std::tie(rhs.internal_format, rhs.format, rhs.width, rhs.height); std::tie(rhs.format_tuple.format, rhs.format_tuple.internal_format, rhs.width,
} rhs.height);
};
}; };
struct TextureCubeConfig { struct TextureCubeConfig {
@ -93,8 +84,8 @@ template <>
struct hash<OpenGL::HostTextureTag> { struct hash<OpenGL::HostTextureTag> {
std::size_t operator()(const OpenGL::HostTextureTag& tag) const noexcept { std::size_t operator()(const OpenGL::HostTextureTag& tag) const noexcept {
std::size_t hash = 0; std::size_t hash = 0;
boost::hash_combine(hash, tag.format); boost::hash_combine(hash, tag.format_tuple.format);
boost::hash_combine(hash, tag.internal_format); boost::hash_combine(hash, tag.format_tuple.internal_format);
boost::hash_combine(hash, tag.width); boost::hash_combine(hash, tag.width);
boost::hash_combine(hash, tag.height); boost::hash_combine(hash, tag.height);
return hash; return hash;
@ -369,6 +360,8 @@ private:
std::unordered_map<TextureCubeConfig, CachedTextureCube> texture_cube_cache; std::unordered_map<TextureCubeConfig, CachedTextureCube> texture_cube_cache;
public: public:
OGLTexture AllocateSurfaceTexture(const FormatTuple& format_tuple, u32 width, u32 height);
// Textures from destroyed surfaces are stored here to be recyled to reduce allocation overhead // Textures from destroyed surfaces are stored here to be recyled to reduce allocation overhead
// in the driver // in the driver
std::unordered_multimap<HostTextureTag, OGLTexture> host_texture_recycler; std::unordered_multimap<HostTextureTag, OGLTexture> host_texture_recycler;