Merge pull request #1160 from bunnei/surface-reserve

gl_rasterizer_cache: Several improvements
This commit is contained in:
bunnei 2018-08-23 12:04:37 -04:00 committed by GitHub
commit 0dce6d7008
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 91 additions and 17 deletions

View file

@ -780,17 +780,30 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
} else if (preserve_contents) {
// If surface parameters changed and we care about keeping the previous data, recreate
// the surface from the old one
return RecreateSurface(surface, params);
UnregisterSurface(surface);
Surface new_surface{RecreateSurface(surface, params)};
RegisterSurface(new_surface);
return new_surface;
} else {
// Delete the old surface before creating a new one to prevent collisions.
UnregisterSurface(surface);
}
}
// Try to get a previously reserved surface
surface = TryGetReservedSurface(params);
// No surface found - create a new one
if (!surface) {
surface = std::make_shared<CachedSurface>(params);
ReserveSurface(surface);
RegisterSurface(surface);
}
// Only load surface from memory if we care about the contents
if (preserve_contents) {
LoadSurface(surface);
}
return surface;
}
@ -799,13 +812,18 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
const SurfaceParams& new_params) {
// Verify surface is compatible for blitting
const auto& params{surface->GetSurfaceParams()};
ASSERT(params.type == new_params.type);
ASSERT_MSG(params.GetCompressionFactor(params.pixel_format) == 1,
"Compressed texture reinterpretation is not supported");
// Create a new surface with the new parameters, and blit the previous surface to it
Surface new_surface{std::make_shared<CachedSurface>(new_params)};
// If format is unchanged, we can do a faster blit without reinterpreting pixel data
if (params.pixel_format == new_params.pixel_format) {
BlitTextures(surface->Texture().handle, params.GetRect(), new_surface->Texture().handle,
new_surface->GetSurfaceParams().GetRect(), params.type,
read_framebuffer.handle, draw_framebuffer.handle);
return new_surface;
}
auto source_format = GetFormatTuple(params.pixel_format, params.component_type);
auto dest_format = GetFormatTuple(new_params.pixel_format, new_params.component_type);
@ -818,9 +836,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
if (source_format.compressed) {
glGetCompressedTextureImage(surface->Texture().handle, 0,
static_cast<GLsizei>(params.SizeInBytes()), nullptr);
} else {
glGetTextureImage(surface->Texture().handle, 0, source_format.format, source_format.type,
params.SizeInBytes(), nullptr);
static_cast<GLsizei>(params.SizeInBytes()), nullptr);
}
// If the new texture is bigger than the previous one, we need to fill in the rest with data
// from the CPU.
if (params.SizeInBytes() < new_params.SizeInBytes()) {
@ -846,17 +868,21 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
const auto& dest_rect{new_params.GetRect()};
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
glTextureSubImage2D(
new_surface->Texture().handle, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, dest_format.type, nullptr);
if (dest_format.compressed) {
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
static_cast<GLsizei>(new_params.SizeInBytes()), nullptr);
} else {
glTextureSubImage2D(new_surface->Texture().handle, 0, 0, 0,
static_cast<GLsizei>(dest_rect.GetWidth()),
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format,
dest_format.type, nullptr);
}
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
pbo.Release();
// Update cache accordingly
UnregisterSurface(surface);
RegisterSurface(new_surface);
return new_surface;
}
@ -931,6 +957,21 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
surface_cache.erase(search);
}
void RasterizerCacheOpenGL::ReserveSurface(const Surface& surface) {
const auto& surface_reserve_key{SurfaceReserveKey::Create(surface->GetSurfaceParams())};
surface_reserve[surface_reserve_key] = surface;
}
Surface RasterizerCacheOpenGL::TryGetReservedSurface(const SurfaceParams& params) {
const auto& surface_reserve_key{SurfaceReserveKey::Create(params)};
auto search{surface_reserve.find(surface_reserve_key)};
if (search != surface_reserve.end()) {
RegisterSurface(search->second);
return search->second;
}
return {};
}
template <typename Map, typename Interval>
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
return boost::make_iterator_range(map.equal_range(interval));

View file

@ -11,6 +11,7 @@
#include <boost/icl/interval_map.hpp>
#include "common/common_types.h"
#include "common/hash.h"
#include "common/math_util.h"
#include "video_core/engines/maxwell_3d.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
@ -682,6 +683,27 @@ struct SurfaceParams {
u32 cache_height;
};
}; // namespace OpenGL
/// Hashable variation of SurfaceParams, used for a key in the surface cache
struct SurfaceReserveKey : Common::HashableStruct<OpenGL::SurfaceParams> {
static SurfaceReserveKey Create(const OpenGL::SurfaceParams& params) {
SurfaceReserveKey res;
res.state = params;
return res;
}
};
namespace std {
template <>
struct hash<SurfaceReserveKey> {
size_t operator()(const SurfaceReserveKey& k) const {
return k.Hash();
}
};
} // namespace std
namespace OpenGL {
class CachedSurface final {
public:
CachedSurface(const SurfaceParams& params);
@ -752,12 +774,23 @@ private:
/// Remove surface from the cache
void UnregisterSurface(const Surface& surface);
/// Reserves a unique surface that can be reused later
void ReserveSurface(const Surface& surface);
/// Tries to get a reserved surface for the specified parameters
Surface TryGetReservedSurface(const SurfaceParams& params);
/// Increase/decrease the number of surface in pages touching the specified region
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache;
PageMap cached_pages;
/// The surface reserve is a "backup" cache, this is where we put unique surfaces that have
/// previously been used. This is to prevent surfaces from being constantly created and
/// destroyed when used with different surface parameters.
std::unordered_map<SurfaceReserveKey, Surface> surface_reserve;
OGLFramebuffer read_framebuffer;
OGLFramebuffer draw_framebuffer;
};