From 57cfa6b47ad770d029f50165fee71d00f0126ec3 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Wed, 24 Apr 2019 16:35:54 -0300 Subject: texture_cache: Split texture cache into different files --- src/video_core/texture_cache/surface_params.cpp | 412 ++++++++++++++++++++++++ 1 file changed, 412 insertions(+) create mode 100644 src/video_core/texture_cache/surface_params.cpp (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp new file mode 100644 index 0000000000..d1f8c53d50 --- /dev/null +++ b/src/video_core/texture_cache/surface_params.cpp @@ -0,0 +1,412 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include "common/cityhash.h" +#include "common/alignment.h" +#include "core/core.h" +#include "video_core/surface.h" +#include "video_core/texture_cache/surface_params.h" +#include "video_core/textures/decoders.h" + +namespace VideoCommon { + +using VideoCore::Surface::ComponentTypeFromDepthFormat; +using VideoCore::Surface::ComponentTypeFromRenderTarget; +using VideoCore::Surface::ComponentTypeFromTexture; +using VideoCore::Surface::PixelFormatFromDepthFormat; +using VideoCore::Surface::PixelFormatFromRenderTargetFormat; +using VideoCore::Surface::PixelFormatFromTextureFormat; +using VideoCore::Surface::SurfaceTarget; +using VideoCore::Surface::SurfaceTargetFromTextureType; + +namespace { +constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { + return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile); +} +} // Anonymous namespace + +SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, + const Tegra::Texture::FullTextureInfo& config) { + SurfaceParams params; + params.is_tiled = config.tic.IsTiled(); + params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); + params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, + params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, + params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, + params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; + params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), + params.srgb_conversion); + params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); + params.type = GetFormatType(params.pixel_format); + params.target = SurfaceTargetFromTextureType(config.tic.texture_type); + params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); + params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); + params.depth = config.tic.Depth(); + if (params.target == SurfaceTarget::TextureCubemap || + params.target == SurfaceTarget::TextureCubeArray) { + params.depth *= 6; + } + params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); + params.unaligned_height = config.tic.Height(); + params.num_levels = config.tic.max_mip_level + 1; + + params.CalculateCachedValues(); + return params; +} + +SurfaceParams SurfaceParams::CreateForDepthBuffer( + Core::System& system, u32 zeta_width, u32 zeta_height, Tegra::DepthFormat format, + u32 block_width, u32 block_height, u32 block_depth, + Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout type) { + SurfaceParams params; + params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; + params.srgb_conversion = false; + params.block_width = 1 << std::min(block_width, 5U); + params.block_height = 1 << std::min(block_height, 5U); + params.block_depth = 1 << std::min(block_depth, 5U); + params.tile_width_spacing = 1; + params.pixel_format = PixelFormatFromDepthFormat(format); + params.component_type = ComponentTypeFromDepthFormat(format); + params.type = GetFormatType(params.pixel_format); + params.width = zeta_width; + params.height = zeta_height; + params.unaligned_height = zeta_height; + params.target = SurfaceTarget::Texture2D; + params.depth = 1; + params.num_levels = 1; + + params.CalculateCachedValues(); + return params; +} + +SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::size_t index) { + const auto& config{system.GPU().Maxwell3D().regs.rt[index]}; + SurfaceParams params; + params.is_tiled = + config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; + params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || + config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; + params.block_width = 1 << config.memory_layout.block_width; + params.block_height = 1 << config.memory_layout.block_height; + params.block_depth = 1 << config.memory_layout.block_depth; + params.tile_width_spacing = 1; + params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); + params.component_type = ComponentTypeFromRenderTarget(config.format); + params.type = GetFormatType(params.pixel_format); + if (params.is_tiled) { + params.width = config.width; + } else { + const u32 bpp = GetFormatBpp(params.pixel_format) / CHAR_BIT; + params.pitch = config.width; + params.width = params.pitch / bpp; + } + params.height = config.height; + params.depth = 1; + params.unaligned_height = config.height; + params.target = SurfaceTarget::Texture2D; + params.num_levels = 1; + + params.CalculateCachedValues(); + return params; +} + +SurfaceParams SurfaceParams::CreateForFermiCopySurface( + const Tegra::Engines::Fermi2D::Regs::Surface& config) { + SurfaceParams params{}; + params.is_tiled = !config.linear; + params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || + config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; + params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, + params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, + params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, + params.tile_width_spacing = 1; + params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); + params.component_type = ComponentTypeFromRenderTarget(config.format); + params.type = GetFormatType(params.pixel_format); + params.width = config.width; + params.height = config.height; + params.unaligned_height = config.height; + // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters + params.target = SurfaceTarget::Texture2D; + params.depth = 1; + params.num_levels = 1; + + params.CalculateCachedValues(); + return params; +} + +u32 SurfaceParams::GetMipWidth(u32 level) const { + return std::max(1U, width >> level); +} + +u32 SurfaceParams::GetMipHeight(u32 level) const { + return std::max(1U, height >> level); +} + +u32 SurfaceParams::GetMipDepth(u32 level) const { + return IsLayered() ? depth : std::max(1U, depth >> level); +} + +bool SurfaceParams::IsLayered() const { + switch (target) { + case SurfaceTarget::Texture1DArray: + case SurfaceTarget::Texture2DArray: + case SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubeArray: + return true; + default: + return false; + } +} + +u32 SurfaceParams::GetMipBlockHeight(u32 level) const { + // Auto block resizing algorithm from: + // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c + if (level == 0) { + return this->block_height; + } + + const u32 height{GetMipHeight(level)}; + const u32 default_block_height{GetDefaultBlockHeight()}; + const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; + u32 block_height = 16; + while (block_height > 1 && blocks_in_y <= block_height * 4) { + block_height >>= 1; + } + return block_height; +} + +u32 SurfaceParams::GetMipBlockDepth(u32 level) const { + if (level == 0) { + return this->block_depth; + } + if (IsLayered()) { + return 1; + } + + const u32 depth{GetMipDepth(level)}; + u32 block_depth = 32; + while (block_depth > 1 && depth * 2 <= block_depth) { + block_depth >>= 1; + } + + if (block_depth == 32 && GetMipBlockHeight(level) >= 4) { + return 16; + } + + return block_depth; +} + +std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const { + std::size_t offset = 0; + for (u32 i = 0; i < level; i++) { + offset += GetInnerMipmapMemorySize(i, false, false); + } + return offset; +} + +std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { + std::size_t offset = 0; + for (u32 i = 0; i < level; i++) { + offset += GetInnerMipmapMemorySize(i, true, false) * GetNumLayers(); + } + return offset; +} + +std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { + return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); +} + +std::size_t SurfaceParams::GetGuestLayerSize() const { + return GetLayerSize(false, false); +} + +std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { + std::size_t size = 0; + for (u32 level = 0; level < num_levels; ++level) { + size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); + } + if (is_tiled && (IsLayered() || target == SurfaceTarget::Texture3D)) { + return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); + } + return size; +} + +std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { + ASSERT(target != SurfaceTarget::Texture3D); + return GetInnerMipmapMemorySize(level, true, false); +} + +u32 SurfaceParams::GetDefaultBlockWidth() const { + return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); +} + +u32 SurfaceParams::GetDefaultBlockHeight() const { + return VideoCore::Surface::GetDefaultBlockHeight(pixel_format); +} + +u32 SurfaceParams::GetBitsPerPixel() const { + return VideoCore::Surface::GetFormatBpp(pixel_format); +} + +u32 SurfaceParams::GetBytesPerPixel() const { + return VideoCore::Surface::GetBytesPerPixel(pixel_format); +} + +bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { + if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) != + std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format, + view_params.component_type, view_params.type)) { + return false; + } + + const SurfaceTarget view_target{view_params.target}; + if (view_target == target) { + return true; + } + + switch (target) { + case SurfaceTarget::Texture1D: + case SurfaceTarget::Texture2D: + case SurfaceTarget::Texture3D: + return false; + case SurfaceTarget::Texture1DArray: + return view_target == SurfaceTarget::Texture1D; + case SurfaceTarget::Texture2DArray: + return view_target == SurfaceTarget::Texture2D; + case SurfaceTarget::TextureCubemap: + return view_target == SurfaceTarget::Texture2D || + view_target == SurfaceTarget::Texture2DArray; + case SurfaceTarget::TextureCubeArray: + return view_target == SurfaceTarget::Texture2D || + view_target == SurfaceTarget::Texture2DArray || + view_target == SurfaceTarget::TextureCubemap; + default: + UNIMPLEMENTED_MSG("Unimplemented texture family={}", static_cast(target)); + return false; + } +} + +bool SurfaceParams::IsPixelFormatZeta() const { + return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && + pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; +} + +void SurfaceParams::CalculateCachedValues() { + switch (target) { + case SurfaceTarget::Texture1D: + case SurfaceTarget::Texture2D: + case SurfaceTarget::Texture3D: + num_layers = 1; + break; + case SurfaceTarget::Texture1DArray: + case SurfaceTarget::Texture2DArray: + case SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubeArray: + num_layers = depth; + break; + default: + UNREACHABLE(); + } + + guest_size_in_bytes = GetInnerMemorySize(false, false, false); + + if (IsPixelFormatASTC(pixel_format)) { + // ASTC is uncompressed in software, in emulated as RGBA8 + host_size_in_bytes = static_cast(width) * static_cast(height) * + static_cast(depth) * 4ULL; + } else { + host_size_in_bytes = GetInnerMemorySize(true, false, false); + } +} + +std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, + bool uncompressed) const { + const bool tiled{as_host_size ? false : is_tiled}; + const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; + const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; + const u32 depth{target == SurfaceTarget::Texture3D ? GetMipDepth(level) : 1U}; + return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth, + GetMipBlockHeight(level), GetMipBlockDepth(level)); +} + +std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, + bool uncompressed) const { + return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers); +} + +std::map> SurfaceParams::CreateViewOffsetMap() const { + std::map> view_offset_map; + switch (target) { + case SurfaceTarget::Texture1D: + case SurfaceTarget::Texture2D: + case SurfaceTarget::Texture3D: { + // TODO(Rodrigo): Add layer iterations for 3D textures + constexpr u32 layer = 0; + for (u32 level = 0; level < num_levels; ++level) { + const std::size_t offset{GetGuestMipmapLevelOffset(level)}; + view_offset_map.insert({offset, {layer, level}}); + } + break; + } + case SurfaceTarget::Texture1DArray: + case SurfaceTarget::Texture2DArray: + case SurfaceTarget::TextureCubemap: + case SurfaceTarget::TextureCubeArray: { + const std::size_t layer_size{GetGuestLayerSize()}; + for (u32 level = 0; level < num_levels; ++level) { + const std::size_t level_offset{GetGuestMipmapLevelOffset(level)}; + for (u32 layer = 0; layer < num_layers; ++layer) { + const auto layer_offset{static_cast(layer_size * layer)}; + const std::size_t offset{level_offset + layer_offset}; + view_offset_map.insert({offset, {layer, level}}); + } + } + break; + } + default: + UNIMPLEMENTED_MSG("Unimplemented surface target {}", static_cast(target)); + } + return view_offset_map; +} + +bool SurfaceParams::IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const { + return IsDimensionValid(view_params, level) && IsDepthValid(view_params, level) && + IsInBounds(view_params, layer, level); +} + +bool SurfaceParams::IsDimensionValid(const SurfaceParams& view_params, u32 level) const { + return view_params.width == GetMipWidth(level) && view_params.height == GetMipHeight(level); +} + +bool SurfaceParams::IsDepthValid(const SurfaceParams& view_params, u32 level) const { + if (view_params.target != SurfaceTarget::Texture3D) { + return true; + } + return view_params.depth == GetMipDepth(level); +} + +bool SurfaceParams::IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const { + return layer + view_params.num_layers <= num_layers && + level + view_params.num_levels <= num_levels; +} + +std::size_t HasheableSurfaceParams::Hash() const { + return static_cast( + Common::CityHash64(reinterpret_cast(this), sizeof(*this))); +} + +bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const { + return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width, + height, depth, pitch, unaligned_height, num_levels, pixel_format, + component_type, type, target) == + std::tie(rhs.is_tiled, rhs.block_width, rhs.block_height, rhs.block_depth, + rhs.tile_width_spacing, rhs.width, rhs.height, rhs.depth, rhs.pitch, + rhs.unaligned_height, rhs.num_levels, rhs.pixel_format, rhs.component_type, + rhs.type, rhs.target); +} + +} // namespace VideoCommon -- cgit v1.2.3 From b906c2d3ec39efd5a1e1b81418bad6e57a8c9ee4 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 7 May 2019 10:56:45 -0400 Subject: Correct Surface Base and Views for new Texture Cache --- src/video_core/texture_cache/copy_params.h | 25 ++ src/video_core/texture_cache/surface_base.cpp | 108 +++++---- src/video_core/texture_cache/surface_base.h | 297 ++++++++++++++++++------ src/video_core/texture_cache/surface_params.cpp | 210 ++++++----------- src/video_core/texture_cache/surface_params.h | 159 ++++--------- src/video_core/texture_cache/surface_view.cpp | 12 +- src/video_core/texture_cache/surface_view.h | 35 ++- 7 files changed, 466 insertions(+), 380 deletions(-) create mode 100644 src/video_core/texture_cache/copy_params.h (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/copy_params.h b/src/video_core/texture_cache/copy_params.h new file mode 100644 index 0000000000..75c2b1f054 --- /dev/null +++ b/src/video_core/texture_cache/copy_params.h @@ -0,0 +1,25 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "common/common_types.h" + +namespace VideoCommon { + +struct CopyParams { + u32 source_x; + u32 source_y; + u32 source_z; + u32 dest_x; + u32 dest_y; + u32 dest_z; + u32 source_level; + u32 dest_level; + u32 width; + u32 height; + u32 depth; +}; + +} // namespace VideoCommon diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index d0779b5027..5273fcb444 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp @@ -4,104 +4,120 @@ #include "common/assert.h" #include "common/common_types.h" -#include "video_core/morton.h" +#include "common/microprofile.h" +#include "video_core/memory_manager.h" #include "video_core/texture_cache/surface_base.h" #include "video_core/texture_cache/surface_params.h" #include "video_core/textures/convert.h" namespace VideoCommon { +MICROPROFILE_DEFINE(GPU_Load_Texture, "GPU", "Texture Load", MP_RGB(128, 192, 128)); +MICROPROFILE_DEFINE(GPU_Flush_Texture, "GPU", "Texture Flush", MP_RGB(128, 192, 128)); + using Tegra::Texture::ConvertFromGuestToHost; using VideoCore::MortonSwizzleMode; -namespace { -void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, - u32 level) { +SurfaceBaseImpl::SurfaceBaseImpl(const GPUVAddr gpu_vaddr, const SurfaceParams& params) + : gpu_addr{gpu_vaddr}, params{params}, mipmap_sizes{params.num_levels}, + mipmap_offsets{params.num_levels}, layer_size{params.GetGuestLayerSize()}, + memory_size{params.GetGuestSizeInBytes()}, host_memory_size{params.GetHostSizeInBytes()} { + u32 offset = 0; + mipmap_offsets.resize(params.num_levels); + mipmap_sizes.resize(params.num_levels); + gpu_addr_end = gpu_addr + memory_size; + for (u32 i = 0; i < params.num_levels; i++) { + mipmap_offsets[i] = offset; + mipmap_sizes[i] = params.GetGuestMipmapSize(i); + offset += mipmap_sizes[i]; + } +} + +void SurfaceBaseImpl::SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, + u8* buffer, u32 level) { const u32 width{params.GetMipWidth(level)}; const u32 height{params.GetMipHeight(level)}; const u32 block_height{params.GetMipBlockHeight(level)}; const u32 block_depth{params.GetMipBlockDepth(level)}; - std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)}; - if (params.IsLayered()) { + std::size_t guest_offset{mipmap_offsets[level]}; + if (params.is_layered) { std::size_t host_offset{0}; - const std::size_t guest_stride = params.GetGuestLayerSize(); + const std::size_t guest_stride = layer_size; const std::size_t host_stride = params.GetHostLayerSize(level); - for (u32 layer = 0; layer < params.GetNumLayers(); layer++) { - MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, - 1, params.GetTileWidthSpacing(), buffer + host_offset, - memory + guest_offset); + for (u32 layer = 0; layer < params.depth; layer++) { + MortonSwizzle(mode, params.pixel_format, width, block_height, height, block_depth, 1, + params.tile_width_spacing, buffer + host_offset, memory + guest_offset); guest_offset += guest_stride; host_offset += host_stride; } } else { - MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, - params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer, + MortonSwizzle(mode, params.pixel_format, width, block_height, height, block_depth, + params.GetMipDepth(level), params.tile_width_spacing, buffer, memory + guest_offset); } } -} // Anonymous namespace -SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} { - staging_buffer.resize(params.GetHostSizeInBytes()); -} - -SurfaceBaseImpl::~SurfaceBaseImpl() = default; - -void SurfaceBaseImpl::LoadBuffer() { - if (params.IsTiled()) { - ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}", - params.GetBlockWidth(), static_cast(params.GetTarget())); - for (u32 level = 0; level < params.GetNumLevels(); ++level) { +void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, + std::vector& staging_buffer) { + MICROPROFILE_SCOPE(GPU_Load_Texture); + auto host_ptr = memory_manager.GetPointer(gpu_addr); + if (params.is_tiled) { + ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture target {}", + params.block_width, static_cast(params.target)); + for (u32 level = 0; level < params.num_levels; ++level) { + const u32 host_offset = params.GetHostMipmapLevelOffset(level); SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, - GetStagingBufferLevelData(level), level); + staging_buffer.data() + host_offset, level); } } else { - ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented"); - const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT}; + ASSERT_MSG(params.num_levels == 1, "Linear mipmap loading is not implemented"); + const u32 bpp{params.GetBytesPerPixel()}; const u32 block_width{params.GetDefaultBlockWidth()}; const u32 block_height{params.GetDefaultBlockHeight()}; - const u32 width{(params.GetWidth() + block_width - 1) / block_width}; - const u32 height{(params.GetHeight() + block_height - 1) / block_height}; + const u32 width{(params.width + block_width - 1) / block_width}; + const u32 height{(params.height + block_height - 1) / block_height}; const u32 copy_size{width * bpp}; - if (params.GetPitch() == copy_size) { + if (params.pitch == copy_size) { std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes()); } else { const u8* start{host_ptr}; u8* write_to{staging_buffer.data()}; for (u32 h = height; h > 0; --h) { std::memcpy(write_to, start, copy_size); - start += params.GetPitch(); + start += params.pitch; write_to += copy_size; } } } - for (u32 level = 0; level < params.GetNumLevels(); ++level) { - ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(), + for (u32 level = 0; level < params.num_levels; ++level) { + const u32 host_offset = params.GetHostMipmapLevelOffset(level); + ConvertFromGuestToHost(staging_buffer.data() + host_offset, params.pixel_format, params.GetMipWidth(level), params.GetMipHeight(level), params.GetMipDepth(level), true, true); } } -void SurfaceBaseImpl::FlushBuffer() { - if (params.IsTiled()) { - ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}", - params.GetBlockWidth()); - for (u32 level = 0; level < params.GetNumLevels(); ++level) { - SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, - GetStagingBufferLevelData(level), level); +void SurfaceBaseImpl::FlushBuffer(std::vector& staging_buffer) { + MICROPROFILE_SCOPE(GPU_Flush_Texture); + if (params.is_tiled) { + ASSERT_MSG(params.block_width == 1, "Block width is defined as {}", params.block_width); + for (u32 level = 0; level < params.num_levels; ++level) { + const u32 host_offset = params.GetHostMipmapLevelOffset(level); + SwizzleFunc(MortonSwizzleMode::LinearToMorton, host_ptr, params, + staging_buffer.data() + host_offset, level); } } else { UNIMPLEMENTED(); /* - ASSERT(params.GetTarget() == SurfaceTarget::Texture2D); - ASSERT(params.GetNumLevels() == 1); + ASSERT(params.target == SurfaceTarget::Texture2D); + ASSERT(params.num_levels == 1); const u32 bpp{params.GetFormatBpp() / 8}; - const u32 copy_size{params.GetWidth() * bpp}; - if (params.GetPitch() == copy_size) { - std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes()); + const u32 copy_size{params.width * bpp}; + if (params.pitch == copy_size) { + std::memcpy(host_ptr, staging_buffer.data(), memory_size); } else { u8* start{host_ptr}; const u8* read_to{staging_buffer.data()}; diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index eed8dc59d5..5fd7add0a7 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -4,166 +4,309 @@ #pragma once +#include #include +#include #include "common/assert.h" #include "common/common_types.h" #include "video_core/gpu.h" +#include "video_core/morton.h" +#include "video_core/texture_cache/copy_params.h" #include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_view.h" +template> +ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp={}) +{ + // Note: BOTH type T and the type after ForwardIt is dereferenced + // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. + // This is stricter than lower_bound requirement (see above) + + first = std::lower_bound(first, last, value, comp); + return first != last && !comp(value, *first) ? first : last; +} + +namespace Tegra { +class MemoryManager; +} + namespace VideoCommon { +using VideoCore::Surface::SurfaceTarget; +using VideoCore::MortonSwizzleMode; + class SurfaceBaseImpl { public: - void LoadBuffer(); + void LoadBuffer(Tegra::MemoryManager& memory_manager, std::vector& staging_buffer); - void FlushBuffer(); + void FlushBuffer(std::vector& staging_buffer); GPUVAddr GetGpuAddr() const { - ASSERT(is_registered); return gpu_addr; } + GPUVAddr GetGpuAddrEnd() const { + return gpu_addr_end; + } + + bool Overlaps(const GPUVAddr start, const GPUVAddr end) const { + return (gpu_addr < end) && (gpu_addr_end > start); + } + + // Use only when recycling a surface + void SetGpuAddr(const GPUVAddr new_addr) { + gpu_addr = new_addr; + gpu_addr_end = new_addr + memory_size; + } + VAddr GetCpuAddr() const { - ASSERT(is_registered); - return cpu_addr; + return gpu_addr; + } + + void SetCpuAddr(const VAddr new_addr) { + cpu_addr = new_addr; } u8* GetHostPtr() const { - ASSERT(is_registered); return host_ptr; } - CacheAddr GetCacheAddr() const { - ASSERT(is_registered); - return cache_addr; + void SetHostPtr(u8* new_addr) { + host_ptr = new_addr; } const SurfaceParams& GetSurfaceParams() const { return params; } - void Register(GPUVAddr gpu_addr_, VAddr cpu_addr_, u8* host_ptr_) { - ASSERT(!is_registered); - is_registered = true; - gpu_addr = gpu_addr_; - cpu_addr = cpu_addr_; - host_ptr = host_ptr_; - cache_addr = ToCacheAddr(host_ptr_); - DecorateSurfaceName(); + std::size_t GetSizeInBytes() const { + return memory_size; } - void Unregister() { - ASSERT(is_registered); - is_registered = false; + std::size_t GetHostSizeInBytes() const { + return host_memory_size; } - bool IsRegistered() const { - return is_registered; + std::size_t GetMipmapSize(const u32 level) const { + return mipmap_sizes[level]; } - std::size_t GetSizeInBytes() const { - return params.GetGuestSizeInBytes(); + bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const { + return params.pixel_format == pixel_format; + } + + bool MatchTarget(VideoCore::Surface::SurfaceTarget target) const { + return params.target == target; + } + + bool MatchesTopology(const SurfaceParams& rhs) const { + const u32 src_bpp = params.GetBytesPerPixel(); + const u32 dst_bpp = rhs.GetBytesPerPixel(); + return std::tie(src_bpp, params.is_tiled) == std::tie(dst_bpp, rhs.is_tiled); + } + + bool MatchesStructure(const SurfaceParams& rhs) const { + if (params.is_tiled) { + const u32 a_width1 = params.GetBlockAlignedWidth(); + const u32 a_width2 = rhs.GetBlockAlignedWidth(); + return std::tie(a_width1, params.height, params.depth, params.block_width, + params.block_height, params.block_depth, params.tile_width_spacing) == + std::tie(a_width2, rhs.height, rhs.depth, rhs.block_width, rhs.block_height, + rhs.block_depth, rhs.tile_width_spacing); + } else { + return std::tie(params.width, params.height, params.pitch) == + std::tie(rhs.width, rhs.height, rhs.pitch); + } + } + + std::optional> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const { + if (candidate_gpu_addr < gpu_addr) + return {}; + const GPUVAddr relative_address = candidate_gpu_addr - gpu_addr; + const u32 layer = relative_address / layer_size; + const GPUVAddr mipmap_address = relative_address - layer_size * layer; + const auto mipmap_it = binary_find(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); + if (mipmap_it != mipmap_offsets.end()) { + return {{layer, std::distance(mipmap_offsets.begin(), mipmap_it)}}; + } + return {}; } - u8* GetStagingBufferLevelData(u32 level) { - return staging_buffer.data() + params.GetHostMipmapLevelOffset(level); + std::vector BreakDown() const { + auto set_up_copy = [](CopyParams& cp, const SurfaceParams& params, const u32 depth, + const u32 level) { + cp.source_x = 0; + cp.source_y = 0; + cp.source_z = 0; + cp.dest_x = 0; + cp.dest_y = 0; + cp.dest_z = 0; + cp.source_level = level; + cp.dest_level = level; + cp.width = params.GetMipWidth(level); + cp.height = params.GetMipHeight(level); + cp.depth = depth; + }; + const u32 layers = params.depth; + const u32 mipmaps = params.num_levels; + if (params.is_layered) { + std::vector result{layers * mipmaps}; + for (std::size_t layer = 0; layer < layers; layer++) { + const u32 layer_offset = layer * mipmaps; + for (std::size_t level = 0; level < mipmaps; level++) { + CopyParams& cp = result[layer_offset + level]; + set_up_copy(cp, params, layer, level); + } + } + return result; + } else { + std::vector result{mipmaps}; + for (std::size_t level = 0; level < mipmaps; level++) { + CopyParams& cp = result[level]; + set_up_copy(cp, params, params.GetMipDepth(level), level); + } + return result; + } } protected: - explicit SurfaceBaseImpl(const SurfaceParams& params); - ~SurfaceBaseImpl(); // non-virtual is intended + explicit SurfaceBaseImpl(const GPUVAddr gpu_vaddr, const SurfaceParams& params); + ~SurfaceBaseImpl() = default; virtual void DecorateSurfaceName() = 0; const SurfaceParams params; - -private: GPUVAddr gpu_addr{}; - VAddr cpu_addr{}; - u8* host_ptr{}; - CacheAddr cache_addr{}; - bool is_registered{}; + GPUVAddr gpu_addr_end{}; + std::vector mipmap_sizes; + std::vector mipmap_offsets; + const std::size_t layer_size; + const std::size_t memory_size; + const std::size_t host_memory_size; + u8* host_ptr; + VAddr cpu_addr; - std::vector staging_buffer; +private: + void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, + u32 level); }; -template +template class SurfaceBase : public SurfaceBaseImpl { public: - virtual void UploadTexture() = 0; + virtual void UploadTexture(std::vector& staging_buffer) = 0; - virtual void DownloadTexture() = 0; + virtual void DownloadTexture(std::vector& staging_buffer) = 0; - TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) { - if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) { - // It can't be a view if it's in a prior address. - return {}; - } + void MarkAsModified(const bool is_modified_, const u64 tick) { + is_modified = is_modified_ || is_protected; + modification_tick = tick; + } - const auto relative_offset{static_cast(view_addr - GetGpuAddr())}; - const auto it{view_offset_map.find(relative_offset)}; - if (it == view_offset_map.end()) { - // Couldn't find an aligned view. - return {}; - } - const auto [layer, level] = it->second; + void MarkAsProtected(const bool is_protected) { + this->is_protected = is_protected; + } - if (!params.IsViewValid(view_params, layer, level)) { - return {}; - } + void MarkAsPicked(const bool is_picked) { + this->is_picked = is_picked; + } - return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels()); + bool IsModified() const { + return is_modified; } - void MarkAsModified(bool is_modified_) { - is_modified = is_modified_; - if (is_modified_) { - modification_tick = texture_cache.Tick(); - } + bool IsProtected() const { + return is_protected; } - TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) { - TView* view{TryGetView(view_addr, view_params)}; - ASSERT(view != nullptr); - return view; + bool IsRegistered() const { + return is_registered; } - bool IsModified() const { - return is_modified; + bool IsPicked() const { + return is_picked; + } + + void MarkAsRegistered(bool is_reg) { + is_registered = is_reg; } u64 GetModificationTick() const { return modification_tick; } + TView EmplaceOverview(const SurfaceParams& overview_params) { + ViewParams vp{}; + vp.base_level = 0; + vp.num_levels = params.num_levels; + vp.target = overview_params.target; + if (params.is_layered && !overview_params.is_layered) { + vp.base_layer = 0; + vp.num_layers = 1; + } else { + vp.base_layer = 0; + vp.num_layers = params.depth; + } + return GetView(vp); + } + + std::optional EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) { + if (view_addr < gpu_addr) + return {}; + if (params.target == SurfaceTarget::Texture3D || view_params.target == SurfaceTarget::Texture3D) { + return {}; + } + const std::size_t size = view_params.GetGuestSizeInBytes(); + const GPUVAddr relative_address = view_addr - gpu_addr; + auto layer_mipmap = GetLayerMipmap(relative_address); + if (!layer_mipmap) { + return {}; + } + const u32 layer = (*layer_mipmap).first; + const u32 mipmap = (*layer_mipmap).second; + if (GetMipmapSize(mipmap) != size) { + // TODO: the view may cover many mimaps, this case can still go on + return {}; + } + ViewParams vp{}; + vp.base_layer = layer; + vp.num_layers = 1; + vp.base_level = mipmap; + vp.num_levels = 1; + vp.target = params.target; + return {GetView(vp)}; + } + + TView GetMainView() const { + return main_view; + } + protected: - explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params) - : SurfaceBaseImpl{params}, texture_cache{texture_cache}, - view_offset_map{params.CreateViewOffsetMap()} {} + explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params) + : SurfaceBaseImpl(gpu_addr, params) {} ~SurfaceBase() = default; - virtual std::unique_ptr CreateView(const ViewKey& view_key) = 0; + virtual TView CreateView(const ViewParams& view_key) = 0; + + std::unordered_map views; + TView main_view; private: - TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) { - const ViewKey key{base_layer, num_layers, base_level, num_levels}; + TView GetView(const ViewParams& key) { const auto [entry, is_cache_miss] = views.try_emplace(key); auto& view{entry->second}; if (is_cache_miss) { view = CreateView(key); } - return view.get(); + return view; } - TTextureCache& texture_cache; - const std::map> view_offset_map; - - std::unordered_map> views; - bool is_modified{}; + bool is_protected{}; + bool is_registered{}; + bool is_picked{}; u64 modification_tick{}; }; diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index d1f8c53d50..d9052152cc 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -7,6 +7,7 @@ #include "common/cityhash.h" #include "common/alignment.h" #include "core/core.h" +#include "video_core/engines/shader_bytecode.h" #include "video_core/surface.h" #include "video_core/texture_cache/surface_params.h" #include "video_core/textures/decoders.h" @@ -22,6 +23,37 @@ using VideoCore::Surface::PixelFormatFromTextureFormat; using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceTargetFromTextureType; +SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) { + switch (type) { + case Tegra::Shader::TextureType::Texture1D: { + if (is_array) + return SurfaceTarget::Texture1DArray; + else + return SurfaceTarget::Texture1D; + } + case Tegra::Shader::TextureType::Texture2D: { + if (is_array) + return SurfaceTarget::Texture2DArray; + else + return SurfaceTarget::Texture2D; + } + case Tegra::Shader::TextureType::Texture3D: { + ASSERT(!is_array); + return SurfaceTarget::Texture3D; + } + case Tegra::Shader::TextureType::TextureCube: { + if (is_array) + return SurfaceTarget::TextureCubeArray; + else + return SurfaceTarget::TextureCubemap; + } + default: { + UNREACHABLE(); + return SurfaceTarget::Texture2D; + } + } +} + namespace { constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile); @@ -29,7 +61,8 @@ constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { } // Anonymous namespace SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, - const Tegra::Texture::FullTextureInfo& config) { + const Tegra::Texture::FullTextureInfo& config, + const VideoCommon::Shader::Sampler& entry) { SurfaceParams params; params.is_tiled = config.tic.IsTiled(); params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); @@ -41,7 +74,8 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.srgb_conversion); params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); params.type = GetFormatType(params.pixel_format); - params.target = SurfaceTargetFromTextureType(config.tic.texture_type); + // TODO: on 1DBuffer we should use the tic info. + params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); params.depth = config.tic.Depth(); @@ -52,8 +86,7 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); params.unaligned_height = config.tic.Height(); params.num_levels = config.tic.max_mip_level + 1; - - params.CalculateCachedValues(); + params.is_layered = params.IsLayered(); return params; } @@ -77,8 +110,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( params.target = SurfaceTarget::Texture2D; params.depth = 1; params.num_levels = 1; - - params.CalculateCachedValues(); + params.is_layered = false; return params; } @@ -108,8 +140,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz params.unaligned_height = config.height; params.target = SurfaceTarget::Texture2D; params.num_levels = 1; - - params.CalculateCachedValues(); + params.is_layered = false; return params; } @@ -128,13 +159,13 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( params.type = GetFormatType(params.pixel_format); params.width = config.width; params.height = config.height; + params.pitch = config.pitch; params.unaligned_height = config.height; // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters params.target = SurfaceTarget::Texture2D; params.depth = 1; params.num_levels = 1; - - params.CalculateCachedValues(); + params.is_layered = params.IsLayered(); return params; } @@ -147,7 +178,7 @@ u32 SurfaceParams::GetMipHeight(u32 level) const { } u32 SurfaceParams::GetMipDepth(u32 level) const { - return IsLayered() ? depth : std::max(1U, depth >> level); + return is_layered ? depth : std::max(1U, depth >> level); } bool SurfaceParams::IsLayered() const { @@ -183,7 +214,7 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const { if (level == 0) { return this->block_depth; } - if (IsLayered()) { + if (is_layered) { return 1; } @@ -216,6 +247,10 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { return offset; } +std::size_t SurfaceParams::GetGuestMipmapSize(u32 level) const { + return GetInnerMipmapMemorySize(level, false, false); +} + std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); } @@ -229,7 +264,7 @@ std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) co for (u32 level = 0; level < num_levels; ++level) { size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); } - if (is_tiled && (IsLayered() || target == SurfaceTarget::Texture3D)) { + if (is_tiled && is_layered) { return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); } return size; @@ -256,150 +291,32 @@ u32 SurfaceParams::GetBytesPerPixel() const { return VideoCore::Surface::GetBytesPerPixel(pixel_format); } -bool SurfaceParams::IsFamiliar(const SurfaceParams& view_params) const { - if (std::tie(is_tiled, tile_width_spacing, pixel_format, component_type, type) != - std::tie(view_params.is_tiled, view_params.tile_width_spacing, view_params.pixel_format, - view_params.component_type, view_params.type)) { - return false; - } - - const SurfaceTarget view_target{view_params.target}; - if (view_target == target) { - return true; - } - - switch (target) { - case SurfaceTarget::Texture1D: - case SurfaceTarget::Texture2D: - case SurfaceTarget::Texture3D: - return false; - case SurfaceTarget::Texture1DArray: - return view_target == SurfaceTarget::Texture1D; - case SurfaceTarget::Texture2DArray: - return view_target == SurfaceTarget::Texture2D; - case SurfaceTarget::TextureCubemap: - return view_target == SurfaceTarget::Texture2D || - view_target == SurfaceTarget::Texture2DArray; - case SurfaceTarget::TextureCubeArray: - return view_target == SurfaceTarget::Texture2D || - view_target == SurfaceTarget::Texture2DArray || - view_target == SurfaceTarget::TextureCubemap; - default: - UNIMPLEMENTED_MSG("Unimplemented texture family={}", static_cast(target)); - return false; - } -} - bool SurfaceParams::IsPixelFormatZeta() const { return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; } -void SurfaceParams::CalculateCachedValues() { - switch (target) { - case SurfaceTarget::Texture1D: - case SurfaceTarget::Texture2D: - case SurfaceTarget::Texture3D: - num_layers = 1; - break; - case SurfaceTarget::Texture1DArray: - case SurfaceTarget::Texture2DArray: - case SurfaceTarget::TextureCubemap: - case SurfaceTarget::TextureCubeArray: - num_layers = depth; - break; - default: - UNREACHABLE(); - } - - guest_size_in_bytes = GetInnerMemorySize(false, false, false); - - if (IsPixelFormatASTC(pixel_format)) { - // ASTC is uncompressed in software, in emulated as RGBA8 - host_size_in_bytes = static_cast(width) * static_cast(height) * - static_cast(depth) * 4ULL; - } else { - host_size_in_bytes = GetInnerMemorySize(true, false, false); - } -} - std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const { const bool tiled{as_host_size ? false : is_tiled}; const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; - const u32 depth{target == SurfaceTarget::Texture3D ? GetMipDepth(level) : 1U}; + const u32 depth{is_layered ? 1U : GetMipDepth(level)}; return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth, GetMipBlockHeight(level), GetMipBlockDepth(level)); } std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const { - return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers); -} - -std::map> SurfaceParams::CreateViewOffsetMap() const { - std::map> view_offset_map; - switch (target) { - case SurfaceTarget::Texture1D: - case SurfaceTarget::Texture2D: - case SurfaceTarget::Texture3D: { - // TODO(Rodrigo): Add layer iterations for 3D textures - constexpr u32 layer = 0; - for (u32 level = 0; level < num_levels; ++level) { - const std::size_t offset{GetGuestMipmapLevelOffset(level)}; - view_offset_map.insert({offset, {layer, level}}); - } - break; - } - case SurfaceTarget::Texture1DArray: - case SurfaceTarget::Texture2DArray: - case SurfaceTarget::TextureCubemap: - case SurfaceTarget::TextureCubeArray: { - const std::size_t layer_size{GetGuestLayerSize()}; - for (u32 level = 0; level < num_levels; ++level) { - const std::size_t level_offset{GetGuestMipmapLevelOffset(level)}; - for (u32 layer = 0; layer < num_layers; ++layer) { - const auto layer_offset{static_cast(layer_size * layer)}; - const std::size_t offset{level_offset + layer_offset}; - view_offset_map.insert({offset, {layer, level}}); - } - } - break; - } - default: - UNIMPLEMENTED_MSG("Unimplemented surface target {}", static_cast(target)); - } - return view_offset_map; -} - -bool SurfaceParams::IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const { - return IsDimensionValid(view_params, level) && IsDepthValid(view_params, level) && - IsInBounds(view_params, layer, level); + return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : depth); } -bool SurfaceParams::IsDimensionValid(const SurfaceParams& view_params, u32 level) const { - return view_params.width == GetMipWidth(level) && view_params.height == GetMipHeight(level); -} - -bool SurfaceParams::IsDepthValid(const SurfaceParams& view_params, u32 level) const { - if (view_params.target != SurfaceTarget::Texture3D) { - return true; - } - return view_params.depth == GetMipDepth(level); -} - -bool SurfaceParams::IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const { - return layer + view_params.num_layers <= num_layers && - level + view_params.num_levels <= num_levels; -} - -std::size_t HasheableSurfaceParams::Hash() const { +std::size_t SurfaceParams::Hash() const { return static_cast( Common::CityHash64(reinterpret_cast(this), sizeof(*this))); } -bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const { +bool SurfaceParams::operator==(const SurfaceParams& rhs) const { return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width, height, depth, pitch, unaligned_height, num_levels, pixel_format, component_type, type, target) == @@ -409,4 +326,27 @@ bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const rhs.type, rhs.target); } +std::string SurfaceParams::TargetName() const { + switch (target) { + case SurfaceTarget::Texture1D: + return "1D"; + 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"; + case SurfaceTarget::TextureCubeArray: + return "CubeArray"; + default: + LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast(target)); + UNREACHABLE(); + return fmt::format("TUK({})", static_cast(target)); + } +} + } // namespace VideoCommon diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index 77dc0ba66c..ec8efa210e 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -6,50 +6,21 @@ #include +#include "common/alignment.h" #include "common/common_types.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/surface.h" +#include "video_core/shader/shader_ir.h" namespace VideoCommon { -class HasheableSurfaceParams { -public: - std::size_t Hash() const; - - bool operator==(const HasheableSurfaceParams& rhs) const; - - bool operator!=(const HasheableSurfaceParams& rhs) const { - return !operator==(rhs); - } - -protected: - // Avoid creation outside of a managed environment. - HasheableSurfaceParams() = default; - - bool is_tiled; - bool srgb_conversion; - u32 block_width; - u32 block_height; - u32 block_depth; - u32 tile_width_spacing; - u32 width; - u32 height; - u32 depth; - u32 pitch; - u32 unaligned_height; - u32 num_levels; - VideoCore::Surface::PixelFormat pixel_format; - VideoCore::Surface::ComponentType component_type; - VideoCore::Surface::SurfaceType type; - VideoCore::Surface::SurfaceTarget target; -}; - -class SurfaceParams final : public HasheableSurfaceParams { +class SurfaceParams { public: /// Creates SurfaceCachedParams from a texture configuration. static SurfaceParams CreateForTexture(Core::System& system, - const Tegra::Texture::FullTextureInfo& config); + const Tegra::Texture::FullTextureInfo& config, + const VideoCommon::Shader::Sampler& entry); /// Creates SurfaceCachedParams for a depth buffer configuration. static SurfaceParams CreateForDepthBuffer( @@ -64,68 +35,33 @@ public: static SurfaceParams CreateForFermiCopySurface( const Tegra::Engines::Fermi2D::Regs::Surface& config); - bool IsTiled() const { - return is_tiled; - } - - bool GetSrgbConversion() const { - return srgb_conversion; - } - - u32 GetBlockWidth() const { - return block_width; - } - - u32 GetTileWidthSpacing() const { - return tile_width_spacing; - } - - u32 GetWidth() const { - return width; - } - - u32 GetHeight() const { - return height; - } - - u32 GetDepth() const { - return depth; - } - - u32 GetPitch() const { - return pitch; - } - - u32 GetNumLevels() const { - return num_levels; - } - - VideoCore::Surface::PixelFormat GetPixelFormat() const { - return pixel_format; - } - - VideoCore::Surface::ComponentType GetComponentType() const { - return component_type; - } + std::size_t Hash() const; - VideoCore::Surface::SurfaceTarget GetTarget() const { - return target; - } + bool operator==(const SurfaceParams& rhs) const; - VideoCore::Surface::SurfaceType GetType() const { - return type; + bool operator!=(const SurfaceParams& rhs) const { + return !operator==(rhs); } std::size_t GetGuestSizeInBytes() const { - return guest_size_in_bytes; + return GetInnerMemorySize(false, false, false); } std::size_t GetHostSizeInBytes() const { + std::size_t host_size_in_bytes; + if (IsPixelFormatASTC(pixel_format)) { + // ASTC is uncompressed in software, in emulated as RGBA8 + host_size_in_bytes = static_cast(Common::AlignUp(width, GetDefaultBlockWidth())) * + static_cast(Common::AlignUp(height, GetDefaultBlockHeight())) * + static_cast(depth) * 4ULL; + } else { + host_size_in_bytes = GetInnerMemorySize(true, false, false); + } return host_size_in_bytes; } - u32 GetNumLayers() const { - return num_layers; + u32 GetBlockAlignedWidth() const { + return Common::AlignUp(width, 64 / GetBytesPerPixel()); } /// Returns the width of a given mipmap level. @@ -137,9 +73,6 @@ public: /// Returns the depth of a given mipmap level. u32 GetMipDepth(u32 level) const; - /// Returns true if these parameters are from a layered surface. - bool IsLayered() const; - /// Returns the block height of a given mipmap level. u32 GetMipBlockHeight(u32 level) const; @@ -152,6 +85,9 @@ public: /// Returns the offset in bytes in host memory (linear) of a given mipmap level. std::size_t GetHostMipmapLevelOffset(u32 level) const; + /// Returns the size in bytes in guest memory of a given mipmap level. + std::size_t GetGuestMipmapSize(u32 level) const; + /// Returns the size in bytes in host memory (linear) of a given mipmap level. std::size_t GetHostMipmapSize(u32 level) const; @@ -173,24 +109,30 @@ public: /// Returns the bytes per pixel. u32 GetBytesPerPixel() const; - /// Returns true if another surface can be familiar with this. This is a loosely defined term - /// that reflects the possibility of these two surface parameters potentially being part of a - /// bigger superset. - bool IsFamiliar(const SurfaceParams& view_params) const; - /// Returns true if the pixel format is a depth and/or stencil format. bool IsPixelFormatZeta() const; - /// Creates a map that redirects an address difference to a layer and mipmap level. - std::map> CreateViewOffsetMap() const; + std::string TargetName() const; - /// Returns true if the passed surface view parameters is equal or a valid subset of this. - bool IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const; + bool is_tiled; + bool srgb_conversion; + bool is_layered; + u32 block_width; + u32 block_height; + u32 block_depth; + u32 tile_width_spacing; + u32 width; + u32 height; + u32 depth; + u32 pitch; + u32 unaligned_height; + u32 num_levels; + VideoCore::Surface::PixelFormat pixel_format; + VideoCore::Surface::ComponentType component_type; + VideoCore::Surface::SurfaceType type; + VideoCore::Surface::SurfaceTarget target; private: - /// Calculates values that can be deduced from HasheableSurfaceParams. - void CalculateCachedValues(); - /// Returns the size of a given mipmap level inside a layer. std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const; @@ -200,19 +142,12 @@ private: /// Returns the size of a layer std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const; - /// Returns true if the passed view width and height match the size of this params in a given - /// mipmap level. - bool IsDimensionValid(const SurfaceParams& view_params, u32 level) const; - - /// Returns true if the passed view depth match the size of this params in a given mipmap level. - bool IsDepthValid(const SurfaceParams& view_params, u32 level) const; - - /// Returns true if the passed view layers and mipmap levels are in bounds. - bool IsInBounds(const SurfaceParams& view_params, u32 layer, u32 level) const; + std::size_t GetNumLayers() const { + return is_layered ? depth : 1; + } - std::size_t guest_size_in_bytes; - std::size_t host_size_in_bytes; - u32 num_layers; + /// Returns true if these parameters are from a layered surface. + bool IsLayered() const; }; } // namespace VideoCommon diff --git a/src/video_core/texture_cache/surface_view.cpp b/src/video_core/texture_cache/surface_view.cpp index 5f4cdbb1ca..467696a4cf 100644 --- a/src/video_core/texture_cache/surface_view.cpp +++ b/src/video_core/texture_cache/surface_view.cpp @@ -9,15 +9,15 @@ namespace VideoCommon { -std::size_t ViewKey::Hash() const { +std::size_t ViewParams::Hash() const { return static_cast(base_layer) ^ static_cast(num_layers << 16) ^ - (static_cast(base_level) << 32) ^ - (static_cast(num_levels) << 48); + (static_cast(base_level) << 24) ^ + (static_cast(num_levels) << 32) ^ (static_cast(target) << 36); } -bool ViewKey::operator==(const ViewKey& rhs) const { - return std::tie(base_layer, num_layers, base_level, num_levels) == - std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels); +bool ViewParams::operator==(const ViewParams& rhs) const { + return std::tie(base_layer, num_layers, base_level, num_levels, target) == + std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels, rhs.target); } } // namespace VideoCommon diff --git a/src/video_core/texture_cache/surface_view.h b/src/video_core/texture_cache/surface_view.h index e73d8f6aee..c122800a68 100644 --- a/src/video_core/texture_cache/surface_view.h +++ b/src/video_core/texture_cache/surface_view.h @@ -7,18 +7,45 @@ #include #include "common/common_types.h" +#include "video_core/surface.h" +#include "video_core/texture_cache/surface_params.h" namespace VideoCommon { -struct ViewKey { +struct ViewParams { std::size_t Hash() const; - bool operator==(const ViewKey& rhs) const; + bool operator==(const ViewParams& rhs) const; u32 base_layer{}; u32 num_layers{}; u32 base_level{}; u32 num_levels{}; + VideoCore::Surface::SurfaceTarget target; + bool IsLayered() const { + switch (target) { + case VideoCore::Surface::SurfaceTarget::Texture1DArray: + case VideoCore::Surface::SurfaceTarget::Texture2DArray: + case VideoCore::Surface::SurfaceTarget::TextureCubemap: + case VideoCore::Surface::SurfaceTarget::TextureCubeArray: + return true; + default: + return false; + } + } +}; + +class ViewBase { +public: + ViewBase(const ViewParams& params) : params{params} {} + ~ViewBase() = default; + + const ViewParams& GetViewParams() const { + return params; + } + +protected: + ViewParams params; }; } // namespace VideoCommon @@ -26,8 +53,8 @@ struct ViewKey { namespace std { template <> -struct hash { - std::size_t operator()(const VideoCommon::ViewKey& k) const noexcept { +struct hash { + std::size_t operator()(const VideoCommon::ViewParams& k) const noexcept { return k.Hash(); } }; -- cgit v1.2.3 From 20e97604f1cddde82b7ec0a4cab412e20c9bb781 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 8 May 2019 18:27:29 -0400 Subject: Reduce amount of size calculations. --- src/common/common_funcs.h | 11 +++++ .../renderer_opengl/gl_texture_cache.cpp | 1 - src/video_core/renderer_opengl/gl_texture_cache.h | 2 +- src/video_core/texture_cache/surface_base.cpp | 22 +++++++--- src/video_core/texture_cache/surface_base.h | 28 +++++------- src/video_core/texture_cache/surface_params.cpp | 31 +------------- src/video_core/texture_cache/surface_params.h | 50 +++++++++++++++++----- src/video_core/texture_cache/texture_cache.h | 40 ++++++++--------- 8 files changed, 97 insertions(+), 88 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index 8b0d34da6e..00a5698f3e 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -4,6 +4,7 @@ #pragma once +#include #include #if !defined(ARCHITECTURE_x86_64) @@ -60,4 +61,14 @@ constexpr u32 MakeMagic(char a, char b, char c, char d) { return a | b << 8 | c << 16 | d << 24; } +template > +ForwardIt BinaryFind(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) { + // Note: BOTH type T and the type after ForwardIt is dereferenced + // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. + // This is stricter than lower_bound requirement (see above) + + first = std::lower_bound(first, last, value, comp); + return first != last && !comp(value, *first) ? first : last; +} + } // namespace Common diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index a58e3a816e..32cb08963e 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -240,7 +240,6 @@ CachedSurface::~CachedSurface() { } void CachedSurface::DownloadTexture(std::vector& staging_buffer) { - LOG_CRITICAL(Render_OpenGL, "Flushing"); MICROPROFILE_SCOPE(OpenGL_Texture_Download); // TODO(Rodrigo): Optimize alignment diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index 1ad01137b4..0a1b57014d 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -133,7 +133,7 @@ protected: const VideoCommon::CopyParams& copy_params) override; void ImageBlit(Surface src_surface, Surface dst_surface, const Common::Rectangle& src_rect, - const Common::Rectangle& dst_rect) override; + const Common::Rectangle& dst_rect) override; private: OGLFramebuffer src_framebuffer; diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index dc50132403..36ca72b4a2 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp @@ -19,19 +19,27 @@ using Tegra::Texture::ConvertFromGuestToHost; using VideoCore::MortonSwizzleMode; SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params) - : params{params}, gpu_addr{gpu_addr}, layer_size{params.GetGuestLayerSize()}, - guest_memory_size{params.GetGuestSizeInBytes()}, host_memory_size{ - params.GetHostSizeInBytes()} { - mipmap_offsets.reserve(params.num_levels); - mipmap_sizes.reserve(params.num_levels); + : params{params}, mipmap_sizes(params.num_levels), + mipmap_offsets(params.num_levels), gpu_addr{gpu_addr}, host_memory_size{ + params.GetHostSizeInBytes()} { std::size_t offset = 0; for (u32 level = 0; level < params.num_levels; ++level) { const std::size_t mipmap_size{params.GetGuestMipmapSize(level)}; - mipmap_sizes.push_back(mipmap_size); - mipmap_offsets.push_back(offset); + mipmap_sizes[level] = mipmap_size; + mipmap_offsets[level] = offset; offset += mipmap_size; } + layer_size = offset; + if (params.is_layered) { + if (params.is_tiled) { + layer_size = + SurfaceParams::AlignLayered(layer_size, params.block_height, params.block_depth); + } + guest_memory_size = layer_size * params.depth; + } else { + guest_memory_size = layer_size; + } } void SurfaceBaseImpl::SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 179e80ddba..095deb6026 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -9,6 +9,7 @@ #include #include "common/assert.h" +#include "common/common_funcs.h" #include "common/common_types.h" #include "video_core/gpu.h" #include "video_core/morton.h" @@ -16,16 +17,6 @@ #include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_view.h" -template > -ForwardIt binary_find(ForwardIt first, ForwardIt last, const T& value, Compare comp = {}) { - // Note: BOTH type T and the type after ForwardIt is dereferenced - // must be implicitly convertible to BOTH Type1 and Type2, used in Compare. - // This is stricter than lower_bound requirement (see above) - - first = std::lower_bound(first, last, value, comp); - return first != last && !comp(value, *first) ? first : last; -} - namespace Tegra { class MemoryManager; } @@ -153,7 +144,7 @@ public: const auto layer{static_cast(relative_address / layer_size)}; const GPUVAddr mipmap_address = relative_address - layer_size * layer; const auto mipmap_it = - binary_find(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); + Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); if (mipmap_it == mipmap_offsets.end()) { return {}; } @@ -172,8 +163,8 @@ protected: virtual void DecorateSurfaceName() = 0; const SurfaceParams params; - const std::size_t layer_size; - const std::size_t guest_memory_size; + std::size_t layer_size; + std::size_t guest_memory_size; const std::size_t host_memory_size; GPUVAddr gpu_addr{}; CacheAddr cache_addr{}; @@ -268,9 +259,11 @@ public: return GetView(ViewParams(overview_params.target, 0, num_layers, 0, params.num_levels)); } - std::optional EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr) { - if (view_addr < gpu_addr || params.target == SurfaceTarget::Texture3D || - params.num_levels == 1 || view_params.target == SurfaceTarget::Texture3D) { + std::optional EmplaceView(const SurfaceParams& view_params, const GPUVAddr view_addr, + const std::size_t candidate_size) { + if (params.target == SurfaceTarget::Texture3D || + (params.num_levels == 1 && !params.is_layered) || + view_params.target == SurfaceTarget::Texture3D) { return {}; } const auto layer_mipmap{GetLayerMipmap(view_addr)}; @@ -279,8 +272,7 @@ public: } const u32 layer{layer_mipmap->first}; const u32 mipmap{layer_mipmap->second}; - const std::size_t size{view_params.GetGuestSizeInBytes()}; - if (GetMipmapSize(mipmap) != size) { + if (GetMipmapSize(mipmap) != candidate_size) { // TODO: The view may cover many mimaps, this case can still go on. // This edge-case can be safely be ignored since it will just result in worse // performance. diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index d9052152cc..b537b26e2d 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -4,13 +4,12 @@ #include -#include "common/cityhash.h" #include "common/alignment.h" +#include "common/cityhash.h" #include "core/core.h" #include "video_core/engines/shader_bytecode.h" #include "video_core/surface.h" #include "video_core/texture_cache/surface_params.h" -#include "video_core/textures/decoders.h" namespace VideoCommon { @@ -169,18 +168,6 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( return params; } -u32 SurfaceParams::GetMipWidth(u32 level) const { - return std::max(1U, width >> level); -} - -u32 SurfaceParams::GetMipHeight(u32 level) const { - return std::max(1U, height >> level); -} - -u32 SurfaceParams::GetMipDepth(u32 level) const { - return is_layered ? depth : std::max(1U, depth >> level); -} - bool SurfaceParams::IsLayered() const { switch (target) { case SurfaceTarget::Texture1DArray: @@ -275,22 +262,6 @@ std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { return GetInnerMipmapMemorySize(level, true, false); } -u32 SurfaceParams::GetDefaultBlockWidth() const { - return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); -} - -u32 SurfaceParams::GetDefaultBlockHeight() const { - return VideoCore::Surface::GetDefaultBlockHeight(pixel_format); -} - -u32 SurfaceParams::GetBitsPerPixel() const { - return VideoCore::Surface::GetFormatBpp(pixel_format); -} - -u32 SurfaceParams::GetBytesPerPixel() const { - return VideoCore::Surface::GetBytesPerPixel(pixel_format); -} - bool SurfaceParams::IsPixelFormatZeta() const { return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index ec8efa210e..e0ec1be0ee 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -10,8 +10,9 @@ #include "common/common_types.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/maxwell_3d.h" -#include "video_core/surface.h" #include "video_core/shader/shader_ir.h" +#include "video_core/surface.h" +#include "video_core/textures/decoders.h" namespace VideoCommon { @@ -50,10 +51,17 @@ public: std::size_t GetHostSizeInBytes() const { std::size_t host_size_in_bytes; if (IsPixelFormatASTC(pixel_format)) { + constexpr std::size_t rgb8_bpp = 4ULL; // ASTC is uncompressed in software, in emulated as RGBA8 - host_size_in_bytes = static_cast(Common::AlignUp(width, GetDefaultBlockWidth())) * - static_cast(Common::AlignUp(height, GetDefaultBlockHeight())) * - static_cast(depth) * 4ULL; + host_size_in_bytes = 0; + for (std::size_t level = 0; level < num_levels; level++) { + const std::size_t width = + Common::AlignUp(GetMipWidth(level), GetDefaultBlockWidth()); + const std::size_t height = + Common::AlignUp(GetMipHeight(level), GetDefaultBlockHeight()); + const std::size_t depth = is_layered ? depth : GetMipDepth(level); + host_size_in_bytes += width * height * depth * rgb8_bpp; + } } else { host_size_in_bytes = GetInnerMemorySize(true, false, false); } @@ -65,13 +73,19 @@ public: } /// Returns the width of a given mipmap level. - u32 GetMipWidth(u32 level) const; + u32 GetMipWidth(u32 level) const { + return std::max(1U, width >> level); + } /// Returns the height of a given mipmap level. - u32 GetMipHeight(u32 level) const; + u32 GetMipHeight(u32 level) const { + return std::max(1U, height >> level); + } /// Returns the depth of a given mipmap level. - u32 GetMipDepth(u32 level) const; + u32 GetMipDepth(u32 level) const { + return is_layered ? depth : std::max(1U, depth >> level); + } /// Returns the block height of a given mipmap level. u32 GetMipBlockHeight(u32 level) const; @@ -79,6 +93,12 @@ public: /// Returns the block depth of a given mipmap level. u32 GetMipBlockDepth(u32 level) const; + // Helper used for out of class size calculations + static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, + const u32 block_depth) { + return Common::AlignUp(out_size, Tegra::Texture::GetGOBSize() * block_height * block_depth); + } + /// Returns the offset in bytes in guest memory of a given mipmap level. std::size_t GetGuestMipmapLevelOffset(u32 level) const; @@ -98,16 +118,24 @@ public: std::size_t GetHostLayerSize(u32 level) const; /// Returns the default block width. - u32 GetDefaultBlockWidth() const; + u32 GetDefaultBlockWidth() const { + return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); + } /// Returns the default block height. - u32 GetDefaultBlockHeight() const; + u32 GetDefaultBlockHeight() const { + return VideoCore::Surface::GetDefaultBlockHeight(pixel_format); + } /// Returns the bits per pixel. - u32 GetBitsPerPixel() const; + u32 GetBitsPerPixel() const { + return VideoCore::Surface::GetFormatBpp(pixel_format); + } /// Returns the bytes per pixel. - u32 GetBytesPerPixel() const; + u32 GetBytesPerPixel() const { + return VideoCore::Surface::GetBytesPerPixel(pixel_format); + } /// Returns true if the pixel format is a depth and/or stencil format. bool IsPixelFormatZeta() const; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 96d1081476..fbfd1ff0ba 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -120,10 +120,6 @@ public: return {}; } - if (regs.color_mask[index].raw == 0) { - return {}; - } - auto surface_view = GetSurface(gpu_addr, SurfaceParams::CreateForFramebuffer(system, index), preserve_contents); if (render_targets[index].target) @@ -165,7 +161,9 @@ public: const Tegra::Engines::Fermi2D::Regs::Surface& dst_config, const Common::Rectangle& src_rect, const Common::Rectangle& dst_rect) { - ImageBlit(GetFermiSurface(src_config), GetFermiSurface(dst_config), src_rect, dst_rect); + TSurface dst_surface = GetFermiSurface(dst_config); + ImageBlit(GetFermiSurface(src_config), dst_surface, src_rect, dst_rect); + dst_surface->MarkAsModified(true, Tick()); } TSurface TryFindFramebufferSurface(const u8* host_ptr) { @@ -270,10 +268,6 @@ private: RecycleStrategy PickStrategy(std::vector& overlaps, const SurfaceParams& params, const GPUVAddr gpu_addr, const bool untopological) { - // Untopological decision - if (untopological) { - return RecycleStrategy::Ignore; - } // 3D Textures decision if (params.block_depth > 1 || params.target == SurfaceTarget::Texture3D) { return RecycleStrategy::Flush; @@ -284,12 +278,16 @@ private: return RecycleStrategy::Flush; } } + // Untopological decision + if (untopological) { + return RecycleStrategy::Ignore; + } return RecycleStrategy::Ignore; } std::pair RecycleSurface(std::vector& overlaps, const SurfaceParams& params, const GPUVAddr gpu_addr, - const u8* host_ptr, const bool preserve_contents, + const bool preserve_contents, const bool untopological) { for (auto surface : overlaps) { Unregister(surface); @@ -328,6 +326,7 @@ private: } Unregister(current_surface); Register(new_surface); + new_surface->MarkAsModified(current_surface->IsModified(), Tick()); return {new_surface, new_surface->GetMainView()}; } @@ -351,6 +350,7 @@ private: if (params.target == SurfaceTarget::Texture3D) { return {}; } + bool modified = false; TSurface new_surface = GetUncachedSurface(gpu_addr, params); for (auto surface : overlaps) { const SurfaceParams& src_params = surface->GetSurfaceParams(); @@ -358,7 +358,7 @@ private: // We send this cases to recycle as they are more complex to handle return {}; } - const std::size_t candidate_size = src_params.GetGuestSizeInBytes(); + const std::size_t candidate_size = surface->GetSizeInBytes(); auto mipmap_layer{new_surface->GetLayerMipmap(surface->GetGpuAddr())}; if (!mipmap_layer) { return {}; @@ -368,6 +368,7 @@ private: if (new_surface->GetMipmapSize(mipmap) != candidate_size) { return {}; } + modified |= surface->IsModified(); // Now we got all the data set up const u32 dst_width{params.GetMipWidth(mipmap)}; const u32 dst_height{params.GetMipHeight(mipmap)}; @@ -381,6 +382,7 @@ private: force_reconfiguration |= surface->IsProtected(); Unregister(surface, true); } + new_surface->MarkAsModified(modified, Tick()); Register(new_surface); return {{new_surface, new_surface->GetMainView()}}; } @@ -399,8 +401,7 @@ private: for (auto surface : overlaps) { if (!surface->MatchesTopology(params)) { - return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, - true); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true); } } @@ -418,27 +419,26 @@ private: } } if (!current_surface->IsInside(gpu_addr, gpu_addr + candidate_size)) { - return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, - false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); } - std::optional view = current_surface->EmplaceView(params, gpu_addr); + std::optional view = + current_surface->EmplaceView(params, gpu_addr, candidate_size); if (view.has_value()) { const bool is_mirage = !current_surface->MatchFormat(params.pixel_format); if (is_mirage) { LOG_CRITICAL(HW_GPU, "Mirage View Unsupported"); - return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, - false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); } return {current_surface, *view}; } - return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); } else { std::optional> view = ReconstructSurface(overlaps, params, gpu_addr, host_ptr); if (view.has_value()) { return *view; } - return RecycleSurface(overlaps, params, gpu_addr, host_ptr, preserve_contents, false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); } } -- cgit v1.2.3 From 1d10810d2b90f89bf393561d27eeb3a9f699b275 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 10 May 2019 04:17:48 -0300 Subject: video_core: Use un-shifted block sizes to avoid integer divisions Instead of storing all block width, height and depths in their shifted form: block_width = 1U << block_shift; Store them like they are provided by the emulated hardware (their block_shift form). This way we can avoid doing the costly Common::AlignUp operation to align texture sizes and drop CPU integer divisions with bitwise logic (defined in Common::AlignBits). --- src/common/alignment.h | 5 +++ src/video_core/engines/fermi_2d.h | 9 ++-- src/video_core/engines/maxwell_dma.h | 4 +- src/video_core/texture_cache/surface_base.cpp | 3 +- src/video_core/texture_cache/surface_params.cpp | 39 +++++++++--------- src/video_core/texture_cache/surface_params.h | 7 ++-- src/video_core/texture_cache/texture_cache.h | 3 ++ src/video_core/textures/decoders.cpp | 55 ++++++++++++++++--------- src/video_core/textures/decoders.h | 4 +- src/video_core/textures/texture.h | 9 ++-- 10 files changed, 78 insertions(+), 60 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/common/alignment.h b/src/common/alignment.h index d94a2291f7..3379a69675 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -19,6 +19,11 @@ constexpr T AlignDown(T value, std::size_t size) { return static_cast(value - value % size); } +template +constexpr T AlignBits(T value, T align) { + return (value + ((1 << align) - 1)) >> align << align; +} + template constexpr bool Is4KBAligned(T value) { static_assert(std::is_unsigned_v, "T must be an unsigned value."); diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 45f59a4d99..3d28afa913 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -63,18 +63,15 @@ public: } u32 BlockWidth() const { - // The block width is stored in log2 format. - return 1 << block_width; + return block_width; } u32 BlockHeight() const { - // The block height is stored in log2 format. - return 1 << block_height; + return block_height; } u32 BlockDepth() const { - // The block depth is stored in log2 format. - return 1 << block_depth; + return block_depth; } }; static_assert(sizeof(Surface) == 0x28, "Surface has incorrect size"); diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index e5942f671c..522fa97dc3 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h @@ -59,11 +59,11 @@ public: }; u32 BlockHeight() const { - return 1 << block_height; + return block_height; } u32 BlockDepth() const { - return 1 << block_depth; + return block_depth; } }; diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 36ca72b4a2..510d1aef5f 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp @@ -22,7 +22,6 @@ SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params) : params{params}, mipmap_sizes(params.num_levels), mipmap_offsets(params.num_levels), gpu_addr{gpu_addr}, host_memory_size{ params.GetHostSizeInBytes()} { - std::size_t offset = 0; for (u32 level = 0; level < params.num_levels; ++level) { const std::size_t mipmap_size{params.GetGuestMipmapSize(level)}; @@ -75,7 +74,7 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, return; } if (params.is_tiled) { - ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture target {}", + ASSERT_MSG(params.block_width == 0, "Block width is defined as {} on texture target {}", params.block_width, static_cast(params.target)); for (u32 level = 0; level < params.num_levels; ++level) { const std::size_t host_offset{params.GetHostMipmapLevelOffset(level)}; diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index b537b26e2d..3a47f404dc 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -96,9 +96,9 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( SurfaceParams params; params.is_tiled = type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; params.srgb_conversion = false; - params.block_width = 1 << std::min(block_width, 5U); - params.block_height = 1 << std::min(block_height, 5U); - params.block_depth = 1 << std::min(block_depth, 5U); + params.block_width = std::min(block_width, 5U); + params.block_height = std::min(block_height, 5U); + params.block_depth = std::min(block_depth, 5U); params.tile_width_spacing = 1; params.pixel_format = PixelFormatFromDepthFormat(format); params.component_type = ComponentTypeFromDepthFormat(format); @@ -120,9 +120,9 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz config.memory_layout.type == Tegra::Engines::Maxwell3D::Regs::InvMemoryLayout::BlockLinear; params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; - params.block_width = 1 << config.memory_layout.block_width; - params.block_height = 1 << config.memory_layout.block_height; - params.block_depth = 1 << config.memory_layout.block_depth; + params.block_width = config.memory_layout.block_width; + params.block_height = config.memory_layout.block_height; + params.block_depth = config.memory_layout.block_depth; params.tile_width_spacing = 1; params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); params.component_type = ComponentTypeFromRenderTarget(config.format); @@ -149,9 +149,9 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( params.is_tiled = !config.linear; params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; - params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, - params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, - params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, + params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 5U) : 0, + params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 5U) : 0, + params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 5U) : 0, params.tile_width_spacing = 1; params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); params.component_type = ComponentTypeFromRenderTarget(config.format); @@ -190,9 +190,9 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { const u32 height{GetMipHeight(level)}; const u32 default_block_height{GetDefaultBlockHeight()}; const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; - u32 block_height = 16; - while (block_height > 1 && blocks_in_y <= block_height * 4) { - block_height >>= 1; + u32 block_height = 4; + while (block_height > 0 && blocks_in_y <= (1U << block_height) * 4) { + --block_height; } return block_height; } @@ -202,17 +202,17 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const { return this->block_depth; } if (is_layered) { - return 1; + return 0; } const u32 depth{GetMipDepth(level)}; - u32 block_depth = 32; - while (block_depth > 1 && depth * 2 <= block_depth) { - block_depth >>= 1; + u32 block_depth = 5; + while (block_depth > 0 && depth * 2 <= (1U << block_depth)) { + --block_depth; } - if (block_depth == 32 && GetMipBlockHeight(level) >= 4) { - return 16; + if (block_depth == 5 && GetMipBlockHeight(level) >= 2) { + return 4; } return block_depth; @@ -252,7 +252,8 @@ std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) co size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); } if (is_tiled && is_layered) { - return Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth); + return Common::AlignBits(size, + Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); } return size; } diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index e0ec1be0ee..7c48782c78 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -54,12 +54,12 @@ public: constexpr std::size_t rgb8_bpp = 4ULL; // ASTC is uncompressed in software, in emulated as RGBA8 host_size_in_bytes = 0; - for (std::size_t level = 0; level < num_levels; level++) { + for (u32 level = 0; level < num_levels; ++level) { const std::size_t width = Common::AlignUp(GetMipWidth(level), GetDefaultBlockWidth()); const std::size_t height = Common::AlignUp(GetMipHeight(level), GetDefaultBlockHeight()); - const std::size_t depth = is_layered ? depth : GetMipDepth(level); + const std::size_t depth = is_layered ? this->depth : GetMipDepth(level); host_size_in_bytes += width * height * depth * rgb8_bpp; } } else { @@ -96,7 +96,8 @@ public: // Helper used for out of class size calculations static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, const u32 block_depth) { - return Common::AlignUp(out_size, Tegra::Texture::GetGOBSize() * block_height * block_depth); + return Common::AlignBits(out_size, + Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); } /// Returns the offset in bytes in guest memory of a given mipmap level. diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 1c2b63dae6..f35d0c88fd 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -81,6 +81,9 @@ public: if (!gpu_addr) { return {}; } + if (gpu_addr == 0x1b7ec0000) { + // __debugbreak(); + } const auto params{SurfaceParams::CreateForTexture(system, config, entry)}; return GetSurface(gpu_addr, params, true).second; } diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 2178053865..f45fd175a6 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -36,10 +36,16 @@ struct alignas(64) SwizzleTable { std::array, N> values{}; }; -constexpr u32 gob_size_x = 64; -constexpr u32 gob_size_y = 8; -constexpr u32 gob_size_z = 1; -constexpr u32 gob_size = gob_size_x * gob_size_y * gob_size_z; +constexpr u32 gob_size_x_shift = 6; +constexpr u32 gob_size_y_shift = 3; +constexpr u32 gob_size_z_shift = 0; +constexpr u32 gob_size_shift = gob_size_x_shift + gob_size_y_shift + gob_size_z_shift; + +constexpr u32 gob_size_x = 1U << gob_size_x_shift; +constexpr u32 gob_size_y = 1U << gob_size_y_shift; +constexpr u32 gob_size_z = 1U << gob_size_z_shift; +constexpr u32 gob_size = 1U << gob_size_shift; + constexpr u32 fast_swizzle_align = 16; constexpr auto legacy_swizzle_table = SwizzleTable(); @@ -171,14 +177,16 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, u32 out_bytes_per_pixel, u8* const swizzled_data, u8* const unswizzled_data, bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) { + const u32 block_height_size{1U << block_height}; + const u32 block_depth_size{1U << block_depth}; if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) { SwizzledData(swizzled_data, unswizzled_data, unswizzle, width, height, depth, - bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth, - width_spacing); + bytes_per_pixel, out_bytes_per_pixel, block_height_size, + block_depth_size, width_spacing); } else { SwizzledData(swizzled_data, unswizzled_data, unswizzle, width, height, depth, - bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth, - width_spacing); + bytes_per_pixel, out_bytes_per_pixel, block_height_size, + block_depth_size, width_spacing); } } @@ -249,16 +257,18 @@ std::vector UnswizzleTexture(u8* address, u32 tile_size_x, u32 tile_size_y, void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 swizzled_width, u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height) { + const u32 block_height_size{1U << block_height}; const u32 image_width_in_gobs{(swizzled_width * bytes_per_pixel + (gob_size_x - 1)) / gob_size_x}; for (u32 line = 0; line < subrect_height; ++line) { const u32 gob_address_y = - (line / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + - ((line % (gob_size_y * block_height)) / gob_size_y) * gob_size; + (line / (gob_size_y * block_height_size)) * gob_size * block_height_size * + image_width_in_gobs + + ((line % (gob_size_y * block_height_size)) / gob_size_y) * gob_size; const auto& table = legacy_swizzle_table[line % gob_size_y]; for (u32 x = 0; x < subrect_width; ++x) { const u32 gob_address = - gob_address_y + (x * bytes_per_pixel / gob_size_x) * gob_size * block_height; + gob_address_y + (x * bytes_per_pixel / gob_size_x) * gob_size * block_height_size; const u32 swizzled_offset = gob_address + table[(x * bytes_per_pixel) % gob_size_x]; u8* source_line = unswizzled_data + line * source_pitch + x * bytes_per_pixel; u8* dest_addr = swizzled_data + swizzled_offset; @@ -271,14 +281,17 @@ void SwizzleSubrect(u32 subrect_width, u32 subrect_height, u32 source_pitch, u32 void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 swizzled_width, u32 bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, u32 block_height, u32 offset_x, u32 offset_y) { + const u32 block_height_size{1U << block_height}; for (u32 line = 0; line < subrect_height; ++line) { const u32 y2 = line + offset_y; - const u32 gob_address_y = (y2 / (gob_size_y * block_height)) * gob_size * block_height + - ((y2 % (gob_size_y * block_height)) / gob_size_y) * gob_size; + const u32 gob_address_y = + (y2 / (gob_size_y * block_height_size)) * gob_size * block_height_size + + ((y2 % (gob_size_y * block_height_size)) / gob_size_y) * gob_size; const auto& table = legacy_swizzle_table[y2 % gob_size_y]; for (u32 x = 0; x < subrect_width; ++x) { const u32 x2 = (x + offset_x) * bytes_per_pixel; - const u32 gob_address = gob_address_y + (x2 / gob_size_x) * gob_size * block_height; + const u32 gob_address = + gob_address_y + (x2 / gob_size_x) * gob_size * block_height_size; const u32 swizzled_offset = gob_address + table[x2 % gob_size_x]; u8* dest_line = unswizzled_data + line * dest_pitch + x * bytes_per_pixel; u8* source_addr = swizzled_data + swizzled_offset; @@ -291,16 +304,18 @@ void UnswizzleSubrect(u32 subrect_width, u32 subrect_height, u32 dest_pitch, u32 void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 dst_y, const u32 block_height, const std::size_t copy_size, const u8* source_data, u8* swizzle_data) { + const u32 block_height_size{1U << block_height}; const u32 image_width_in_gobs{(width + gob_size_x - 1) / gob_size_x}; std::size_t count = 0; for (std::size_t y = dst_y; y < height && count < copy_size; ++y) { const std::size_t gob_address_y = - (y / (gob_size_y * block_height)) * gob_size * block_height * image_width_in_gobs + - ((y % (gob_size_y * block_height)) / gob_size_y) * gob_size; + (y / (gob_size_y * block_height_size)) * gob_size * block_height_size * + image_width_in_gobs + + ((y % (gob_size_y * block_height_size)) / gob_size_y) * gob_size; const auto& table = legacy_swizzle_table[y % gob_size_y]; for (std::size_t x = dst_x; x < width && count < copy_size; ++x) { const std::size_t gob_address = - gob_address_y + (x / gob_size_x) * gob_size * block_height; + gob_address_y + (x / gob_size_x) * gob_size * block_height_size; const std::size_t swizzled_offset = gob_address + table[x % gob_size_x]; const u8* source_line = source_data + count; u8* dest_addr = swizzle_data + swizzled_offset; @@ -356,9 +371,9 @@ std::vector DecodeTexture(const std::vector& texture_data, TextureFormat std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth) { if (tiled) { - const u32 aligned_width = Common::AlignUp(width * bytes_per_pixel, gob_size_x); - const u32 aligned_height = Common::AlignUp(height, gob_size_y * block_height); - const u32 aligned_depth = Common::AlignUp(depth, gob_size_z * block_depth); + const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, gob_size_x_shift); + const u32 aligned_height = Common::AlignBits(height, gob_size_y_shift + block_height); + const u32 aligned_depth = Common::AlignBits(depth, gob_size_z_shift + block_depth); return aligned_width * aligned_height * aligned_depth; } else { return width * height * depth * bytes_per_pixel; diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index e072d84017..eaec9b5a5b 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h @@ -12,8 +12,8 @@ namespace Tegra::Texture { // GOBSize constant. Calculated by 64 bytes in x multiplied by 8 y coords, represents // an small rect of (64/bytes_per_pixel)X8. -inline std::size_t GetGOBSize() { - return 512; +inline std::size_t GetGOBSizeShift() { + return 9; } /// Unswizzles a swizzled texture without changing its format. diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index 219bfd5598..f22b4e7c77 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h @@ -219,20 +219,17 @@ struct TICEntry { u32 BlockWidth() const { ASSERT(IsTiled()); - // The block height is stored in log2 format. - return 1 << block_width; + return block_width; } u32 BlockHeight() const { ASSERT(IsTiled()); - // The block height is stored in log2 format. - return 1 << block_height; + return block_height; } u32 BlockDepth() const { ASSERT(IsTiled()); - // The block height is stored in log2 format. - return 1 << block_depth; + return block_depth; } bool IsTiled() const { -- cgit v1.2.3 From 70071a17df344d02aa06e7826ec31d401672b1b9 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 10 May 2019 22:12:35 -0400 Subject: texture_cache: Optimize GetMipBlockHeight and GetMipBlockDepth --- src/common/bit_util.h | 44 +++++++++++++++++++++++++ src/video_core/texture_cache/surface_params.cpp | 19 ++++------- 2 files changed, 50 insertions(+), 13 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/common/bit_util.h b/src/common/bit_util.h index d032df4131..6f7d5a9479 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -97,4 +97,48 @@ inline u32 CountTrailingZeroes64(u64 value) { } #endif +#ifdef _MSC_VER + +inline u32 MostSignificantBit32(const u32 value) { + unsigned long result; + _BitScanReverse(&result, value); + return static_cast(result); +} + +inline u32 MostSignificantBit64(const u64 value) { + unsigned long result; + _BitScanReverse64(&result, value); + return static_cast(result); +} + +#else + +inline u32 MostSignificantBit32(const u32 value) { + return 31U - static_cast(__builtin_clz(value)); +} + +inline u32 MostSignificantBit64(const u64 value) { + return 63U - static_cast(__builtin_clzll(value)); +} + +#endif + +inline u32 Log2Floor32(const u32 value) { + return MostSignificantBit32(value); +} + +inline u32 Log2Ceil32(const u32 value) { + const u32 log2_f = Log2Floor32(value); + return log2_f + ((value ^ (1U << log2_f)) != 0U); +} + +inline u32 Log2Floor64(const u64 value) { + return MostSignificantBit64(value); +} + +inline u32 Log2Ceil64(const u64 value) { + const u64 log2_f = static_cast(Log2Floor64(value)); + return static_cast(log2_f + ((value ^ (1ULL << log2_f)) != 0ULL)); +} + } // namespace Common diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 3a47f404dc..e7e671d8c5 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -5,6 +5,7 @@ #include #include "common/alignment.h" +#include "common/bit_util.h" #include "common/cityhash.h" #include "core/core.h" #include "video_core/engines/shader_bytecode.h" @@ -190,11 +191,8 @@ u32 SurfaceParams::GetMipBlockHeight(u32 level) const { const u32 height{GetMipHeight(level)}; const u32 default_block_height{GetDefaultBlockHeight()}; const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; - u32 block_height = 4; - while (block_height > 0 && blocks_in_y <= (1U << block_height) * 4) { - --block_height; - } - return block_height; + const u32 block_height = Common::Log2Ceil32(blocks_in_y); + return std::clamp(block_height, 3U, 8U) - 3U; } u32 SurfaceParams::GetMipBlockDepth(u32 level) const { @@ -206,15 +204,10 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const { } const u32 depth{GetMipDepth(level)}; - u32 block_depth = 5; - while (block_depth > 0 && depth * 2 <= (1U << block_depth)) { - --block_depth; - } - - if (block_depth == 5 && GetMipBlockHeight(level) >= 2) { - return 4; + const u32 block_depth = Common::Log2Ceil32(depth); + if (block_depth > 4) { + return 5 - (GetMipBlockHeight(level) >= 2); } - return block_depth; } -- cgit v1.2.3 From 291139ade3de6ec4319c6d03f289dfa9c092b588 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Fri, 10 May 2019 23:02:14 -0300 Subject: surface_params: Optimize CreateForTexture Instead of using Common::AlignUp, use Common::AlignBits to align the texture compression factor. --- src/video_core/surface.h | 142 ++++++++++++------------ src/video_core/texture_cache/surface_params.cpp | 6 +- 2 files changed, 76 insertions(+), 72 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/surface.h b/src/video_core/surface.h index b783e4b277..8e98033f33 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -122,71 +122,71 @@ enum class SurfaceTarget { TextureCubeArray, }; -constexpr std::array compression_factor_table = {{ - 1, // ABGR8U - 1, // ABGR8S - 1, // ABGR8UI - 1, // B5G6R5U - 1, // A2B10G10R10U - 1, // A1B5G5R5U - 1, // R8U - 1, // R8UI - 1, // RGBA16F - 1, // RGBA16U - 1, // RGBA16UI - 1, // R11FG11FB10F - 1, // RGBA32UI - 4, // DXT1 - 4, // DXT23 - 4, // DXT45 - 4, // DXN1 - 4, // DXN2UNORM - 4, // DXN2SNORM - 4, // BC7U - 4, // BC6H_UF16 - 4, // BC6H_SF16 - 4, // ASTC_2D_4X4 - 1, // BGRA8 - 1, // RGBA32F - 1, // RG32F - 1, // R32F - 1, // R16F - 1, // R16U - 1, // R16S - 1, // R16UI - 1, // R16I - 1, // RG16 - 1, // RG16F - 1, // RG16UI - 1, // RG16I - 1, // RG16S - 1, // RGB32F - 1, // RGBA8_SRGB - 1, // RG8U - 1, // RG8S - 1, // RG32UI - 1, // R32UI - 4, // ASTC_2D_8X8 - 4, // ASTC_2D_8X5 - 4, // ASTC_2D_5X4 - 1, // BGRA8_SRGB - 4, // DXT1_SRGB - 4, // DXT23_SRGB - 4, // DXT45_SRGB - 4, // BC7U_SRGB - 4, // ASTC_2D_4X4_SRGB - 4, // ASTC_2D_8X8_SRGB - 4, // ASTC_2D_8X5_SRGB - 4, // ASTC_2D_5X4_SRGB - 4, // ASTC_2D_5X5 - 4, // ASTC_2D_5X5_SRGB - 4, // ASTC_2D_10X8 - 4, // ASTC_2D_10X8_SRGB - 1, // Z32F - 1, // Z16 - 1, // Z24S8 - 1, // S8Z24 - 1, // Z32FS8 +inline constexpr std::array compression_factor_shift_table = {{ + 0, // ABGR8U + 0, // ABGR8S + 0, // ABGR8UI + 0, // B5G6R5U + 0, // A2B10G10R10U + 0, // A1B5G5R5U + 0, // R8U + 0, // R8UI + 0, // RGBA16F + 0, // RGBA16U + 0, // RGBA16UI + 0, // R11FG11FB10F + 0, // RGBA32UI + 2, // DXT1 + 2, // DXT23 + 2, // DXT45 + 2, // DXN1 + 2, // DXN2UNORM + 2, // DXN2SNORM + 2, // BC7U + 2, // BC6H_UF16 + 2, // BC6H_SF16 + 2, // ASTC_2D_4X4 + 0, // BGRA8 + 0, // RGBA32F + 0, // RG32F + 0, // R32F + 0, // R16F + 0, // R16U + 0, // R16S + 0, // R16UI + 0, // R16I + 0, // RG16 + 0, // RG16F + 0, // RG16UI + 0, // RG16I + 0, // RG16S + 0, // RGB32F + 0, // RGBA8_SRGB + 0, // RG8U + 0, // RG8S + 0, // RG32UI + 0, // R32UI + 2, // ASTC_2D_8X8 + 2, // ASTC_2D_8X5 + 2, // ASTC_2D_5X4 + 0, // BGRA8_SRGB + 2, // DXT1_SRGB + 2, // DXT23_SRGB + 2, // DXT45_SRGB + 2, // BC7U_SRGB + 2, // ASTC_2D_4X4_SRGB + 2, // ASTC_2D_8X8_SRGB + 2, // ASTC_2D_8X5_SRGB + 2, // ASTC_2D_5X4_SRGB + 2, // ASTC_2D_5X5 + 2, // ASTC_2D_5X5_SRGB + 2, // ASTC_2D_10X8 + 2, // ASTC_2D_10X8_SRGB + 0, // Z32F + 0, // Z16 + 0, // Z24S8 + 0, // S8Z24 + 0, // Z32FS8 }}; /** @@ -195,12 +195,14 @@ constexpr std::array compression_factor_table = {{ * compressed image. This is used for maintaining proper surface sizes for compressed * texture formats. */ -static constexpr u32 GetCompressionFactor(PixelFormat format) { - if (format == PixelFormat::Invalid) - return 0; +inline constexpr u32 GetCompressionFactorShift(PixelFormat format) { + DEBUG_ASSERT(format != PixelFormat::Invalid); + DEBUG_ASSERT(static_cast(format) < compression_factor_table.size()); + return compression_factor_shift_table[static_cast(format)]; +} - ASSERT(static_cast(format) < compression_factor_table.size()); - return compression_factor_table[static_cast(format)]; +inline constexpr u32 GetCompressionFactor(PixelFormat format) { + return 1U << GetCompressionFactorShift(format); } constexpr std::array block_width_table = {{ diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index e7e671d8c5..6f39f84686 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -76,8 +76,10 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.type = GetFormatType(params.pixel_format); // TODO: on 1DBuffer we should use the tic info. params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); - params.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format)); - params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); + params.width = + Common::AlignBits(config.tic.Width(), GetCompressionFactorShift(params.pixel_format)); + params.height = + Common::AlignBits(config.tic.Height(), GetCompressionFactorShift(params.pixel_format)); params.depth = config.tic.Depth(); if (params.target == SurfaceTarget::TextureCubemap || params.target == SurfaceTarget::TextureCubeArray) { -- cgit v1.2.3 From c50c8891117af461255eecffbe4e58a7a4445db5 Mon Sep 17 00:00:00 2001 From: ReinUsesLisp Date: Sun, 12 May 2019 18:31:03 -0300 Subject: surface_params: Ensure pitch is always written to avoid surface leaks --- src/video_core/texture_cache/surface_params.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 6f39f84686..8472b69dc6 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -111,6 +111,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( params.unaligned_height = zeta_height; params.target = SurfaceTarget::Texture2D; params.depth = 1; + params.pitch = 0; params.num_levels = 1; params.is_layered = false; return params; @@ -131,6 +132,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz params.component_type = ComponentTypeFromRenderTarget(config.format); params.type = GetFormatType(params.pixel_format); if (params.is_tiled) { + params.pitch = 0; params.width = config.width; } else { const u32 bpp = GetFormatBpp(params.pixel_format) / CHAR_BIT; -- cgit v1.2.3 From 53e9e3966a1187de887027aaf1d0fec75fe3718f Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sun, 12 May 2019 20:33:52 -0400 Subject: texture_cache: General Fixes Fixed ASTC mipmaps loading Fixed alignment on openGL upload/download Fixed Block Height Calculation Removed unalign_height --- .../renderer_opengl/gl_texture_cache.cpp | 11 ++- src/video_core/surface.h | 84 +++++++++++++++++++++- src/video_core/texture_cache/surface_base.cpp | 18 ++++- src/video_core/texture_cache/surface_base.h | 4 ++ src/video_core/texture_cache/surface_params.cpp | 52 ++++++++------ src/video_core/texture_cache/surface_params.h | 27 ++++--- src/video_core/textures/convert.cpp | 14 ++-- src/video_core/textures/convert.h | 7 +- 8 files changed, 170 insertions(+), 47 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index a55097e5f2..197c9f02c6 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -23,6 +23,7 @@ using VideoCore::MortonSwizzleMode; using VideoCore::Surface::ComponentType; using VideoCore::Surface::PixelFormat; +using VideoCore::Surface::SurfaceCompression; using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceType; @@ -242,10 +243,10 @@ void CachedSurface::DownloadTexture(std::vector& staging_buffer) { MICROPROFILE_SCOPE(OpenGL_Texture_Download); // TODO(Rodrigo): Optimize alignment - glPixelStorei(GL_PACK_ALIGNMENT, 1); SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); for (u32 level = 0; level < params.num_levels; ++level) { + glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); glPixelStorei(GL_PACK_ROW_LENGTH, static_cast(params.GetMipWidth(level))); const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); if (is_compressed) { @@ -270,10 +271,14 @@ void CachedSurface::UploadTexture(std::vector& staging_buffer) { void CachedSurface::UploadTextureMipmap(u32 level, std::vector& staging_buffer) { // TODO(Rodrigo): Optimize alignment - glPixelStorei(GL_UNPACK_ALIGNMENT, 1); + glPixelStorei(GL_UNPACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast(params.GetMipWidth(level))); - const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); + auto compression_type = params.GetCompressionType(); + + const std::size_t mip_offset = compression_type == SurfaceCompression::Converted + ? params.GetConvertedMipmapOffset(level) + : params.GetHostMipmapLevelOffset(level); u8* buffer{staging_buffer.data() + mip_offset}; if (is_compressed) { const auto image_size{static_cast(params.GetHostMipmapSize(level))}; diff --git a/src/video_core/surface.h b/src/video_core/surface.h index 8e98033f33..5d49214e5c 100644 --- a/src/video_core/surface.h +++ b/src/video_core/surface.h @@ -197,7 +197,7 @@ inline constexpr std::array compression_factor_shift_table */ inline constexpr u32 GetCompressionFactorShift(PixelFormat format) { DEBUG_ASSERT(format != PixelFormat::Invalid); - DEBUG_ASSERT(static_cast(format) < compression_factor_table.size()); + DEBUG_ASSERT(static_cast(format) < compression_factor_shift_table.size()); return compression_factor_shift_table[static_cast(format)]; } @@ -438,6 +438,88 @@ static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) { return GetFormatBpp(pixel_format) / CHAR_BIT; } +enum class SurfaceCompression : u8 { + None = 0, + Compressed = 1, + Converted = 2, + Rearranged = 3, +}; + +inline constexpr std::array compression_type_table = {{ + SurfaceCompression::None, // ABGR8U + SurfaceCompression::None, // ABGR8S + SurfaceCompression::None, // ABGR8UI + SurfaceCompression::None, // B5G6R5U + SurfaceCompression::None, // A2B10G10R10U + SurfaceCompression::None, // A1B5G5R5U + SurfaceCompression::None, // R8U + SurfaceCompression::None, // R8UI + SurfaceCompression::None, // RGBA16F + SurfaceCompression::None, // RGBA16U + SurfaceCompression::None, // RGBA16UI + SurfaceCompression::None, // R11FG11FB10F + SurfaceCompression::None, // RGBA32UI + SurfaceCompression::Compressed, // DXT1 + SurfaceCompression::Compressed, // DXT23 + SurfaceCompression::Compressed, // DXT45 + SurfaceCompression::Compressed, // DXN1 + SurfaceCompression::Compressed, // DXN2UNORM + SurfaceCompression::Compressed, // DXN2SNORM + SurfaceCompression::Compressed, // BC7U + SurfaceCompression::Compressed, // BC6H_UF16 + SurfaceCompression::Compressed, // BC6H_SF16 + SurfaceCompression::Converted, // ASTC_2D_4X4 + SurfaceCompression::None, // BGRA8 + SurfaceCompression::None, // RGBA32F + SurfaceCompression::None, // RG32F + SurfaceCompression::None, // R32F + SurfaceCompression::None, // R16F + SurfaceCompression::None, // R16U + SurfaceCompression::None, // R16S + SurfaceCompression::None, // R16UI + SurfaceCompression::None, // R16I + SurfaceCompression::None, // RG16 + SurfaceCompression::None, // RG16F + SurfaceCompression::None, // RG16UI + SurfaceCompression::None, // RG16I + SurfaceCompression::None, // RG16S + SurfaceCompression::None, // RGB32F + SurfaceCompression::None, // RGBA8_SRGB + SurfaceCompression::None, // RG8U + SurfaceCompression::None, // RG8S + SurfaceCompression::None, // RG32UI + SurfaceCompression::None, // R32UI + SurfaceCompression::Converted, // ASTC_2D_8X8 + SurfaceCompression::Converted, // ASTC_2D_8X5 + SurfaceCompression::Converted, // ASTC_2D_5X4 + SurfaceCompression::None, // BGRA8_SRGB + SurfaceCompression::Compressed, // DXT1_SRGB + SurfaceCompression::Compressed, // DXT23_SRGB + SurfaceCompression::Compressed, // DXT45_SRGB + SurfaceCompression::Compressed, // BC7U_SRGB + SurfaceCompression::Converted, // ASTC_2D_4X4_SRGB + SurfaceCompression::Converted, // ASTC_2D_8X8_SRGB + SurfaceCompression::Converted, // ASTC_2D_8X5_SRGB + SurfaceCompression::Converted, // ASTC_2D_5X4_SRGB + SurfaceCompression::Converted, // ASTC_2D_5X5 + SurfaceCompression::Converted, // ASTC_2D_5X5_SRGB + SurfaceCompression::Converted, // ASTC_2D_10X8 + SurfaceCompression::Converted, // ASTC_2D_10X8_SRGB + SurfaceCompression::None, // Z32F + SurfaceCompression::None, // Z16 + SurfaceCompression::None, // Z24S8 + SurfaceCompression::Rearranged, // S8Z24 + SurfaceCompression::None, // Z32FS8 +}}; + +static constexpr SurfaceCompression GetFormatCompressionType(PixelFormat format) { + if (format == PixelFormat::Invalid) + return SurfaceCompression::None; + + ASSERT(static_cast(format) < compression_type_table.size()); + return compression_type_table[static_cast(format)]; +} + SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type); bool SurfaceTargetIsLayered(SurfaceTarget target); diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 510d1aef5f..ceff510439 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp @@ -17,6 +17,7 @@ MICROPROFILE_DEFINE(GPU_Flush_Texture, "GPU", "Texture Flush", MP_RGB(128, 192, using Tegra::Texture::ConvertFromGuestToHost; using VideoCore::MortonSwizzleMode; +using VideoCore::Surface::SurfaceCompression; SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params) : params{params}, mipmap_sizes(params.num_levels), @@ -102,9 +103,20 @@ void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager, } } - for (u32 level = 0; level < params.num_levels; ++level) { - const std::size_t host_offset{params.GetHostMipmapLevelOffset(level)}; - ConvertFromGuestToHost(staging_buffer.data() + host_offset, params.pixel_format, + auto compression_type = params.GetCompressionType(); + if (compression_type == SurfaceCompression::None || + compression_type == SurfaceCompression::Compressed) + return; + + for (u32 level_up = params.num_levels; level_up > 0; --level_up) { + const u32 level = level_up - 1; + const std::size_t in_host_offset{params.GetHostMipmapLevelOffset(level)}; + const std::size_t out_host_offset = compression_type == SurfaceCompression::Rearranged + ? in_host_offset + : params.GetConvertedMipmapOffset(level); + u8* in_buffer = staging_buffer.data() + in_host_offset; + u8* out_buffer = staging_buffer.data() + out_host_offset; + ConvertFromGuestToHost(in_buffer, out_buffer, params.pixel_format, params.GetMipWidth(level), params.GetMipHeight(level), params.GetMipDepth(level), true, true); } diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 78db2d665a..cb7f227061 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -93,6 +93,10 @@ public: return mipmap_sizes[level]; } + bool IsLinear() const { + return !params.is_tiled; + } + bool MatchFormat(VideoCore::Surface::PixelFormat pixel_format) const { return params.pixel_format == pixel_format; } diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 8472b69dc6..d9d157d023 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -76,17 +76,14 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.type = GetFormatType(params.pixel_format); // TODO: on 1DBuffer we should use the tic info. params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); - params.width = - Common::AlignBits(config.tic.Width(), GetCompressionFactorShift(params.pixel_format)); - params.height = - Common::AlignBits(config.tic.Height(), GetCompressionFactorShift(params.pixel_format)); + params.width = config.tic.Width(); + params.height = config.tic.Height(); params.depth = config.tic.Depth(); if (params.target == SurfaceTarget::TextureCubemap || params.target == SurfaceTarget::TextureCubeArray) { params.depth *= 6; } params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); - params.unaligned_height = config.tic.Height(); params.num_levels = config.tic.max_mip_level + 1; params.is_layered = params.IsLayered(); return params; @@ -108,7 +105,6 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( params.type = GetFormatType(params.pixel_format); params.width = zeta_width; params.height = zeta_height; - params.unaligned_height = zeta_height; params.target = SurfaceTarget::Texture2D; params.depth = 1; params.pitch = 0; @@ -141,7 +137,6 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz } params.height = config.height; params.depth = 1; - params.unaligned_height = config.height; params.target = SurfaceTarget::Texture2D; params.num_levels = 1; params.is_layered = false; @@ -164,7 +159,6 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( params.width = config.width; params.height = config.height; params.pitch = config.pitch; - params.unaligned_height = config.height; // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters params.target = SurfaceTarget::Texture2D; params.depth = 1; @@ -185,18 +179,18 @@ bool SurfaceParams::IsLayered() const { } } +// Auto block resizing algorithm from: +// https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c u32 SurfaceParams::GetMipBlockHeight(u32 level) const { - // Auto block resizing algorithm from: - // https://cgit.freedesktop.org/mesa/mesa/tree/src/gallium/drivers/nouveau/nv50/nv50_miptree.c if (level == 0) { return this->block_height; } - const u32 height{GetMipHeight(level)}; + const u32 height_new{GetMipHeight(level)}; const u32 default_block_height{GetDefaultBlockHeight()}; - const u32 blocks_in_y{(height + default_block_height - 1) / default_block_height}; - const u32 block_height = Common::Log2Ceil32(blocks_in_y); - return std::clamp(block_height, 3U, 8U) - 3U; + const u32 blocks_in_y{(height_new + default_block_height - 1) / default_block_height}; + const u32 block_height_new = Common::Log2Ceil32(blocks_in_y); + return std::clamp(block_height_new, 3U, 7U) - 3U; } u32 SurfaceParams::GetMipBlockDepth(u32 level) const { @@ -207,12 +201,12 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const { return 0; } - const u32 depth{GetMipDepth(level)}; - const u32 block_depth = Common::Log2Ceil32(depth); - if (block_depth > 4) { + const u32 depth_new{GetMipDepth(level)}; + const u32 block_depth_new = Common::Log2Ceil32(depth_new); + if (block_depth_new > 4) { return 5 - (GetMipBlockHeight(level) >= 2); } - return block_depth; + return block_depth_new; } std::size_t SurfaceParams::GetGuestMipmapLevelOffset(u32 level) const { @@ -231,6 +225,14 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const { return offset; } +std::size_t SurfaceParams::GetConvertedMipmapOffset(u32 level) const { + std::size_t offset = 0; + for (u32 i = 0; i < level; i++) { + offset += GetConvertedMipmapSize(i); + } + return offset; +} + std::size_t SurfaceParams::GetGuestMipmapSize(u32 level) const { return GetInnerMipmapMemorySize(level, false, false); } @@ -239,6 +241,14 @@ std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); } +std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { + constexpr std::size_t rgb8_bpp = 4ULL; + const std::size_t width_t = GetMipWidth(level); + const std::size_t height_t = GetMipHeight(level); + const std::size_t depth_t = is_layered ? depth : GetMipDepth(level); + return width_t * height_t * depth_t * rgb8_bpp; +} + std::size_t SurfaceParams::GetGuestLayerSize() const { return GetLayerSize(false, false); } @@ -287,12 +297,10 @@ std::size_t SurfaceParams::Hash() const { bool SurfaceParams::operator==(const SurfaceParams& rhs) const { return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width, - height, depth, pitch, unaligned_height, num_levels, pixel_format, - component_type, type, target) == + height, depth, pitch, num_levels, pixel_format, component_type, type, target) == std::tie(rhs.is_tiled, rhs.block_width, rhs.block_height, rhs.block_depth, rhs.tile_width_spacing, rhs.width, rhs.height, rhs.depth, rhs.pitch, - rhs.unaligned_height, rhs.num_levels, rhs.pixel_format, rhs.component_type, - rhs.type, rhs.target); + rhs.num_levels, rhs.pixel_format, rhs.component_type, rhs.type, rhs.target); } std::string SurfaceParams::TargetName() const { diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index 7c48782c78..b3082173f2 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -7,6 +7,7 @@ #include #include "common/alignment.h" +#include "common/bit_util.h" #include "common/common_types.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/maxwell_3d.h" @@ -16,6 +17,8 @@ namespace VideoCommon { +using VideoCore::Surface::SurfaceCompression; + class SurfaceParams { public: /// Creates SurfaceCachedParams from a texture configuration. @@ -50,17 +53,12 @@ public: std::size_t GetHostSizeInBytes() const { std::size_t host_size_in_bytes; - if (IsPixelFormatASTC(pixel_format)) { + if (GetCompressionType() == SurfaceCompression::Converted) { constexpr std::size_t rgb8_bpp = 4ULL; // ASTC is uncompressed in software, in emulated as RGBA8 host_size_in_bytes = 0; for (u32 level = 0; level < num_levels; ++level) { - const std::size_t width = - Common::AlignUp(GetMipWidth(level), GetDefaultBlockWidth()); - const std::size_t height = - Common::AlignUp(GetMipHeight(level), GetDefaultBlockHeight()); - const std::size_t depth = is_layered ? this->depth : GetMipDepth(level); - host_size_in_bytes += width * height * depth * rgb8_bpp; + host_size_in_bytes += GetConvertedMipmapSize(level); } } else { host_size_in_bytes = GetInnerMemorySize(true, false, false); @@ -93,6 +91,12 @@ public: /// Returns the block depth of a given mipmap level. u32 GetMipBlockDepth(u32 level) const; + u32 GetRowAlignment(u32 level) const { + const u32 bpp = + GetCompressionType() == SurfaceCompression::Converted ? 4 : GetBytesPerPixel(); + return 1U << Common::CountTrailingZeroes32(GetMipWidth(level) * bpp); + } + // Helper used for out of class size calculations static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, const u32 block_depth) { @@ -106,12 +110,16 @@ public: /// Returns the offset in bytes in host memory (linear) of a given mipmap level. std::size_t GetHostMipmapLevelOffset(u32 level) const; + std::size_t GetConvertedMipmapOffset(u32 level) const; + /// Returns the size in bytes in guest memory of a given mipmap level. std::size_t GetGuestMipmapSize(u32 level) const; /// Returns the size in bytes in host memory (linear) of a given mipmap level. std::size_t GetHostMipmapSize(u32 level) const; + std::size_t GetConvertedMipmapSize(u32 level) const; + /// Returns the size of a layer in bytes in guest memory. std::size_t GetGuestLayerSize() const; @@ -141,6 +149,10 @@ public: /// Returns true if the pixel format is a depth and/or stencil format. bool IsPixelFormatZeta() const; + SurfaceCompression GetCompressionType() const { + return VideoCore::Surface::GetFormatCompressionType(pixel_format); + } + std::string TargetName() const; bool is_tiled; @@ -154,7 +166,6 @@ public: u32 height; u32 depth; u32 pitch; - u32 unaligned_height; u32 num_levels; VideoCore::Surface::PixelFormat pixel_format; VideoCore::Surface::ComponentType component_type; diff --git a/src/video_core/textures/convert.cpp b/src/video_core/textures/convert.cpp index 82050bd512..f3efa7eb05 100644 --- a/src/video_core/textures/convert.cpp +++ b/src/video_core/textures/convert.cpp @@ -62,19 +62,19 @@ static void ConvertZ24S8ToS8Z24(u8* data, u32 width, u32 height) { SwapS8Z24ToZ24S8(data, width, height); } -void ConvertFromGuestToHost(u8* data, PixelFormat pixel_format, u32 width, u32 height, u32 depth, - bool convert_astc, bool convert_s8z24) { +void ConvertFromGuestToHost(u8* in_data, u8* out_data, PixelFormat pixel_format, u32 width, + u32 height, u32 depth, bool convert_astc, bool convert_s8z24) { if (convert_astc && IsPixelFormatASTC(pixel_format)) { // Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC. u32 block_width{}; u32 block_height{}; std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format); - const std::vector rgba8_data = - Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height); - std::copy(rgba8_data.begin(), rgba8_data.end(), data); + const std::vector rgba8_data = Tegra::Texture::ASTC::Decompress( + in_data, width, height, depth, block_width, block_height); + std::copy(rgba8_data.begin(), rgba8_data.end(), out_data); } else if (convert_s8z24 && pixel_format == PixelFormat::S8Z24) { - Tegra::Texture::ConvertS8Z24ToZ24S8(data, width, height); + Tegra::Texture::ConvertS8Z24ToZ24S8(in_data, width, height); } } @@ -90,4 +90,4 @@ void ConvertFromHostToGuest(u8* data, PixelFormat pixel_format, u32 width, u32 h } } -} // namespace Tegra::Texture \ No newline at end of file +} // namespace Tegra::Texture diff --git a/src/video_core/textures/convert.h b/src/video_core/textures/convert.h index 12542e71c6..d5d6c77bb2 100644 --- a/src/video_core/textures/convert.h +++ b/src/video_core/textures/convert.h @@ -12,10 +12,11 @@ enum class PixelFormat; namespace Tegra::Texture { -void ConvertFromGuestToHost(u8* data, VideoCore::Surface::PixelFormat pixel_format, u32 width, - u32 height, u32 depth, bool convert_astc, bool convert_s8z24); +void ConvertFromGuestToHost(u8* in_data, u8* out_data, VideoCore::Surface::PixelFormat pixel_format, + u32 width, u32 height, u32 depth, bool convert_astc, + bool convert_s8z24); void ConvertFromHostToGuest(u8* data, VideoCore::Surface::PixelFormat pixel_format, u32 width, u32 height, u32 depth, bool convert_astc, bool convert_s8z24); -} // namespace Tegra::Texture \ No newline at end of file +} // namespace Tegra::Texture -- cgit v1.2.3 From 12649d1daf24ccd4a5dd3821ff083e62f28887ab Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Fri, 24 May 2019 15:34:31 -0400 Subject: texture_cache uncompress-compress is untopological. This makes conflicts between non compress and compress textures to be auto recycled. It also limits the amount of mipmaps a texture can have if it goes above it's limit. --- .../renderer_opengl/gl_texture_cache.cpp | 10 ++++----- src/video_core/texture_cache/surface_base.h | 18 +++++++++++++-- src/video_core/texture_cache/surface_params.cpp | 4 ++++ src/video_core/texture_cache/surface_params.h | 14 ++++++++++++ src/video_core/texture_cache/texture_cache.h | 26 ++++++++++++---------- 5 files changed, 53 insertions(+), 19 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 9e9734f9ee..e6f08a7640 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -195,17 +195,17 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte switch (params.target) { case SurfaceTarget::Texture1D: - glTextureStorage1D(texture.handle, params.num_levels, internal_format, params.width); + glTextureStorage1D(texture.handle, params.emulated_levels, internal_format, params.width); break; case SurfaceTarget::Texture2D: case SurfaceTarget::TextureCubemap: - glTextureStorage2D(texture.handle, params.num_levels, internal_format, params.width, + glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, params.width, params.height); break; case SurfaceTarget::Texture3D: case SurfaceTarget::Texture2DArray: case SurfaceTarget::TextureCubeArray: - glTextureStorage3D(texture.handle, params.num_levels, internal_format, params.width, + glTextureStorage3D(texture.handle, params.emulated_levels, internal_format, params.width, params.height, params.depth); break; default: @@ -245,7 +245,7 @@ void CachedSurface::DownloadTexture(std::vector& staging_buffer) { // TODO(Rodrigo): Optimize alignment SCOPE_EXIT({ glPixelStorei(GL_PACK_ROW_LENGTH, 0); }); - for (u32 level = 0; level < params.num_levels; ++level) { + for (u32 level = 0; level < params.emulated_levels; ++level) { glPixelStorei(GL_PACK_ALIGNMENT, std::min(8U, params.GetRowAlignment(level))); glPixelStorei(GL_PACK_ROW_LENGTH, static_cast(params.GetMipWidth(level))); const std::size_t mip_offset = params.GetHostMipmapLevelOffset(level); @@ -264,7 +264,7 @@ void CachedSurface::DownloadTexture(std::vector& staging_buffer) { void CachedSurface::UploadTexture(std::vector& staging_buffer) { MICROPROFILE_SCOPE(OpenGL_Texture_Upload); SCOPE_EXIT({ glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); }); - for (u32 level = 0; level < params.num_levels; ++level) { + for (u32 level = 0; level < params.emulated_levels; ++level) { UploadTextureMipmap(level, staging_buffer); } } diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 77c2d67582..70b5258c99 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -32,6 +32,12 @@ enum class MatchStructureResult : u32 { None = 2, }; +enum class MatchTopologyResult : u32 { + FullMatch = 0, + CompressUnmatch = 1, + None = 2, +}; + class StagingCache { public: StagingCache() {} @@ -136,12 +142,20 @@ public: params.target == SurfaceTarget::Texture2D && params.num_levels == 1; } - bool MatchesTopology(const SurfaceParams& rhs) const { + MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const { const u32 src_bpp{params.GetBytesPerPixel()}; const u32 dst_bpp{rhs.GetBytesPerPixel()}; const bool ib1 = params.IsBuffer(); const bool ib2 = rhs.IsBuffer(); - return std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2); + if (std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2)) { + const bool cb1 = params.IsCompressed(); + const bool cb2 = rhs.IsCompressed(); + if (cb1 == cb2) { + return MatchTopologyResult::FullMatch; + } + return MatchTopologyResult::CompressUnmatch; + } + return MatchTopologyResult::None; } MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const { diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index d9d157d023..77c09264a4 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -85,6 +85,7 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, } params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); params.num_levels = config.tic.max_mip_level + 1; + params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap()); params.is_layered = params.IsLayered(); return params; } @@ -109,6 +110,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer( params.depth = 1; params.pitch = 0; params.num_levels = 1; + params.emulated_levels = 1; params.is_layered = false; return params; } @@ -139,6 +141,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz params.depth = 1; params.target = SurfaceTarget::Texture2D; params.num_levels = 1; + params.emulated_levels = 1; params.is_layered = false; return params; } @@ -163,6 +166,7 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface( params.target = SurfaceTarget::Texture2D; params.depth = 1; params.num_levels = 1; + params.emulated_levels = 1; params.is_layered = params.IsLayered(); return params; } diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index c3affd6218..5fde695b68 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -160,6 +160,19 @@ public: return std::min(t_src_height, t_dst_height); } + u32 MaxPossibleMipmap() const { + const u32 max_mipmap_w = Common::Log2Ceil32(width) + 1U; + const u32 max_mipmap_h = Common::Log2Ceil32(height) + 1U; + const u32 max_mipmap = std::max(max_mipmap_w, max_mipmap_h); + if (target != VideoCore::Surface::SurfaceTarget::Texture3D) + return max_mipmap; + return std::max(max_mipmap, Common::Log2Ceil32(depth) + 1U); + } + + bool IsCompressed() const { + return GetDefaultBlockHeight() > 1 || GetDefaultBlockWidth() > 1; + } + /// Returns the default block width. u32 GetDefaultBlockWidth() const { return VideoCore::Surface::GetDefaultBlockWidth(pixel_format); @@ -205,6 +218,7 @@ public: u32 depth; u32 pitch; u32 num_levels; + u32 emulated_levels; VideoCore::Surface::PixelFormat pixel_format; VideoCore::Surface::ComponentType component_type; VideoCore::Surface::SurfaceType type; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index d2093e5815..69ef7a2bd1 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -305,7 +305,7 @@ private: * due to topological reasons. **/ RecycleStrategy PickStrategy(std::vector& overlaps, const SurfaceParams& params, - const GPUVAddr gpu_addr, const bool untopological) { + const GPUVAddr gpu_addr, const MatchTopologyResult untopological) { if (Settings::values.use_accurate_gpu_emulation) { return RecycleStrategy::Flush; } @@ -320,8 +320,8 @@ private: } } // Untopological decision - if (untopological) { - return RecycleStrategy::Ignore; + if (untopological == MatchTopologyResult::CompressUnmatch) { + return RecycleStrategy::Flush; } return RecycleStrategy::Ignore; } @@ -341,7 +341,7 @@ private: std::pair RecycleSurface(std::vector& overlaps, const SurfaceParams& params, const GPUVAddr gpu_addr, const bool preserve_contents, - const bool untopological) { + const MatchTopologyResult untopological) { const bool do_load = Settings::values.use_accurate_gpu_emulation && preserve_contents; for (auto surface : overlaps) { Unregister(surface); @@ -502,9 +502,10 @@ private: // matches at certain level we are pretty much done. if (l1_cache.count(cache_addr) > 0) { TSurface current_surface = l1_cache[cache_addr]; - if (!current_surface->MatchesTopology(params)) { + auto topological_result = current_surface->MatchesTopology(params); + if (topological_result != MatchTopologyResult::FullMatch) { std::vector overlaps{current_surface}; - return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, topological_result); } MatchStructureResult s_result = current_surface->MatchesStructure(params); if (s_result != MatchStructureResult::None && @@ -534,8 +535,9 @@ private: // we do a topological test to ensure we can find some relationship. If it fails // inmediatly recycle the texture for (auto surface : overlaps) { - if (!surface->MatchesTopology(params)) { - return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, true); + auto topological_result = surface->MatchesTopology(params); + if (topological_result != MatchTopologyResult::FullMatch) { + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, topological_result); } } @@ -553,7 +555,7 @@ private: return *view; } } - return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch); } // Now we check if the candidate is a mipmap/layer of the overlap std::optional view = @@ -576,13 +578,13 @@ private: pair.first->EmplaceView(params, gpu_addr, candidate_size); if (mirage_view) return {pair.first, *mirage_view}; - return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch); } return {current_surface, *view}; } // The next case is unsafe, so if we r in accurate GPU, just skip it if (Settings::values.use_accurate_gpu_emulation) { - return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch); } // This is the case the texture is a part of the parent. if (current_surface->MatchesSubTexture(params, gpu_addr)) { @@ -599,7 +601,7 @@ private: } } // We failed all the tests, recycle the overlaps into a new texture. - return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, false); + return RecycleSurface(overlaps, params, gpu_addr, preserve_contents, MatchTopologyResult::FullMatch); } std::pair InitializeSurface(GPUVAddr gpu_addr, const SurfaceParams& params, -- cgit v1.2.3 From d3596eaead07670508892a116004486debe15ea8 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 1 Jun 2019 23:03:22 -0400 Subject: texture_cache: move some large methods to cpp files --- src/video_core/texture_cache/surface_base.cpp | 103 +++++++++++++++++++++++ src/video_core/texture_cache/surface_base.h | 106 ++---------------------- src/video_core/texture_cache/surface_params.cpp | 33 -------- src/video_core/texture_cache/surface_params.h | 32 +++++-- 4 files changed, 135 insertions(+), 139 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_base.cpp b/src/video_core/texture_cache/surface_base.cpp index 7e90960f79..8c6edb04f7 100644 --- a/src/video_core/texture_cache/surface_base.cpp +++ b/src/video_core/texture_cache/surface_base.cpp @@ -42,6 +42,109 @@ SurfaceBaseImpl::SurfaceBaseImpl(GPUVAddr gpu_addr, const SurfaceParams& params) } } +MatchTopologyResult SurfaceBaseImpl::MatchesTopology(const SurfaceParams& rhs) const { + const u32 src_bpp{params.GetBytesPerPixel()}; + const u32 dst_bpp{rhs.GetBytesPerPixel()}; + const bool ib1 = params.IsBuffer(); + const bool ib2 = rhs.IsBuffer(); + if (std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2)) { + const bool cb1 = params.IsCompressed(); + const bool cb2 = rhs.IsCompressed(); + if (cb1 == cb2) { + return MatchTopologyResult::FullMatch; + } + return MatchTopologyResult::CompressUnmatch; + } + return MatchTopologyResult::None; +} + +MatchStructureResult SurfaceBaseImpl::MatchesStructure(const SurfaceParams& rhs) const { + // Buffer surface Check + if (params.IsBuffer()) { + const std::size_t wd1 = params.width * params.GetBytesPerPixel(); + const std::size_t wd2 = rhs.width * rhs.GetBytesPerPixel(); + if (wd1 == wd2) { + return MatchStructureResult::FullMatch; + } + return MatchStructureResult::None; + } + + // Linear Surface check + if (!params.is_tiled) { + if (std::tie(params.width, params.height, params.pitch) == + std::tie(rhs.width, rhs.height, rhs.pitch)) { + return MatchStructureResult::FullMatch; + } + return MatchStructureResult::None; + } + + // Tiled Surface check + if (std::tie(params.depth, params.block_width, params.block_height, params.block_depth, + params.tile_width_spacing, params.num_levels) == + std::tie(rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth, + rhs.tile_width_spacing, rhs.num_levels)) { + if (std::tie(params.width, params.height) == std::tie(rhs.width, rhs.height)) { + return MatchStructureResult::FullMatch; + } + const u32 ws = SurfaceParams::ConvertWidth(rhs.GetBlockAlignedWidth(), params.pixel_format, + rhs.pixel_format); + const u32 hs = + SurfaceParams::ConvertHeight(rhs.height, params.pixel_format, rhs.pixel_format); + const u32 w1 = params.GetBlockAlignedWidth(); + if (std::tie(w1, params.height) == std::tie(ws, hs)) { + return MatchStructureResult::SemiMatch; + } + } + return MatchStructureResult::None; +} + +std::optional> SurfaceBaseImpl::GetLayerMipmap( + const GPUVAddr candidate_gpu_addr) const { + if (candidate_gpu_addr < gpu_addr) { + return {}; + } + const auto relative_address{static_cast(candidate_gpu_addr - gpu_addr)}; + const auto layer{static_cast(relative_address / layer_size)}; + const GPUVAddr mipmap_address = relative_address - layer_size * layer; + const auto mipmap_it = + Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); + if (mipmap_it == mipmap_offsets.end()) { + return {}; + } + const auto level{static_cast(std::distance(mipmap_offsets.begin(), mipmap_it))}; + return std::make_pair(layer, level); +} + +std::vector SurfaceBaseImpl::BreakDownLayered(const SurfaceParams& in_params) const { + const u32 layers{params.depth}; + const u32 mipmaps{params.num_levels}; + std::vector result; + result.reserve(static_cast(layers) * static_cast(mipmaps)); + + for (u32 layer = 0; layer < layers; layer++) { + for (u32 level = 0; level < mipmaps; level++) { + const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level); + const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level); + result.emplace_back(width, height, layer, level); + } + } + return result; +} + +std::vector SurfaceBaseImpl::BreakDownNonLayered(const SurfaceParams& in_params) const { + const u32 mipmaps{params.num_levels}; + std::vector result; + result.reserve(mipmaps); + + for (u32 level = 0; level < mipmaps; level++) { + const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level); + const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level); + const u32 depth{std::min(params.GetMipDepth(level), in_params.GetMipDepth(level))}; + result.emplace_back(width, height, depth, level); + } + return result; +} + void SurfaceBaseImpl::SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, u32 level) { const u32 width{params.GetMipWidth(level)}; diff --git a/src/video_core/texture_cache/surface_base.h b/src/video_core/texture_cache/surface_base.h index 70b5258c99..9d19ecd5fe 100644 --- a/src/video_core/texture_cache/surface_base.h +++ b/src/video_core/texture_cache/surface_base.h @@ -136,83 +136,17 @@ public: return params.target == target; } + MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const; + + MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const; + bool MatchesSubTexture(const SurfaceParams& rhs, const GPUVAddr other_gpu_addr) const { return std::tie(gpu_addr, params.target, params.num_levels) == std::tie(other_gpu_addr, rhs.target, rhs.num_levels) && params.target == SurfaceTarget::Texture2D && params.num_levels == 1; } - MatchTopologyResult MatchesTopology(const SurfaceParams& rhs) const { - const u32 src_bpp{params.GetBytesPerPixel()}; - const u32 dst_bpp{rhs.GetBytesPerPixel()}; - const bool ib1 = params.IsBuffer(); - const bool ib2 = rhs.IsBuffer(); - if (std::tie(src_bpp, params.is_tiled, ib1) == std::tie(dst_bpp, rhs.is_tiled, ib2)) { - const bool cb1 = params.IsCompressed(); - const bool cb2 = rhs.IsCompressed(); - if (cb1 == cb2) { - return MatchTopologyResult::FullMatch; - } - return MatchTopologyResult::CompressUnmatch; - } - return MatchTopologyResult::None; - } - - MatchStructureResult MatchesStructure(const SurfaceParams& rhs) const { - // Buffer surface Check - if (params.IsBuffer()) { - const std::size_t wd1 = params.width * params.GetBytesPerPixel(); - const std::size_t wd2 = rhs.width * rhs.GetBytesPerPixel(); - if (wd1 == wd2) { - return MatchStructureResult::FullMatch; - } - return MatchStructureResult::None; - } - - // Linear Surface check - if (!params.is_tiled) { - if (std::tie(params.width, params.height, params.pitch) == - std::tie(rhs.width, rhs.height, rhs.pitch)) { - return MatchStructureResult::FullMatch; - } - return MatchStructureResult::None; - } - - // Tiled Surface check - if (std::tie(params.depth, params.block_width, params.block_height, params.block_depth, - params.tile_width_spacing, params.num_levels) == - std::tie(rhs.depth, rhs.block_width, rhs.block_height, rhs.block_depth, - rhs.tile_width_spacing, rhs.num_levels)) { - if (std::tie(params.width, params.height) == std::tie(rhs.width, rhs.height)) { - return MatchStructureResult::FullMatch; - } - const u32 ws = SurfaceParams::ConvertWidth(rhs.GetBlockAlignedWidth(), - params.pixel_format, rhs.pixel_format); - const u32 hs = - SurfaceParams::ConvertHeight(rhs.height, params.pixel_format, rhs.pixel_format); - const u32 w1 = params.GetBlockAlignedWidth(); - if (std::tie(w1, params.height) == std::tie(ws, hs)) { - return MatchStructureResult::SemiMatch; - } - } - return MatchStructureResult::None; - } - - std::optional> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const { - if (candidate_gpu_addr < gpu_addr) { - return {}; - } - const auto relative_address{static_cast(candidate_gpu_addr - gpu_addr)}; - const auto layer{static_cast(relative_address / layer_size)}; - const GPUVAddr mipmap_address = relative_address - layer_size * layer; - const auto mipmap_it = - Common::BinaryFind(mipmap_offsets.begin(), mipmap_offsets.end(), mipmap_address); - if (mipmap_it == mipmap_offsets.end()) { - return {}; - } - const auto level{static_cast(std::distance(mipmap_offsets.begin(), mipmap_it))}; - return std::make_pair(layer, level); - } + std::optional> GetLayerMipmap(const GPUVAddr candidate_gpu_addr) const; std::vector BreakDown(const SurfaceParams& in_params) const { return params.is_layered ? BreakDownLayered(in_params) : BreakDownNonLayered(in_params); @@ -241,35 +175,9 @@ private: void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, u32 level); - std::vector BreakDownLayered(const SurfaceParams& in_params) const { - const u32 layers{params.depth}; - const u32 mipmaps{params.num_levels}; - std::vector result; - result.reserve(static_cast(layers) * static_cast(mipmaps)); - - for (u32 layer = 0; layer < layers; layer++) { - for (u32 level = 0; level < mipmaps; level++) { - const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level); - const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level); - result.emplace_back(width, height, layer, level); - } - } - return result; - } - - std::vector BreakDownNonLayered(const SurfaceParams& in_params) const { - const u32 mipmaps{params.num_levels}; - std::vector result; - result.reserve(mipmaps); + std::vector BreakDownLayered(const SurfaceParams& in_params) const; - for (u32 level = 0; level < mipmaps; level++) { - const u32 width = SurfaceParams::IntersectWidth(params, in_params, level, level); - const u32 height = SurfaceParams::IntersectHeight(params, in_params, level, level); - const u32 depth{std::min(params.GetMipDepth(level), in_params.GetMipDepth(level))}; - result.emplace_back(width, height, depth, level); - } - return result; - } + std::vector BreakDownNonLayered(const SurfaceParams& in_params) const; }; template diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 77c09264a4..60a7356bbc 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -6,7 +6,6 @@ #include "common/alignment.h" #include "common/bit_util.h" -#include "common/cityhash.h" #include "core/core.h" #include "video_core/engines/shader_bytecode.h" #include "video_core/surface.h" @@ -237,14 +236,6 @@ std::size_t SurfaceParams::GetConvertedMipmapOffset(u32 level) const { return offset; } -std::size_t SurfaceParams::GetGuestMipmapSize(u32 level) const { - return GetInnerMipmapMemorySize(level, false, false); -} - -std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { - return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); -} - std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { constexpr std::size_t rgb8_bpp = 4ULL; const std::size_t width_t = GetMipWidth(level); @@ -253,10 +244,6 @@ std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { return width_t * height_t * depth_t * rgb8_bpp; } -std::size_t SurfaceParams::GetGuestLayerSize() const { - return GetLayerSize(false, false); -} - std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { std::size_t size = 0; for (u32 level = 0; level < num_levels; ++level) { @@ -269,16 +256,6 @@ std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) co return size; } -std::size_t SurfaceParams::GetHostLayerSize(u32 level) const { - ASSERT(target != SurfaceTarget::Texture3D); - return GetInnerMipmapMemorySize(level, true, false); -} - -bool SurfaceParams::IsPixelFormatZeta() const { - return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && - pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; -} - std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const { const bool tiled{as_host_size ? false : is_tiled}; @@ -289,16 +266,6 @@ std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size GetMipBlockHeight(level), GetMipBlockDepth(level)); } -std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, - bool uncompressed) const { - return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : depth); -} - -std::size_t SurfaceParams::Hash() const { - return static_cast( - Common::CityHash64(reinterpret_cast(this), sizeof(*this))); -} - bool SurfaceParams::operator==(const SurfaceParams& rhs) const { return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width, height, depth, pitch, num_levels, pixel_format, component_type, type, target) == diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index 5fde695b68..c51e174cd0 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -8,6 +8,7 @@ #include "common/alignment.h" #include "common/bit_util.h" +#include "common/cityhash.h" #include "common/common_types.h" #include "video_core/engines/fermi_2d.h" #include "video_core/engines/maxwell_3d.h" @@ -39,7 +40,10 @@ public: static SurfaceParams CreateForFermiCopySurface( const Tegra::Engines::Fermi2D::Regs::Surface& config); - std::size_t Hash() const; + std::size_t Hash() const { + return static_cast( + Common::CityHash64(reinterpret_cast(this), sizeof(*this))); + } bool operator==(const SurfaceParams& rhs) const; @@ -113,18 +117,27 @@ public: std::size_t GetConvertedMipmapOffset(u32 level) const; /// Returns the size in bytes in guest memory of a given mipmap level. - std::size_t GetGuestMipmapSize(u32 level) const; + std::size_t GetGuestMipmapSize(u32 level) const { + return GetInnerMipmapMemorySize(level, false, false); + } /// Returns the size in bytes in host memory (linear) of a given mipmap level. - std::size_t GetHostMipmapSize(u32 level) const; + std::size_t GetHostMipmapSize(u32 level) const { + return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); + } std::size_t GetConvertedMipmapSize(u32 level) const; /// Returns the size of a layer in bytes in guest memory. - std::size_t GetGuestLayerSize() const; + std::size_t GetGuestLayerSize() const { + return GetLayerSize(false, false); + } /// Returns the size of a layer in bytes in host memory for a given mipmap level. - std::size_t GetHostLayerSize(u32 level) const; + std::size_t GetHostLayerSize(u32 level) const { + ASSERT(target != VideoCore::Surface::SurfaceTarget::Texture3D); + return GetInnerMipmapMemorySize(level, true, false); + } static u32 ConvertWidth(u32 width, VideoCore::Surface::PixelFormat pixel_format_from, VideoCore::Surface::PixelFormat pixel_format_to) { @@ -194,7 +207,10 @@ public: } /// Returns true if the pixel format is a depth and/or stencil format. - bool IsPixelFormatZeta() const; + bool IsPixelFormatZeta() const { + return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && + pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; + } SurfaceCompression GetCompressionType() const { return VideoCore::Surface::GetFormatCompressionType(pixel_format); @@ -229,7 +245,9 @@ private: std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const; /// Returns the size of all mipmap levels and aligns as needed. - std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const; + std::size_t GetInnerMemorySize(bool as_host_size, bool layer_only, bool uncompressed) const { + return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : depth); + } /// Returns the size of a layer std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const; -- cgit v1.2.3 From 5865e58a62e8bda7eb9f6517ca47f5a53e6a1398 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Wed, 12 Jun 2019 09:32:26 -0400 Subject: texture_cache: correct texture buffer on surface params --- src/video_core/texture_cache/surface_params.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 60a7356bbc..f789da2c4d 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -74,10 +74,17 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); params.type = GetFormatType(params.pixel_format); // TODO: on 1DBuffer we should use the tic info. - params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); - params.width = config.tic.Width(); - params.height = config.tic.Height(); - params.depth = config.tic.Depth(); + if (!config.tic.IsBuffer()) { + params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray()); + params.width = config.tic.Width(); + params.height = config.tic.Height(); + params.depth = config.tic.Depth(); + } else { + params.target = SurfaceTarget::TextureBuffer; + params.width = config.tic.Width(); + params.height = 0; + params.depth = 0; + } if (params.target == SurfaceTarget::TextureCubemap || params.target == SurfaceTarget::TextureCubeArray) { params.depth *= 6; -- cgit v1.2.3 From aa94638d43be2b3ce626bc59a81e68b32c245859 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Sat, 15 Jun 2019 11:08:11 -0400 Subject: texture_cache: Corrections to buffers and shadow formats use. --- src/video_core/texture_cache/surface_params.cpp | 44 +++++++++++++++++++------ 1 file changed, 34 insertions(+), 10 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index f789da2c4d..290ba438d0 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -16,11 +16,13 @@ namespace VideoCommon { using VideoCore::Surface::ComponentTypeFromDepthFormat; using VideoCore::Surface::ComponentTypeFromRenderTarget; using VideoCore::Surface::ComponentTypeFromTexture; +using VideoCore::Surface::PixelFormat; using VideoCore::Surface::PixelFormatFromDepthFormat; using VideoCore::Surface::PixelFormatFromRenderTargetFormat; using VideoCore::Surface::PixelFormatFromTextureFormat; using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceTargetFromTextureType; +using VideoCore::Surface::SurfaceType; SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) { switch (type) { @@ -71,6 +73,24 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), params.srgb_conversion); + params.type = GetFormatType(params.pixel_format); + if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) { + switch (params.pixel_format) { + case PixelFormat::R16F: { + params.pixel_format = PixelFormat::Z16; + break; + } + case PixelFormat::R32F: { + params.pixel_format = PixelFormat::Z32F; + break; + } + default: { + UNIMPLEMENTED_MSG("Unimplemented shadow convert format: {}", + static_cast(params.pixel_format)); + } + } + params.type = GetFormatType(params.pixel_format); + } params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); params.type = GetFormatType(params.pixel_format); // TODO: on 1DBuffer we should use the tic info. @@ -79,20 +99,24 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.width = config.tic.Width(); params.height = config.tic.Height(); params.depth = config.tic.Depth(); + params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); + if (params.target == SurfaceTarget::TextureCubemap || + params.target == SurfaceTarget::TextureCubeArray) { + params.depth *= 6; + } + params.num_levels = config.tic.max_mip_level + 1; + params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap()); + params.is_layered = params.IsLayered(); } else { params.target = SurfaceTarget::TextureBuffer; params.width = config.tic.Width(); - params.height = 0; - params.depth = 0; + params.pitch = params.width * params.GetBytesPerPixel(); + params.height = 1; + params.depth = 1; + params.num_levels = 1; + params.emulated_levels = 1; + params.is_layered = false; } - if (params.target == SurfaceTarget::TextureCubemap || - params.target == SurfaceTarget::TextureCubeArray) { - params.depth *= 6; - } - params.pitch = params.is_tiled ? 0 : config.tic.Pitch(); - params.num_levels = config.tic.max_mip_level + 1; - params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap()); - params.is_layered = params.IsLayered(); return params; } -- cgit v1.2.3 From 8660ceb08eb5be516737eb9a0146b13a9cf8b7de Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Mon, 17 Jun 2019 19:19:47 -0400 Subject: texture_cache: Correct format R16U as sibling --- src/video_core/texture_cache/surface_params.cpp | 1 + src/video_core/texture_cache/texture_cache.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 290ba438d0..a670fc1a90 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -76,6 +76,7 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, params.type = GetFormatType(params.pixel_format); if (entry.IsShadow() && params.type == SurfaceType::ColorTexture) { switch (params.pixel_format) { + case PixelFormat::R16U: case PixelFormat::R16F: { params.pixel_format = PixelFormat::Z16; break; diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 353fa4e31b..78821503e2 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -258,7 +258,7 @@ protected: for (u32 i = 0; i < max_formats; i++) { siblings_table[static_cast(i)] = PixelFormat::Invalid; } - make_siblings(PixelFormat::Z16, PixelFormat::R16F); + make_siblings(PixelFormat::Z16, PixelFormat::R16U); make_siblings(PixelFormat::Z32F, PixelFormat::R32F); make_siblings(PixelFormat::Z32FS8, PixelFormat::RG32F); sampled_textures_stack.resize(64); -- cgit v1.2.3 From 4cbbcaa004d52d2f26eaa23a6017dc15a983d4b0 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Tue, 25 Jun 2019 18:03:25 -0400 Subject: surface_params: Corrections, asserts and documentation. --- src/video_core/texture_cache/surface_params.cpp | 4 +- src/video_core/texture_cache/surface_params.h | 97 ++++++++++++++----------- 2 files changed, 58 insertions(+), 43 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index a670fc1a90..340ed2ca08 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -269,11 +269,11 @@ std::size_t SurfaceParams::GetConvertedMipmapOffset(u32 level) const { } std::size_t SurfaceParams::GetConvertedMipmapSize(u32 level) const { - constexpr std::size_t rgb8_bpp = 4ULL; + constexpr std::size_t rgba8_bpp = 4ULL; const std::size_t width_t = GetMipWidth(level); const std::size_t height_t = GetMipHeight(level); const std::size_t depth_t = is_layered ? depth : GetMipDepth(level); - return width_t * height_t * depth_t * rgb8_bpp; + return width_t * height_t * depth_t * rgba8_bpp; } std::size_t SurfaceParams::GetLayerSize(bool as_host_size, bool uncompressed) const { diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h index c51e174cd0..4dfb882f01 100644 --- a/src/video_core/texture_cache/surface_params.h +++ b/src/video_core/texture_cache/surface_params.h @@ -95,25 +95,21 @@ public: /// Returns the block depth of a given mipmap level. u32 GetMipBlockDepth(u32 level) const; + /// returns the best possible row/pitch alignment for the surface. u32 GetRowAlignment(u32 level) const { const u32 bpp = GetCompressionType() == SurfaceCompression::Converted ? 4 : GetBytesPerPixel(); return 1U << Common::CountTrailingZeroes32(GetMipWidth(level) * bpp); } - // Helper used for out of class size calculations - static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, - const u32 block_depth) { - return Common::AlignBits(out_size, - Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); - } - /// Returns the offset in bytes in guest memory of a given mipmap level. std::size_t GetGuestMipmapLevelOffset(u32 level) const; /// Returns the offset in bytes in host memory (linear) of a given mipmap level. std::size_t GetHostMipmapLevelOffset(u32 level) const; + /// Returns the offset in bytes in host memory (linear) of a given mipmap level + // for a texture that is converted in host gpu. std::size_t GetConvertedMipmapOffset(u32 level) const; /// Returns the size in bytes in guest memory of a given mipmap level. @@ -139,40 +135,7 @@ public: return GetInnerMipmapMemorySize(level, true, false); } - static u32 ConvertWidth(u32 width, VideoCore::Surface::PixelFormat pixel_format_from, - VideoCore::Surface::PixelFormat pixel_format_to) { - const u32 bw1 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_from); - const u32 bw2 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_to); - return (width * bw2 + bw1 - 1) / bw1; - } - - static u32 ConvertHeight(u32 height, VideoCore::Surface::PixelFormat pixel_format_from, - VideoCore::Surface::PixelFormat pixel_format_to) { - const u32 bh1 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_from); - const u32 bh2 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_to); - return (height * bh2 + bh1 - 1) / bh1; - } - - // this finds the maximun possible width between 2 2D layers of different formats - static u32 IntersectWidth(const SurfaceParams& src_params, const SurfaceParams& dst_params, - const u32 src_level, const u32 dst_level) { - const u32 bw1 = src_params.GetDefaultBlockWidth(); - const u32 bw2 = dst_params.GetDefaultBlockWidth(); - const u32 t_src_width = (src_params.GetMipWidth(src_level) * bw2 + bw1 - 1) / bw1; - const u32 t_dst_width = (dst_params.GetMipWidth(dst_level) * bw1 + bw2 - 1) / bw2; - return std::min(t_src_width, t_dst_width); - } - - // this finds the maximun possible height between 2 2D layers of different formats - static u32 IntersectHeight(const SurfaceParams& src_params, const SurfaceParams& dst_params, - const u32 src_level, const u32 dst_level) { - const u32 bh1 = src_params.GetDefaultBlockHeight(); - const u32 bh2 = dst_params.GetDefaultBlockHeight(); - const u32 t_src_height = (src_params.GetMipHeight(src_level) * bh2 + bh1 - 1) / bh1; - const u32 t_dst_height = (dst_params.GetMipHeight(dst_level) * bh1 + bh2 - 1) / bh2; - return std::min(t_src_height, t_dst_height); - } - + /// Returns the max possible mipmap that the texture can have in host gpu u32 MaxPossibleMipmap() const { const u32 max_mipmap_w = Common::Log2Ceil32(width) + 1U; const u32 max_mipmap_h = Common::Log2Ceil32(height) + 1U; @@ -182,6 +145,7 @@ public: return std::max(max_mipmap, Common::Log2Ceil32(depth) + 1U); } + /// Returns if the guest surface is a compressed surface. bool IsCompressed() const { return GetDefaultBlockHeight() > 1 || GetDefaultBlockWidth() > 1; } @@ -212,16 +176,67 @@ public: pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; } + /// Returns how the compression should be handled for this texture. Values + /// are: None(no compression), Compressed(texture is compressed), + /// Converted(texture is converted before upload/ after download), + /// Rearranged(texture is swizzled before upload/after download). SurfaceCompression GetCompressionType() const { return VideoCore::Surface::GetFormatCompressionType(pixel_format); } + /// Returns is the surface is a TextureBuffer type of surface. bool IsBuffer() const { return target == VideoCore::Surface::SurfaceTarget::TextureBuffer; } + /// Returns the debug name of the texture for use in graphic debuggers. std::string TargetName() const; + // Helper used for out of class size calculations + static std::size_t AlignLayered(const std::size_t out_size, const u32 block_height, + const u32 block_depth) { + return Common::AlignBits(out_size, + Tegra::Texture::GetGOBSizeShift() + block_height + block_depth); + } + + /// Converts a width from a type of surface into another. This helps represent the + /// equivalent value between compressed/non-compressed textures. + static u32 ConvertWidth(u32 width, VideoCore::Surface::PixelFormat pixel_format_from, + VideoCore::Surface::PixelFormat pixel_format_to) { + const u32 bw1 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_from); + const u32 bw2 = VideoCore::Surface::GetDefaultBlockWidth(pixel_format_to); + return (width * bw2 + bw1 - 1) / bw1; + } + + /// Converts a height from a type of surface into another. This helps represent the + /// equivalent value between compressed/non-compressed textures. + static u32 ConvertHeight(u32 height, VideoCore::Surface::PixelFormat pixel_format_from, + VideoCore::Surface::PixelFormat pixel_format_to) { + const u32 bh1 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_from); + const u32 bh2 = VideoCore::Surface::GetDefaultBlockHeight(pixel_format_to); + return (height * bh2 + bh1 - 1) / bh1; + } + + // Finds the maximun possible width between 2 2D layers of different formats + static u32 IntersectWidth(const SurfaceParams& src_params, const SurfaceParams& dst_params, + const u32 src_level, const u32 dst_level) { + const u32 bw1 = src_params.GetDefaultBlockWidth(); + const u32 bw2 = dst_params.GetDefaultBlockWidth(); + const u32 t_src_width = (src_params.GetMipWidth(src_level) * bw2 + bw1 - 1) / bw1; + const u32 t_dst_width = (dst_params.GetMipWidth(dst_level) * bw1 + bw2 - 1) / bw2; + return std::min(t_src_width, t_dst_width); + } + + // Finds the maximun possible height between 2 2D layers of different formats + static u32 IntersectHeight(const SurfaceParams& src_params, const SurfaceParams& dst_params, + const u32 src_level, const u32 dst_level) { + const u32 bh1 = src_params.GetDefaultBlockHeight(); + const u32 bh2 = dst_params.GetDefaultBlockHeight(); + const u32 t_src_height = (src_params.GetMipHeight(src_level) * bh2 + bh1 - 1) / bh1; + const u32 t_dst_height = (dst_params.GetMipHeight(dst_level) * bh1 + bh2 - 1) / bh2; + return std::min(t_src_height, t_dst_height); + } + bool is_tiled; bool srgb_conversion; bool is_layered; -- cgit v1.2.3 From 98de1132e79410ccb1f5aa809d52e83b2e7d3760 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 4 Jul 2019 19:38:19 -0400 Subject: texture_cache: Correct Texture Buffer Uploading --- src/video_core/renderer_opengl/gl_texture_cache.cpp | 17 +++++++++++++++-- src/video_core/renderer_opengl/gl_texture_cache.h | 1 + src/video_core/texture_cache/surface_params.cpp | 2 ++ 3 files changed, 18 insertions(+), 2 deletions(-) (limited to 'src/video_core/texture_cache/surface_params.cpp') diff --git a/src/video_core/renderer_opengl/gl_texture_cache.cpp b/src/video_core/renderer_opengl/gl_texture_cache.cpp index 97014a6765..780526b66c 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.cpp +++ b/src/video_core/renderer_opengl/gl_texture_cache.cpp @@ -141,6 +141,8 @@ const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType compon GLenum GetTextureTarget(const SurfaceTarget& target) { switch (target) { + case SurfaceTarget::TextureBuffer: + return GL_TEXTURE_BUFFER; case SurfaceTarget::Texture1D: return GL_TEXTURE_1D; case SurfaceTarget::Texture2D: @@ -191,7 +193,8 @@ void ApplyTextureDefaults(const SurfaceParams& params, GLuint texture) { } } -OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum internal_format) { +OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum internal_format, + OGLBuffer& texture_buffer) { OGLTexture texture; texture.Create(target); @@ -199,6 +202,11 @@ OGLTexture CreateTexture(const SurfaceParams& params, GLenum target, GLenum inte case SurfaceTarget::Texture1D: glTextureStorage1D(texture.handle, params.emulated_levels, internal_format, params.width); break; + case SurfaceTarget::TextureBuffer: + texture_buffer.Create(); + glNamedBufferStorage(texture_buffer.handle, params.width * params.GetBytesPerPixel(), + nullptr, GL_DYNAMIC_STORAGE_BIT); + glTextureBuffer(texture.handle, internal_format, texture_buffer.handle); case SurfaceTarget::Texture2D: case SurfaceTarget::TextureCubemap: glTextureStorage2D(texture.handle, params.emulated_levels, internal_format, params.width, @@ -229,7 +237,7 @@ CachedSurface::CachedSurface(const GPUVAddr gpu_addr, const SurfaceParams& param type = tuple.type; is_compressed = tuple.compressed; target = GetTextureTarget(params.target); - texture = CreateTexture(params, target, internal_format); + texture = CreateTexture(params, target, internal_format, texture_buffer); DecorateSurfaceName(); main_view = CreateViewInner( ViewParams(params.target, 0, params.is_layered ? params.depth : 1, 0, params.num_levels), @@ -316,6 +324,11 @@ void CachedSurface::UploadTextureMipmap(u32 level, std::vector& staging_buff glTextureSubImage1D(texture.handle, level, 0, params.GetMipWidth(level), format, type, buffer); break; + case SurfaceTarget::TextureBuffer: + ASSERT(level == 0); + glNamedBufferSubData(texture_buffer.handle, 0, + params.GetMipWidth(level) * params.GetBytesPerPixel(), buffer); + break; case SurfaceTarget::Texture1DArray: case SurfaceTarget::Texture2D: glTextureSubImage2D(texture.handle, level, 0, 0, params.GetMipWidth(level), diff --git a/src/video_core/renderer_opengl/gl_texture_cache.h b/src/video_core/renderer_opengl/gl_texture_cache.h index d4c6e9a305..e7cc66fbbd 100644 --- a/src/video_core/renderer_opengl/gl_texture_cache.h +++ b/src/video_core/renderer_opengl/gl_texture_cache.h @@ -67,6 +67,7 @@ private: u32 view_count{}; OGLTexture texture; + OGLBuffer texture_buffer; }; class CachedSurfaceView final : public VideoCommon::ViewBase { diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp index 340ed2ca08..9c56e2b4f1 100644 --- a/src/video_core/texture_cache/surface_params.cpp +++ b/src/video_core/texture_cache/surface_params.cpp @@ -310,6 +310,8 @@ std::string SurfaceParams::TargetName() const { switch (target) { case SurfaceTarget::Texture1D: return "1D"; + case SurfaceTarget::TextureBuffer: + return "TexBuffer"; case SurfaceTarget::Texture2D: return "2D"; case SurfaceTarget::Texture3D: -- cgit v1.2.3