rasterizer_cache: mark reinterpreted surfaces and add ability to reload marked surfaces on next use.

This commit is contained in:
Fernando Sahmkow 2019-02-08 19:40:32 -04:00 committed by FernandoS27
parent d583fc1e97
commit 44ea2810e4
2 changed files with 78 additions and 0 deletions

View File

@ -1007,6 +1007,8 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
if (surface) { if (surface) {
if (surface->GetSurfaceParams().IsCompatibleSurface(params)) { if (surface->GetSurfaceParams().IsCompatibleSurface(params)) {
// Use the cached surface as-is // Use the cached surface as-is
if (surface->MustReload())
LoadSurface(surface);
return surface; return surface;
} 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
@ -1014,6 +1016,9 @@ Surface RasterizerCacheOpenGL::GetSurface(const SurfaceParams& params, bool pres
Surface new_surface{RecreateSurface(surface, params)}; Surface new_surface{RecreateSurface(surface, params)};
Unregister(surface); Unregister(surface);
Register(new_surface); Register(new_surface);
if (new_surface->IsUploaded()) {
RegisterReinterpretSurface(new_surface);
}
return 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.

View File

@ -347,6 +347,10 @@ public:
return cached_size_in_bytes; return cached_size_in_bytes;
} }
std::size_t GetMemorySize() const {
return memory_size;
}
void Flush() override { void Flush() override {
FlushGLBuffer(); FlushGLBuffer();
} }
@ -396,6 +400,26 @@ public:
Tegra::Texture::SwizzleSource swizzle_z, Tegra::Texture::SwizzleSource swizzle_z,
Tegra::Texture::SwizzleSource swizzle_w); Tegra::Texture::SwizzleSource swizzle_w);
void MarkReinterpreted() {
reinterpreted = true;
}
bool IsReinterpreted() {
return reinterpreted;
}
void MarkForReload(bool reload) {
must_reload = reload;
}
bool MustReload() {
return must_reload;
}
bool IsUploaded() {
return params.identity == SurfaceParams::SurfaceClass::Uploaded;
}
private: private:
void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle); void UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle, GLuint draw_fb_handle);
@ -409,6 +433,9 @@ private:
GLenum gl_internal_format{}; GLenum gl_internal_format{};
std::size_t cached_size_in_bytes{}; std::size_t cached_size_in_bytes{};
std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA}; std::array<GLenum, 4> swizzle{GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA};
std::size_t memory_size;
bool reinterpreted = false;
bool must_reload = false;
}; };
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
@ -469,6 +496,9 @@ private:
OGLFramebuffer read_framebuffer; OGLFramebuffer read_framebuffer;
OGLFramebuffer draw_framebuffer; OGLFramebuffer draw_framebuffer;
bool run_texception_pass = false;
bool texception = false;
/// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one
/// using the new format. /// using the new format.
OGLBuffer copy_pbo; OGLBuffer copy_pbo;
@ -476,6 +506,49 @@ private:
std::array<Surface, Maxwell::NumRenderTargets> last_color_buffers; std::array<Surface, Maxwell::NumRenderTargets> last_color_buffers;
std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers; std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers;
Surface last_depth_buffer; Surface last_depth_buffer;
using SurfaceIntervalCache = boost::icl::interval_map<VAddr, Surface>;
using SurfaceInterval = typename IntervalCache::interval_type;
static auto GetReinterpretInterval(const Surface& object) {
return SurfaceInterval::right_open(object->GetAddr() + 1,
object->GetAddr() + object->GetMemorySize() - 1);
}
// Reinterpreted surfaces are very fragil as the game may keep rendering into them.
SurfaceIntervalCache reinterpreted_surfaces;
void RegisterReinterpretSurface(Surface r_surface) {
auto interval = GetReinterpretInterval(r_surface);
reinterpreted_surfaces.insert({interval, r_surface});
r_surface->MarkReinterpreted();
run_texception_pass = true;
}
Surface CollideOnReinterpretedSurface(VAddr addr) const {
const SurfaceInterval interval{addr};
for (auto& pair :
boost::make_iterator_range(reinterpreted_surfaces.equal_range(interval))) {
return pair.second;
}
return nullptr;
}
protected:
void Register(const Surface& object) {
RasterizerCache<Surface>::Register(object);
}
/// Unregisters an object from the cache
void Unregister(const Surface& object) {
const auto& params = object->GetSurfaceParams();
if (object->IsReinterpreted()) {
auto interval = GetReinterpretInterval(object);
reinterpreted_surfaces.erase(interval);
}
RasterizerCache<Surface>::Unregister(object);
}
}; };
} // namespace OpenGL } // namespace OpenGL