Correct Surface Base and Views for new Texture Cache
This commit is contained in:
parent
3b26206dbd
commit
3d471e732d
|
@ -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
|
|
@ -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()};
|
||||||
|
|
|
@ -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())};
|
void MarkAsProtected(const bool is_protected) {
|
||||||
const auto it{view_offset_map.find(relative_offset)};
|
this->is_protected = is_protected;
|
||||||
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 MarkAsPicked(const bool is_picked) {
|
||||||
}
|
this->is_picked = is_picked;
|
||||||
|
|
||||||
void MarkAsModified(bool is_modified_) {
|
|
||||||
is_modified = is_modified_;
|
|
||||||
if (is_modified_) {
|
|
||||||
modification_tick = texture_cache.Tick();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
TView* GetView(GPUVAddr view_addr, const SurfaceParams& view_params) {
|
|
||||||
TView* view{TryGetView(view_addr, view_params)};
|
|
||||||
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{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
Reference in New Issue