forked from ShuriZma/suyu
Merge pull request #1160 from bunnei/surface-reserve
gl_rasterizer_cache: Several improvements
This commit is contained in:
commit
0dce6d7008
|
@ -780,17 +780,30 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
|
||||||
} else if (preserve_contents) {
|
} else if (preserve_contents) {
|
||||||
// If surface parameters changed and we care about keeping the previous data, recreate
|
// If surface parameters changed and we care about keeping the previous data, recreate
|
||||||
// the surface from the old one
|
// 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 {
|
} else {
|
||||||
// Delete the old surface before creating a new one to prevent collisions.
|
// Delete the old surface before creating a new one to prevent collisions.
|
||||||
UnregisterSurface(surface);
|
UnregisterSurface(surface);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Try to get a previously reserved surface
|
||||||
|
surface = TryGetReservedSurface(params);
|
||||||
|
|
||||||
// No surface found - create a new one
|
// No surface found - create a new one
|
||||||
|
if (!surface) {
|
||||||
surface = std::make_shared<CachedSurface>(params);
|
surface = std::make_shared<CachedSurface>(params);
|
||||||
|
ReserveSurface(surface);
|
||||||
RegisterSurface(surface);
|
RegisterSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only load surface from memory if we care about the contents
|
||||||
|
if (preserve_contents) {
|
||||||
LoadSurface(surface);
|
LoadSurface(surface);
|
||||||
|
}
|
||||||
|
|
||||||
return surface;
|
return surface;
|
||||||
}
|
}
|
||||||
|
@ -799,13 +812,18 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
const SurfaceParams& new_params) {
|
const SurfaceParams& new_params) {
|
||||||
// Verify surface is compatible for blitting
|
// Verify surface is compatible for blitting
|
||||||
const auto& params{surface->GetSurfaceParams()};
|
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
|
// Create a new surface with the new parameters, and blit the previous surface to it
|
||||||
Surface new_surface{std::make_shared<CachedSurface>(new_params)};
|
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 source_format = GetFormatTuple(params.pixel_format, params.component_type);
|
||||||
auto dest_format = GetFormatTuple(new_params.pixel_format, new_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);
|
glBindBuffer(GL_PIXEL_PACK_BUFFER, pbo.handle);
|
||||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
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,
|
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
|
// If the new texture is bigger than the previous one, we need to fill in the rest with data
|
||||||
// from the CPU.
|
// from the CPU.
|
||||||
if (params.SizeInBytes() < new_params.SizeInBytes()) {
|
if (params.SizeInBytes() < new_params.SizeInBytes()) {
|
||||||
|
@ -846,17 +868,21 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& surface,
|
||||||
const auto& dest_rect{new_params.GetRect()};
|
const auto& dest_rect{new_params.GetRect()};
|
||||||
|
|
||||||
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbo.handle);
|
||||||
glTextureSubImage2D(
|
if (dest_format.compressed) {
|
||||||
new_surface->Texture().handle, 0, 0, 0, static_cast<GLsizei>(dest_rect.GetWidth()),
|
glCompressedTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0,
|
||||||
static_cast<GLsizei>(dest_rect.GetHeight()), dest_format.format, dest_format.type, nullptr);
|
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);
|
glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
|
||||||
|
|
||||||
pbo.Release();
|
pbo.Release();
|
||||||
|
|
||||||
// Update cache accordingly
|
|
||||||
UnregisterSurface(surface);
|
|
||||||
RegisterSurface(new_surface);
|
|
||||||
|
|
||||||
return new_surface;
|
return new_surface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -931,6 +957,21 @@ void RasterizerCacheOpenGL::UnregisterSurface(const Surface& surface) {
|
||||||
surface_cache.erase(search);
|
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>
|
template <typename Map, typename Interval>
|
||||||
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
constexpr auto RangeFromInterval(Map& map, const Interval& interval) {
|
||||||
return boost::make_iterator_range(map.equal_range(interval));
|
return boost::make_iterator_range(map.equal_range(interval));
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include <boost/icl/interval_map.hpp>
|
#include <boost/icl/interval_map.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
#include "common/hash.h"
|
||||||
#include "common/math_util.h"
|
#include "common/math_util.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||||
|
@ -682,6 +683,27 @@ struct SurfaceParams {
|
||||||
u32 cache_height;
|
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 {
|
class CachedSurface final {
|
||||||
public:
|
public:
|
||||||
CachedSurface(const SurfaceParams& params);
|
CachedSurface(const SurfaceParams& params);
|
||||||
|
@ -752,12 +774,23 @@ private:
|
||||||
/// Remove surface from the cache
|
/// Remove surface from the cache
|
||||||
void UnregisterSurface(const Surface& surface);
|
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
|
/// Increase/decrease the number of surface in pages touching the specified region
|
||||||
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
|
void UpdatePagesCachedCount(Tegra::GPUVAddr addr, u64 size, int delta);
|
||||||
|
|
||||||
std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache;
|
std::unordered_map<Tegra::GPUVAddr, Surface> surface_cache;
|
||||||
PageMap cached_pages;
|
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 read_framebuffer;
|
||||||
OGLFramebuffer draw_framebuffer;
|
OGLFramebuffer draw_framebuffer;
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue