1 // Copyright 2019 yuzu Emulator Project 2 // Licensed under GPLv2 or any later version 3 // Refer to the license.txt file included. 4 5 #pragma once 6 7 #include <utility> 8 9 #include "common/alignment.h" 10 #include "common/bit_util.h" 11 #include "common/cityhash.h" 12 #include "common/common_types.h" 13 #include "video_core/engines/fermi_2d.h" 14 #include "video_core/engines/maxwell_3d.h" 15 #include "video_core/shader/shader_ir.h" 16 #include "video_core/surface.h" 17 #include "video_core/textures/decoders.h" 18 19 namespace VideoCommon { 20 21 class FormatLookupTable; 22 23 class SurfaceParams { 24 public: 25 /// Creates SurfaceCachedParams from a texture configuration. 26 static SurfaceParams CreateForTexture(const FormatLookupTable& lookup_table, 27 const Tegra::Texture::TICEntry& tic, 28 const VideoCommon::Shader::Sampler& entry); 29 30 /// Creates SurfaceCachedParams from an image configuration. 31 static SurfaceParams CreateForImage(const FormatLookupTable& lookup_table, 32 const Tegra::Texture::TICEntry& tic, 33 const VideoCommon::Shader::Image& entry); 34 35 /// Creates SurfaceCachedParams for a depth buffer configuration. 36 static SurfaceParams CreateForDepthBuffer(Tegra::Engines::Maxwell3D& maxwell3d); 37 38 /// Creates SurfaceCachedParams from a framebuffer configuration. 39 static SurfaceParams CreateForFramebuffer(Tegra::Engines::Maxwell3D& maxwell3d, 40 std::size_t index); 41 42 /// Creates SurfaceCachedParams from a Fermi2D surface configuration. 43 static SurfaceParams CreateForFermiCopySurface( 44 const Tegra::Engines::Fermi2D::Regs::Surface& config); 45 46 /// Obtains the texture target from a shader's sampler entry. 47 static VideoCore::Surface::SurfaceTarget ExpectedTarget( 48 const VideoCommon::Shader::Sampler& entry); 49 50 /// Obtains the texture target from a shader's sampler entry. 51 static VideoCore::Surface::SurfaceTarget ExpectedTarget( 52 const VideoCommon::Shader::Image& entry); 53 Hash()54 std::size_t Hash() const { 55 return static_cast<std::size_t>( 56 Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this))); 57 } 58 59 bool operator==(const SurfaceParams& rhs) const; 60 61 bool operator!=(const SurfaceParams& rhs) const { 62 return !operator==(rhs); 63 } 64 GetGuestSizeInBytes()65 std::size_t GetGuestSizeInBytes() const { 66 return GetInnerMemorySize(false, false, false); 67 } 68 GetHostSizeInBytes(bool is_converted)69 std::size_t GetHostSizeInBytes(bool is_converted) const { 70 if (!is_converted) { 71 return GetInnerMemorySize(true, false, false); 72 } 73 // ASTC is uncompressed in software, in emulated as RGBA8 74 std::size_t host_size_in_bytes = 0; 75 for (u32 level = 0; level < num_levels; ++level) { 76 host_size_in_bytes += GetConvertedMipmapSize(level) * GetNumLayers(); 77 } 78 return host_size_in_bytes; 79 } 80 GetBlockAlignedWidth()81 u32 GetBlockAlignedWidth() const { 82 return Common::AlignUp(width, 64 / GetBytesPerPixel()); 83 } 84 85 /// Returns the width of a given mipmap level. GetMipWidth(u32 level)86 u32 GetMipWidth(u32 level) const { 87 return std::max(1U, width >> level); 88 } 89 90 /// Returns the height of a given mipmap level. GetMipHeight(u32 level)91 u32 GetMipHeight(u32 level) const { 92 return std::max(1U, height >> level); 93 } 94 95 /// Returns the depth of a given mipmap level. GetMipDepth(u32 level)96 u32 GetMipDepth(u32 level) const { 97 return is_layered ? depth : std::max(1U, depth >> level); 98 } 99 100 /// Returns the block height of a given mipmap level. 101 u32 GetMipBlockHeight(u32 level) const; 102 103 /// Returns the block depth of a given mipmap level. 104 u32 GetMipBlockDepth(u32 level) const; 105 106 /// Returns the best possible row/pitch alignment for the surface. GetRowAlignment(u32 level,bool is_converted)107 u32 GetRowAlignment(u32 level, bool is_converted) const { 108 const u32 bpp = is_converted ? 4 : GetBytesPerPixel(); 109 return 1U << Common::CountTrailingZeroes32(GetMipWidth(level) * bpp); 110 } 111 112 /// Returns the offset in bytes in guest memory of a given mipmap level. 113 std::size_t GetGuestMipmapLevelOffset(u32 level) const; 114 115 /// Returns the offset in bytes in host memory (linear) of a given mipmap level. 116 std::size_t GetHostMipmapLevelOffset(u32 level, bool is_converted) const; 117 118 /// Returns the size in bytes in guest memory of a given mipmap level. GetGuestMipmapSize(u32 level)119 std::size_t GetGuestMipmapSize(u32 level) const { 120 return GetInnerMipmapMemorySize(level, false, false); 121 } 122 123 /// Returns the size in bytes in host memory (linear) of a given mipmap level. GetHostMipmapSize(u32 level)124 std::size_t GetHostMipmapSize(u32 level) const { 125 return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); 126 } 127 128 std::size_t GetConvertedMipmapSize(u32 level) const; 129 130 /// Get this texture Tegra Block size in guest memory layout 131 u32 GetBlockSize() const; 132 133 /// Get X, Y coordinates max sizes of a single block. 134 std::pair<u32, u32> GetBlockXY() const; 135 136 /// Get the offset in x, y, z coordinates from a memory offset 137 std::tuple<u32, u32, u32> GetBlockOffsetXYZ(u32 offset) const; 138 139 /// Returns the size of a layer in bytes in guest memory. GetGuestLayerSize()140 std::size_t GetGuestLayerSize() const { 141 return GetLayerSize(false, false); 142 } 143 144 /// Returns the size of a layer in bytes in host memory for a given mipmap level. GetHostLayerSize(u32 level)145 std::size_t GetHostLayerSize(u32 level) const { 146 ASSERT(target != VideoCore::Surface::SurfaceTarget::Texture3D); 147 return GetInnerMipmapMemorySize(level, true, false); 148 } 149 150 /// Returns the max possible mipmap that the texture can have in host gpu MaxPossibleMipmap()151 u32 MaxPossibleMipmap() const { 152 const u32 max_mipmap_w = Common::Log2Ceil32(width) + 1U; 153 const u32 max_mipmap_h = Common::Log2Ceil32(height) + 1U; 154 const u32 max_mipmap = std::max(max_mipmap_w, max_mipmap_h); 155 if (target != VideoCore::Surface::SurfaceTarget::Texture3D) 156 return max_mipmap; 157 return std::max(max_mipmap, Common::Log2Ceil32(depth) + 1U); 158 } 159 160 /// Returns if the guest surface is a compressed surface. IsCompressed()161 bool IsCompressed() const { 162 return GetDefaultBlockHeight() > 1 || GetDefaultBlockWidth() > 1; 163 } 164 165 /// Returns the default block width. GetDefaultBlockWidth()166 u32 GetDefaultBlockWidth() const { 167 return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); 168 } 169 170 /// Returns the default block height. GetDefaultBlockHeight()171 u32 GetDefaultBlockHeight() const { 172 return VideoCore::Surface::GetDefaultBlockHeight(pixel_format); 173 } 174 175 /// Returns the bits per pixel. GetBitsPerPixel()176 u32 GetBitsPerPixel() const { 177 return VideoCore::Surface::GetFormatBpp(pixel_format); 178 } 179 180 /// Returns the bytes per pixel. GetBytesPerPixel()181 u32 GetBytesPerPixel() const { 182 return VideoCore::Surface::GetBytesPerPixel(pixel_format); 183 } 184 185 /// Returns true if the pixel format is a depth and/or stencil format. IsPixelFormatZeta()186 bool IsPixelFormatZeta() const { 187 return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && 188 pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; 189 } 190 191 /// Returns is the surface is a TextureBuffer type of surface. IsBuffer()192 bool IsBuffer() const { 193 return target == VideoCore::Surface::SurfaceTarget::TextureBuffer; 194 } 195 196 /// Returns the number of layers in the surface. GetNumLayers()197 std::size_t GetNumLayers() const { 198 return is_layered ? depth : 1; 199 } 200 201 /// Returns the debug name of the texture for use in graphic debuggers. 202 std::string TargetName() const; 203 204 // Helper used for out of class size calculations AlignLayered(const std::size_t out_size,const u32 block_height,const u32 block_depth)205 static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, 206 const u32 block_depth) { 207 return Common::AlignBits(out_size, 208 Tegra::Texture::GOB_SIZE_SHIFT + block_height + block_depth); 209 } 210 211 /// Converts a width from a type of surface into another. This helps represent the 212 /// equivalent value between compressed/non-compressed textures. ConvertWidth(u32 width,VideoCore::Surface::PixelFormat pixel_format_from,VideoCore::Surface::PixelFormat pixel_format_to)213 static u32 ConvertWidth(u32 width, VideoCore::Surface::PixelFormat pixel_format_from, 214 VideoCore::Surface::PixelFormat pixel_format_to) { 215 const u32 bw1 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_from); 216 const u32 bw2 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_to); 217 return (width * bw2 + bw1 - 1) / bw1; 218 } 219 220 /// Converts a height from a type of surface into another. This helps represent the 221 /// equivalent value between compressed/non-compressed textures. ConvertHeight(u32 height,VideoCore::Surface::PixelFormat pixel_format_from,VideoCore::Surface::PixelFormat pixel_format_to)222 static u32 ConvertHeight(u32 height, VideoCore::Surface::PixelFormat pixel_format_from, 223 VideoCore::Surface::PixelFormat pixel_format_to) { 224 const u32 bh1 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_from); 225 const u32 bh2 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_to); 226 return (height * bh2 + bh1 - 1) / bh1; 227 } 228 229 // Finds the maximun possible width between 2 2D layers of different formats IntersectWidth(const SurfaceParams & src_params,const SurfaceParams & dst_params,const u32 src_level,const u32 dst_level)230 static u32 IntersectWidth(const SurfaceParams& src_params, const SurfaceParams& dst_params, 231 const u32 src_level, const u32 dst_level) { 232 const u32 bw1 = src_params.GetDefaultBlockWidth(); 233 const u32 bw2 = dst_params.GetDefaultBlockWidth(); 234 const u32 t_src_width = (src_params.GetMipWidth(src_level) * bw2 + bw1 - 1) / bw1; 235 const u32 t_dst_width = (dst_params.GetMipWidth(dst_level) * bw1 + bw2 - 1) / bw2; 236 return std::min(t_src_width, t_dst_width); 237 } 238 239 // Finds the maximun possible height between 2 2D layers of different formats IntersectHeight(const SurfaceParams & src_params,const SurfaceParams & dst_params,const u32 src_level,const u32 dst_level)240 static u32 IntersectHeight(const SurfaceParams& src_params, const SurfaceParams& dst_params, 241 const u32 src_level, const u32 dst_level) { 242 const u32 bh1 = src_params.GetDefaultBlockHeight(); 243 const u32 bh2 = dst_params.GetDefaultBlockHeight(); 244 const u32 t_src_height = (src_params.GetMipHeight(src_level) * bh2 + bh1 - 1) / bh1; 245 const u32 t_dst_height = (dst_params.GetMipHeight(dst_level) * bh1 + bh2 - 1) / bh2; 246 return std::min(t_src_height, t_dst_height); 247 } 248 249 bool is_tiled; 250 bool srgb_conversion; 251 bool is_layered; 252 u32 block_width; 253 u32 block_height; 254 u32 block_depth; 255 u32 tile_width_spacing; 256 u32 width; 257 u32 height; 258 u32 depth; 259 u32 pitch; 260 u32 num_levels; 261 u32 emulated_levels; 262 VideoCore::Surface::PixelFormat pixel_format; 263 VideoCore::Surface::SurfaceType type; 264 VideoCore::Surface::SurfaceTarget target; 265 266 private: 267 /// Returns the size of a given mipmap level inside a layer. 268 std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const; 269 270 /// Returns the size of all mipmap levels and aligns as needed. GetInnerMemorySize(bool as_host_size,bool layer_only,bool uncompressed)271 std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const { 272 return GetLayerSize(as_host_size, uncompressed) * 273 (layer_only ? 1U : (is_layered ? depth : 1U)); 274 } 275 276 /// Returns the size of a layer 277 std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const; 278 279 /// Returns true if these parameters are from a layered surface. 280 bool IsLayered() const; 281 }; 282 283 } // namespace VideoCommon 284 285 namespace std { 286 287 template <> 288 struct hash<VideoCommon::SurfaceParams> { 289 std::size_t operator()(const VideoCommon::SurfaceParams& k) const noexcept { 290 return k.Hash(); 291 } 292 }; 293 294 } // namespace std 295