yuzu-emu
/
yuzu
Archived
1
0
Fork 0

Correct Surface Base and Views for new Texture Cache

This commit is contained in:
Fernando Sahmkow 2019-05-07 10:56:45 -04:00 committed by ReinUsesLisp
parent 3b26206dbd
commit 3d471e732d
7 changed files with 472 additions and 386 deletions

View File

@ -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

View File

@ -4,104 +4,120 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.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_base.h"
#include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_params.h"
#include "video_core/textures/convert.h" #include "video_core/textures/convert.h"
namespace VideoCommon { 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 Tegra::Texture::ConvertFromGuestToHost;
using VideoCore::MortonSwizzleMode; using VideoCore::MortonSwizzleMode;
namespace { SurfaceBaseImpl::SurfaceBaseImpl(const GPUVAddr gpu_vaddr, const SurfaceParams& params)
void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer, : gpu_addr{gpu_vaddr}, params{params}, mipmap_sizes{params.num_levels},
u32 level) { 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 width{params.GetMipWidth(level)};
const u32 height{params.GetMipHeight(level)}; const u32 height{params.GetMipHeight(level)};
const u32 block_height{params.GetMipBlockHeight(level)}; const u32 block_height{params.GetMipBlockHeight(level)};
const u32 block_depth{params.GetMipBlockDepth(level)}; const u32 block_depth{params.GetMipBlockDepth(level)};
std::size_t guest_offset{params.GetGuestMipmapLevelOffset(level)}; std::size_t guest_offset{mipmap_offsets[level]};
if (params.IsLayered()) { if (params.is_layered) {
std::size_t host_offset{0}; 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); const std::size_t host_stride = params.GetHostLayerSize(level);
for (u32 layer = 0; layer < params.GetNumLayers(); layer++) { for (u32 layer = 0; layer < params.depth; layer++) {
MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, MortonSwizzle(mode, params.pixel_format, width, block_height, height, block_depth, 1,
1, params.GetTileWidthSpacing(), buffer + host_offset, params.tile_width_spacing, buffer + host_offset, memory + guest_offset);
memory + guest_offset);
guest_offset += guest_stride; guest_offset += guest_stride;
host_offset += host_stride; host_offset += host_stride;
} }
} else { } else {
MortonSwizzle(mode, params.GetPixelFormat(), width, block_height, height, block_depth, MortonSwizzle(mode, params.pixel_format, width, block_height, height, block_depth,
params.GetMipDepth(level), params.GetTileWidthSpacing(), buffer, params.GetMipDepth(level), params.tile_width_spacing, buffer,
memory + guest_offset); memory + guest_offset);
} }
} }
} // Anonymous namespace
SurfaceBaseImpl::SurfaceBaseImpl(const SurfaceParams& params) : params{params} { void SurfaceBaseImpl::LoadBuffer(Tegra::MemoryManager& memory_manager,
staging_buffer.resize(params.GetHostSizeInBytes()); std::vector<u8>& staging_buffer) {
} MICROPROFILE_SCOPE(GPU_Load_Texture);
auto host_ptr = memory_manager.GetPointer(gpu_addr);
SurfaceBaseImpl::~SurfaceBaseImpl() = default; if (params.is_tiled) {
ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture target {}",
void SurfaceBaseImpl::LoadBuffer() { params.block_width, static_cast<u32>(params.target));
if (params.IsTiled()) { for (u32 level = 0; level < params.num_levels; ++level) {
ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {} on texture target {}", const u32 host_offset = params.GetHostMipmapLevelOffset(level);
params.GetBlockWidth(), static_cast<u32>(params.GetTarget()));
for (u32 level = 0; level < params.GetNumLevels(); ++level) {
SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params, SwizzleFunc(MortonSwizzleMode::MortonToLinear, host_ptr, params,
GetStagingBufferLevelData(level), level); staging_buffer.data() + host_offset, level);
} }
} else { } else {
ASSERT_MSG(params.GetNumLevels() == 1, "Linear mipmap loading is not implemented"); ASSERT_MSG(params.num_levels == 1, "Linear mipmap loading is not implemented");
const u32 bpp{GetFormatBpp(params.GetPixelFormat()) / CHAR_BIT}; const u32 bpp{params.GetBytesPerPixel()};
const u32 block_width{params.GetDefaultBlockWidth()}; const u32 block_width{params.GetDefaultBlockWidth()};
const u32 block_height{params.GetDefaultBlockHeight()}; const u32 block_height{params.GetDefaultBlockHeight()};
const u32 width{(params.GetWidth() + block_width - 1) / block_width}; const u32 width{(params.width + block_width - 1) / block_width};
const u32 height{(params.GetHeight() + block_height - 1) / block_height}; const u32 height{(params.height + block_height - 1) / block_height};
const u32 copy_size{width * bpp}; 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()); std::memcpy(staging_buffer.data(), host_ptr, params.GetHostSizeInBytes());
} else { } else {
const u8* start{host_ptr}; const u8* start{host_ptr};
u8* write_to{staging_buffer.data()}; u8* write_to{staging_buffer.data()};
for (u32 h = height; h > 0; --h) { for (u32 h = height; h > 0; --h) {
std::memcpy(write_to, start, copy_size); std::memcpy(write_to, start, copy_size);
start += params.GetPitch(); start += params.pitch;
write_to += copy_size; write_to += copy_size;
} }
} }
} }
for (u32 level = 0; level < params.GetNumLevels(); ++level) { for (u32 level = 0; level < params.num_levels; ++level) {
ConvertFromGuestToHost(GetStagingBufferLevelData(level), params.GetPixelFormat(), const u32 host_offset = params.GetHostMipmapLevelOffset(level);
ConvertFromGuestToHost(staging_buffer.data() + host_offset, params.pixel_format,
params.GetMipWidth(level), params.GetMipHeight(level), params.GetMipWidth(level), params.GetMipHeight(level),
params.GetMipDepth(level), true, true); params.GetMipDepth(level), true, true);
} }
} }
void SurfaceBaseImpl::FlushBuffer() { void SurfaceBaseImpl::FlushBuffer(std::vector<u8>& staging_buffer) {
if (params.IsTiled()) { MICROPROFILE_SCOPE(GPU_Flush_Texture);
ASSERT_MSG(params.GetBlockWidth() == 1, "Block width is defined as {}", if (params.is_tiled) {
params.GetBlockWidth()); ASSERT_MSG(params.block_width == 1, "Block width is defined as {}", params.block_width);
for (u32 level = 0; level < params.GetNumLevels(); ++level) { for (u32 level = 0; level < params.num_levels; ++level) {
SwizzleFunc(MortonSwizzleMode::LinearToMorton, GetHostPtr(), params, const u32 host_offset = params.GetHostMipmapLevelOffset(level);
GetStagingBufferLevelData(level), level); SwizzleFunc(MortonSwizzleMode::LinearToMorton, host_ptr, params,
staging_buffer.data() + host_offset, level);
} }
} else { } else {
UNIMPLEMENTED(); UNIMPLEMENTED();
/* /*
ASSERT(params.GetTarget() == SurfaceTarget::Texture2D); ASSERT(params.target == SurfaceTarget::Texture2D);
ASSERT(params.GetNumLevels() == 1); ASSERT(params.num_levels == 1);
const u32 bpp{params.GetFormatBpp() / 8}; const u32 bpp{params.GetFormatBpp() / 8};
const u32 copy_size{params.GetWidth() * bpp}; const u32 copy_size{params.width * bpp};
if (params.GetPitch() == copy_size) { if (params.pitch == copy_size) {
std::memcpy(host_ptr, staging_buffer.data(), GetSizeInBytes()); std::memcpy(host_ptr, staging_buffer.data(), memory_size);
} else { } else {
u8* start{host_ptr}; u8* start{host_ptr};
const u8* read_to{staging_buffer.data()}; const u8* read_to{staging_buffer.data()};

View File

@ -4,166 +4,309 @@
#pragma once #pragma once
#include <algorithm>
#include <unordered_map> #include <unordered_map>
#include <vector>
#include "common/assert.h" #include "common/assert.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/gpu.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_params.h"
#include "video_core/texture_cache/surface_view.h" #include "video_core/texture_cache/surface_view.h"
template<class ForwardIt, class T, class Compare=std::less<>>
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 { namespace VideoCommon {
using VideoCore::Surface::SurfaceTarget;
using VideoCore::MortonSwizzleMode;
class SurfaceBaseImpl { class SurfaceBaseImpl {
public: public:
void LoadBuffer(); void LoadBuffer(Tegra::MemoryManager& memory_manager, std::vector<u8>& staging_buffer);
void FlushBuffer(); void FlushBuffer(std::vector<u8>& staging_buffer);
GPUVAddr GetGpuAddr() const { GPUVAddr GetGpuAddr() const {
ASSERT(is_registered);
return gpu_addr; 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 { VAddr GetCpuAddr() const {
ASSERT(is_registered); return gpu_addr;
return cpu_addr; }
void SetCpuAddr(const VAddr new_addr) {
cpu_addr = new_addr;
} }
u8* GetHostPtr() const { u8* GetHostPtr() const {
ASSERT(is_registered);
return host_ptr; return host_ptr;
} }
CacheAddr GetCacheAddr() const { void SetHostPtr(u8* new_addr) {
ASSERT(is_registered); host_ptr = new_addr;
return cache_addr;
} }
const SurfaceParams& GetSurfaceParams() const { const SurfaceParams& GetSurfaceParams() const {
return params; 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();
}
void Unregister() {
ASSERT(is_registered);
is_registered = false;
}
bool IsRegistered() const {
return is_registered;
}
std::size_t GetSizeInBytes() const { std::size_t GetSizeInBytes() const {
return params.GetGuestSizeInBytes(); return memory_size;
} }
u8* GetStagingBufferLevelData(u32 level) { std::size_t GetHostSizeInBytes() const {
return staging_buffer.data() + params.GetHostMipmapLevelOffset(level); return host_memory_size;
}
std::size_t GetMipmapSize(const u32 level) const {
return mipmap_sizes[level];
}
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<std::pair<u32, u32>> 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 {};
}
std::vector<CopyParams> 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<CopyParams> 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<CopyParams> 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: protected:
explicit SurfaceBaseImpl(const SurfaceParams& params); explicit SurfaceBaseImpl(const GPUVAddr gpu_vaddr, const SurfaceParams& params);
~SurfaceBaseImpl(); // non-virtual is intended ~SurfaceBaseImpl() = default;
virtual void DecorateSurfaceName() = 0; virtual void DecorateSurfaceName() = 0;
const SurfaceParams params; const SurfaceParams params;
GPUVAddr gpu_addr{};
GPUVAddr gpu_addr_end{};
std::vector<u32> mipmap_sizes;
std::vector<u32> 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;
private: private:
GPUVAddr gpu_addr{}; void SwizzleFunc(MortonSwizzleMode mode, u8* memory, const SurfaceParams& params, u8* buffer,
VAddr cpu_addr{}; u32 level);
u8* host_ptr{};
CacheAddr cache_addr{};
bool is_registered{};
std::vector<u8> staging_buffer;
}; };
template <typename TTextureCache, typename TView> template <typename TView>
class SurfaceBase : public SurfaceBaseImpl { class SurfaceBase : public SurfaceBaseImpl {
public: public:
virtual void UploadTexture() = 0; virtual void UploadTexture(std::vector<u8>& staging_buffer) = 0;
virtual void DownloadTexture() = 0; virtual void DownloadTexture(std::vector<u8>& staging_buffer) = 0;
TView* TryGetView(GPUVAddr view_addr, const SurfaceParams& view_params) { void MarkAsModified(const bool is_modified_, const u64 tick) {
if (view_addr < GetGpuAddr() || !params.IsFamiliar(view_params)) { is_modified = is_modified_ || is_protected;
// It can't be a view if it's in a prior address. modification_tick = tick;
return {};
}
const auto relative_offset{static_cast<u64>(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;
if (!params.IsViewValid(view_params, layer, level)) {
return {};
}
return GetView(layer, view_params.GetNumLayers(), level, view_params.GetNumLevels());
} }
void MarkAsModified(bool is_modified_) { void MarkAsProtected(const bool is_protected) {
is_modified = is_modified_; this->is_protected = is_protected;
if (is_modified_) {
modification_tick = texture_cache.Tick();
}
} }
TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) { void MarkAsPicked(const bool is_picked) {
TView* view{TryGetView(view_addr, view_params)}; this->is_picked = is_picked;
ASSERT(view != nullptr);
return view;
} }
bool IsModified() const { bool IsModified() const {
return is_modified; return is_modified;
} }
bool IsProtected() const {
return is_protected;
}
bool IsRegistered() const {
return is_registered;
}
bool IsPicked() const {
return is_picked;
}
void MarkAsRegistered(bool is_reg) {
is_registered = is_reg;
}
u64 GetModificationTick() const { u64 GetModificationTick() const {
return modification_tick; 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<TView> 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: protected:
explicit SurfaceBase(TTextureCache& texture_cache, const SurfaceParams& params) explicit SurfaceBase(const GPUVAddr gpu_addr, const SurfaceParams& params)
: SurfaceBaseImpl{params}, texture_cache{texture_cache}, : SurfaceBaseImpl(gpu_addr, params) {}
view_offset_map{params.CreateViewOffsetMap()} {}
~SurfaceBase() = default; ~SurfaceBase() = default;
virtual std::unique_ptr<TView> CreateView(const ViewKey& view_key) = 0; virtual TView CreateView(const ViewParams& view_key) = 0;
std::unordered_map<ViewParams, TView> views;
TView main_view;
private: private:
TView* GetView(u32 base_layer, u32 num_layers, u32 base_level, u32 num_levels) { TView GetView(const ViewParams& key) {
const ViewKey key{base_layer, num_layers, base_level, num_levels};
const auto [entry, is_cache_miss] = views.try_emplace(key); const auto [entry, is_cache_miss] = views.try_emplace(key);
auto& view{entry->second}; auto& view{entry->second};
if (is_cache_miss) { if (is_cache_miss) {
view = CreateView(key); view = CreateView(key);
} }
return view.get(); return view;
} }
TTextureCache& texture_cache;
const std::map<u64, std::pair<u32, u32>> view_offset_map;
std::unordered_map<ViewKey, std::unique_ptr<TView>> views;
bool is_modified{}; bool is_modified{};
bool is_protected{};
bool is_registered{};
bool is_picked{};
u64 modification_tick{}; u64 modification_tick{};
}; };

View File

@ -7,6 +7,7 @@
#include "common/cityhash.h" #include "common/cityhash.h"
#include "common/alignment.h" #include "common/alignment.h"
#include "core/core.h" #include "core/core.h"
#include "video_core/engines/shader_bytecode.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/texture_cache/surface_params.h" #include "video_core/texture_cache/surface_params.h"
#include "video_core/textures/decoders.h" #include "video_core/textures/decoders.h"
@ -22,6 +23,37 @@ using VideoCore::Surface::PixelFormatFromTextureFormat;
using VideoCore::Surface::SurfaceTarget; using VideoCore::Surface::SurfaceTarget;
using VideoCore::Surface::SurfaceTargetFromTextureType; 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 { namespace {
constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) { constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / 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 } // Anonymous namespace
SurfaceParams SurfaceParams::CreateForTexture(Core::System& system, SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
const Tegra::Texture::FullTextureInfo& config) { const Tegra::Texture::FullTextureInfo& config,
const VideoCommon::Shader::Sampler& entry) {
SurfaceParams params; SurfaceParams params;
params.is_tiled = config.tic.IsTiled(); params.is_tiled = config.tic.IsTiled();
params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); params.srgb_conversion = config.tic.IsSrgbConversionEnabled();
@ -41,7 +74,8 @@ SurfaceParams SurfaceParams::CreateForTexture(Core::System& system,
params.srgb_conversion); params.srgb_conversion);
params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value()); params.component_type = ComponentTypeFromTexture(config.tic.r_type.Value());
params.type = GetFormatType(params.pixel_format); 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.width = Common::AlignUp(config.tic.Width(), GetCompressionFactor(params.pixel_format));
params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format)); params.height = Common::AlignUp(config.tic.Height(), GetCompressionFactor(params.pixel_format));
params.depth = config.tic.Depth(); 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.pitch = params.is_tiled ? 0 : config.tic.Pitch();
params.unaligned_height = config.tic.Height(); params.unaligned_height = config.tic.Height();
params.num_levels = config.tic.max_mip_level + 1; params.num_levels = config.tic.max_mip_level + 1;
params.is_layered = params.IsLayered();
params.CalculateCachedValues();
return params; return params;
} }
@ -77,8 +110,7 @@ SurfaceParams SurfaceParams::CreateForDepthBuffer(
params.target = SurfaceTarget::Texture2D; params.target = SurfaceTarget::Texture2D;
params.depth = 1; params.depth = 1;
params.num_levels = 1; params.num_levels = 1;
params.is_layered = false;
params.CalculateCachedValues();
return params; return params;
} }
@ -108,8 +140,7 @@ SurfaceParams SurfaceParams::CreateForFramebuffer(Core::System& system, std::siz
params.unaligned_height = config.height; params.unaligned_height = config.height;
params.target = SurfaceTarget::Texture2D; params.target = SurfaceTarget::Texture2D;
params.num_levels = 1; params.num_levels = 1;
params.is_layered = false;
params.CalculateCachedValues();
return params; return params;
} }
@ -128,13 +159,13 @@ SurfaceParams SurfaceParams::CreateForFermiCopySurface(
params.type = GetFormatType(params.pixel_format); params.type = GetFormatType(params.pixel_format);
params.width = config.width; params.width = config.width;
params.height = config.height; params.height = config.height;
params.pitch = config.pitch;
params.unaligned_height = config.height; params.unaligned_height = config.height;
// TODO(Rodrigo): Try to guess the surface target from depth and layer parameters // TODO(Rodrigo): Try to guess the surface target from depth and layer parameters
params.target = SurfaceTarget::Texture2D; params.target = SurfaceTarget::Texture2D;
params.depth = 1; params.depth = 1;
params.num_levels = 1; params.num_levels = 1;
params.is_layered = params.IsLayered();
params.CalculateCachedValues();
return params; return params;
} }
@ -147,7 +178,7 @@ u32 SurfaceParams::GetMipHeight(u32 level) const {
} }
u32 SurfaceParams::GetMipDepth(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 { bool SurfaceParams::IsLayered() const {
@ -183,7 +214,7 @@ u32 SurfaceParams::GetMipBlockDepth(u32 level) const {
if (level == 0) { if (level == 0) {
return this->block_depth; return this->block_depth;
} }
if (IsLayered()) { if (is_layered) {
return 1; return 1;
} }
@ -216,6 +247,10 @@ std::size_t SurfaceParams::GetHostMipmapLevelOffset(u32 level) const {
return offset; return offset;
} }
std::size_t SurfaceParams::GetGuestMipmapSize(u32 level) const {
return GetInnerMipmapMemorySize(level, false, false);
}
std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const { std::size_t SurfaceParams::GetHostMipmapSize(u32 level) const {
return GetInnerMipmapMemorySize(level, true, false) * GetNumLayers(); 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) { for (u32 level = 0; level < num_levels; ++level) {
size += GetInnerMipmapMemorySize(level, as_host_size, uncompressed); 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 Common::AlignUp(size, Tegra::Texture::GetGOBSize() * block_height * block_depth);
} }
return size; return size;
@ -256,150 +291,32 @@ u32 SurfaceParams::GetBytesPerPixel() const {
return VideoCore::Surface::GetBytesPerPixel(pixel_format); 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<u32>(target));
return false;
}
}
bool SurfaceParams::IsPixelFormatZeta() const { bool SurfaceParams::IsPixelFormatZeta() const {
return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat && return pixel_format >= VideoCore::Surface::PixelFormat::MaxColorFormat &&
pixel_format < VideoCore::Surface::PixelFormat::MaxDepthStencilFormat; 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<std::size_t>(width) * static_cast<std::size_t>(height) *
static_cast<std::size_t>(depth) * 4ULL;
} else {
host_size_in_bytes = GetInnerMemorySize(true, false, false);
}
}
std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size, std::size_t SurfaceParams::GetInnerMipmapMemorySize(u32 level, bool as_host_size,
bool uncompressed) const { bool uncompressed) const {
const bool tiled{as_host_size ? false : is_tiled}; const bool tiled{as_host_size ? false : is_tiled};
const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())}; const u32 width{GetMipmapSize(uncompressed, GetMipWidth(level), GetDefaultBlockWidth())};
const u32 height{GetMipmapSize(uncompressed, GetMipHeight(level), GetDefaultBlockHeight())}; 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, return Tegra::Texture::CalculateSize(tiled, GetBytesPerPixel(), width, height, depth,
GetMipBlockHeight(level), GetMipBlockDepth(level)); GetMipBlockHeight(level), GetMipBlockDepth(level));
} }
std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only, std::size_t SurfaceParams::GetInnerMemorySize(bool as_host_size, bool layer_only,
bool uncompressed) const { bool uncompressed) const {
return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : num_layers); return GetLayerSize(as_host_size, uncompressed) * (layer_only ? 1U : depth);
} }
std::map<u64, std::pair<u32, u32>> SurfaceParams::CreateViewOffsetMap() const { std::size_t SurfaceParams::Hash() const {
std::map<u64, std::pair<u32, u32>> 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<std::size_t>(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<u32>(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<std::size_t>( return static_cast<std::size_t>(
Common::CityHash64(reinterpret_cast<const char*>(this), sizeof(*this))); Common::CityHash64(reinterpret_cast<const char*>(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, return std::tie(is_tiled, block_width, block_height, block_depth, tile_width_spacing, width,
height, depth, pitch, unaligned_height, num_levels, pixel_format, height, depth, pitch, unaligned_height, num_levels, pixel_format,
component_type, type, target) == component_type, type, target) ==
@ -409,4 +326,27 @@ bool HasheableSurfaceParams::operator==(const HasheableSurfaceParams& rhs) const
rhs.type, rhs.target); 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<u32>(target));
UNREACHABLE();
return fmt::format("TUK({})", static_cast<u32>(target));
}
}
} // namespace VideoCommon } // namespace VideoCommon

View File

@ -6,50 +6,21 @@
#include <map> #include <map>
#include "common/alignment.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/engines/fermi_2d.h" #include "video_core/engines/fermi_2d.h"
#include "video_core/engines/maxwell_3d.h" #include "video_core/engines/maxwell_3d.h"
#include "video_core/surface.h" #include "video_core/surface.h"
#include "video_core/shader/shader_ir.h"
namespace VideoCommon { namespace VideoCommon {
class HasheableSurfaceParams { class SurfaceParams {
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 {
public: public:
/// Creates SurfaceCachedParams from a texture configuration. /// Creates SurfaceCachedParams from a texture configuration.
static SurfaceParams CreateForTexture(Core::System& system, 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. /// Creates SurfaceCachedParams for a depth buffer configuration.
static SurfaceParams CreateForDepthBuffer( static SurfaceParams CreateForDepthBuffer(
@ -64,68 +35,33 @@ public:
static SurfaceParams CreateForFermiCopySurface( static SurfaceParams CreateForFermiCopySurface(
const Tegra::Engines::Fermi2D::Regs::Surface& config); const Tegra::Engines::Fermi2D::Regs::Surface& config);
bool IsTiled() const { std::size_t Hash() const;
return is_tiled;
}
bool GetSrgbConversion() const { bool operator==(const SurfaceParams& rhs) const;
return srgb_conversion;
}
u32 GetBlockWidth() const { bool operator!=(const SurfaceParams& rhs) const {
return block_width; return !operator==(rhs);
}
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;
}
VideoCore::Surface::SurfaceTarget GetTarget() const {
return target;
}
VideoCore::Surface::SurfaceType GetType() const {
return type;
} }
std::size_t GetGuestSizeInBytes() const { std::size_t GetGuestSizeInBytes() const {
return guest_size_in_bytes; return GetInnerMemorySize(false, false, false);
} }
std::size_t GetHostSizeInBytes() const { 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<std::size_t>(Common::AlignUp(width, GetDefaultBlockWidth())) *
static_cast<std::size_t>(Common::AlignUp(height, GetDefaultBlockHeight())) *
static_cast<std::size_t>(depth) * 4ULL;
} else {
host_size_in_bytes = GetInnerMemorySize(true, false, false);
}
return host_size_in_bytes; return host_size_in_bytes;
} }
u32 GetNumLayers() const { u32 GetBlockAlignedWidth() const {
return num_layers; return Common::AlignUp(width, 64 / GetBytesPerPixel());
} }
/// Returns the width of a given mipmap level. /// Returns the width of a given mipmap level.
@ -137,9 +73,6 @@ public:
/// Returns the depth of a given mipmap level. /// Returns the depth of a given mipmap level.
u32 GetMipDepth(u32 level) const; 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. /// Returns the block height of a given mipmap level.
u32 GetMipBlockHeight(u32 level) const; u32 GetMipBlockHeight(u32 level) const;
@ -152,6 +85,9 @@ public:
/// Returns the offset in bytes in host memory (linear) of a given mipmap level. /// Returns the offset in bytes in host memory (linear) of a given mipmap level.
std::size_t GetHostMipmapLevelOffset(u32 level) const; 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. /// 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;
@ -173,24 +109,30 @@ public:
/// Returns the bytes per pixel. /// Returns the bytes per pixel.
u32 GetBytesPerPixel() const; 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. /// Returns true if the pixel format is a depth and/or stencil format.
bool IsPixelFormatZeta() const; bool IsPixelFormatZeta() const;
/// Creates a map that redirects an address difference to a layer and mipmap level. std::string TargetName() const;
std::map<u64, std::pair<u32, u32>> CreateViewOffsetMap() const;
/// Returns true if the passed surface view parameters is equal or a valid subset of this. bool is_tiled;
bool IsViewValid(const SurfaceParams& view_params, u32 layer, u32 level) const; 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: private:
/// Calculates values that can be deduced from HasheableSurfaceParams.
void CalculateCachedValues();
/// Returns the size of a given mipmap level inside a layer. /// Returns the size of a given mipmap level inside a layer.
std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const; std::size_t GetInnerMipmapMemorySize(u32 level, bool as_host_size, bool uncompressed) const;
@ -200,19 +142,12 @@ private:
/// Returns the size of a layer /// Returns the size of a layer
std::size_t GetLayerSize(bool as_host_size, bool uncompressed) const; 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 std::size_t GetNumLayers() const {
/// mipmap level. return is_layered ? depth : 1;
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. /// Returns true if these parameters are from a layered surface.
bool IsDepthValid(const SurfaceParams& view_params, u32 level) const; bool IsLayered() 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 guest_size_in_bytes;
std::size_t host_size_in_bytes;
u32 num_layers;
}; };
} // namespace VideoCommon } // namespace VideoCommon

View File

@ -9,15 +9,15 @@
namespace VideoCommon { namespace VideoCommon {
std::size_t ViewKey::Hash() const { std::size_t ViewParams::Hash() const {
return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^ return static_cast<std::size_t>(base_layer) ^ static_cast<std::size_t>(num_layers << 16) ^
(static_cast<std::size_t>(base_level) << 32) ^ (static_cast<std::size_t>(base_level) << 24) ^
(static_cast<std::size_t>(num_levels) << 48); (static_cast<std::size_t>(num_levels) << 32) ^ (static_cast<std::size_t>(target) << 36);
} }
bool ViewKey::operator==(const ViewKey& rhs) const { bool ViewParams::operator==(const ViewParams& rhs) const {
return std::tie(base_layer, num_layers, base_level, num_levels) == 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); std::tie(rhs.base_layer, rhs.num_layers, rhs.base_level, rhs.num_levels, rhs.target);
} }
} // namespace VideoCommon } // namespace VideoCommon

View File

@ -7,18 +7,45 @@
#include <functional> #include <functional>
#include "common/common_types.h" #include "common/common_types.h"
#include "video_core/surface.h"
#include "video_core/texture_cache/surface_params.h"
namespace VideoCommon { namespace VideoCommon {
struct ViewKey { struct ViewParams {
std::size_t Hash() const; std::size_t Hash() const;
bool operator==(const ViewKey& rhs) const; bool operator==(const ViewParams& rhs) const;
u32 base_layer{}; u32 base_layer{};
u32 num_layers{}; u32 num_layers{};
u32 base_level{}; u32 base_level{};
u32 num_levels{}; 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 } // namespace VideoCommon
@ -26,8 +53,8 @@ struct ViewKey {
namespace std { namespace std {
template <> template <>
struct hash<VideoCommon::ViewKey> { struct hash<VideoCommon::ViewParams> {
std::size_t operator()(const VideoCommon::ViewKey& k) const noexcept { std::size_t operator()(const VideoCommon::ViewParams& k) const noexcept {
return k.Hash(); return k.Hash();
} }
}; };