texture_cache: Remove old rasterizer cache
This commit is contained in:
		 Fernando Sahmkow
					Fernando Sahmkow
				
			
				
					committed by
					
						 ReinUsesLisp
						ReinUsesLisp
					
				
			
			
				
	
			
			
			 ReinUsesLisp
						ReinUsesLisp
					
				
			
						parent
						
							2d83553ea7
						
					
				
				
					commit
					4db28f72f6
				
			
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							| @@ -1,575 +0,0 @@ | ||||
| // Copyright 2018 yuzu Emulator Project | ||||
| // Licensed under GPLv2 or any later version | ||||
| // Refer to the license.txt file included. | ||||
|  | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <memory> | ||||
| #include <string> | ||||
| #include <tuple> | ||||
| #include <vector> | ||||
|  | ||||
| #include "common/alignment.h" | ||||
| #include "common/bit_util.h" | ||||
| #include "common/common_types.h" | ||||
| #include "common/hash.h" | ||||
| #include "common/math_util.h" | ||||
| #include "video_core/engines/fermi_2d.h" | ||||
| #include "video_core/engines/maxwell_3d.h" | ||||
| #include "video_core/rasterizer_cache.h" | ||||
| #include "video_core/renderer_opengl/gl_resource_manager.h" | ||||
| #include "video_core/renderer_opengl/gl_shader_gen.h" | ||||
| #include "video_core/surface.h" | ||||
| #include "video_core/textures/decoders.h" | ||||
| #include "video_core/textures/texture.h" | ||||
|  | ||||
| namespace OpenGL { | ||||
|  | ||||
| class CachedSurface; | ||||
| using Surface = std::shared_ptr<CachedSurface>; | ||||
| using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, Common::Rectangle<u32>>; | ||||
|  | ||||
| using SurfaceTarget = VideoCore::Surface::SurfaceTarget; | ||||
| using SurfaceType = VideoCore::Surface::SurfaceType; | ||||
| using PixelFormat = VideoCore::Surface::PixelFormat; | ||||
| using ComponentType = VideoCore::Surface::ComponentType; | ||||
| using Maxwell = Tegra::Engines::Maxwell3D::Regs; | ||||
|  | ||||
| struct SurfaceParams { | ||||
|     enum class SurfaceClass { | ||||
|         Uploaded, | ||||
|         RenderTarget, | ||||
|         DepthBuffer, | ||||
|         Copy, | ||||
|     }; | ||||
|  | ||||
|     static std::string SurfaceTargetName(SurfaceTarget target) { | ||||
|         switch (target) { | ||||
|         case SurfaceTarget::Texture1D: | ||||
|             return "Texture1D"; | ||||
|         case SurfaceTarget::Texture2D: | ||||
|             return "Texture2D"; | ||||
|         case SurfaceTarget::Texture3D: | ||||
|             return "Texture3D"; | ||||
|         case SurfaceTarget::Texture1DArray: | ||||
|             return "Texture1DArray"; | ||||
|         case SurfaceTarget::Texture2DArray: | ||||
|             return "Texture2DArray"; | ||||
|         case SurfaceTarget::TextureCubemap: | ||||
|             return "TextureCubemap"; | ||||
|         case SurfaceTarget::TextureCubeArray: | ||||
|             return "TextureCubeArray"; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target)); | ||||
|             UNREACHABLE(); | ||||
|             return fmt::format("TextureUnknown({})", static_cast<u32>(target)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     u32 GetFormatBpp() const { | ||||
|         return VideoCore::Surface::GetFormatBpp(pixel_format); | ||||
|     } | ||||
|  | ||||
|     /// Returns the rectangle corresponding to this surface | ||||
|     Common::Rectangle<u32> GetRect(u32 mip_level = 0) const; | ||||
|  | ||||
|     /// Returns the total size of this surface in bytes, adjusted for compression | ||||
|     std::size_t SizeInBytesRaw(bool ignore_tiled = false) const { | ||||
|         const u32 compression_factor{GetCompressionFactor(pixel_format)}; | ||||
|         const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)}; | ||||
|         const size_t uncompressed_size{ | ||||
|             Tegra::Texture::CalculateSize((ignore_tiled ? false : is_tiled), bytes_per_pixel, width, | ||||
|                                           height, depth, block_height, block_depth)}; | ||||
|  | ||||
|         // Divide by compression_factor^2, as height and width are factored by this | ||||
|         return uncompressed_size / (compression_factor * compression_factor); | ||||
|     } | ||||
|  | ||||
|     /// Returns the size of this surface as an OpenGL texture in bytes | ||||
|     std::size_t SizeInBytesGL() const { | ||||
|         return SizeInBytesRaw(true); | ||||
|     } | ||||
|  | ||||
|     /// Returns the size of this surface as a cube face in bytes | ||||
|     std::size_t SizeInBytesCubeFace() const { | ||||
|         return size_in_bytes / 6; | ||||
|     } | ||||
|  | ||||
|     /// Returns the size of this surface as an OpenGL cube face in bytes | ||||
|     std::size_t SizeInBytesCubeFaceGL() const { | ||||
|         return size_in_bytes_gl / 6; | ||||
|     } | ||||
|  | ||||
|     /// Returns the exact size of memory occupied by the texture in VRAM, including mipmaps. | ||||
|     std::size_t MemorySize() const { | ||||
|         std::size_t size = InnerMemorySize(false, is_layered); | ||||
|         if (is_layered) | ||||
|             return size * depth; | ||||
|         return size; | ||||
|     } | ||||
|  | ||||
|     /// Returns true if the parameters constitute a valid rasterizer surface. | ||||
|     bool IsValid() const { | ||||
|         return gpu_addr && host_ptr && height && width; | ||||
|     } | ||||
|  | ||||
|     /// Returns the exact size of the memory occupied by a layer in a texture in VRAM, including | ||||
|     /// mipmaps. | ||||
|     std::size_t LayerMemorySize() const { | ||||
|         return InnerMemorySize(false, true); | ||||
|     } | ||||
|  | ||||
|     /// Returns the size of a layer of this surface in OpenGL. | ||||
|     std::size_t LayerSizeGL(u32 mip_level) const { | ||||
|         return InnerMipmapMemorySize(mip_level, true, is_layered, false); | ||||
|     } | ||||
|  | ||||
|     std::size_t GetMipmapSizeGL(u32 mip_level, bool ignore_compressed = true) const { | ||||
|         std::size_t size = InnerMipmapMemorySize(mip_level, true, is_layered, ignore_compressed); | ||||
|         if (is_layered) | ||||
|             return size * depth; | ||||
|         return size; | ||||
|     } | ||||
|  | ||||
|     std::size_t GetMipmapLevelOffset(u32 mip_level) const { | ||||
|         std::size_t offset = 0; | ||||
|         for (u32 i = 0; i < mip_level; i++) | ||||
|             offset += InnerMipmapMemorySize(i, false, is_layered); | ||||
|         return offset; | ||||
|     } | ||||
|  | ||||
|     std::size_t GetMipmapLevelOffsetGL(u32 mip_level) const { | ||||
|         std::size_t offset = 0; | ||||
|         for (u32 i = 0; i < mip_level; i++) | ||||
|             offset += InnerMipmapMemorySize(i, true, is_layered); | ||||
|         return offset; | ||||
|     } | ||||
|  | ||||
|     std::size_t GetMipmapSingleSize(u32 mip_level) const { | ||||
|         return InnerMipmapMemorySize(mip_level, false, is_layered); | ||||
|     } | ||||
|  | ||||
|     u32 MipWidth(u32 mip_level) const { | ||||
|         return std::max(1U, width >> mip_level); | ||||
|     } | ||||
|  | ||||
|     u32 MipWidthGobAligned(u32 mip_level) const { | ||||
|         return Common::AlignUp(std::max(1U, width >> mip_level), 64U * 8U / GetFormatBpp()); | ||||
|     } | ||||
|  | ||||
|     u32 MipHeight(u32 mip_level) const { | ||||
|         return std::max(1U, height >> mip_level); | ||||
|     } | ||||
|  | ||||
|     u32 MipDepth(u32 mip_level) const { | ||||
|         return is_layered ? depth : std::max(1U, depth >> mip_level); | ||||
|     } | ||||
|  | ||||
|     // Auto block resizing algorithm from: | ||||
|     // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c | ||||
|     u32 MipBlockHeight(u32 mip_level) const { | ||||
|         if (mip_level == 0) | ||||
|             return block_height; | ||||
|         u32 alt_height = MipHeight(mip_level); | ||||
|         u32 h = GetDefaultBlockHeight(pixel_format); | ||||
|         u32 blocks_in_y = (alt_height + h - 1) / h; | ||||
|         u32 bh = 16; | ||||
|         while (bh > 1 && blocks_in_y <= bh * 4) { | ||||
|             bh >>= 1; | ||||
|         } | ||||
|         return bh; | ||||
|     } | ||||
|  | ||||
|     u32 MipBlockDepth(u32 mip_level) const { | ||||
|         if (mip_level == 0) { | ||||
|             return block_depth; | ||||
|         } | ||||
|  | ||||
|         if (is_layered) { | ||||
|             return 1; | ||||
|         } | ||||
|  | ||||
|         const u32 mip_depth = MipDepth(mip_level); | ||||
|         u32 bd = 32; | ||||
|         while (bd > 1 && mip_depth * 2 <= bd) { | ||||
|             bd >>= 1; | ||||
|         } | ||||
|  | ||||
|         if (bd == 32) { | ||||
|             const u32 bh = MipBlockHeight(mip_level); | ||||
|             if (bh >= 4) { | ||||
|                 return 16; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return bd; | ||||
|     } | ||||
|  | ||||
|     u32 RowAlign(u32 mip_level) const { | ||||
|         const u32 m_width = MipWidth(mip_level); | ||||
|         const u32 bytes_per_pixel = GetBytesPerPixel(pixel_format); | ||||
|         const u32 l2 = Common::CountTrailingZeroes32(m_width * bytes_per_pixel); | ||||
|         return (1U << l2); | ||||
|     } | ||||
|  | ||||
|     /// Creates SurfaceParams from a texture configuration | ||||
|     static SurfaceParams CreateForTexture(const Tegra::Texture::FullTextureInfo& config, | ||||
|                                           const GLShader::SamplerEntry& entry); | ||||
|  | ||||
|     /// Creates SurfaceParams from a framebuffer configuration | ||||
|     static SurfaceParams CreateForFramebuffer(std::size_t index); | ||||
|  | ||||
|     /// Creates SurfaceParams for a depth buffer configuration | ||||
|     static SurfaceParams CreateForDepthBuffer( | ||||
|         u32 zeta_width, u32 zeta_height, GPUVAddr zeta_address, Tegra::DepthFormat format, | ||||
|         u32 block_width, u32 block_height, u32 block_depth, | ||||
|         Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type); | ||||
|  | ||||
|     /// Creates SurfaceParams for a Fermi2D surface copy | ||||
|     static SurfaceParams CreateForFermiCopySurface( | ||||
|         const Tegra::Engines::Fermi2D::Regs::Surface& config); | ||||
|  | ||||
|     /// Checks if surfaces are compatible for caching | ||||
|     bool IsCompatibleSurface(const SurfaceParams& other) const { | ||||
|         if (std::tie(pixel_format, type, width, height, target, depth, is_tiled) == | ||||
|             std::tie(other.pixel_format, other.type, other.width, other.height, other.target, | ||||
|                      other.depth, other.is_tiled)) { | ||||
|             if (!is_tiled) | ||||
|                 return true; | ||||
|             return std::tie(block_height, block_depth, tile_width_spacing) == | ||||
|                    std::tie(other.block_height, other.block_depth, other.tile_width_spacing); | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     /// Initializes parameters for caching, should be called after everything has been initialized | ||||
|     void InitCacheParameters(GPUVAddr gpu_addr); | ||||
|  | ||||
|     std::string TargetName() const { | ||||
|         switch (target) { | ||||
|         case SurfaceTarget::Texture1D: | ||||
|             return "1D"; | ||||
|         case SurfaceTarget::TextureBuffer: | ||||
|             return "Buffer"; | ||||
|         case SurfaceTarget::Texture2D: | ||||
|             return "2D"; | ||||
|         case SurfaceTarget::Texture3D: | ||||
|             return "3D"; | ||||
|         case SurfaceTarget::Texture1DArray: | ||||
|             return "1DArray"; | ||||
|         case SurfaceTarget::Texture2DArray: | ||||
|             return "2DArray"; | ||||
|         case SurfaceTarget::TextureCubemap: | ||||
|             return "Cube"; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target)); | ||||
|             UNREACHABLE(); | ||||
|             return fmt::format("TUK({})", static_cast<u32>(target)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::string ClassName() const { | ||||
|         switch (identity) { | ||||
|         case SurfaceClass::Uploaded: | ||||
|             return "UP"; | ||||
|         case SurfaceClass::RenderTarget: | ||||
|             return "RT"; | ||||
|         case SurfaceClass::DepthBuffer: | ||||
|             return "DB"; | ||||
|         case SurfaceClass::Copy: | ||||
|             return "CP"; | ||||
|         default: | ||||
|             LOG_CRITICAL(HW_GPU, "Unimplemented surface_class={}", static_cast<u32>(identity)); | ||||
|             UNREACHABLE(); | ||||
|             return fmt::format("CUK({})", static_cast<u32>(identity)); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     std::string IdentityString() const { | ||||
|         return ClassName() + '_' + TargetName() + '_' + (is_tiled ? 'T' : 'L'); | ||||
|     } | ||||
|  | ||||
|     bool is_tiled; | ||||
|     u32 block_width; | ||||
|     u32 block_height; | ||||
|     u32 block_depth; | ||||
|     u32 tile_width_spacing; | ||||
|     PixelFormat pixel_format; | ||||
|     ComponentType component_type; | ||||
|     SurfaceType type; | ||||
|     u32 width; | ||||
|     u32 height; | ||||
|     u32 depth; | ||||
|     u32 unaligned_height; | ||||
|     u32 pitch; | ||||
|     SurfaceTarget target; | ||||
|     SurfaceClass identity; | ||||
|     u32 max_mip_level; | ||||
|     bool is_layered; | ||||
|     bool is_array; | ||||
|     bool srgb_conversion; | ||||
|     // Parameters used for caching | ||||
|     u8* host_ptr; | ||||
|     GPUVAddr gpu_addr; | ||||
|     std::size_t size_in_bytes; | ||||
|     std::size_t size_in_bytes_gl; | ||||
|  | ||||
|     // Render target specific parameters, not used in caching | ||||
|     struct { | ||||
|         u32 index; | ||||
|         u32 array_mode; | ||||
|         u32 volume; | ||||
|         u32 layer_stride; | ||||
|         u32 base_layer; | ||||
|     } rt; | ||||
|  | ||||
| private: | ||||
|     std::size_t InnerMipmapMemorySize(u32 mip_level, bool force_gl = false, bool layer_only = false, | ||||
|                                       bool uncompressed = false) const; | ||||
|     std::size_t InnerMemorySize(bool force_gl = false, bool layer_only = false, | ||||
|                                 bool uncompressed = false) const; | ||||
| }; | ||||
|  | ||||
| }; // 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; | ||||
|         res.state.identity = {}; // Ignore the origin of the texture | ||||
|         res.state.gpu_addr = {}; // Ignore GPU vaddr in caching | ||||
|         res.state.rt = {};       // Ignore rt config in caching | ||||
|         return res; | ||||
|     } | ||||
| }; | ||||
| namespace std { | ||||
| template <> | ||||
| struct hash<SurfaceReserveKey> { | ||||
|     std::size_t operator()(const SurfaceReserveKey& k) const { | ||||
|         return k.Hash(); | ||||
|     } | ||||
| }; | ||||
| } // namespace std | ||||
|  | ||||
| namespace OpenGL { | ||||
|  | ||||
| class RasterizerOpenGL; | ||||
|  | ||||
| // This is used to store temporary big buffers, | ||||
| // instead of creating/destroying all the time | ||||
| struct RasterizerTemporaryMemory { | ||||
|     std::vector<std::vector<u8>> gl_buffer; | ||||
| }; | ||||
|  | ||||
| class CachedSurface final : public RasterizerCacheObject { | ||||
| public: | ||||
|     explicit CachedSurface(const SurfaceParams& params); | ||||
|  | ||||
|     VAddr GetCpuAddr() const override { | ||||
|         return cpu_addr; | ||||
|     } | ||||
|  | ||||
|     std::size_t GetSizeInBytes() const override { | ||||
|         return cached_size_in_bytes; | ||||
|     } | ||||
|  | ||||
|     std::size_t GetMemorySize() const { | ||||
|         return memory_size; | ||||
|     } | ||||
|  | ||||
|     const OGLTexture& Texture() const { | ||||
|         return texture; | ||||
|     } | ||||
|  | ||||
|     const OGLTexture& Texture(bool as_array) { | ||||
|         if (params.is_array == as_array) { | ||||
|             return texture; | ||||
|         } else { | ||||
|             EnsureTextureDiscrepantView(); | ||||
|             return discrepant_view; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     GLenum Target() const { | ||||
|         return gl_target; | ||||
|     } | ||||
|  | ||||
|     const SurfaceParams& GetSurfaceParams() const { | ||||
|         return params; | ||||
|     } | ||||
|  | ||||
|     // Read/Write data in Switch memory to/from gl_buffer | ||||
|     void LoadGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem); | ||||
|     void FlushGLBuffer(RasterizerTemporaryMemory& res_cache_tmp_mem); | ||||
|  | ||||
|     // Upload data in gl_buffer to this surface's texture | ||||
|     void UploadGLTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, GLuint read_fb_handle, | ||||
|                          GLuint draw_fb_handle); | ||||
|  | ||||
|     void UpdateSwizzle(Tegra::Texture::SwizzleSource swizzle_x, | ||||
|                        Tegra::Texture::SwizzleSource swizzle_y, | ||||
|                        Tegra::Texture::SwizzleSource swizzle_z, | ||||
|                        Tegra::Texture::SwizzleSource swizzle_w); | ||||
|  | ||||
|     void MarkReinterpreted() { | ||||
|         reinterpreted = true; | ||||
|     } | ||||
|  | ||||
|     bool IsReinterpreted() const { | ||||
|         return reinterpreted; | ||||
|     } | ||||
|  | ||||
|     void MarkForReload(bool reload) { | ||||
|         must_reload = reload; | ||||
|     } | ||||
|  | ||||
|     bool MustReload() const { | ||||
|         return must_reload; | ||||
|     } | ||||
|  | ||||
|     bool IsUploaded() const { | ||||
|         return params.identity == SurfaceParams::SurfaceClass::Uploaded; | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void UploadGLMipmapTexture(RasterizerTemporaryMemory& res_cache_tmp_mem, u32 mip_map, | ||||
|                                GLuint read_fb_handle, GLuint draw_fb_handle); | ||||
|  | ||||
|     void EnsureTextureDiscrepantView(); | ||||
|  | ||||
|     OGLTexture texture; | ||||
|     OGLTexture discrepant_view; | ||||
|     OGLBuffer texture_buffer; | ||||
|     SurfaceParams params{}; | ||||
|     GLenum gl_target{}; | ||||
|     GLenum gl_internal_format{}; | ||||
|     std::size_t cached_size_in_bytes{}; | ||||
|     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; | ||||
|     VAddr cpu_addr{}; | ||||
| }; | ||||
|  | ||||
| class RasterizerCacheOpenGL final : public RasterizerCache<Surface> { | ||||
| public: | ||||
|     explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer); | ||||
|  | ||||
|     /// Get a surface based on the texture configuration | ||||
|     Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config, | ||||
|                               const GLShader::SamplerEntry& entry); | ||||
|  | ||||
|     /// Get the depth surface based on the framebuffer configuration | ||||
|     Surface GetDepthBufferSurface(bool preserve_contents); | ||||
|  | ||||
|     /// Get the color surface based on the framebuffer configuration and the specified render target | ||||
|     Surface GetColorBufferSurface(std::size_t index, bool preserve_contents); | ||||
|  | ||||
|     /// Tries to find a framebuffer using on the provided CPU address | ||||
|     Surface TryFindFramebufferSurface(const u8* host_ptr) const; | ||||
|  | ||||
|     /// Copies the contents of one surface to another | ||||
|     void FermiCopySurface(const Tegra::Engines::Fermi2D::Regs::Surface& src_config, | ||||
|                           const Tegra::Engines::Fermi2D::Regs::Surface& dst_config, | ||||
|                           const Common::Rectangle<u32>& src_rect, | ||||
|                           const Common::Rectangle<u32>& dst_rect); | ||||
|  | ||||
|     void SignalPreDrawCall(); | ||||
|     void SignalPostDrawCall(); | ||||
|  | ||||
| protected: | ||||
|     void FlushObjectInner(const Surface& object) override { | ||||
|         object->FlushGLBuffer(temporal_memory); | ||||
|     } | ||||
|  | ||||
| private: | ||||
|     void LoadSurface(const Surface& surface); | ||||
|     Surface GetSurface(const SurfaceParams& params, bool preserve_contents = true); | ||||
|  | ||||
|     /// Gets an uncached surface, creating it if need be | ||||
|     Surface GetUncachedSurface(const SurfaceParams& params); | ||||
|  | ||||
|     /// Recreates a surface with new parameters | ||||
|     Surface RecreateSurface(const Surface& old_surface, const SurfaceParams& new_params); | ||||
|  | ||||
|     /// 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); | ||||
|  | ||||
|     // Partialy reinterpret a surface based on a triggering_surface that collides with it. | ||||
|     // returns true if the reinterpret was successful, false in case it was not. | ||||
|     bool PartialReinterpretSurface(Surface triggering_surface, Surface intersect); | ||||
|  | ||||
|     /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data | ||||
|     void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); | ||||
|     void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); | ||||
|     void FastCopySurface(const Surface& src_surface, const Surface& dst_surface); | ||||
|     void CopySurface(const Surface& src_surface, const Surface& dst_surface, | ||||
|                      const GLuint copy_pbo_handle, const GLenum src_attachment = 0, | ||||
|                      const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0); | ||||
|  | ||||
|     /// 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; | ||||
|  | ||||
|     bool texception = false; | ||||
|  | ||||
|     /// Use a Pixel Buffer Object to download the previous texture and then upload it to the new one | ||||
|     /// using the new format. | ||||
|     OGLBuffer copy_pbo; | ||||
|  | ||||
|     std::array<Surface, Maxwell::NumRenderTargets> last_color_buffers; | ||||
|     std::array<Surface, Maxwell::NumRenderTargets> current_color_buffers; | ||||
|     Surface last_depth_buffer; | ||||
|  | ||||
|     RasterizerTemporaryMemory temporal_memory; | ||||
|  | ||||
|     using SurfaceIntervalCache = boost::icl::interval_map<CacheAddr, Surface>; | ||||
|     using SurfaceInterval = typename SurfaceIntervalCache::interval_type; | ||||
|  | ||||
|     static auto GetReinterpretInterval(const Surface& object) { | ||||
|         return SurfaceInterval::right_open(object->GetCacheAddr() + 1, | ||||
|                                            object->GetCacheAddr() + object->GetMemorySize() - 1); | ||||
|     } | ||||
|  | ||||
|     // Reinterpreted surfaces are very fragil as the game may keep rendering into them. | ||||
|     SurfaceIntervalCache reinterpreted_surfaces; | ||||
|  | ||||
|     void RegisterReinterpretSurface(Surface reinterpret_surface) { | ||||
|         auto interval = GetReinterpretInterval(reinterpret_surface); | ||||
|         reinterpreted_surfaces.insert({interval, reinterpret_surface}); | ||||
|         reinterpret_surface->MarkReinterpreted(); | ||||
|     } | ||||
|  | ||||
|     Surface CollideOnReinterpretedSurface(CacheAddr addr) const { | ||||
|         const SurfaceInterval interval{addr}; | ||||
|         for (auto& pair : | ||||
|              boost::make_iterator_range(reinterpreted_surfaces.equal_range(interval))) { | ||||
|             return pair.second; | ||||
|         } | ||||
|         return nullptr; | ||||
|     } | ||||
|  | ||||
|     void Register(const Surface& object) override { | ||||
|         RasterizerCache<Surface>::Register(object); | ||||
|     } | ||||
|  | ||||
|     /// Unregisters an object from the cache | ||||
|     void Unregister(const Surface& object) override { | ||||
|         if (object->IsReinterpreted()) { | ||||
|             auto interval = GetReinterpretInterval(object); | ||||
|             reinterpreted_surfaces.erase(interval); | ||||
|         } | ||||
|         RasterizerCache<Surface>::Unregister(object); | ||||
|     } | ||||
| }; | ||||
|  | ||||
| } // namespace OpenGL | ||||
		Reference in New Issue
	
	Block a user