rasterizer_cache: mark reinterpreted surfaces and add ability to reload marked surfaces on next use.
This commit is contained in:
parent
d583fc1e97
commit
44ea2810e4
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
Reference in New Issue