From a49b5d46e7fb7c949041a6a64d4d9fd44b92e316 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Sun, 22 Mar 2026 13:01:08 +0100 Subject: [PATCH 01/17] common: rework small cache & add texture cache API --- src/common/small_cache.hpp | 88 +++++--- src/core/c_api.cpp | 132 ++++++++++++ src/core/c_api.h | 188 ++++++++++++++++++ .../tegra_x1/gpu/renderer/texture_cache.cpp | 48 ++--- .../tegra_x1/gpu/renderer/texture_cache.hpp | 31 ++- 5 files changed, 431 insertions(+), 56 deletions(-) diff --git a/src/common/small_cache.hpp b/src/common/small_cache.hpp index c1a59eb6..ab5e7150 100644 --- a/src/common/small_cache.hpp +++ b/src/common/small_cache.hpp @@ -1,5 +1,6 @@ #pragma once +#include #include #include @@ -20,32 +21,46 @@ class SmallCache { public: using map_iter = typename std::map::iterator; + using iterator_category = std::forward_iterator_tag; + using value_type = std::pair; + using difference_type = std::ptrdiff_t; + using pointer = value_type*; + using reference = value_type&; + iterator(SmallCache* cache_, usize fast_index_) : cache{cache_}, fast_index{fast_index_} { - advance_fast(); + AdvanceFast(); } iterator(SmallCache* cache, map_iter slow_it) - : cache(cache), fast_index(fast_cache_size), slow_it(slow_it) {} + : cache{cache}, fast_index{fast_cache_size}, slow_it{slow_it} {} - std::pair operator*() const { - if (fast_index < fast_cache_size) { - auto& e = cache->fast_cache[fast_index]; - return {e.key, e.value}; - } - return {slow_it->first, slow_it->second}; + reference operator*() const { + if (fast_index < fast_cache_size) + return cache->fast_cache[fast_index].value(); + + return *slow_it; } + pointer operator->() const { return &(**this); } + iterator& operator++() { if (fast_index < fast_cache_size) { ++fast_index; - advance_fast(); + AdvanceFast(); } else { ++slow_it; } + return *this; } + iterator operator++(int) { + iterator tmp = *this; + ++(*this); + return tmp; + } + bool operator==(const iterator& other) const { return cache == other.cache && fast_index == other.fast_index && (fast_index < fast_cache_size || slow_it == other.slow_it); @@ -56,9 +71,9 @@ class SmallCache { } private: - void advance_fast() { + void AdvanceFast() { while (fast_index < fast_cache_size && - !cache->fast_cache[fast_index].occupied) { + !cache->fast_cache[fast_index].has_value()) { ++fast_index; } @@ -72,9 +87,29 @@ class SmallCache { map_iter slow_it; }; + SmallCache() = default; + + SmallCache(const SmallCache&) = delete; + SmallCache& operator=(const SmallCache&) = delete; + + SmallCache(SmallCache&&) = default; + SmallCache& operator=(SmallCache&&) = default; + + // TODO: const versions as well iterator begin() { return iterator(this, 0); } iterator end() { return iterator(this, slow_cache.end()); } + // Functions + usize GetCount() const { + usize count = 0; + for (auto& entry : fast_cache) { + if (entry.has_value()) + count++; + } + + return count + slow_cache.size(); + } + void Clear() { fast_cache.fill({}); slow_cache.clear(); @@ -84,23 +119,26 @@ class SmallCache { AlreadyPresent, }; - T& Add(KeyT key, const T& value = {}) { + template + T& Add(KeyT key, Args&&... args) { // Insert into fast cache if possible for (auto& entry : fast_cache) { - if (!entry.occupied) { - entry.occupied = true; - entry.key = key; - entry.value = value; - return entry.value; + if (!entry.has_value()) { + entry.emplace( + std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); + return entry.value().second; } else { - ASSERT_THROWING(entry.key != key, Common, + ASSERT_THROWING(entry.value().first != key, Common, AddError::AlreadyPresent, "Entry already present"); } } // Fallback to slow cache - auto res = slow_cache.emplace(key, value); + auto res = slow_cache.emplace( + std::piecewise_construct, std::forward_as_tuple(key), + std::forward_as_tuple(std::forward(args)...)); ASSERT_THROWING(res.second, Common, AddError::AlreadyPresent, "Entry already present"); return res.first->second; @@ -109,7 +147,7 @@ class SmallCache { iterator Remove(iterator it) { // Fast cache if (it.fast_index < fast_cache_size) { - fast_cache[it.fast_index].occupied = false; + fast_cache[it.fast_index] = std::nullopt; // Advance to the next element iterator next = it; @@ -132,7 +170,7 @@ class SmallCache { iterator FindIter(KeyT key) { // Fast cache for (u32 i = 0; i < fast_cache_size; i++) { - if (fast_cache[i].occupied && fast_cache[i].key == key) + if (fast_cache[i].has_value() && fast_cache[i].value().first == key) return iterator(this, i); } @@ -150,7 +188,7 @@ class SmallCache { if (it == end()) return std::nullopt; - return &(*it).second; + return &it->second; } T& FindOrAdd(KeyT key) { @@ -162,11 +200,7 @@ class SmallCache { } private: - struct FastCacheEntry { - bool occupied{false}; - KeyT key; - T value; - }; + using FastCacheEntry = std::optional>; std::array fast_cache; std::map slow_cache; diff --git a/src/core/c_api.cpp b/src/core/c_api.cpp index ec155d8e..2e20ac19 100644 --- a/src/core/c_api.cpp +++ b/src/core/c_api.cpp @@ -8,6 +8,8 @@ #include "core/horizon/loader/nca_loader.hpp" #include "core/horizon/loader/plugins/manager.hpp" #include "core/horizon/ui/handler_base.hpp" +#include "core/hw/tegra_x1/gpu/gpu.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" #include #define HYDRA_EXPORT extern "C" __attribute__((visibility("default"))) @@ -990,3 +992,133 @@ HYDRA_EXPORT uint64_t hydra_debugger_resolved_stack_frame_get_address( resolved_stack_frame) ->addr; } + +// Texture cache + +// Texture cache +HYDRA_EXPORT void hydra_texture_cache_lock() { + hydra::RENDERER_INSTANCE.GetTextureCache().GetMutex().lock(); +} + +HYDRA_EXPORT void hydra_texture_cache_unlock() { + hydra::RENDERER_INSTANCE.GetTextureCache().GetMutex().unlock(); +} + +HYDRA_EXPORT uint32_t hydra_texture_cache_get_texture_memory_count() { + // HACK + return static_cast( + hydra::RENDERER_INSTANCE.GetTextureCache().GetMemoryCount()); +} + +HYDRA_EXPORT const void* +hydra_texture_cache_get_texture_memory(uint32_t index) { + return &hydra::RENDERER_INSTANCE.GetTextureCache().GetMemory(index); +} + +// Texture memory +HYDRA_EXPORT uint32_t +hydra_texture_memory_get_sparse_texture_count(const void* mem) { + // HACK + return static_cast( + static_cast(mem) + ->GetSparseTextureCount()); +} + +HYDRA_EXPORT const void* +hydra_texture_memory_get_sparse_texture(const void* mem, uint32_t index) { + return &static_cast( + mem) + ->GetSparseTexture(index); +} + +// Sparse texture +HYDRA_EXPORT uint32_t +hydra_sparse_texture_get_texture_group_count(const void* sparse_tex) { + // HACK + return static_cast( + static_cast( + sparse_tex) + ->GetGroupCount()); +} + +HYDRA_EXPORT const void* +hydra_sparse_texture_get_texture_group(const void* sparse_tex, uint32_t index) { + return &static_cast< + const hydra::hw::tegra_x1::gpu::renderer::SparseTexture*>( + sparse_tex) + ->GetGroup(index); +} + +// Texture group +HYDRA_EXPORT const void* +hydra_texture_group_get_texture_descriptor(const void* group) { + return &static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureGroup*>(group) + ->base->GetDescriptor(); +} + +// Texture descriptor +HYDRA_EXPORT uint64_t hydra_texture_descriptor_get_ptr(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->ptr; +} + +HYDRA_EXPORT HydraTextureType +hydra_texture_descriptor_get_type(const void* descriptor) { + return static_cast( + static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->type); +} + +HYDRA_EXPORT HydraTextureFormat +hydra_texture_descriptor_get_format(const void* descriptor) { + return static_cast( + static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->format); +} + +HYDRA_EXPORT uint32_t +hydra_texture_descriptor_get_width(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->width; +} + +HYDRA_EXPORT uint32_t +hydra_texture_descriptor_get_height(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->height; +} + +HYDRA_EXPORT uint32_t +hydra_texture_descriptor_get_depth(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->depth; +} + +HYDRA_EXPORT uint64_t +hydra_texture_descriptor_get_layer_size(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->GetLayerSizeInBytes(); +} + +HYDRA_EXPORT uint64_t +hydra_texture_descriptor_get_size(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->GetSizeInBytes(); +} diff --git a/src/core/c_api.h b/src/core/c_api.h index 852473c6..7146e988 100644 --- a/src/core/c_api.h +++ b/src/core/c_api.h @@ -383,6 +383,194 @@ hydra_string hydra_debugger_resolved_stack_frame_get_function( uint64_t hydra_debugger_resolved_stack_frame_get_address( const void* resolved_stack_frame); +// Texture cache + +// Texture cache +void hydra_texture_cache_lock(); +void hydra_texture_cache_unlock(); +uint32_t hydra_texture_cache_get_texture_memory_count(); +const void* hydra_texture_cache_get_texture_memory(uint32_t index); + +// Texture memory +uint32_t hydra_texture_memory_get_sparse_texture_count(const void* mem); +const void* hydra_texture_memory_get_sparse_texture(const void* mem, + uint32_t index); + +// Sparse texture +uint32_t hydra_sparse_texture_get_texture_group_count(const void* sparse_tex); +const void* hydra_sparse_texture_get_texture_group(const void* sparse_tex, + uint32_t index); + +// Texture group +const void* hydra_texture_group_get_texture_descriptor(const void* group); + +// Texture descriptor +typedef enum HydraTextureType : uint32_t { + HYDRA_TEXTURE_TYPE_1D = 0, + HYDRA_TEXTURE_TYPE_1D_ARRAY, + HYDRA_TEXTURE_TYPE_1D_BUFFER, + HYDRA_TEXTURE_TYPE_2D, + HYDRA_TEXTURE_TYPE_2D_ARRAY, + HYDRA_TEXTURE_TYPE_3D, + HYDRA_TEXTURE_TYPE_CUBE, + HYDRA_TEXTURE_TYPE_CUBE_ARRAY, +} HydraTextureType; + +typedef enum HydraTextureFormat : uint32_t { + HYDRA_TEXTURE_FORMAT_INVALID = 0, + + HYDRA_TEXTURE_FORMAT_R8_UNORM, + HYDRA_TEXTURE_FORMAT_R8_SNORM, + HYDRA_TEXTURE_FORMAT_R8_UINT, + HYDRA_TEXTURE_FORMAT_R8_SINT, + HYDRA_TEXTURE_FORMAT_R16_FLOAT, + HYDRA_TEXTURE_FORMAT_R16_UNORM, + HYDRA_TEXTURE_FORMAT_R16_SNORM, + HYDRA_TEXTURE_FORMAT_R16_UINT, + HYDRA_TEXTURE_FORMAT_R16_SINT, + HYDRA_TEXTURE_FORMAT_R32_FLOAT, + HYDRA_TEXTURE_FORMAT_R32_UINT, + HYDRA_TEXTURE_FORMAT_R32_SINT, + + HYDRA_TEXTURE_FORMAT_RG8_UNORM, + HYDRA_TEXTURE_FORMAT_RG8_SNORM, + HYDRA_TEXTURE_FORMAT_RG8_UINT, + HYDRA_TEXTURE_FORMAT_RG8_SINT, + HYDRA_TEXTURE_FORMAT_RG16_FLOAT, + HYDRA_TEXTURE_FORMAT_RG16_UNORM, + HYDRA_TEXTURE_FORMAT_RG16_SNORM, + HYDRA_TEXTURE_FORMAT_RG16_UINT, + HYDRA_TEXTURE_FORMAT_RG16_SINT, + HYDRA_TEXTURE_FORMAT_RG32_FLOAT, + HYDRA_TEXTURE_FORMAT_RG32_UINT, + HYDRA_TEXTURE_FORMAT_RG32_SINT, + + HYDRA_TEXTURE_FORMAT_RGB32_FLOAT, + HYDRA_TEXTURE_FORMAT_RGB32_UINT, + HYDRA_TEXTURE_FORMAT_RGB32_SINT, + + HYDRA_TEXTURE_FORMAT_RGBA8_UNORM, + HYDRA_TEXTURE_FORMAT_RGBA8_SNORM, + HYDRA_TEXTURE_FORMAT_RGBA8_UINT, + HYDRA_TEXTURE_FORMAT_RGBA8_SINT, + HYDRA_TEXTURE_FORMAT_RGBA16_FLOAT, + HYDRA_TEXTURE_FORMAT_RGBA16_UNORM, + HYDRA_TEXTURE_FORMAT_RGBA16_SNORM, + HYDRA_TEXTURE_FORMAT_RGBA16_UINT, + HYDRA_TEXTURE_FORMAT_RGBA16_SINT, + HYDRA_TEXTURE_FORMAT_RGBA32_FLOAT, + HYDRA_TEXTURE_FORMAT_RGBA32_UINT, + HYDRA_TEXTURE_FORMAT_RGBA32_SINT, + + HYDRA_TEXTURE_FORMAT_S8_UINT, + HYDRA_TEXTURE_FORMAT_Z16_UNORM, + HYDRA_TEXTURE_FORMAT_Z24_UNORM_X8_UINT, + HYDRA_TEXTURE_FORMAT_Z32_FLOAT, + HYDRA_TEXTURE_FORMAT_Z24_UNORM_S8_UINT, + HYDRA_TEXTURE_FORMAT_Z32_FLOAT_X24_S8_UINT, + + HYDRA_TEXTURE_FORMAT_RGBX8_UNORM_SRGB, + HYDRA_TEXTURE_FORMAT_RGBA8_UNORM_SRGB, + + HYDRA_TEXTURE_FORMAT_RGBA4_UNORM, + HYDRA_TEXTURE_FORMAT_RGB5_UNORM, + HYDRA_TEXTURE_FORMAT_RGB5A1_UNORM, + HYDRA_TEXTURE_FORMAT_R5G6B5_UNORM, + HYDRA_TEXTURE_FORMAT_RGB10A2_UNORM, + HYDRA_TEXTURE_FORMAT_RGB10A2_UINT, + HYDRA_TEXTURE_FORMAT_RG11B10_FLOAT, + HYDRA_TEXTURE_FORMAT_E5BGR9_FLOAT, + + HYDRA_TEXTURE_FORMAT_BC1_RGB, + HYDRA_TEXTURE_FORMAT_BC1_RGBA, + HYDRA_TEXTURE_FORMAT_BC2_RGBA, + HYDRA_TEXTURE_FORMAT_BC3_RGBA, + HYDRA_TEXTURE_FORMAT_BC1_RGB_SRGB, + HYDRA_TEXTURE_FORMAT_BC1_RGBA_SRGB, + HYDRA_TEXTURE_FORMAT_BC2_RGBA_SRGB, + HYDRA_TEXTURE_FORMAT_BC3_RGBA_SRGB, + HYDRA_TEXTURE_FORMAT_BC4_R_UNORM, + HYDRA_TEXTURE_FORMAT_BC4_R_SNORM, + HYDRA_TEXTURE_FORMAT_BC5_RG_UNORM, + HYDRA_TEXTURE_FORMAT_BC5_RG_SNORM, + HYDRA_TEXTURE_FORMAT_BC7_RGBA_UNORM, + HYDRA_TEXTURE_FORMAT_BC7_RGBA_UNORM_SRGB, + HYDRA_TEXTURE_FORMAT_BC6H_RGBA_SF16_FLOAT, + HYDRA_TEXTURE_FORMAT_BC6H_RGBA_UF16_FLOAT, + + HYDRA_TEXTURE_FORMAT_RGBX8_UNORM, + HYDRA_TEXTURE_FORMAT_RGBX8_SNORM, + HYDRA_TEXTURE_FORMAT_RGBX8_UINT, + HYDRA_TEXTURE_FORMAT_RGBX8_SINT, + HYDRA_TEXTURE_FORMAT_RGBX16_FLOAT, + HYDRA_TEXTURE_FORMAT_RGBX16_UNORM, + HYDRA_TEXTURE_FORMAT_RGBX16_SNORM, + HYDRA_TEXTURE_FORMAT_RGBX16_UINT, + HYDRA_TEXTURE_FORMAT_RGBX16_SINT, + HYDRA_TEXTURE_FORMAT_RGBX32_FLOAT, + HYDRA_TEXTURE_FORMAT_RGBX32_UINT, + HYDRA_TEXTURE_FORMAT_RGBX32_SINT, + + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_4X4, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X4, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X5, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X5, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X6, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X5, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X6, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X8, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X5, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X6, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X8, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X10, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X10, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X12, + + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_4X4_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X4_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X5_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X5_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X6_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X5_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X6_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X8_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X5_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X6_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X8_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X10_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X10_SRGB, + HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X12_SRGB, + + HYDRA_TEXTURE_FORMAT_B5G6R5_UNORM, + HYDRA_TEXTURE_FORMAT_BGR5_UNORM, + HYDRA_TEXTURE_FORMAT_BGR5A1_UNORM, + HYDRA_TEXTURE_FORMAT_A1BGR5_UNORM, + HYDRA_TEXTURE_FORMAT_BGRX8_UNORM, + HYDRA_TEXTURE_FORMAT_BGRA8_UNORM, + HYDRA_TEXTURE_FORMAT_BGRX8_UNORM_SRGB, + HYDRA_TEXTURE_FORMAT_BGRA8_UNORM_SRGB, + + HYDRA_TEXTURE_FORMAT_ETC2_R_UNORM, + HYDRA_TEXTURE_FORMAT_ETC2_R_SNORM, + HYDRA_TEXTURE_FORMAT_ETC2_RG_UNORM, + HYDRA_TEXTURE_FORMAT_ETC2_RG_SNORM, + HYDRA_TEXTURE_FORMAT_ETC2_RGB, + HYDRA_TEXTURE_FORMAT_PTA_ETC2_RGB, + HYDRA_TEXTURE_FORMAT_ETC2_RGBA, + HYDRA_TEXTURE_FORMAT_ETC2_RGB_SRGB, + HYDRA_TEXTURE_FORMAT_PTA_ETC2_RGB_SRGB, + HYDRA_TEXTURE_FORMAT_ETC2_RGBA_SRGB, +} HydraTextureFormat; + +uint64_t hydra_texture_descriptor_get_ptr(const void* descriptor); +HydraTextureType hydra_texture_descriptor_get_type(const void* descriptor); +HydraTextureFormat hydra_texture_descriptor_get_format(const void* descriptor); +uint32_t hydra_texture_descriptor_get_width(const void* descriptor); +uint32_t hydra_texture_descriptor_get_height(const void* descriptor); +uint32_t hydra_texture_descriptor_get_depth(const void* descriptor); +uint64_t hydra_texture_descriptor_get_layer_size(const void* descriptor); +uint64_t hydra_texture_descriptor_get_size(const void* descriptor); + #ifdef __cplusplus } #endif diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index cf68f8cd..604839d9 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -9,10 +9,10 @@ namespace hydra::hw::tegra_x1::gpu::renderer { TextureCache::~TextureCache() { for (auto& [key, mem] : entries) { - for (const auto& [key, sparse_tex] : mem.cache) { - for (const auto& [key, group] : sparse_tex.cache) { + for (auto& [key, sparse_tex] : mem.cache) { + for (auto& [key, group] : sparse_tex.cache) { delete group.base; - for (const auto& [key, view] : group.view_cache) + for (auto& [key, view] : group.view_cache) delete view; } } @@ -43,22 +43,22 @@ TextureBase* TextureCache::Find(ICommandBuffer* command_buffer, // Merge with previous if overlapping if (it != entries.begin()) { auto prev = std::prev(it); - const auto& prev_mem = prev->second; + auto& prev_mem = prev->second; if (prev_mem.range.GetEnd() > mem.range.GetBegin()) { - mem = MergeMemories(mem, prev_mem); + MergeMemories(mem, prev_mem); it = entries.erase(prev); } } // Merge with following entries while (it != entries.end() && it->first < mem.range.GetEnd()) { - const auto& crnt_mem = it->second; - mem = MergeMemories(mem, crnt_mem); + auto& crnt_mem = it->second; + MergeMemories(mem, crnt_mem); it = entries.erase(it); } // Insert merged interval - auto inserted = entries.emplace(mem.range.GetBegin(), mem); + auto inserted = entries.emplace(mem.range.GetBegin(), std::move(mem)); return AddToMemory(command_buffer, inserted.first->second, descriptor, usage); } @@ -82,27 +82,19 @@ void TextureCache::InvalidateMemory(Range range) { } } -TextureMem TextureCache::MergeMemories(const TextureMem& a, - const TextureMem& b) { - TextureMem res; - res.range = a.range.Union(b.range); - res.info = { - .modified_timestamp = - std::max(a.info.modified_timestamp, b.info.modified_timestamp), +void TextureCache::MergeMemories(TextureMem& mem, TextureMem& other) { + mem.range = mem.range.Union(other.range); + mem.info = { + .modified_timestamp = std::max(mem.info.modified_timestamp, + other.info.modified_timestamp), .read_timestamp = - std::max(a.info.read_timestamp, b.info.read_timestamp), + std::max(mem.info.read_timestamp, other.info.read_timestamp), .written_timestamp = - std::max(a.info.written_timestamp, b.info.written_timestamp), + std::max(mem.info.written_timestamp, other.info.written_timestamp), }; - // HACK - for (const auto& [key, tex] : const_cast(a).cache) - res.cache.Add(key, tex); - - for (const auto& [key, tex] : const_cast(b).cache) - res.cache.Add(key, tex); - - return res; + for (auto& [key, tex] : other.cache) + mem.cache.Add(key, std::move(tex)); } TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, @@ -133,7 +125,7 @@ TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, } // Check if it is a proper layer view - for (const auto& [key, group] : sparse_tex.cache) { + for (auto& [key, group] : sparse_tex.cache) { if (group.base->GetDescriptor().GetRange().Contains(range)) { const auto offset = static_cast( range.GetBegin() - group.base->GetDescriptor().ptr); @@ -283,10 +275,10 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, const auto& descriptor = base->GetDescriptor(); const auto range = descriptor.GetRange(); const auto layer_size = descriptor.GetLayerSizeInBytes(); - for (const auto& [key, sparse_tex] : mem.cache) { + for (auto& [key, sparse_tex] : mem.cache) { // TODO: skip this sparse texture - for (const auto& [key, other_group] : sparse_tex.cache) { + for (auto& [key, other_group] : sparse_tex.cache) { const auto other_base = other_group.base; const auto& other_descriptor = other_base->GetDescriptor(); const auto other_range = other_descriptor.GetRange(); diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp index 3d079ab3..ced74f7f 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp @@ -24,6 +24,16 @@ struct TextureGroup { struct SparseTexture { SmallCache cache; + + // Debug + usize GetGroupCount() const { return cache.GetCount(); } + + const TextureGroup& GetGroup(u32 index) const { + // HACK: const cast + auto it = const_cast&>(cache).begin(); + std::advance(it, index); + return it->second; + } }; struct TextureMemInfo { @@ -40,6 +50,16 @@ struct TextureMem { Range range; TextureMemInfo info; SmallCache cache; + + // Debug + usize GetSparseTextureCount() const { return cache.GetCount(); } + + const SparseTexture& GetSparseTexture(u32 index) const { + // HACK: const cast + auto it = const_cast&>(cache).begin(); + std::advance(it, index); + return it->second; + } }; // TODO: destroy textures @@ -53,13 +73,22 @@ class TextureCache { void InvalidateMemory(Range range); + // Debug + usize GetMemoryCount() const { return entries.size(); } + + const TextureMem& GetMemory(u32 index) const { + auto it = entries.begin(); + std::advance(it, index); + return it->second; + } + private: std::mutex mutex; TextureDecoder texture_decoder; std::map entries; - TextureMem MergeMemories(const TextureMem& a, const TextureMem& b); + void MergeMemories(TextureMem& mem, TextureMem& other); TextureBase* AddToMemory(ICommandBuffer* command_buffer, TextureMem& mem, const TextureDescriptor& descriptor, TextureUsage usage); From 50ec03b175e6a0283883accc37dd58f7581edb7d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Tue, 24 Mar 2026 16:05:49 +0100 Subject: [PATCH 02/17] swiftui: basic texture viewer --- src/frontend/CMakeLists.txt | 3 + src/frontend/swiftui/Api.swift | 407 +++++++++--------- src/frontend/swiftui/HydraApp.swift | 7 +- .../texture_viewer/TextureListView.swift | 59 +++ .../swiftui/texture_viewer/TextureView.swift | 35 ++ .../texture_viewer/TextureViewer.swift | 8 + 6 files changed, 310 insertions(+), 209 deletions(-) create mode 100644 src/frontend/swiftui/texture_viewer/TextureListView.swift create mode 100644 src/frontend/swiftui/texture_viewer/TextureView.swift create mode 100644 src/frontend/swiftui/texture_viewer/TextureViewer.swift diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt index 414f8b89..fb742aed 100644 --- a/src/frontend/CMakeLists.txt +++ b/src/frontend/CMakeLists.txt @@ -77,6 +77,9 @@ elseif (FRONTEND STREQUAL "SwiftUI") swiftui/debugger/DebuggerView.swift swiftui/debugger/DebuggerListView.swift swiftui/debugger/DebuggersView.swift + swiftui/texture_viewer/TextureViewer.swift + swiftui/texture_viewer/TextureListView.swift + swiftui/texture_viewer/TextureView.swift ) if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") diff --git a/src/frontend/swiftui/Api.swift b/src/frontend/swiftui/Api.swift index 4042b542..d62a2523 100644 --- a/src/frontend/swiftui/Api.swift +++ b/src/frontend/swiftui/Api.swift @@ -1,5 +1,73 @@ import SwiftUI +protocol HandleStruct: Identifiable, Hashable { + var handle: UnsafeRawPointer { get } +} + +extension HandleStruct { + var id: UnsafeRawPointer { handle } + + func hash(into hasher: inout Hasher) { + hasher.combine(handle) + } + + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.handle == rhs.handle + } +} + +protocol MutableHandleStruct: Identifiable, Hashable { + var handle: UnsafeMutableRawPointer { get } +} + +extension MutableHandleStruct { + var id: UnsafeMutableRawPointer { handle } + + func hash(into hasher: inout Hasher) { + hasher.combine(handle) + } + + static func == (lhs: Self, rhs: Self) -> Bool { + lhs.handle == rhs.handle + } +} + +class HandleClass: Identifiable, Hashable { + fileprivate var handle: UnsafeRawPointer + + fileprivate init(handle: UnsafeRawPointer) { + self.handle = handle + } + + static func == (lhs: HandleClass, rhs: HandleClass) + -> Bool + { + lhs.handle == rhs.handle + } + + func hash(into hasher: inout Hasher) { + hasher.combine(self.handle) + } +} + +class MutableHandleClass: Identifiable, Hashable { + fileprivate var handle: UnsafeMutableRawPointer + + fileprivate init(handle: UnsafeMutableRawPointer) { + self.handle = handle + } + + static func == (lhs: MutableHandleClass, rhs: MutableHandleClass) + -> Bool + { + lhs.handle == rhs.handle + } + + func hash(into hasher: inout Hasher) { + hasher.combine(self.handle) + } +} + // Types // TODO: avoid copying /* @@ -113,7 +181,7 @@ extension String { // String list struct HydraStringList { - private let handle: UnsafeMutableRawPointer + internal let handle: UnsafeMutableRawPointer fileprivate init(handle: UnsafeMutableRawPointer) { self.handle = handle @@ -155,7 +223,7 @@ struct HydraStringList { // String view list struct HydraStringViewList { - private let handle: UnsafeMutableRawPointer + internal let handle: UnsafeMutableRawPointer fileprivate init(handle: UnsafeMutableRawPointer) { self.handle = handle @@ -197,7 +265,7 @@ struct HydraStringViewList { // String to string map struct HydraStringToStringMap { - private let handle: UnsafeMutableRawPointer + internal let handle: UnsafeMutableRawPointer fileprivate init(handle: UnsafeMutableRawPointer) { self.handle = handle @@ -240,7 +308,7 @@ struct HydraStringToStringMap { // Loader plugin struct HydraLoaderPluginConfig { - private let handle: UnsafeMutableRawPointer + internal let handle: UnsafeMutableRawPointer fileprivate init(handle: UnsafeMutableRawPointer) { self.handle = handle @@ -265,7 +333,7 @@ struct HydraLoaderPluginConfig { } struct HydraLoaderPluginConfigList { - private let handle: UnsafeMutableRawPointer + internal let handle: UnsafeMutableRawPointer fileprivate init(handle: UnsafeMutableRawPointer) { self.handle = handle @@ -432,7 +500,7 @@ enum HydraPluginError: Error { } class HydraLoaderPlugin { - private let handle: UnsafeMutableRawPointer + internal let handle: UnsafeMutableRawPointer init(path: String) throws { guard @@ -479,27 +547,15 @@ class HydraLoaderPlugin { } } -class HydraLoaderPluginOptionConfig: Hashable, Identifiable { - private let handle: UnsafeMutableRawPointer - - fileprivate init(handle: UnsafeMutableRawPointer) { - self.handle = hydra_loader_plugin_option_config_copy(handle) +class HydraLoaderPluginOptionConfig: MutableHandleClass { + fileprivate override init(handle: UnsafeMutableRawPointer) { + super.init(handle: hydra_loader_plugin_option_config_copy(handle)) } deinit { hydra_loader_plugin_option_config_destroy(self.handle) } - static func == (lhs: HydraLoaderPluginOptionConfig, rhs: HydraLoaderPluginOptionConfig) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - var name: String { String(withHydraString: hydra_loader_plugin_option_config_get_name(self.handle)) } @@ -531,80 +587,44 @@ class HydraLoaderPluginOptionConfig: Hashable, Identifiable { } // Filesystem -class HydraFilesystem { - fileprivate let handle: UnsafeMutableRawPointer - +class HydraFilesystem: MutableHandleClass { init() { - self.handle = hydra_create_filesystem() + super.init(handle: hydra_create_filesystem()) } deinit { hydra_filesystem_destroy(self.handle) } - static func == (lhs: HydraFilesystem, rhs: HydraFilesystem) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - func tryInstallFirmware() { hydra_try_install_firmware_to_filesystem(self.handle) } } -class HydraFile: Hashable, Identifiable { - fileprivate let handle: UnsafeMutableRawPointer - +class HydraFile: MutableHandleClass { init(path: String) { - self.handle = path.withHydraString { hydraPath in + super.init(handle: path.withHydraString { hydraPath in hydra_open_file(hydraPath) - } + }) } deinit { hydra_file_close(self.handle) } - - static func == (lhs: HydraFile, rhs: HydraFile) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } } -class HydraContentArchive: Hashable, Identifiable { +class HydraContentArchive: MutableHandleClass { private let file: HydraFile // For ref counting - fileprivate let handle: UnsafeMutableRawPointer - init(file: HydraFile) { self.file = file - self.handle = hydra_create_content_archive(file.handle) + super.init(handle: hydra_create_content_archive(file.handle)) } deinit { hydra_content_archive_destroy(self.handle) } - static func == (lhs: HydraContentArchive, rhs: HydraContentArchive) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - var contentType: HydraContentArchiveContentType { hydra_content_archive_get_content_type(self.handle) } @@ -621,13 +641,7 @@ enum HydraLoaderContent { case romfs } -class HydraLoader: Hashable, Identifiable { - fileprivate let handle: UnsafeMutableRawPointer - - fileprivate init(handle: UnsafeMutableRawPointer) { - self.handle = handle - } - +class HydraLoader: MutableHandleClass { convenience init(path: String) throws { guard let handle = path.withHydraString({ hydraPath in @@ -643,16 +657,6 @@ class HydraLoader: Hashable, Identifiable { hydra_loader_destroy(self.handle) } - static func == (lhs: HydraLoader, rhs: HydraLoader) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - var titleId: UInt64 { hydra_loader_get_title_id(self.handle) } @@ -734,23 +738,13 @@ class HydraNcaLoader: HydraLoader { } } -class HydraNacp: Hashable, Identifiable { - private let handle: UnsafeMutableRawPointer +struct HydraNacp: MutableHandleStruct { + internal let handle: UnsafeMutableRawPointer - fileprivate init(handle: UnsafeMutableRawPointer) { + init(handle: UnsafeMutableRawPointer) { self.handle = handle } - static func == (lhs: HydraNacp, rhs: HydraNacp) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - var title: HydraNacpTitle { HydraNacpTitle(handle: hydra_nacp_get_title(self.handle)) } @@ -760,23 +754,13 @@ class HydraNacp: Hashable, Identifiable { } } -class HydraNacpTitle: Hashable, Identifiable { - private let handle: UnsafeRawPointer +struct HydraNacpTitle: HandleStruct { + internal let handle: UnsafeRawPointer - fileprivate init(handle: UnsafeRawPointer) { + init(handle: UnsafeRawPointer) { self.handle = handle } - static func == (lhs: HydraNacpTitle, rhs: HydraNacpTitle) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - var name: String { String(withHydraString: hydra_nacp_title_get_name(self.handle)) } @@ -787,27 +771,15 @@ class HydraNacpTitle: Hashable, Identifiable { } // User manager -class HydraUserManager: Hashable, Identifiable { - private let handle: UnsafeMutableRawPointer - +class HydraUserManager: MutableHandleClass { init() { - self.handle = hydra_create_user_manager() + super.init(handle: hydra_create_user_manager()) } deinit { hydra_user_manager_destroy(self.handle) } - static func == (lhs: HydraUserManager, rhs: HydraUserManager) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - func flush() { hydra_user_manager_flush(self.handle) } @@ -848,17 +820,13 @@ class HydraUserManager: Hashable, Identifiable { } } -struct HydraUser: Hashable, Identifiable { - private let handle: UnsafeMutableRawPointer +struct HydraUser: MutableHandleStruct { + internal let handle: UnsafeMutableRawPointer - fileprivate init(handle: UnsafeMutableRawPointer) { + init(handle: UnsafeMutableRawPointer) { self.handle = handle } - var id: UnsafeMutableRawPointer { - self.handle - } - var nickname: String { get { String(withHydraString: hydra_user_get_nickname(self.handle)) @@ -892,27 +860,15 @@ struct HydraUser: Hashable, Identifiable { } // Emulation context -class HydraEmulationContext: Hashable, Identifiable { - private let handle: UnsafeMutableRawPointer - +class HydraEmulationContext: MutableHandleClass { init() { - self.handle = hydra_create_emulation_context() + super.init(handle: hydra_create_emulation_context()) } deinit { hydra_emulation_context_destroy(self.handle) } - static func == (lhs: HydraEmulationContext, rhs: HydraEmulationContext) - -> Bool - { - lhs.handle == rhs.handle - } - - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) - } - var surface: UnsafeMutableRawPointer { get { // TODO: handle this properly @@ -990,17 +946,13 @@ func hydraDebuggerManagerGetDebuggerForCurrentProcess() -> HydraDebugger { HydraDebugger(handle: hydra_debugger_manager_get_debugger_for_process(nil)) } -struct HydraDebugger: Hashable, Identifiable { - private var handle: UnsafeMutableRawPointer +struct HydraDebugger: MutableHandleStruct { + internal let handle: UnsafeMutableRawPointer - fileprivate init(handle: UnsafeMutableRawPointer) { + init(handle: UnsafeMutableRawPointer) { self.handle = handle } - var id: UnsafeMutableRawPointer { - self.handle - } - var name: String { String(withHydraString: hydra_debugger_get_name(self.handle)) } @@ -1032,17 +984,13 @@ struct HydraDebugger: Hashable, Identifiable { } } -struct HydraDebuggerThread: Hashable, Identifiable { - private var handle: UnsafeMutableRawPointer +struct HydraDebuggerThread: MutableHandleStruct { + internal let handle: UnsafeMutableRawPointer - fileprivate init(handle: UnsafeMutableRawPointer) { + init(handle: UnsafeMutableRawPointer) { self.handle = handle } - var id: UnsafeMutableRawPointer { - self.handle - } - var name: String { String(withHydraString: hydra_debugger_thread_get_name(self.handle)) } @@ -1072,16 +1020,8 @@ struct HydraDebuggerThread: Hashable, Identifiable { } } -struct HydraDebuggerMessage: Hashable, Identifiable { - private var handle: UnsafeRawPointer - - fileprivate init(handle: UnsafeRawPointer) { - self.handle = handle - } - - var id: UnsafeRawPointer { - self.handle - } +struct HydraDebuggerMessage: HandleStruct { + internal let handle: UnsafeRawPointer var logLevel: HydraLogLevel { hydra_debugger_message_get_log_level(self.handle) @@ -1114,83 +1054,134 @@ struct HydraDebuggerMessage: Hashable, Identifiable { } } -class HydraDebuggerStackTrace: Hashable, Identifiable { - private var handle: UnsafeMutableRawPointer +class HydraDebuggerStackTrace: MutableHandleClass { + deinit { + hydra_debugger_stack_trace_destroy(self.handle) + } - fileprivate init(handle: UnsafeMutableRawPointer) { - self.handle = handle + var frameCount: Int { + Int(hydra_debugger_stack_trace_get_frame_count(self.handle)) + } + + func getFrame(at index: Int) -> HydraDebuggerStackFrame { + HydraDebuggerStackFrame( + handle: hydra_debugger_stack_trace_get_frame(self.handle, UInt32(index))) } +} + +struct HydraDebuggerStackFrame: HandleStruct { + internal let handle: UnsafeRawPointer + func resolve() -> HydraDebuggerResolvedStackFrame { + HydraDebuggerResolvedStackFrame(handle: hydra_debugger_stack_frame_resolve(self.handle)) + } +} + +class HydraDebuggerResolvedStackFrame: MutableHandleClass { deinit { - hydra_debugger_stack_trace_destroy(self.handle) + hydra_debugger_resolved_stack_frame_destroy(self.handle) } - static func == (lhs: HydraDebuggerStackTrace, rhs: HydraDebuggerStackTrace) - -> Bool - { - lhs.handle == rhs.handle + var module: String { + String(withHydraString: hydra_debugger_resolved_stack_frame_get_module(self.handle)) } - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) + var function: String { + String(withHydraString: hydra_debugger_resolved_stack_frame_get_function(self.handle)) } - var frameCount: Int { - Int(hydra_debugger_stack_trace_get_frame_count(self.handle)) + var address: UInt64 { + hydra_debugger_resolved_stack_frame_get_address(self.handle) } +} - func getFrame(at index: Int) -> HydraDebuggerStackFrame { - HydraDebuggerStackFrame( - handle: hydra_debugger_stack_trace_get_frame(self.handle, UInt32(index))) +// Texture cache + +// Texture cache +func hydraTextureCacheLock() { + hydra_texture_cache_lock() +} + +func hydraTextureCacheUnlock() { + hydra_texture_cache_unlock() +} + +func hydraTextureCacheGetTextureMemoryCount() -> Int { + Int(hydra_texture_cache_get_texture_memory_count()) +} + +func hydraTextureCacheGetTextureMemory(at index: Int) -> HydraTextureMemory { + HydraTextureMemory(handle: hydra_texture_cache_get_texture_memory(UInt32(index))) +} + +// Texture memory +struct HydraTextureMemory: HandleStruct { + internal let handle: UnsafeRawPointer + + var sparseTextureCount: Int { + Int(hydra_texture_memory_get_sparse_texture_count(self.handle)) + } + + func getSparseTexture(at index: Int) -> HydraSparseTexture { + HydraSparseTexture(handle: hydra_texture_memory_get_sparse_texture(self.handle, UInt32(index))) } } -struct HydraDebuggerStackFrame: Hashable, Identifiable { - private var handle: UnsafeRawPointer +// Sparse texture +struct HydraSparseTexture: HandleStruct { + internal let handle: UnsafeRawPointer - fileprivate init(handle: UnsafeRawPointer) { - self.handle = handle + var textureGroupCount: Int { + Int(hydra_sparse_texture_get_texture_group_count(self.handle)) } - var id: UnsafeRawPointer { - self.handle + func getTextureGroup(at index: Int) -> HydraTextureGroup { + HydraTextureGroup(handle: hydra_sparse_texture_get_texture_group(self.handle, UInt32(index))) } +} - func resolve() -> HydraDebuggerResolvedStackFrame { - HydraDebuggerResolvedStackFrame(handle: hydra_debugger_stack_frame_resolve(self.handle)) +// Texture group +struct HydraTextureGroup: HandleStruct { + internal let handle: UnsafeRawPointer + + var descriptor: HydraTextureDescriptor { + HydraTextureDescriptor(handle: hydra_texture_group_get_texture_descriptor(self.handle)) } } -class HydraDebuggerResolvedStackFrame: Hashable, Identifiable { - private var handle: UnsafeMutableRawPointer +// Texture descriptor +struct HydraTextureDescriptor: HandleStruct { + internal let handle: UnsafeRawPointer - fileprivate init(handle: UnsafeMutableRawPointer) { - self.handle = handle + var ptr: UInt64 { + hydra_texture_descriptor_get_ptr(self.handle) } - deinit { - hydra_debugger_resolved_stack_frame_destroy(self.handle) + var type: HydraTextureType { + hydra_texture_descriptor_get_type(self.handle) } - static func == (lhs: HydraDebuggerResolvedStackFrame, rhs: HydraDebuggerResolvedStackFrame) - -> Bool - { - lhs.handle == rhs.handle + var format: HydraTextureFormat { + hydra_texture_descriptor_get_format(self.handle) } - func hash(into hasher: inout Hasher) { - hasher.combine(self.handle) + var width: UInt32 { + hydra_texture_descriptor_get_width(self.handle) } - var module: String { - String(withHydraString: hydra_debugger_resolved_stack_frame_get_module(self.handle)) + var height: UInt32 { + hydra_texture_descriptor_get_height(self.handle) } - var function: String { - String(withHydraString: hydra_debugger_resolved_stack_frame_get_function(self.handle)) + var depth: UInt32 { + hydra_texture_descriptor_get_depth(self.handle) } - var address: UInt64 { - hydra_debugger_resolved_stack_frame_get_address(self.handle) + var layerSize: UInt64 { + hydra_texture_descriptor_get_layer_size(self.handle) + } + + var size: UInt64 { + hydra_texture_descriptor_get_size(self.handle) } } diff --git a/src/frontend/swiftui/HydraApp.swift b/src/frontend/swiftui/HydraApp.swift index 935fe056..634416f8 100644 --- a/src/frontend/swiftui/HydraApp.swift +++ b/src/frontend/swiftui/HydraApp.swift @@ -21,7 +21,7 @@ class GlobalState: ObservableObject { init() { hydraLoaderPluginManagerRefresh() isHandheldMode = hydraConfigGetHandheldMode().pointee - + let gamePathsOption = hydraConfigGetGamePaths() for i in 0.. Date: Sat, 28 Mar 2026 09:31:18 +0100 Subject: [PATCH 03/17] engines/3d: always configure shader stages --- src/core/hw/tegra_x1/gpu/engines/3d.cpp | 80 +++++++++++++------------ 1 file changed, 41 insertions(+), 39 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/engines/3d.cpp b/src/core/hw/tegra_x1/gpu/engines/3d.cpp index 171b4fd4..115bec9c 100644 --- a/src/core/hw/tegra_x1/gpu/engines/3d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/3d.cpp @@ -222,9 +222,7 @@ ThreeD::ThreeD() { SINGLETON_SET_INSTANCE(ThreeD, Engines); // TODO: choose based on Macro backend - { - macro_driver = new macro::interpreter::Driver(this); - } + { macro_driver = new macro::interpreter::Driver(this); } // Initialize default state @@ -849,29 +847,30 @@ void ThreeD::ConfigureShaderStage( // TODO: storage buffers // Textures - RENDERER_INSTANCE.UnbindTextures(shader_type); - auto tex_const_buffer = reinterpret_cast( - bound_const_buffers[stage_index] - [regs.bindless_texture_const_buffer_slot] - .GetBegin()); - for (const auto [const_buffer_index, renderer_index] : - resource_mapping.textures) { - const auto texture_handle = tex_const_buffer[const_buffer_index]; - - // Image - const auto image_handle = get_image_handle(texture_handle); - const auto& tic = tex_header_pool[image_handle]; - const auto texture = GetTexture(tic); - - // Sampler - const auto sampler_handle = get_sampler_handle(texture_handle); - const auto& tsc = tex_sampler_pool[sampler_handle]; - const auto sampler = GetSampler(tsc); - - if (texture && sampler) - RENDERER_INSTANCE.BindTexture(texture, sampler, shader_type, - renderer_index); - // TODO: else bind null texture + if (tex_header_pool && tex_sampler_pool) { + RENDERER_INSTANCE.UnbindTextures(shader_type); + auto tex_const_buffer = reinterpret_cast( + bound_const_buffers[stage_index] + [regs.bindless_texture_const_buffer_slot] + .GetBegin()); + for (const auto [const_buffer_index, renderer_index] : + resource_mapping.textures) { + const auto texture_handle = tex_const_buffer[const_buffer_index]; + + // Image + const auto image_handle = get_image_handle(texture_handle); + const auto& tic = tex_header_pool[image_handle]; + const auto texture = GetTexture(tic); + + // Sampler + const auto sampler_handle = get_sampler_handle(texture_handle); + const auto& tsc = tex_sampler_pool[sampler_handle]; + const auto sampler = GetSampler(tsc); + + if (texture && sampler) + RENDERER_INSTANCE.BindTexture(texture, sampler, shader_type, + renderer_index); + } } } @@ -913,19 +912,22 @@ bool ThreeD::DrawInternal() { // Configure stages const auto tex_header_pool_gpu_addr = u64(regs.tex_header_pool); const auto tex_sampler_pool_gpu_addr = u64(regs.tex_sampler_pool); - // TODO: remove the condition - if (tex_header_pool_gpu_addr != 0x0 && tex_sampler_pool_gpu_addr != 0x0) { - const auto tex_header_pool = reinterpret_cast( - tls_crnt_gmmu->UnmapAddr(tex_header_pool_gpu_addr)); - const auto tex_sampler_pool = reinterpret_cast( - tls_crnt_gmmu->UnmapAddr(tex_sampler_pool_gpu_addr)); - - // TODO: configure all stages - ConfigureShaderStage(ShaderStage::VertexB, tex_header_pool, - tex_sampler_pool); - ConfigureShaderStage(ShaderStage::Fragment, tex_header_pool, - tex_sampler_pool); - } + const auto tex_header_pool = + tex_header_pool_gpu_addr != 0x0 + ? reinterpret_cast( + tls_crnt_gmmu->UnmapAddr(tex_header_pool_gpu_addr)) + : nullptr; + const auto tex_sampler_pool = + tex_sampler_pool_gpu_addr != 0x0 + ? reinterpret_cast( + tls_crnt_gmmu->UnmapAddr(tex_sampler_pool_gpu_addr)) + : nullptr; + + // TODO: configure all stages + ConfigureShaderStage(ShaderStage::VertexB, tex_header_pool, + tex_sampler_pool); + ConfigureShaderStage(ShaderStage::Fragment, tex_header_pool, + tex_sampler_pool); return true; } From 17f71bca324bd4f56e916f7079dc5c413177d484 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Sat, 28 Mar 2026 10:06:34 +0100 Subject: [PATCH 04/17] display: clean up binder --- src/core/horizon/display/binder.cpp | 56 ++++++++++++++++------------- 1 file changed, 31 insertions(+), 25 deletions(-) diff --git a/src/core/horizon/display/binder.cpp b/src/core/horizon/display/binder.cpp index 1827a4d5..6bd8cc0c 100644 --- a/src/core/horizon/display/binder.cpp +++ b/src/core/horizon/display/binder.cpp @@ -47,14 +47,14 @@ void Binder::QueueBuffer(i32 slot, const BqBufferInput& input) { std::lock_guard lock(queue_mutex); queued_buffers.push({slot, input}); buffers[slot].queued = true; + } - // Time - const auto now = clock_t::now(); - accumulated_dt += now - last_queue_time; - last_queue_time = now; + // Time + const auto now = clock_t::now(); + accumulated_dt += now - last_queue_time; + last_queue_time = now; - queue_cv.notify_all(); - } + queue_cv.notify_all(); // Debug // TODO: only do this for the main process @@ -62,21 +62,25 @@ void Binder::QueueBuffer(i32 slot, const BqBufferInput& input) { } i32 Binder::ConsumeBuffer(BqBufferInput& out_input) { - // Wait for a buffer to become available - std::unique_lock lock(queue_mutex); - // TODO: should we wait? - // queue_cv.wait_for(lock, std::chrono::milliseconds(67), - // [&] { return !queued_buffers.empty(); }); + i32 slot; + { + // Wait for a buffer to become available + std::lock_guard lock(queue_mutex); + // TODO: should we wait? + // queue_cv.wait_for(lock, std::chrono::milliseconds(67), + // [&] { return !queued_buffers.empty(); }); - if (queued_buffers.empty()) - return -1; + if (queued_buffers.empty()) + return -1; - // Get the first queued buffer - const auto [slot, input] = queued_buffers.front(); - queued_buffers.pop(); - buffers[slot].queued = false; + // Get the first queued buffer + const auto [tmp_slot, tmp_input] = queued_buffers.front(); + slot = tmp_slot; + out_input = tmp_input; - out_input = input; + queued_buffers.pop(); + buffers[slot].queued = false; + } queue_cv.notify_all(); @@ -87,14 +91,16 @@ i32 Binder::ConsumeBuffer(BqBufferInput& out_input) { } void Binder::UnqueueAllBuffers() { - // Wait for a buffer to become available - std::unique_lock lock(queue_mutex); + { + // Wait for a buffer to become available + std::lock_guard lock(queue_mutex); - // Unqueue all - while (!queued_buffers.empty()) { - const auto [slot, input] = queued_buffers.front(); - queued_buffers.pop(); - buffers[slot].queued = false; + // Unqueue all + while (!queued_buffers.empty()) { + const auto [slot, input] = queued_buffers.front(); + queued_buffers.pop(); + buffers[slot].queued = false; + } } queue_cv.notify_all(); From fbb20cea58d085d015780c8eef88ea684b0fd74a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Sun, 29 Mar 2026 18:59:42 +0200 Subject: [PATCH 05/17] renderer: clean up texture formats --- src/core/hw/tegra_x1/gpu/renderer/const.cpp | 647 +++++--------------- src/core/hw/tegra_x1/gpu/renderer/const.hpp | 9 + 2 files changed, 170 insertions(+), 486 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.cpp b/src/core/hw/tegra_x1/gpu/renderer/const.cpp index 42620896..5c15b150 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.cpp @@ -4,6 +4,152 @@ namespace hydra::hw::tegra_x1::gpu::renderer { namespace { +#define FORMAT(bytes_per_block, block_width, block_height, is_depth_stencil) \ + TextureFormatInfo { \ + bytes_per_block, block_width, block_height, is_depth_stencil \ + } +#define COLOR_FORMAT(bytes_per_block, block_width, block_height) \ + FORMAT(bytes_per_block, block_width, block_height, false) +#define DEPTH_STENCIL_FORMAT(bytes_per_block, block_width, block_height) \ + FORMAT(bytes_per_block, block_width, block_height, true) + +TextureFormatInfo texture_format_infos[] = { + FORMAT(0, 0, 0, false), // Invalid + COLOR_FORMAT(1, 1, 1), // R8Unorm + COLOR_FORMAT(1, 1, 1), // R8Snorm + COLOR_FORMAT(1, 1, 1), // R8Uint + COLOR_FORMAT(1, 1, 1), // R8Sint + COLOR_FORMAT(2, 1, 1), // R16Float + COLOR_FORMAT(2, 1, 1), // R16Unorm + COLOR_FORMAT(2, 1, 1), // R16Snorm + COLOR_FORMAT(2, 1, 1), // R16Uint + COLOR_FORMAT(2, 1, 1), // R16Sint + COLOR_FORMAT(4, 1, 1), // R32Float + COLOR_FORMAT(4, 1, 1), // R32Uint + COLOR_FORMAT(4, 1, 1), // R32Sint + COLOR_FORMAT(2, 1, 1), // RG8Unorm + COLOR_FORMAT(2, 1, 1), // RG8Snorm + COLOR_FORMAT(2, 1, 1), // RG8Uint + COLOR_FORMAT(2, 1, 1), // RG8Sint + COLOR_FORMAT(4, 1, 1), // RG16Float + COLOR_FORMAT(4, 1, 1), // RG16Unorm + COLOR_FORMAT(4, 1, 1), // RG16Snorm + COLOR_FORMAT(4, 1, 1), // RG16Uint + COLOR_FORMAT(4, 1, 1), // RG16Sint + COLOR_FORMAT(8, 1, 1), // RG32Float + COLOR_FORMAT(8, 1, 1), // RG32Uint + COLOR_FORMAT(8, 1, 1), // RG32Sint + COLOR_FORMAT(12, 1, 1), // RGB32Float + COLOR_FORMAT(12, 1, 1), // RGB32Uint + COLOR_FORMAT(12, 1, 1), // RGB32Sint + COLOR_FORMAT(4, 1, 1), // RGBA8Unorm + COLOR_FORMAT(4, 1, 1), // RGBA8Snorm + COLOR_FORMAT(4, 1, 1), // RGBA8Uint + COLOR_FORMAT(4, 1, 1), // RGBA8Sint + COLOR_FORMAT(8, 1, 1), // RGBA16Float + COLOR_FORMAT(8, 1, 1), // RGBA16Unorm + COLOR_FORMAT(8, 1, 1), // RGBA16Snorm + COLOR_FORMAT(8, 1, 1), // RGBA16Uint + COLOR_FORMAT(8, 1, 1), // RGBA16Sint + COLOR_FORMAT(16, 1, 1), // RGBA32Float + COLOR_FORMAT(16, 1, 1), // RGBA32Uint + COLOR_FORMAT(16, 1, 1), // RGBA32Sint + DEPTH_STENCIL_FORMAT(1, 1, 1), // S8Uint + DEPTH_STENCIL_FORMAT(2, 1, 1), // Z16Unorm + DEPTH_STENCIL_FORMAT(4, 1, 1), // Z24Unorm_X8Uint + DEPTH_STENCIL_FORMAT(4, 1, 1), // Z32Float + DEPTH_STENCIL_FORMAT(4, 1, 1), // Z24Unorm_S8Uint + DEPTH_STENCIL_FORMAT(8, 1, 1), // Z32Float_X24S8Uint + COLOR_FORMAT(4, 1, 1), // RGBX8Unorm_sRGB + COLOR_FORMAT(4, 1, 1), // RGBA8Unorm_sRGB + COLOR_FORMAT(2, 1, 1), // RGBA4Unorm + COLOR_FORMAT(2, 1, 1), // RGB5Unorm + COLOR_FORMAT(2, 1, 1), // RGB5A1Unorm + COLOR_FORMAT(2, 1, 1), // R5G6B5Unorm + COLOR_FORMAT(4, 1, 1), // RGB10A2Unorm + COLOR_FORMAT(4, 1, 1), // RGB10A2Uint + COLOR_FORMAT(4, 1, 1), // RG11B10Float + COLOR_FORMAT(4, 1, 1), // E5BGR9Float + COLOR_FORMAT(8, 4, 4), // BC1_RGB + COLOR_FORMAT(8, 4, 4), // BC1_RGBA + COLOR_FORMAT(16, 4, 4), // BC2_RGBA + COLOR_FORMAT(16, 4, 4), // BC3_RGBA + COLOR_FORMAT(8, 4, 4), // BC1_RGB_sRGB + COLOR_FORMAT(8, 4, 4), // BC1_RGBA_sRGB + COLOR_FORMAT(16, 4, 4), // BC2_RGBA_sRGB + COLOR_FORMAT(16, 4, 4), // BC3_RGBA_sRGB + COLOR_FORMAT(8, 4, 4), // BC4_RUnorm + COLOR_FORMAT(8, 4, 4), // BC4_RSnorm + COLOR_FORMAT(16, 4, 4), // BC5_RGUnorm + COLOR_FORMAT(16, 4, 4), // BC5_RGSnorm + COLOR_FORMAT(16, 4, 4), // BC7_RGBAUnorm + COLOR_FORMAT(16, 4, 4), // BC7_RGBAUnorm_sRGB + COLOR_FORMAT(16, 4, 4), // BC6H_RGBA_SF16_Float + COLOR_FORMAT(16, 4, 4), // BC6H_RGBA_UF16_Float + COLOR_FORMAT(4, 1, 1), // RGBX8Unorm + COLOR_FORMAT(4, 1, 1), // RGBX8Snorm + COLOR_FORMAT(4, 1, 1), // RGBX8Uint + COLOR_FORMAT(4, 1, 1), // RGBX8Sint + COLOR_FORMAT(8, 1, 1), // RGBX16Float + COLOR_FORMAT(8, 1, 1), // RGBX16Unorm + COLOR_FORMAT(8, 1, 1), // RGBX16Snorm + COLOR_FORMAT(8, 1, 1), // RGBX16Uint + COLOR_FORMAT(8, 1, 1), // RGBX16Sint + COLOR_FORMAT(16, 1, 1), // RGBX32Float + COLOR_FORMAT(16, 1, 1), // RGBX32Uint + COLOR_FORMAT(16, 1, 1), // RGBX32Sint + COLOR_FORMAT(16, 4, 4), // ASTC_RGBA_4x4 + COLOR_FORMAT(16, 5, 4), // ASTC_RGBA_5x4 + COLOR_FORMAT(16, 5, 5), // ASTC_RGBA_5x5 + COLOR_FORMAT(16, 6, 5), // ASTC_RGBA_6x5 + COLOR_FORMAT(16, 6, 6), // ASTC_RGBA_6x6 + COLOR_FORMAT(16, 8, 5), // ASTC_RGBA_8x5 + COLOR_FORMAT(16, 8, 6), // ASTC_RGBA_8x6 + COLOR_FORMAT(16, 8, 8), // ASTC_RGBA_8x8 + COLOR_FORMAT(16, 10, 5), // ASTC_RGBA_10x5 + COLOR_FORMAT(16, 10, 6), // ASTC_RGBA_10x6 + COLOR_FORMAT(16, 10, 8), // ASTC_RGBA_10x8 + COLOR_FORMAT(16, 10, 10), // ASTC_RGBA_10x10 + COLOR_FORMAT(16, 12, 10), // ASTC_RGBA_12x10 + COLOR_FORMAT(16, 12, 12), // ASTC_RGBA_12x12 + COLOR_FORMAT(16, 4, 4), // ASTC_RGBA_4x4_sRGB + COLOR_FORMAT(16, 5, 4), // ASTC_RGBA_5x4_sRGB + COLOR_FORMAT(16, 5, 5), // ASTC_RGBA_5x5_sRGB + COLOR_FORMAT(16, 6, 5), // ASTC_RGBA_6x5_sRGB + COLOR_FORMAT(16, 6, 6), // ASTC_RGBA_6x6_sRGB + COLOR_FORMAT(16, 8, 5), // ASTC_RGBA_8x5_sRGB + COLOR_FORMAT(16, 8, 6), // ASTC_RGBA_8x6_sRGB + COLOR_FORMAT(16, 8, 8), // ASTC_RGBA_8x8_sRGB + COLOR_FORMAT(16, 10, 5), // ASTC_RGBA_10x5_sRGB + COLOR_FORMAT(16, 10, 6), // ASTC_RGBA_10x6_sRGB + COLOR_FORMAT(16, 10, 8), // ASTC_RGBA_10x8_sRGB + COLOR_FORMAT(16, 10, 10), // ASTC_RGBA_10x10_sRGB + COLOR_FORMAT(16, 12, 10), // ASTC_RGBA_12x10_sRGB + COLOR_FORMAT(16, 12, 12), // ASTC_RGBA_12x12_sRGB + COLOR_FORMAT(2, 1, 1), // B5G6R5Unorm + COLOR_FORMAT(2, 1, 1), // BGR5Unorm + COLOR_FORMAT(2, 1, 1), // BGR5A1Unorm + COLOR_FORMAT(2, 1, 1), // A1BGR5Unorm + COLOR_FORMAT(4, 1, 1), // BGRX8Unorm + COLOR_FORMAT(4, 1, 1), // BGRA8Unorm + COLOR_FORMAT(4, 1, 1), // BGRX8Unorm_sRGB + COLOR_FORMAT(4, 1, 1), // BGRA8Unorm_sRGB + COLOR_FORMAT(8, 4, 4), // ETC2_R_Unorm + COLOR_FORMAT(8, 4, 4), // ETC2_R_Snorm + COLOR_FORMAT(16, 4, 4), // ETC2_RG_Unorm + COLOR_FORMAT(16, 4, 4), // ETC2_RG_Snorm + COLOR_FORMAT(8, 4, 4), // ETC2_RGB + COLOR_FORMAT(8, 4, 4), // PTA_ETC2_RGB + COLOR_FORMAT(16, 4, 4), // ETC2_RGBA + COLOR_FORMAT(8, 4, 4), // ETC2_RGB_sRGB + COLOR_FORMAT(8, 4, 4), // PTA_ETC2_RGB_sRGB + COLOR_FORMAT(16, 4, 4), // ETC2_RGBA_sRGB +}; + +#undef DEPTH_STENCIL_FORMAT +#undef COLOR_FORMAT +#undef FORMAT + enum class TextureTypeCompatibility { _1D, _1DBuffer, @@ -31,6 +177,10 @@ static TextureTypeCompatibility ToTextureTypeCompatibility(TextureType type) { } // namespace +const TextureFormatInfo& GetTextureFormatInfo(TextureFormat format) { + return texture_format_infos[static_cast(format)]; +} + TextureFormat to_texture_format(NvColorFormat color_format) { #define NV_COLOR_FORMAT_CASE(color_format, texture_format) \ case NvColorFormat::color_format: \ @@ -223,370 +373,26 @@ TextureFormat to_texture_format(DepthSurfaceFormat depth_surface_format) { } u32 get_texture_format_bpp(const TextureFormat format) { - switch (format) { - case TextureFormat::Invalid: - throw GetTextureFormatBppError::InvalidFormat; - case TextureFormat::R8Unorm: - case TextureFormat::R8Snorm: - case TextureFormat::R8Uint: - case TextureFormat::R8Sint: - return 1; - case TextureFormat::R16Float: - case TextureFormat::R16Unorm: - case TextureFormat::R16Snorm: - case TextureFormat::R16Uint: - case TextureFormat::R16Sint: - return 2; - case TextureFormat::R32Float: - case TextureFormat::R32Uint: - case TextureFormat::R32Sint: - return 4; - case TextureFormat::RG8Unorm: - case TextureFormat::RG8Snorm: - case TextureFormat::RG8Uint: - case TextureFormat::RG8Sint: - return 2; - case TextureFormat::RG16Float: - case TextureFormat::RG16Unorm: - case TextureFormat::RG16Snorm: - case TextureFormat::RG16Uint: - case TextureFormat::RG16Sint: - return 4; - case TextureFormat::RG32Float: - case TextureFormat::RG32Uint: - case TextureFormat::RG32Sint: - return 8; - case TextureFormat::RGB32Float: - case TextureFormat::RGB32Uint: - case TextureFormat::RGB32Sint: - return 12; - case TextureFormat::RGBA8Unorm: - case TextureFormat::RGBA8Snorm: - case TextureFormat::RGBA8Uint: - case TextureFormat::RGBA8Sint: - case TextureFormat::RGBA8Unorm_sRGB: - case TextureFormat::RGBX8Unorm: - case TextureFormat::RGBX8Snorm: - case TextureFormat::RGBX8Uint: - case TextureFormat::RGBX8Sint: - case TextureFormat::RGBX8Unorm_sRGB: - return 4; - case TextureFormat::RGBA16Float: - case TextureFormat::RGBA16Unorm: - case TextureFormat::RGBA16Snorm: - case TextureFormat::RGBA16Uint: - case TextureFormat::RGBA16Sint: - case TextureFormat::RGBX16Float: - case TextureFormat::RGBX16Unorm: - case TextureFormat::RGBX16Snorm: - case TextureFormat::RGBX16Uint: - case TextureFormat::RGBX16Sint: - return 8; - case TextureFormat::RGBA32Float: - case TextureFormat::RGBA32Uint: - case TextureFormat::RGBA32Sint: - case TextureFormat::RGBX32Float: - case TextureFormat::RGBX32Uint: - case TextureFormat::RGBX32Sint: - return 16; - case TextureFormat::S8Uint: - return 1; - case TextureFormat::Z16Unorm: - return 2; - case TextureFormat::Z24Unorm_X8Uint: - case TextureFormat::Z24Unorm_S8Uint: - return 4; - case TextureFormat::Z32Float: - return 4; - case TextureFormat::Z32Float_X24S8Uint: - return 8; - return 4; - case TextureFormat::RGBA4Unorm: - return 2; - case TextureFormat::RGB5Unorm: - case TextureFormat::RGB5A1Unorm: - case TextureFormat::R5G6B5Unorm: - return 2; - case TextureFormat::RGB10A2Unorm: - case TextureFormat::RGB10A2Uint: - return 4; - case TextureFormat::RG11B10Float: - return 4; - case TextureFormat::E5BGR9Float: - return 4; - case TextureFormat::B5G6R5Unorm: - case TextureFormat::BGR5Unorm: - case TextureFormat::BGR5A1Unorm: - case TextureFormat::A1BGR5Unorm: - return 2; - case TextureFormat::BGRX8Unorm: - case TextureFormat::BGRA8Unorm: - case TextureFormat::BGRX8Unorm_sRGB: - case TextureFormat::BGRA8Unorm_sRGB: - return 4; - default: + const auto& info = GetTextureFormatInfo(format); + if (info.block_width != 1 || info.block_height != 1) throw GetTextureFormatBppError::UnsupportedFormatForBpp; - } + + return info.bytes_per_block; } u32 get_texture_format_stride(const TextureFormat format, u32 width) { - // TODO: check this - switch (format) { - case TextureFormat::Invalid: - return 0; - case TextureFormat::R8Unorm: - case TextureFormat::R8Snorm: - case TextureFormat::R8Uint: - case TextureFormat::R8Sint: - return width; - case TextureFormat::R16Float: - case TextureFormat::R16Unorm: - case TextureFormat::R16Snorm: - case TextureFormat::R16Uint: - case TextureFormat::R16Sint: - return width * 2; - case TextureFormat::R32Float: - case TextureFormat::R32Uint: - case TextureFormat::R32Sint: - return width * 4; - case TextureFormat::RG8Unorm: - case TextureFormat::RG8Snorm: - case TextureFormat::RG8Uint: - case TextureFormat::RG8Sint: - return width * 2; - case TextureFormat::RG16Float: - case TextureFormat::RG16Unorm: - case TextureFormat::RG16Snorm: - case TextureFormat::RG16Uint: - case TextureFormat::RG16Sint: - return width * 4; - case TextureFormat::RG32Float: - case TextureFormat::RG32Uint: - case TextureFormat::RG32Sint: - return width * 8; - case TextureFormat::RGB32Float: - case TextureFormat::RGB32Uint: - case TextureFormat::RGB32Sint: - return width * 12; - case TextureFormat::RGBA8Unorm: - case TextureFormat::RGBA8Snorm: - case TextureFormat::RGBA8Uint: - case TextureFormat::RGBA8Sint: - case TextureFormat::RGBA8Unorm_sRGB: - case TextureFormat::RGBX8Unorm: - case TextureFormat::RGBX8Snorm: - case TextureFormat::RGBX8Uint: - case TextureFormat::RGBX8Sint: - case TextureFormat::RGBX8Unorm_sRGB: - return width * 4; - case TextureFormat::RGBA16Float: - case TextureFormat::RGBA16Unorm: - case TextureFormat::RGBA16Snorm: - case TextureFormat::RGBA16Uint: - case TextureFormat::RGBA16Sint: - case TextureFormat::RGBX16Float: - case TextureFormat::RGBX16Unorm: - case TextureFormat::RGBX16Snorm: - case TextureFormat::RGBX16Uint: - case TextureFormat::RGBX16Sint: - return width * 8; - case TextureFormat::RGBA32Float: - case TextureFormat::RGBA32Uint: - case TextureFormat::RGBA32Sint: - case TextureFormat::RGBX32Float: - case TextureFormat::RGBX32Uint: - case TextureFormat::RGBX32Sint: - return width * 16; - case TextureFormat::S8Uint: - return width; - case TextureFormat::Z16Unorm: - return width * 2; - case TextureFormat::Z24Unorm_X8Uint: - case TextureFormat::Z24Unorm_S8Uint: - return width * 4; - case TextureFormat::Z32Float: - return width * 4; - case TextureFormat::Z32Float_X24S8Uint: - return width * 8; - return width * 4; - case TextureFormat::RGBA4Unorm: - return width * 2; - case TextureFormat::RGB5Unorm: - case TextureFormat::RGB5A1Unorm: - case TextureFormat::R5G6B5Unorm: - return width * 2; - case TextureFormat::RGB10A2Unorm: - case TextureFormat::RGB10A2Uint: - return width * 4; - case TextureFormat::RG11B10Float: - return width * 4; - case TextureFormat::E5BGR9Float: - return width * 4; - case TextureFormat::BC1_RGB: - case TextureFormat::BC1_RGBA: - case TextureFormat::BC1_RGB_sRGB: - case TextureFormat::BC1_RGBA_sRGB: - return ((width + 3) / 4) * 8; - case TextureFormat::BC2_RGBA: - case TextureFormat::BC3_RGBA: - case TextureFormat::BC2_RGBA_sRGB: - case TextureFormat::BC3_RGBA_sRGB: - return ((width + 3) / 4) * 16; - case TextureFormat::BC4_RUnorm: - case TextureFormat::BC4_RSnorm: - return ((width + 3) / 4) * 8; - case TextureFormat::BC5_RGUnorm: - case TextureFormat::BC5_RGSnorm: - return ((width + 3) / 4) * 16; - case TextureFormat::BC7_RGBAUnorm: - case TextureFormat::BC7_RGBAUnorm_sRGB: - return ((width + 3) / 4) * 16; - case TextureFormat::BC6H_RGBA_SF16_Float: - case TextureFormat::BC6H_RGBA_UF16_Float: - return ((width + 3) / 4) * 16; - case TextureFormat::ASTC_RGBA_4x4: - case TextureFormat::ASTC_RGBA_4x4_sRGB: - return ((width + 3) / 4) * 16; - case TextureFormat::ASTC_RGBA_5x4: - case TextureFormat::ASTC_RGBA_5x4_sRGB: - return ((width + 4) / 5) * 16; - case TextureFormat::ASTC_RGBA_5x5: - case TextureFormat::ASTC_RGBA_5x5_sRGB: - return ((width + 4) / 5) * 16; - case TextureFormat::ASTC_RGBA_6x5: - case TextureFormat::ASTC_RGBA_6x5_sRGB: - return ((width + 5) / 6) * 16; - case TextureFormat::ASTC_RGBA_6x6: - case TextureFormat::ASTC_RGBA_6x6_sRGB: - return ((width + 5) / 6) * 16; - case TextureFormat::ASTC_RGBA_8x5: - case TextureFormat::ASTC_RGBA_8x5_sRGB: - return ((width + 7) / 8) * 16; - case TextureFormat::ASTC_RGBA_8x6: - case TextureFormat::ASTC_RGBA_8x6_sRGB: - return ((width + 7) / 8) * 16; - case TextureFormat::ASTC_RGBA_8x8: - case TextureFormat::ASTC_RGBA_8x8_sRGB: - return ((width + 7) / 8) * 16; - case TextureFormat::ASTC_RGBA_10x5: - case TextureFormat::ASTC_RGBA_10x5_sRGB: - return ((width + 9) / 10) * 16; - case TextureFormat::ASTC_RGBA_10x6: - case TextureFormat::ASTC_RGBA_10x6_sRGB: - return ((width + 9) / 10) * 16; - case TextureFormat::ASTC_RGBA_10x8: - case TextureFormat::ASTC_RGBA_10x8_sRGB: - return ((width + 9) / 10) * 16; - case TextureFormat::ASTC_RGBA_10x10: - case TextureFormat::ASTC_RGBA_10x10_sRGB: - return ((width + 9) / 10) * 16; - case TextureFormat::ASTC_RGBA_12x10: - case TextureFormat::ASTC_RGBA_12x10_sRGB: - return ((width + 11) / 12) * 16; - case TextureFormat::ASTC_RGBA_12x12: - case TextureFormat::ASTC_RGBA_12x12_sRGB: - return ((width + 11) / 12) * 16; - case TextureFormat::B5G6R5Unorm: - case TextureFormat::BGR5Unorm: - case TextureFormat::BGR5A1Unorm: - case TextureFormat::A1BGR5Unorm: - return width * 2; - case TextureFormat::BGRX8Unorm: - case TextureFormat::BGRA8Unorm: - case TextureFormat::BGRX8Unorm_sRGB: - case TextureFormat::BGRA8Unorm_sRGB: - return width * 4; - case TextureFormat::ETC2_R_Unorm: - case TextureFormat::ETC2_R_Snorm: - return ((width + 3) / 4) * 8; - case TextureFormat::ETC2_RG_Unorm: - case TextureFormat::ETC2_RG_Snorm: - return ((width + 3) / 4) * 16; - case TextureFormat::ETC2_RGB: - case TextureFormat::PTA_ETC2_RGB: - case TextureFormat::ETC2_RGB_sRGB: - case TextureFormat::PTA_ETC2_RGB_sRGB: - return ((width + 3) / 4) * 8; - case TextureFormat::ETC2_RGBA: - case TextureFormat::ETC2_RGBA_sRGB: - return ((width + 3) / 4) * 16; - } + const auto& info = GetTextureFormatInfo(format); + return ceil_divide(width, info.block_width) * info.bytes_per_block; } bool is_texture_format_compressed(const TextureFormat format) { - switch (format) { - case TextureFormat::BC1_RGB: - case TextureFormat::BC1_RGBA: - case TextureFormat::BC1_RGB_sRGB: - case TextureFormat::BC1_RGBA_sRGB: - case TextureFormat::BC2_RGBA: - case TextureFormat::BC3_RGBA: - case TextureFormat::BC2_RGBA_sRGB: - case TextureFormat::BC3_RGBA_sRGB: - case TextureFormat::BC4_RUnorm: - case TextureFormat::BC4_RSnorm: - case TextureFormat::BC5_RGUnorm: - case TextureFormat::BC5_RGSnorm: - case TextureFormat::BC7_RGBAUnorm: - case TextureFormat::BC7_RGBAUnorm_sRGB: - case TextureFormat::BC6H_RGBA_SF16_Float: - case TextureFormat::BC6H_RGBA_UF16_Float: - case TextureFormat::ASTC_RGBA_4x4: - case TextureFormat::ASTC_RGBA_4x4_sRGB: - case TextureFormat::ASTC_RGBA_5x4: - case TextureFormat::ASTC_RGBA_5x4_sRGB: - case TextureFormat::ASTC_RGBA_5x5: - case TextureFormat::ASTC_RGBA_5x5_sRGB: - case TextureFormat::ASTC_RGBA_6x5: - case TextureFormat::ASTC_RGBA_6x5_sRGB: - case TextureFormat::ASTC_RGBA_6x6: - case TextureFormat::ASTC_RGBA_6x6_sRGB: - case TextureFormat::ASTC_RGBA_8x5: - case TextureFormat::ASTC_RGBA_8x5_sRGB: - case TextureFormat::ASTC_RGBA_8x6: - case TextureFormat::ASTC_RGBA_8x6_sRGB: - case TextureFormat::ASTC_RGBA_8x8: - case TextureFormat::ASTC_RGBA_8x8_sRGB: - case TextureFormat::ASTC_RGBA_10x5: - case TextureFormat::ASTC_RGBA_10x5_sRGB: - case TextureFormat::ASTC_RGBA_10x6: - case TextureFormat::ASTC_RGBA_10x6_sRGB: - case TextureFormat::ASTC_RGBA_10x8: - case TextureFormat::ASTC_RGBA_10x8_sRGB: - case TextureFormat::ASTC_RGBA_10x10: - case TextureFormat::ASTC_RGBA_10x10_sRGB: - case TextureFormat::ASTC_RGBA_12x10: - case TextureFormat::ASTC_RGBA_12x10_sRGB: - case TextureFormat::ASTC_RGBA_12x12: - case TextureFormat::ASTC_RGBA_12x12_sRGB: - case TextureFormat::ETC2_R_Unorm: - case TextureFormat::ETC2_R_Snorm: - case TextureFormat::ETC2_RG_Unorm: - case TextureFormat::ETC2_RG_Snorm: - case TextureFormat::ETC2_RGB: - case TextureFormat::PTA_ETC2_RGB: - case TextureFormat::ETC2_RGB_sRGB: - case TextureFormat::PTA_ETC2_RGB_sRGB: - case TextureFormat::ETC2_RGBA: - case TextureFormat::ETC2_RGBA_sRGB: - return true; - default: - return false; - } + const auto& info = GetTextureFormatInfo(format); + return info.block_width != 1 || info.block_height != 1; } bool is_texture_format_depth_or_stencil(const TextureFormat format) { - switch (format) { - case TextureFormat::S8Uint: - case TextureFormat::Z16Unorm: - case TextureFormat::Z24Unorm_X8Uint: - case TextureFormat::Z32Float: - case TextureFormat::Z24Unorm_S8Uint: - case TextureFormat::Z32Float_X24S8Uint: - return true; - default: - return false; - } + const auto& info = GetTextureFormatInfo(format); + return info.is_depth_stencil; } ColorDataType to_color_data_type(ColorSurfaceFormat format) { @@ -810,140 +616,9 @@ SwizzleChannels::SwizzleChannels(const TextureFormat format, #undef SWIZZLE } -bool texture_format_can_be_swizzled(TextureFormat format) { - switch (format) { - case TextureFormat::R8Unorm: - case TextureFormat::R8Snorm: - case TextureFormat::R8Uint: - case TextureFormat::R8Sint: - case TextureFormat::R16Float: - case TextureFormat::R16Unorm: - case TextureFormat::R16Snorm: - case TextureFormat::R16Uint: - case TextureFormat::R16Sint: - case TextureFormat::R32Float: - case TextureFormat::R32Uint: - case TextureFormat::R32Sint: - case TextureFormat::RG8Unorm: - case TextureFormat::RG8Snorm: - case TextureFormat::RG8Uint: - case TextureFormat::RG8Sint: - case TextureFormat::RG16Float: - case TextureFormat::RG16Unorm: - case TextureFormat::RG16Snorm: - case TextureFormat::RG16Uint: - case TextureFormat::RG16Sint: - case TextureFormat::RG32Float: - case TextureFormat::RG32Uint: - case TextureFormat::RG32Sint: - case TextureFormat::RGB32Float: - case TextureFormat::RGB32Uint: - case TextureFormat::RGB32Sint: - case TextureFormat::RGBA8Unorm: - case TextureFormat::RGBA8Snorm: - case TextureFormat::RGBA8Uint: - case TextureFormat::RGBA8Sint: - case TextureFormat::RGBA8Unorm_sRGB: - case TextureFormat::RGBX8Unorm: - case TextureFormat::RGBX8Snorm: - case TextureFormat::RGBX8Uint: - case TextureFormat::RGBX8Sint: - case TextureFormat::RGBX8Unorm_sRGB: - case TextureFormat::RGBA16Float: - case TextureFormat::RGBA16Unorm: - case TextureFormat::RGBA16Snorm: - case TextureFormat::RGBA16Uint: - case TextureFormat::RGBA16Sint: - case TextureFormat::RGBX16Float: - case TextureFormat::RGBX16Unorm: - case TextureFormat::RGBX16Snorm: - case TextureFormat::RGBX16Uint: - case TextureFormat::RGBX16Sint: - case TextureFormat::RGBA32Float: - case TextureFormat::RGBA32Uint: - case TextureFormat::RGBA32Sint: - case TextureFormat::RGBX32Float: - case TextureFormat::RGBX32Uint: - case TextureFormat::RGBX32Sint: - case TextureFormat::RGBA4Unorm: - case TextureFormat::RGB5Unorm: - case TextureFormat::RGB5A1Unorm: - case TextureFormat::R5G6B5Unorm: - case TextureFormat::RGB10A2Unorm: - case TextureFormat::RGB10A2Uint: - case TextureFormat::RG11B10Float: - case TextureFormat::E5BGR9Float: - case TextureFormat::BC1_RGB: - case TextureFormat::BC1_RGBA: - case TextureFormat::BC1_RGB_sRGB: - case TextureFormat::BC1_RGBA_sRGB: - case TextureFormat::BC2_RGBA: - case TextureFormat::BC3_RGBA: - case TextureFormat::BC2_RGBA_sRGB: - case TextureFormat::BC3_RGBA_sRGB: - case TextureFormat::BC4_RUnorm: - case TextureFormat::BC4_RSnorm: - case TextureFormat::BC5_RGUnorm: - case TextureFormat::BC5_RGSnorm: - case TextureFormat::BC7_RGBAUnorm: - case TextureFormat::BC7_RGBAUnorm_sRGB: - case TextureFormat::BC6H_RGBA_SF16_Float: - case TextureFormat::BC6H_RGBA_UF16_Float: - case TextureFormat::ASTC_RGBA_4x4: - case TextureFormat::ASTC_RGBA_4x4_sRGB: - case TextureFormat::ASTC_RGBA_5x4: - case TextureFormat::ASTC_RGBA_5x4_sRGB: - case TextureFormat::ASTC_RGBA_5x5: - case TextureFormat::ASTC_RGBA_5x5_sRGB: - case TextureFormat::ASTC_RGBA_6x5: - case TextureFormat::ASTC_RGBA_6x5_sRGB: - case TextureFormat::ASTC_RGBA_6x6: - case TextureFormat::ASTC_RGBA_6x6_sRGB: - case TextureFormat::ASTC_RGBA_8x5: - case TextureFormat::ASTC_RGBA_8x5_sRGB: - case TextureFormat::ASTC_RGBA_8x6: - case TextureFormat::ASTC_RGBA_8x6_sRGB: - case TextureFormat::ASTC_RGBA_8x8: - case TextureFormat::ASTC_RGBA_8x8_sRGB: - case TextureFormat::ASTC_RGBA_10x5: - case TextureFormat::ASTC_RGBA_10x5_sRGB: - case TextureFormat::ASTC_RGBA_10x6: - case TextureFormat::ASTC_RGBA_10x6_sRGB: - case TextureFormat::ASTC_RGBA_10x8: - case TextureFormat::ASTC_RGBA_10x8_sRGB: - case TextureFormat::ASTC_RGBA_10x10: - case TextureFormat::ASTC_RGBA_10x10_sRGB: - case TextureFormat::ASTC_RGBA_12x10: - case TextureFormat::ASTC_RGBA_12x10_sRGB: - case TextureFormat::ASTC_RGBA_12x12: - case TextureFormat::ASTC_RGBA_12x12_sRGB: - case TextureFormat::B5G6R5Unorm: - case TextureFormat::BGR5Unorm: - case TextureFormat::BGR5A1Unorm: - case TextureFormat::A1BGR5Unorm: - case TextureFormat::BGRX8Unorm: - case TextureFormat::BGRA8Unorm: - case TextureFormat::BGRX8Unorm_sRGB: - case TextureFormat::BGRA8Unorm_sRGB: - case TextureFormat::ETC2_R_Unorm: - case TextureFormat::ETC2_R_Snorm: - case TextureFormat::ETC2_RG_Unorm: - case TextureFormat::ETC2_RG_Snorm: - case TextureFormat::ETC2_RGB: - case TextureFormat::PTA_ETC2_RGB: - case TextureFormat::ETC2_RGB_sRGB: - case TextureFormat::PTA_ETC2_RGB_sRGB: - case TextureFormat::ETC2_RGBA: - case TextureFormat::ETC2_RGBA_sRGB: - return true; - default: - return false; - } -} - SwizzleChannels get_texture_format_default_swizzle_channels(const TextureFormat format) { - if (!texture_format_can_be_swizzled(format)) + if (is_texture_format_depth_or_stencil(format)) return {ImageSwizzle::Zero, ImageSwizzle::Zero, ImageSwizzle::Zero, ImageSwizzle::Zero}; diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.hpp b/src/core/hw/tegra_x1/gpu/renderer/const.hpp index b8568028..c19824d2 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.hpp @@ -152,6 +152,15 @@ enum class TextureFormat { ETC2_RGBA_sRGB, }; +struct TextureFormatInfo { + u32 bytes_per_block; + u32 block_width; + u32 block_height; + bool is_depth_stencil; +}; + +const TextureFormatInfo& GetTextureFormatInfo(TextureFormat format); + TextureFormat to_texture_format(NvColorFormat color_format); TextureFormat to_texture_format(const ImageFormatWord image_format_word, bool is_srgb); From ceaad13282091f55d6cbd8841ff37dafb607d476 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Sun, 29 Mar 2026 19:37:56 +0200 Subject: [PATCH 06/17] gpu: rework texture layers --- src/core/c_api.cpp | 4 +- src/core/emulation_context.cpp | 15 +- src/core/hw/tegra_x1/gpu/engines/2d.cpp | 16 +- src/core/hw/tegra_x1/gpu/engines/3d.cpp | 32 ++-- src/core/hw/tegra_x1/gpu/gpu.cpp | 4 +- src/core/hw/tegra_x1/gpu/renderer/const.cpp | 3 + src/core/hw/tegra_x1/gpu/renderer/const.hpp | 28 +++- .../tegra_x1/gpu/renderer/metal/texture.cpp | 138 ++++++++---------- .../tegra_x1/gpu/renderer/metal/texture.hpp | 15 +- .../hw/tegra_x1/gpu/renderer/texture_base.hpp | 23 ++- .../tegra_x1/gpu/renderer/texture_cache.cpp | 40 ++--- .../tegra_x1/gpu/renderer/texture_decoder.cpp | 6 +- 12 files changed, 173 insertions(+), 151 deletions(-) diff --git a/src/core/c_api.cpp b/src/core/c_api.cpp index 2e20ac19..9cc68d96 100644 --- a/src/core/c_api.cpp +++ b/src/core/c_api.cpp @@ -1112,7 +1112,7 @@ hydra_texture_descriptor_get_layer_size(const void* descriptor) { return static_cast< const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( descriptor) - ->GetLayerSizeInBytes(); + ->GetLayerSize(); } HYDRA_EXPORT uint64_t @@ -1120,5 +1120,5 @@ hydra_texture_descriptor_get_size(const void* descriptor) { return static_cast< const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( descriptor) - ->GetSizeInBytes(); + ->GetSize(); } diff --git a/src/core/emulation_context.cpp b/src/core/emulation_context.cpp index eae205b2..a1e001e3 100644 --- a/src/core/emulation_context.cpp +++ b/src/core/emulation_context.cpp @@ -282,8 +282,8 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { hw::tegra_x1::gpu::renderer::TextureDescriptor descriptor( 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, - hw::tegra_x1::gpu::NvKind::Generic_16BX2, width, height, 1, 0x0, - stride); + hw::tegra_x1::gpu::NvKind::Generic_16BX2, width, height, 1, 1, + 1, 0x0, 0x0, 0x0, stride); nintendo_logo = gpu->GetRenderer().CreateTexture(descriptor); // Command buffer @@ -294,9 +294,7 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { std::memcpy(reinterpret_cast(tmp_buffer->GetPtr()), data, size); free(data); - nintendo_logo->CopyFrom(command_buffer, tmp_buffer, stride, - uint3({0, 0, 0}), - usize3({width, height, 1})); + nintendo_logo->CopyFrom(command_buffer, tmp_buffer); gpu->GetRenderer().FreeTemporaryBuffer(tmp_buffer); } } @@ -310,8 +308,8 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { hw::tegra_x1::gpu::renderer::TextureDescriptor descriptor( 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, - hw::tegra_x1::gpu::NvKind::Generic_16BX2, width, height, 1, 0x0, - stride); + hw::tegra_x1::gpu::NvKind::Generic_16BX2, width, height, 1, 1, + 1, 0x0, 0x0, 0x0, stride); startup_movie.reserve(frame_count); // Command buffer @@ -327,8 +325,7 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { gpu->GetRenderer().AllocateTemporaryBuffer(size); std::memcpy(reinterpret_cast(tmp_buffer->GetPtr()), data + i * height * width, size); - frame->CopyFrom(command_buffer, tmp_buffer, stride, - uint3({0, 0, 0}), usize3({width, height, 1})); + frame->CopyFrom(command_buffer, tmp_buffer); gpu->GetRenderer().FreeTemporaryBuffer(tmp_buffer); startup_movie.push_back(frame); } diff --git a/src/core/hw/tegra_x1/gpu/engines/2d.cpp b/src/core/hw/tegra_x1/gpu/engines/2d.cpp index 363e22ea..f3c41cbb 100644 --- a/src/core/hw/tegra_x1/gpu/engines/2d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/2d.cpp @@ -28,13 +28,12 @@ void TwoD::Copy(const u32 index, const u32 pixels_from_memory_src_y0_int) { const auto src_height = static_cast(pixels.dst_height * dvdy); dst->BlitFrom(tls_crnt_command_buffer, src, - {static_cast(src_x0), static_cast(src_y0), - static_cast(regs.src.layer)}, - {src_width, src_height, 1}, + {static_cast(src_x0), static_cast(src_y0), 0.0f}, + {src_width, src_height, 1}, 0, regs.src.layer, {static_cast(pixels.dst_x0), - static_cast(pixels.dst_y0), - static_cast(regs.dst.layer)}, - {pixels.dst_width, pixels.dst_height, 1}); + static_cast(pixels.dst_y0), 0.0f}, + {pixels.dst_width, pixels.dst_height, 1}, 0, regs.dst.layer, + 1, 1); } #pragma GCC diagnostic pop @@ -45,9 +44,8 @@ renderer::TextureBase* TwoD::GetTexture(const Texture2DInfo& info, tls_crnt_gmmu->UnmapAddr(info.addr), renderer::TextureType::_2D, renderer::to_texture_format(info.format), NvKind::Pitch, // TODO: correct? - u32(info.width), u32(info.height), 1, - 0, // HACK - /*u32(info.stride)*/ + u32(info.width), u32(info.height), 1, 1, 1, 0x0, 0x0, 0x0, // HACK + /*u32(info.stride)*/ renderer::get_texture_format_stride( renderer::to_texture_format(info.format), info.width) // HACK ); diff --git a/src/core/hw/tegra_x1/gpu/engines/3d.cpp b/src/core/hw/tegra_x1/gpu/engines/3d.cpp index 115bec9c..e184278e 100644 --- a/src/core/hw/tegra_x1/gpu/engines/3d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/3d.cpp @@ -465,8 +465,9 @@ ThreeD::GetColorTargetTexture(u32 render_target_index) const { NvKind::Pitch, // TODO: correct? GetMinimumWidth(render_target.width, format, width_hint, render_target.tile_mode.is_linear), - render_target.height, 1, - 0, // TODO + render_target.height, 1, 1, render_target.array_mode.layers, + render_target.tile_mode.width, render_target.tile_mode.height, + render_target.tile_mode.depth, get_texture_format_stride(format, render_target.width)); return RENDERER_INSTANCE.GetTextureCache().Find( @@ -488,8 +489,9 @@ renderer::TextureBase* ThreeD::GetDepthStencilTargetTexture() const { tls_crnt_gmmu->UnmapAddr(gpu_addr), renderer::TextureType::_2D, format, NvKind::Pitch, // TODO: correct? GetMinimumWidth(regs.depth_target_width, format, width_hint, false), - regs.depth_target_height, 1, - 0, // TODO + regs.depth_target_height, 1, 1, regs.depth_target_array_mode.layers, + regs.depth_target_tile_mode.width, regs.depth_target_tile_mode.height, + regs.depth_target_tile_mode.depth, get_texture_format_stride(format, regs.depth_target_width)); return RENDERER_INSTANCE.GetTextureCache().Find( @@ -778,13 +780,23 @@ ThreeD::GetTexture(const TextureImageControl& tic) const { break; } + const auto type = ToTextureType(tic.texture_type); + + u32 depth = tic.depth_minus_one + 1; + u32 layer_count = 1; + if (type != renderer::TextureType::_3D) { + layer_count = depth; + depth = 1; + if (type == renderer::TextureType::Cube || + type == renderer::TextureType::CubeArray) + layer_count *= 6; + } + const renderer::TextureDescriptor descriptor( - tls_crnt_gmmu->UnmapAddr(gpu_addr), ToTextureType(tic.texture_type), - format, kind, static_cast(tic.width_minus_one + 1), - static_cast(tic.height_minus_one + 1), - static_cast(tic.depth_minus_one + 1), - tic.tile_height_gobs_log2, // TODO: correct? - stride, + tls_crnt_gmmu->UnmapAddr(gpu_addr), type, format, kind, + tic.width_minus_one + 1, tic.height_minus_one + 1, depth, + tic.mip_max_levels + 1, layer_count, tic.tile_width_gobs_log2, + tic.tile_height_gobs_log2, tic.tile_depth_gobs_log2, stride, renderer::SwizzleChannels( format, tic.format_word.swizzle_x, tic.format_word.swizzle_y, tic.format_word.swizzle_z, tic.format_word.swizzle_w)); diff --git a/src/core/hw/tegra_x1/gpu/gpu.cpp b/src/core/hw/tegra_x1/gpu/gpu.cpp index e7f917ec..a80a6a53 100644 --- a/src/core/hw/tegra_x1/gpu/gpu.cpp +++ b/src/core/hw/tegra_x1/gpu/gpu.cpp @@ -95,8 +95,8 @@ renderer::TextureBase* Gpu::GetTexture(renderer::ICommandBuffer* command_buffer, buff.planes[0].offset), renderer::TextureType::_2D, renderer::to_texture_format(buff.planes[0].color_format), - buff.planes[0].kind, buff.planes[0].width, buff.planes[0].height, 1, - buff.planes[0].block_height_log2, buff.planes[0].pitch); + buff.planes[0].kind, buff.planes[0].width, buff.planes[0].height, 1, 1, + 1, 0x0, buff.planes[0].block_height_log2, 0x0, buff.planes[0].pitch); return renderer->GetTextureCache().Find(command_buffer, descriptor, renderer::TextureUsage::Present); diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.cpp b/src/core/hw/tegra_x1/gpu/renderer/const.cpp index 5c15b150..ecb26a3f 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.cpp @@ -656,6 +656,9 @@ u32 TextureDescriptor::GetHash() const { hash.Add(width); hash.Add(height); hash.Add(depth); + // TODO + // hash.Add(level_count); + hash.Add(layer_count); hash.Add(stride); hash.Add(ToTextureTypeCompatibility(type)); diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.hpp b/src/core/hw/tegra_x1/gpu/renderer/const.hpp index c19824d2..83cf1a53 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.hpp @@ -220,7 +220,11 @@ struct TextureDescriptor { u32 width; u32 height; u32 depth; + u32 level_count; + u32 layer_count; + u32 block_width_log2; u32 block_height_log2; + u32 block_depth_log2; u32 stride; SwizzleChannels swizzle_channels; // TODO: more @@ -228,25 +232,33 @@ struct TextureDescriptor { TextureDescriptor(const uptr ptr_, const TextureType type_, const TextureFormat format_, const NvKind kind_, const u32 width_, const u32 height_, const u32 depth_, - const u32 block_height_log2_, const u32 stride_, + const u32 level_count_, const u32 layer_count_, + const u32 block_width_log2_, const u32 block_height_log2_, + const u32 block_depth_log2_, const u32 stride_, const SwizzleChannels& swizzle_channels_) : ptr{ptr_}, type{type_}, format{format_}, kind{kind_}, width{width_}, - height{height_}, depth{depth_}, block_height_log2{block_height_log2_}, - stride{stride_}, swizzle_channels{swizzle_channels_} {} + height{height_}, depth{depth_}, level_count{level_count_}, + layer_count{layer_count_}, block_width_log2{block_width_log2_}, + block_height_log2{block_height_log2_}, + block_depth_log2{block_depth_log2_}, stride{stride_}, + swizzle_channels{swizzle_channels_} {} TextureDescriptor(const uptr ptr_, const TextureType type_, const TextureFormat format_, const NvKind kind_, const u32 width_, const u32 height_, const u32 depth_, - const u32 block_height_log2_, const u32 stride_) + const u32 level_count_, const u32 layer_count_, + const u32 block_width_log2_, const u32 block_height_log2_, + const u32 block_depth_log2_, const u32 stride_) : TextureDescriptor( ptr_, type_, format_, kind_, width_, height_, depth_, - block_height_log2_, stride_, + level_count_, layer_count_, block_width_log2_, block_height_log2_, + block_depth_log2_, stride_, get_texture_format_default_swizzle_channels(format_)) {} - u64 GetLayerSizeInBytes() const { return height * stride; } - u64 GetSizeInBytes() const { return depth * GetLayerSizeInBytes(); } + u32 GetLayerSize() const { return depth * align(height, 16u) * stride; } + u32 GetSize() const { return layer_count * GetLayerSize(); } Range GetRange() const { - return Range::FromSize(ptr, GetSizeInBytes()); + return Range::FromSize(ptr, GetSize()); } u32 GetHash() const; diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp index 0f228953..6cb9c892 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp @@ -15,26 +15,30 @@ Texture::Texture(const TextureDescriptor& descriptor) desc->setTextureType(type); desc->setWidth(descriptor.width); desc->setHeight(descriptor.height); + desc->setDepth(descriptor.depth); + // TODO + // desc->setMipmapLevelCount(descriptor.level_count); desc->setStorageMode(MTL::StorageModePrivate); switch (descriptor.type) { case TextureType::_1DArray: case TextureType::_2DArray: - desc->setArrayLength(descriptor.depth); + desc->setArrayLength(descriptor.layer_count); break; - case TextureType::CubeArray: - // TODO: correct? - ASSERT_DEBUG(descriptor.depth % 6 == 0, MetalRenderer, - "Invalid cube array depth {}", descriptor.depth); - desc->setArrayLength(descriptor.depth / 6); + case TextureType::Cube: + ASSERT_DEBUG(descriptor.layer_count == 6, MetalRenderer, + "Invalid cube layer count {}", descriptor.layer_count); break; - case TextureType::_3D: - desc->setDepth(descriptor.depth); + case TextureType::CubeArray: + ASSERT_DEBUG(descriptor.layer_count % 6 == 0, MetalRenderer, + "Invalid cube array layer count {}", + descriptor.layer_count); + desc->setArrayLength(descriptor.layer_count / 6); break; default: - ASSERT_DEBUG(descriptor.depth == 1, MetalRenderer, - "Invalid depth {} for type {}", descriptor.depth, - descriptor.type); + ASSERT_DEBUG(descriptor.layer_count == 1, MetalRenderer, + "Invalid {} layer count {}", descriptor.type, + descriptor.layer_count); break; } @@ -86,72 +90,73 @@ TextureBase* Texture::CreateView(const TextureViewDescriptor& descriptor) { } void Texture::CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, - const usize src_stride, uint3 dst_origin, usize3 size) { + const uint3 dst_origin, const usize3 size, + const Range levels, const Range layers) { const auto command_buffer_impl = static_cast(command_buffer); const auto mtl_src = static_cast(src)->GetBuffer(); auto encoder = command_buffer_impl->GetBlitCommandEncoder(); - u32 dst_layer = 0; - u32 layer_count = 1; - if (descriptor.type != TextureType::_3D) { - dst_layer = dst_origin.z(); - dst_origin.z() = 0; - layer_count = static_cast(size.z()); - size.z() = 1; - } - - const auto bytes_per_image = descriptor.depth * src_stride; - for (u32 i = 0; i < layer_count; i++) { - const auto crnt_dst_layer = dst_layer + i; - encoder->copyFromBuffer( - mtl_src, crnt_dst_layer * bytes_per_image, src_stride, - bytes_per_image, MTL::Size(size.x(), size.y(), size.z()), texture, - crnt_dst_layer, 0, - MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); + // TODO: bytes per image + for (u32 layer = layers.GetBegin(); layer < layers.GetEnd(); layer++) { + for (u32 level = levels.GetBegin(); level < levels.GetEnd(); level++) { + encoder->copyFromBuffer( + mtl_src, + layer * descriptor.GetLayerSize() + + /*descriptor.GetLevelOffset(level)*/ 0, + descriptor.stride, + align(descriptor.height, 16u) * descriptor.stride, + MTL::Size(size.x(), size.y(), size.z()), texture, layer, level, + MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); + } } } void Texture::CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, - uint3 src_origin, uint3 dst_origin, usize3 size) { + const uint3 src_origin, const u32 src_level, + const u32 src_layer, const uint3 dst_origin, + const u32 dst_level, const u32 dst_layer, + const usize3 size, const u32 level_count, + const u32 layer_count) { const auto command_buffer_impl = static_cast(command_buffer); const auto mtl_src = static_cast(src)->GetTexture(); auto encoder = command_buffer_impl->GetBlitCommandEncoder(); - u32 src_layer = 0; - u32 dst_layer = 0; - u32 layer_count = 1; - if (descriptor.type != TextureType::_3D) { - dst_layer = dst_origin.z(); - dst_origin.z() = 0; - } - - if (src->GetDescriptor().type != TextureType::_3D) { - src_layer = src_origin.z(); - src_origin.z() = 0; - } - - if (descriptor.type != TextureType::_3D || - src->GetDescriptor().type != TextureType::_3D) { - layer_count = static_cast(size.z()); - size.z() = 1; - } - for (u32 i = 0; i < layer_count; i++) { - encoder->copyFromTexture( - mtl_src, src_layer + i, 0, - MTL::Origin(src_origin.x(), src_origin.y(), src_origin.z()), - MTL::Size(size.x(), size.y(), size.z()), texture, dst_layer + i, 0, - MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); + for (u32 j = 0; j < level_count; j++) { + encoder->copyFromTexture( + mtl_src, src_layer + i, src_level + j, + MTL::Origin(src_origin.x(), src_origin.y(), src_origin.z()), + MTL::Size(size.x(), size.y(), size.z()), texture, dst_layer + i, + dst_level + j, + MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); + } } } void Texture::BlitFrom(ICommandBuffer* command_buffer, const TextureBase* src, const float3 src_origin, const usize3 src_size, - const float3 dst_origin, const usize3 dst_size) { + const u32 src_level, const u32 src_layer, + const float3 dst_origin, const usize3 dst_size, + const u32 dst_level, const u32 dst_layer, + const u32 level_count, const u32 layer_count) { + // TODO: support a wider range of parameters + ASSERT_DEBUG(src_level == 0, MetalRenderer, "Unsupported source level {}", + src_level); + ASSERT_DEBUG(src_layer == 0, MetalRenderer, "Unsupported source layer {}", + src_layer); + ASSERT_DEBUG(dst_level == 0, MetalRenderer, + "Unsupported destination level {}", dst_level); + ASSERT_DEBUG(dst_layer == 0, MetalRenderer, + "Unsupported destination layer {}", dst_layer); + ASSERT_DEBUG(level_count == 1, MetalRenderer, "Unsupported level_count {}", + level_count); + ASSERT_DEBUG(layer_count == 1, MetalRenderer, "Unsupported layer_count {}", + layer_count); + const auto command_buffer_impl = static_cast(command_buffer); METAL_RENDERER_INSTANCE.BlitTexture( @@ -173,29 +178,10 @@ MTL::Texture* Texture::CreateViewImpl(TextureFormat format, swizzle_components[pixel_format_info.component_indices[2]], swizzle_components[pixel_format_info.component_indices[3]]); - // TODO: ranges and levels - - u32 levels = 1; - switch (descriptor.type) { - case TextureType::_1DArray: - case TextureType::_2DArray: - case TextureType::CubeArray: - levels = descriptor.depth; - break; - case TextureType::Cube: - // TODO: assert that depth is 6 - levels = 6; - break; - case TextureType::_3D: - // TODO: assert that depth matches - break; - default: - break; - } - return base_texture->newTextureView( to_mtl_pixel_format(format), ToMtlTextureType(this->descriptor.type), - NS::Range(0, 1), NS::Range(0, levels), swizzle_channels_mtl); + NS::Range(0, 1), NS::Range(0, descriptor.layer_count), + swizzle_channels_mtl); } } // namespace hydra::hw::tegra_x1::gpu::renderer::metal diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp index 475d111e..3f4f2fc5 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp @@ -15,16 +15,21 @@ class Texture final : public TextureBase { // Copying void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, - const usize src_stride, const uint3 dst_origin, - const usize3 size) override; + const uint3 dst_origin, const usize3 size, + const Range levels, const Range layers) override; void CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, - const uint3 src_origin, const uint3 dst_origin, - const usize3 size) override; + const uint3 src_origin, const u32 src_level, + const u32 src_layer, const uint3 dst_origin, + const u32 dst_level, const u32 dst_layer, const usize3 size, + const u32 level_count, const u32 layer_count) override; // Blitting void BlitFrom(ICommandBuffer* command_buffer, const TextureBase* src, const float3 src_origin, const usize3 src_size, - const float3 dst_origin, const usize3 dst_size) override; + const u32 src_level, const u32 src_layer, + const float3 dst_origin, const usize3 dst_size, + const u32 dst_level, const u32 dst_layer, + const u32 level_count, const u32 layer_count) override; private: bool owns_base{false}; diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp index 7faa779c..e924c08e 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp @@ -18,21 +18,30 @@ class TextureBase { // Copying virtual void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, - const usize src_stride, const uint3 dst_origin, - const usize3 size) = 0; + const uint3 dst_origin, const usize3 size, + const Range levels, const Range layers) = 0; void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src) { - CopyFrom(command_buffer, src, descriptor.stride, uint3({0, 0, 0}), - usize3({descriptor.width, descriptor.height, 1})); + CopyFrom( + command_buffer, src, uint3({0, 0, 0}), + usize3({descriptor.width, descriptor.height, descriptor.depth}), + Range(0, descriptor.level_count), + Range(0, descriptor.layer_count)); } virtual void CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, const uint3 src_origin, - const uint3 dst_origin, const usize3 size) = 0; + const u32 src_level, const u32 src_layer, + const uint3 dst_origin, const u32 dst_level, + const u32 dst_layer, const usize3 size, + const u32 level_count, const u32 layer_count) = 0; // Blitting virtual void BlitFrom(ICommandBuffer* command_buffer, const TextureBase* src, const float3 src_origin, - const usize3 src_size, const float3 dst_origin, - const usize3 dst_size) = 0; + const usize3 src_size, const u32 src_level, + const u32 src_layer, const float3 dst_origin, + const usize3 dst_size, const u32 dst_level, + const u32 dst_layer, const u32 level_count, + const u32 layer_count) = 0; // Getters const TextureDescriptor& GetDescriptor() const { return descriptor; } diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index 604839d9..ff7411b1 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -102,7 +102,6 @@ TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, const TextureDescriptor& descriptor, TextureUsage usage) { const auto range = descriptor.GetRange(); - const auto layer_size = descriptor.GetLayerSizeInBytes(); // Check if it is a new entry auto sparse_tex_opt = mem.cache.Find(descriptor.GetHash()); @@ -129,10 +128,10 @@ TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, if (group.base->GetDescriptor().GetRange().Contains(range)) { const auto offset = static_cast( range.GetBegin() - group.base->GetDescriptor().ptr); - ASSERT_ALIGNMENT_DEBUG(offset, layer_size, Gpu, + ASSERT_ALIGNMENT_DEBUG(offset, descriptor.GetLayerSize(), Gpu, "texture view offset"); - const auto layers = - Range::FromSize(offset / layer_size, descriptor.depth); + const auto layers = Range::FromSize( + offset / descriptor.GetLayerSize(), descriptor.GetLayerSize()); return GetTextureView( group, TextureViewDescriptor(descriptor.format, descriptor.swizzle_channels, @@ -235,9 +234,10 @@ TextureBase* TextureCache::GetTexture(ICommandBuffer* command_buffer, } // Otherwise, get a texture view - auto view_desc = TextureViewDescriptor( - descriptor.format, descriptor.swizzle_channels, Range(0, 1), - Range(0, descriptor.depth)); + auto view_desc = + TextureViewDescriptor(descriptor.format, descriptor.swizzle_channels, + Range(0, descriptor.level_count), + Range(0, descriptor.layer_count)); return GetTextureView(group, view_desc); } @@ -274,7 +274,6 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, const auto base = group.base; const auto& descriptor = base->GetDescriptor(); const auto range = descriptor.GetRange(); - const auto layer_size = descriptor.GetLayerSizeInBytes(); for (auto& [key, sparse_tex] : mem.cache) { // TODO: skip this sparse texture @@ -286,6 +285,7 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, // Check if the textures can actually be copied if (other_descriptor.width != descriptor.width || other_descriptor.height != descriptor.height || + other_descriptor.depth != descriptor.depth || other_descriptor.stride != descriptor.stride) continue; @@ -295,24 +295,24 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, copy_range.GetBegin() - range.GetBegin(); // Check if the textures are aligned properly - if (dst_offset % layer_size != 0x0) + if (dst_offset % descriptor.GetLayerSize() != 0x0) continue; // Now copy const auto src_layer = static_cast( (copy_range.GetBegin() - other_range.GetBegin()) / - layer_size); - const auto dst_layer = - static_cast(dst_offset / layer_size); - const auto layer_count = - static_cast(copy_range.GetSize() / layer_size); + descriptor.GetLayerSize()); + const auto dst_layer = static_cast( + dst_offset / descriptor.GetLayerSize()); + const auto layer_count = static_cast( + copy_range.GetSize() / descriptor.GetLayerSize()); // TODO: make sure the formats match - base->CopyFrom(command_buffer, other_base, - uint3({0, 0, src_layer}), - uint3({0, 0, dst_layer}), + base->CopyFrom(command_buffer, other_base, uint3({0, 0, 0}), + 0, src_layer, uint3({0, 0, 0}), 0, dst_layer, usize3({descriptor.width, descriptor.height, - layer_count})); + descriptor.depth}), + descriptor.level_count, layer_count); } } } @@ -359,8 +359,8 @@ void TextureCache::DecodeTexture(ICommandBuffer* command_buffer, const auto& descriptor = group.base->GetDescriptor(); // Align the height to 16 bytes (TODO: why 16?) - auto tmp_buffer = RENDERER_INSTANCE.AllocateTemporaryBuffer( - descriptor.depth * align(descriptor.height, 16u) * descriptor.stride); + auto tmp_buffer = + RENDERER_INSTANCE.AllocateTemporaryBuffer(descriptor.GetSize()); texture_decoder.Decode(descriptor, (u8*)tmp_buffer->GetPtr()); group.base->CopyFrom(command_buffer, tmp_buffer); RENDERER_INSTANCE.FreeTemporaryBuffer(tmp_buffer); diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp index 3c4ade5a..3a730081 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp @@ -14,12 +14,12 @@ void TextureDecoder::Decode(const TextureDescriptor& descriptor, u8* out_data) { switch (descriptor.kind) { case NvKind::Pitch: case NvKind::PitchNoSwizzle: - std::memcpy(out_data, in_data, - descriptor.depth * descriptor.height * descriptor.stride); + std::memcpy(out_data, in_data, descriptor.GetSize()); break; default: decode_generic_16bx2(descriptor.stride, - descriptor.depth * descriptor.height, + descriptor.layer_count * descriptor.depth * + descriptor.height, descriptor.block_height_log2, in_data, out_data); break; } From 49f63f1b56149ca00e805a93772a72f03eed7917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Fri, 3 Apr 2026 09:51:38 +0200 Subject: [PATCH 07/17] renderer: fix 3D texture copying --- .../tegra_x1/gpu/renderer/metal/texture.cpp | 8 +- .../tegra_x1/gpu/renderer/texture_cache.cpp | 95 +++++++++++++++---- 2 files changed, 79 insertions(+), 24 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp index 6cb9c892..207730f5 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp @@ -125,13 +125,15 @@ void Texture::CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, auto encoder = command_buffer_impl->GetBlitCommandEncoder(); + // TODO: levels + (void)level_count; for (u32 i = 0; i < layer_count; i++) { - for (u32 j = 0; j < level_count; j++) { + for (u32 j = 0; j < /*level_count*/ 1; j++) { encoder->copyFromTexture( - mtl_src, src_layer + i, src_level + j, + mtl_src, src_layer + i, src_level /* + j*/, MTL::Origin(src_origin.x(), src_origin.y(), src_origin.z()), MTL::Size(size.x(), size.y(), size.z()), texture, dst_layer + i, - dst_level + j, + dst_level /* + j*/, MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); } } diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index ff7411b1..bc664018 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -131,7 +131,7 @@ TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, ASSERT_ALIGNMENT_DEBUG(offset, descriptor.GetLayerSize(), Gpu, "texture view offset"); const auto layers = Range::FromSize( - offset / descriptor.GetLayerSize(), descriptor.GetLayerSize()); + offset / descriptor.GetLayerSize(), descriptor.layer_count); return GetTextureView( group, TextureViewDescriptor(descriptor.format, descriptor.swizzle_channels, @@ -285,7 +285,6 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, // Check if the textures can actually be copied if (other_descriptor.width != descriptor.width || other_descriptor.height != descriptor.height || - other_descriptor.depth != descriptor.depth || other_descriptor.stride != descriptor.stride) continue; @@ -294,25 +293,79 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, const auto dst_offset = copy_range.GetBegin() - range.GetBegin(); - // Check if the textures are aligned properly - if (dst_offset % descriptor.GetLayerSize() != 0x0) - continue; - - // Now copy - const auto src_layer = static_cast( - (copy_range.GetBegin() - other_range.GetBegin()) / - descriptor.GetLayerSize()); - const auto dst_layer = static_cast( - dst_offset / descriptor.GetLayerSize()); - const auto layer_count = static_cast( - copy_range.GetSize() / descriptor.GetLayerSize()); - - // TODO: make sure the formats match - base->CopyFrom(command_buffer, other_base, uint3({0, 0, 0}), - 0, src_layer, uint3({0, 0, 0}), 0, dst_layer, - usize3({descriptor.width, descriptor.height, - descriptor.depth}), - descriptor.level_count, layer_count); + if (descriptor.type != TextureType::_3D && + other_descriptor.type != + TextureType::_3D) { // Neither 3D + // Layer + const auto src_layer = static_cast( + (copy_range.GetBegin() - other_range.GetBegin()) / + descriptor.GetLayerSize()); + const auto dst_layer = static_cast( + dst_offset / descriptor.GetLayerSize()); + const auto layer_count = static_cast( + copy_range.GetSize() / descriptor.GetLayerSize()); + + // Copy + // TODO: make sure the formats match + base->CopyFrom( + command_buffer, other_base, uint3({0, 0, 0}), 0, + src_layer, uint3({0, 0, 0}), 0, dst_layer, + usize3({descriptor.width, descriptor.height, 1}), + std::min(descriptor.level_count, + other_descriptor.level_count), + layer_count); + } else if (descriptor.type == TextureType::_3D && + other_descriptor.type == + TextureType::_3D) { // Both 3D + const auto slice_size = + descriptor.height * + descriptor.stride; // TODO: calculate properly + + // Z + const auto src_z = static_cast( + (copy_range.GetBegin() - other_range.GetBegin()) / + slice_size); + const auto dst_z = + static_cast(dst_offset / slice_size); + const auto z_count = + static_cast(copy_range.GetSize() / slice_size); + + // Copy + // TODO: make sure the formats match + base->CopyFrom(command_buffer, other_base, + uint3({0, 0, src_z}), 0, 0, + uint3({0, 0, dst_z}), 0, 0, + usize3({descriptor.width, + descriptor.height, z_count}), + std::min(descriptor.level_count, + other_descriptor.level_count), + 1); + } else if (descriptor.type == TextureType::_3D && + other_descriptor.type == + TextureType::_2D) { // HACK: special case + const auto slice_size = + descriptor.height * + descriptor.stride; // TODO: calculate properly + + // Z + const auto dst_z = + static_cast(dst_offset / slice_size); + + // Copy + // TODO: make sure the formats match + base->CopyFrom( + command_buffer, other_base, uint3({0, 0, 0}), 0, 0, + uint3({0, 0, dst_z}), 0, 0, + usize3({descriptor.width, descriptor.height, 1}), + std::min(descriptor.level_count, + other_descriptor.level_count), + 1); + } else { + LOG_WARN(Gpu, + "Unimplemented texture copy (source: {}, " + "destination: {})", + descriptor.type, other_descriptor.type); + } } } } From 6eb8732956eaeb438a5971c226050433d909f5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Fri, 3 Apr 2026 12:51:43 +0200 Subject: [PATCH 08/17] gpu: rework texture stride --- src/core/CMakeLists.txt | 2 - src/core/c_api.cpp | 2 +- src/core/emulation_context.cpp | 18 ++-- src/core/hw/tegra_x1/gpu/engines/2d.cpp | 11 ++- src/core/hw/tegra_x1/gpu/engines/3d.cpp | 86 +++++++++++-------- src/core/hw/tegra_x1/gpu/engines/3d.hpp | 4 +- src/core/hw/tegra_x1/gpu/gpu.cpp | 15 ++-- src/core/hw/tegra_x1/gpu/renderer/const.cpp | 4 +- src/core/hw/tegra_x1/gpu/renderer/const.hpp | 72 ++++++++++------ .../tegra_x1/gpu/renderer/metal/texture.cpp | 8 +- .../tegra_x1/gpu/renderer/texture_cache.cpp | 40 ++++++--- .../tegra_x1/gpu/renderer/texture_cache.hpp | 3 +- .../tegra_x1/gpu/renderer/texture_decoder.cpp | 28 ------ .../tegra_x1/gpu/renderer/texture_decoder.hpp | 17 ---- 14 files changed, 168 insertions(+), 142 deletions(-) delete mode 100644 src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp delete mode 100644 src/core/hw/tegra_x1/gpu/renderer/texture_decoder.hpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ebd5be1b..4ef28efd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -555,8 +555,6 @@ add_library(hydra-core hw/tegra_x1/gpu/renderer/buffer_cache.cpp hw/tegra_x1/gpu/renderer/buffer_cache.hpp hw/tegra_x1/gpu/renderer/texture_base.hpp - hw/tegra_x1/gpu/renderer/texture_decoder.cpp - hw/tegra_x1/gpu/renderer/texture_decoder.hpp hw/tegra_x1/gpu/renderer/texture_cache.cpp hw/tegra_x1/gpu/renderer/texture_cache.hpp hw/tegra_x1/gpu/renderer/sampler_base.hpp diff --git a/src/core/c_api.cpp b/src/core/c_api.cpp index 9cc68d96..e0791878 100644 --- a/src/core/c_api.cpp +++ b/src/core/c_api.cpp @@ -1112,7 +1112,7 @@ hydra_texture_descriptor_get_layer_size(const void* descriptor) { return static_cast< const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( descriptor) - ->GetLayerSize(); + ->layer_size; } HYDRA_EXPORT uint64_t diff --git a/src/core/emulation_context.cpp b/src/core/emulation_context.cpp index a1e001e3..9367ba3b 100644 --- a/src/core/emulation_context.cpp +++ b/src/core/emulation_context.cpp @@ -281,9 +281,12 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { const u32 size = height * stride; hw::tegra_x1::gpu::renderer::TextureDescriptor descriptor( 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, - hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, - hw::tegra_x1::gpu::NvKind::Generic_16BX2, width, height, 1, 1, - 1, 0x0, 0x0, 0x0, stride); + hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, true, + stride, width, height, 1, 1, 1, 0x0, 0x0, 0x0, + hw::tegra_x1::gpu::renderer:: + get_texture_format_default_swizzle_channels( + hw::tegra_x1::gpu::renderer::TextureFormat:: + RGBA8Unorm)); nintendo_logo = gpu->GetRenderer().CreateTexture(descriptor); // Command buffer @@ -307,9 +310,12 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { const u32 size = height * stride; hw::tegra_x1::gpu::renderer::TextureDescriptor descriptor( 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, - hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, - hw::tegra_x1::gpu::NvKind::Generic_16BX2, width, height, 1, 1, - 1, 0x0, 0x0, 0x0, stride); + hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, true, + stride, width, height, 1, 1, 1, 0x0, 0x0, 0x0, + hw::tegra_x1::gpu::renderer:: + get_texture_format_default_swizzle_channels( + hw::tegra_x1::gpu::renderer::TextureFormat:: + RGBA8Unorm)); startup_movie.reserve(frame_count); // Command buffer diff --git a/src/core/hw/tegra_x1/gpu/engines/2d.cpp b/src/core/hw/tegra_x1/gpu/engines/2d.cpp index f3c41cbb..7fccec7e 100644 --- a/src/core/hw/tegra_x1/gpu/engines/2d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/2d.cpp @@ -40,15 +40,14 @@ void TwoD::Copy(const u32 index, const u32 pixels_from_memory_src_y0_int) { renderer::TextureBase* TwoD::GetTexture(const Texture2DInfo& info, renderer::TextureUsage usage) { + // TODO: layer const renderer::TextureDescriptor descriptor( tls_crnt_gmmu->UnmapAddr(info.addr), renderer::TextureType::_2D, renderer::to_texture_format(info.format), - NvKind::Pitch, // TODO: correct? - u32(info.width), u32(info.height), 1, 1, 1, 0x0, 0x0, 0x0, // HACK - /*u32(info.stride)*/ - renderer::get_texture_format_stride( - renderer::to_texture_format(info.format), info.width) // HACK - ); + info.layout == MemoryLayout::Pitch, info.stride, info.width, + info.height, 1, 1, info.depth, 0x0, 0x0, 0x0, // HACK + renderer::get_texture_format_default_swizzle_channels( + renderer::to_texture_format(info.format))); return RENDERER_INSTANCE.GetTextureCache().Find(tls_crnt_command_buffer, descriptor, usage); diff --git a/src/core/hw/tegra_x1/gpu/engines/3d.cpp b/src/core/hw/tegra_x1/gpu/engines/3d.cpp index e184278e..f058e1c6 100644 --- a/src/core/hw/tegra_x1/gpu/engines/3d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/3d.cpp @@ -4,6 +4,7 @@ #include "core/hw/tegra_x1/gpu/gpu.hpp" #include "core/hw/tegra_x1/gpu/macro/interpreter/driver.hpp" #include "core/hw/tegra_x1/gpu/renderer/buffer_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/const.hpp" #include "core/hw/tegra_x1/gpu/renderer/render_pass_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/sampler_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/shader_base.hpp" @@ -186,9 +187,8 @@ renderer::BlendFactor get_blend_factor(u32 blend_factor) { // Render target width is aligned to the stride, lets try to figure out the real // one -u32 GetMinimumWidth(u32 width, renderer::TextureFormat format, u32 width_hint, - bool is_linear) { - if (is_linear || width <= width_hint) +u32 GetMinimumWidth(u32 width, renderer::TextureFormat format, u32 width_hint) { + if (width <= width_hint) return width; // Get the smallest width that would still align up to the same GOB @@ -458,17 +458,41 @@ ThreeD::GetColorTargetTexture(u32 render_target_index) const { } const auto format = renderer::to_texture_format(render_target.format); - const u32 width_hint = - regs.screen_scissor.horizontal.x + regs.screen_scissor.horizontal.width; + + // Depth and layer count + auto type = renderer::TextureType::_2D; + u32 depth = 1; + u32 layer_count = 1; + if (render_target.tile_mode.is_3d) { + type = renderer::TextureType::_3D; + depth = render_target.array_mode.layers; + } else { + layer_count = render_target.array_mode.layers; + if (layer_count > 1) + type = renderer::TextureType::_2DArray; + } + + // Width and stride + const bool is_linear = render_target.tile_mode.is_linear; + u32 width, stride; + if (is_linear) { + width = render_target.width_or_stride / + renderer::get_texture_format_bpp(format); + stride = render_target.width_or_stride; + } else { + const u32 width_hint = regs.screen_scissor.horizontal.x + + regs.screen_scissor.horizontal.width; + width = + GetMinimumWidth(render_target.width_or_stride, format, width_hint); + stride = 0; + } + const renderer::TextureDescriptor descriptor( - tls_crnt_gmmu->UnmapAddr(gpu_addr), renderer::TextureType::_2D, format, - NvKind::Pitch, // TODO: correct? - GetMinimumWidth(render_target.width, format, width_hint, - render_target.tile_mode.is_linear), - render_target.height, 1, 1, render_target.array_mode.layers, + tls_crnt_gmmu->UnmapAddr(gpu_addr), type, format, is_linear, stride, + width, render_target.height, depth, layer_count, render_target.tile_mode.width, render_target.tile_mode.height, render_target.tile_mode.depth, - get_texture_format_stride(format, render_target.width)); + !is_linear ? render_target.layer_stride * 4 : 0); return RENDERER_INSTANCE.GetTextureCache().Find( tls_crnt_command_buffer, descriptor, renderer::TextureUsage::Write); @@ -482,17 +506,17 @@ renderer::TextureBase* ThreeD::GetDepthStencilTargetTexture() const { return nullptr; } - const auto format = renderer::to_texture_format(regs.depth_target_format); - const u32 width_hint = - regs.screen_scissor.horizontal.x + regs.screen_scissor.horizontal.width; + const auto type = regs.depth_target_array_mode.layers > 1 + ? renderer::TextureType::_2DArray + : renderer::TextureType::_2D; + const renderer::TextureDescriptor descriptor( - tls_crnt_gmmu->UnmapAddr(gpu_addr), renderer::TextureType::_2D, format, - NvKind::Pitch, // TODO: correct? - GetMinimumWidth(regs.depth_target_width, format, width_hint, false), - regs.depth_target_height, 1, 1, regs.depth_target_array_mode.layers, - regs.depth_target_tile_mode.width, regs.depth_target_tile_mode.height, - regs.depth_target_tile_mode.depth, - get_texture_format_stride(format, regs.depth_target_width)); + tls_crnt_gmmu->UnmapAddr(gpu_addr), type, + renderer::to_texture_format(regs.depth_target_format), false, 0, + regs.depth_target_width, regs.depth_target_height, 1, + regs.depth_target_array_mode.layers, regs.depth_target_tile_mode.width, + regs.depth_target_tile_mode.height, regs.depth_target_tile_mode.depth, + regs.depth_target_layer_stride * 4); return RENDERER_INSTANCE.GetTextureCache().Find( tls_crnt_command_buffer, descriptor, renderer::TextureUsage::Write); @@ -760,23 +784,17 @@ ThreeD::GetTexture(const TextureImageControl& tic) const { const auto format = renderer::to_texture_format(tic.format_word, tic.is_srgb); - NvKind kind; - u32 stride; + bool is_linear = false; + u32 linear_stride = 0; switch (tic.hdr_version) { case TicHdrVersion::Pitch: - kind = NvKind::Pitch; - stride = static_cast(tic.pitch_5_20) << 5u; + is_linear = true; + linear_stride = static_cast(tic.pitch_5_20) << 5u; break; case TicHdrVersion::BlockLinear: - kind = NvKind::Generic_16BX2; - // TODO: is the alignment correct? - stride = align( - get_texture_format_stride(format, tic.width_minus_one + 1), 64u); break; default: LOG_NOT_IMPLEMENTED(Engines, "TIC HDR version {}", tic.hdr_version); - kind = NvKind::Pitch; - stride = get_texture_format_stride(format, tic.width_minus_one + 1); break; } @@ -793,10 +811,10 @@ ThreeD::GetTexture(const TextureImageControl& tic) const { } const renderer::TextureDescriptor descriptor( - tls_crnt_gmmu->UnmapAddr(gpu_addr), type, format, kind, - tic.width_minus_one + 1, tic.height_minus_one + 1, depth, + tls_crnt_gmmu->UnmapAddr(gpu_addr), type, format, is_linear, + linear_stride, tic.width_minus_one + 1, tic.height_minus_one + 1, depth, tic.mip_max_levels + 1, layer_count, tic.tile_width_gobs_log2, - tic.tile_height_gobs_log2, tic.tile_depth_gobs_log2, stride, + tic.tile_height_gobs_log2, tic.tile_depth_gobs_log2, renderer::SwizzleChannels( format, tic.format_word.swizzle_x, tic.format_word.swizzle_y, tic.format_word.swizzle_z, tic.format_word.swizzle_w)); diff --git a/src/core/hw/tegra_x1/gpu/engines/3d.hpp b/src/core/hw/tegra_x1/gpu/engines/3d.hpp index 5c6b4684..1a679b98 100644 --- a/src/core/hw/tegra_x1/gpu/engines/3d.hpp +++ b/src/core/hw/tegra_x1/gpu/engines/3d.hpp @@ -154,7 +154,7 @@ struct TextureSamplerControl { struct RenderTarget { Iova addr; - u32 width; + u32 width_or_stride; u32 height; ColorSurfaceFormat format; struct { @@ -169,7 +169,7 @@ struct RenderTarget { u16 layers; bool volume : 1; // TODO: what is this? } array_mode; - u32 array_pitch; + u32 layer_stride; u32 base_layer; u32 mark; // TODO: what is this? u32 padding[6]; diff --git a/src/core/hw/tegra_x1/gpu/gpu.cpp b/src/core/hw/tegra_x1/gpu/gpu.cpp index a80a6a53..47be18a8 100644 --- a/src/core/hw/tegra_x1/gpu/gpu.cpp +++ b/src/core/hw/tegra_x1/gpu/gpu.cpp @@ -84,19 +84,24 @@ renderer::TextureBase* Gpu::GetTexture(renderer::ICommandBuffer* command_buffer, const NvGraphicsBuffer& buff) { std::lock_guard texture_cache_lock(renderer->GetTextureCache().GetMutex()); + const auto& plane = buff.planes[0]; + LOG_DEBUG(Gpu, "Map id: {}, width: {}, " "height: {}", - buff.nvmap_id, buff.planes[0].width, buff.planes[0].height); + buff.nvmap_id, plane.width, plane.height); + + const bool is_linear = + (plane.kind == NvKind::Pitch || plane.kind == NvKind::PitchNoSwizzle); // TODO: why are there more planes? renderer::TextureDescriptor descriptor( mmu->UnmapAddr(GetMap(static_cast(buff.nvmap_id)).addr + - buff.planes[0].offset), + plane.offset), renderer::TextureType::_2D, - renderer::to_texture_format(buff.planes[0].color_format), - buff.planes[0].kind, buff.planes[0].width, buff.planes[0].height, 1, 1, - 1, 0x0, buff.planes[0].block_height_log2, 0x0, buff.planes[0].pitch); + renderer::to_texture_format(plane.color_format), is_linear, plane.pitch, + plane.width, plane.height, 1, 1, 0x0, plane.block_height_log2, 0x0, + static_cast(plane.size)); return renderer->GetTextureCache().Find(command_buffer, descriptor, renderer::TextureUsage::Present); diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.cpp b/src/core/hw/tegra_x1/gpu/renderer/const.cpp index ecb26a3f..6f6c1787 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.cpp @@ -653,13 +653,15 @@ get_texture_format_default_swizzle_channels(const TextureFormat format) { u32 TextureDescriptor::GetHash() const { HashCode hash; hash.Add(ptr); + hash.Add(is_linear); + hash.Add(linear_stride); hash.Add(width); hash.Add(height); hash.Add(depth); // TODO // hash.Add(level_count); hash.Add(layer_count); - hash.Add(stride); + hash.Add(layer_size); hash.Add(ToTextureTypeCompatibility(type)); diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.hpp b/src/core/hw/tegra_x1/gpu/renderer/const.hpp index 83cf1a53..1d930aec 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.hpp @@ -216,7 +216,8 @@ struct TextureDescriptor { uptr ptr; TextureType type; TextureFormat format; - NvKind kind; + bool is_linear; + u32 linear_stride; u32 width; u32 height; u32 depth; @@ -225,43 +226,66 @@ struct TextureDescriptor { u32 block_width_log2; u32 block_height_log2; u32 block_depth_log2; - u32 stride; + u32 layer_size; SwizzleChannels swizzle_channels; - // TODO: more TextureDescriptor(const uptr ptr_, const TextureType type_, - const TextureFormat format_, const NvKind kind_, - const u32 width_, const u32 height_, const u32 depth_, + const TextureFormat format_, const bool is_linear_, + const u32 linear_stride_, const u32 width_, + const u32 height_, const u32 depth_, const u32 level_count_, const u32 layer_count_, const u32 block_width_log2_, const u32 block_height_log2_, - const u32 block_depth_log2_, const u32 stride_, + const u32 block_depth_log2_, const SwizzleChannels& swizzle_channels_) - : ptr{ptr_}, type{type_}, format{format_}, kind{kind_}, width{width_}, - height{height_}, depth{depth_}, level_count{level_count_}, - layer_count{layer_count_}, block_width_log2{block_width_log2_}, + : ptr{ptr_}, type{type_}, format{format_}, is_linear{is_linear_}, + linear_stride{linear_stride_}, width{width_}, height{height_}, + depth{depth_}, level_count{level_count_}, layer_count{layer_count_}, + block_width_log2{block_width_log2_}, block_height_log2{block_height_log2_}, - block_depth_log2{block_depth_log2_}, stride{stride_}, - swizzle_channels{swizzle_channels_} {} + block_depth_log2{block_depth_log2_}, swizzle_channels{ + swizzle_channels_} { + layer_size = CalculateLayerSize(); + } TextureDescriptor(const uptr ptr_, const TextureType type_, - const TextureFormat format_, const NvKind kind_, - const u32 width_, const u32 height_, const u32 depth_, - const u32 level_count_, const u32 layer_count_, - const u32 block_width_log2_, const u32 block_height_log2_, - const u32 block_depth_log2_, const u32 stride_) - : TextureDescriptor( - ptr_, type_, format_, kind_, width_, height_, depth_, - level_count_, layer_count_, block_width_log2_, block_height_log2_, - block_depth_log2_, stride_, - get_texture_format_default_swizzle_channels(format_)) {} - - u32 GetLayerSize() const { return depth * align(height, 16u) * stride; } - u32 GetSize() const { return layer_count * GetLayerSize(); } + const TextureFormat format_, const bool is_linear_, + const u32 linear_stride_, const u32 width_, + const u32 height_, const u32 depth_, + const u32 layer_count_, const u32 block_width_log2_, + const u32 block_height_log2_, const u32 block_depth_log2_, + const u32 layer_size_ = 0) + : ptr{ptr_}, type{type_}, format{format_}, is_linear{is_linear_}, + linear_stride{linear_stride_}, width{width_}, height{height_}, + depth{depth_}, layer_count{layer_count_}, + block_width_log2{block_width_log2_}, + block_height_log2{block_height_log2_}, + block_depth_log2{block_depth_log2_}, layer_size{layer_size_}, + swizzle_channels{ + get_texture_format_default_swizzle_channels(format_)} { + // HACK + level_count = 1; + + if (layer_size == 0) + layer_size = CalculateLayerSize(); + } + + u32 GetSize() const { return layer_count * layer_size; } Range GetRange() const { return Range::FromSize(ptr, GetSize()); } u32 GetHash() const; + + private: + u32 CalculateLayerSize() const { + // HACK + if (is_linear) { + return depth * align(height, 16u) * linear_stride; + } else { + return depth * align(height, 16u) * + align(get_texture_format_stride(format, width), 64u); + } + } }; struct TextureViewDescriptor { diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp index 207730f5..005be0f3 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp @@ -99,14 +99,16 @@ void Texture::CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, auto encoder = command_buffer_impl->GetBlitCommandEncoder(); // TODO: bytes per image + // TODO: don't align + const auto stride = align( + get_texture_format_stride(descriptor.format, descriptor.width), 64u); for (u32 layer = layers.GetBegin(); layer < layers.GetEnd(); layer++) { for (u32 level = levels.GetBegin(); level < levels.GetEnd(); level++) { encoder->copyFromBuffer( mtl_src, - layer * descriptor.GetLayerSize() + + layer * descriptor.layer_size + /*descriptor.GetLevelOffset(level)*/ 0, - descriptor.stride, - align(descriptor.height, 16u) * descriptor.stride, + stride, descriptor.height * stride, MTL::Size(size.x(), size.y(), size.z()), texture, layer, level, MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); } diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index bc664018..d0857069 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -1,6 +1,7 @@ #include "core/hw/tegra_x1/gpu/renderer/texture_cache.hpp" #include "core/hw/tegra_x1/gpu/gpu.hpp" +#include "core/hw/tegra_x1/gpu/memory_util.hpp" #include "core/hw/tegra_x1/gpu/renderer/buffer_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/const.hpp" #include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" @@ -128,10 +129,10 @@ TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, if (group.base->GetDescriptor().GetRange().Contains(range)) { const auto offset = static_cast( range.GetBegin() - group.base->GetDescriptor().ptr); - ASSERT_ALIGNMENT_DEBUG(offset, descriptor.GetLayerSize(), Gpu, + ASSERT_ALIGNMENT_DEBUG(offset, descriptor.layer_size, Gpu, "texture view offset"); const auto layers = Range::FromSize( - offset / descriptor.GetLayerSize(), descriptor.layer_count); + offset / descriptor.layer_size, descriptor.layer_count); return GetTextureView( group, TextureViewDescriptor(descriptor.format, descriptor.swizzle_channels, @@ -284,8 +285,7 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, // Check if the textures can actually be copied if (other_descriptor.width != descriptor.width || - other_descriptor.height != descriptor.height || - other_descriptor.stride != descriptor.stride) + other_descriptor.height != descriptor.height) continue; if (range.Intersects(other_range)) { @@ -299,11 +299,11 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, // Layer const auto src_layer = static_cast( (copy_range.GetBegin() - other_range.GetBegin()) / - descriptor.GetLayerSize()); + descriptor.layer_size); const auto dst_layer = static_cast( - dst_offset / descriptor.GetLayerSize()); + dst_offset / descriptor.layer_size); const auto layer_count = static_cast( - copy_range.GetSize() / descriptor.GetLayerSize()); + copy_range.GetSize() / descriptor.layer_size); // Copy // TODO: make sure the formats match @@ -319,7 +319,9 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, TextureType::_3D) { // Both 3D const auto slice_size = descriptor.height * - descriptor.stride; // TODO: calculate properly + align(get_texture_format_stride(descriptor.format, + descriptor.width), + 64u); // TODO: calculate properly // Z const auto src_z = static_cast( @@ -345,7 +347,9 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, TextureType::_2D) { // HACK: special case const auto slice_size = descriptor.height * - descriptor.stride; // TODO: calculate properly + align(get_texture_format_stride(descriptor.format, + descriptor.width), + 64u); // TODO: calculate properly // Z const auto dst_z = @@ -397,7 +401,7 @@ u32 TextureCache::GetDataHash(const TextureBase* texture) { constexpr u32 SAMPLE_COUNT = 37; const auto& descriptor = texture->GetDescriptor(); - u64 mem_range = descriptor.stride * descriptor.height; + u64 mem_range = descriptor.GetSize(); u64 mem_step = std::max(mem_range / SAMPLE_COUNT, 1ull); HashCode hash; @@ -414,7 +418,21 @@ void TextureCache::DecodeTexture(ICommandBuffer* command_buffer, // Align the height to 16 bytes (TODO: why 16?) auto tmp_buffer = RENDERER_INSTANCE.AllocateTemporaryBuffer(descriptor.GetSize()); - texture_decoder.Decode(descriptor, (u8*)tmp_buffer->GetPtr()); + + u8* in_data = reinterpret_cast(descriptor.ptr); + u8* out_data = reinterpret_cast(tmp_buffer->GetPtr()); + if (descriptor.is_linear) { + std::memcpy(out_data, in_data, descriptor.GetSize()); + } else { + // HACK + decode_generic_16bx2(align(get_texture_format_stride(descriptor.format, + descriptor.width), + 64u), + descriptor.layer_count * descriptor.depth * + descriptor.height, + descriptor.block_height_log2, in_data, out_data); + } + group.base->CopyFrom(command_buffer, tmp_buffer); RENDERER_INSTANCE.FreeTemporaryBuffer(tmp_buffer); } diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp index ced74f7f..06fd437b 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp @@ -1,6 +1,6 @@ #pragma once -#include "core/hw/tegra_x1/gpu/renderer/texture_decoder.hpp" +#include "core/hw/tegra_x1/gpu/renderer/const.hpp" namespace hydra::hw::tegra_x1::cpu { class IMmu; @@ -84,7 +84,6 @@ class TextureCache { private: std::mutex mutex; - TextureDecoder texture_decoder; std::map entries; diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp deleted file mode 100644 index 3a730081..00000000 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#include "core/hw/tegra_x1/gpu/renderer/texture_decoder.hpp" - -#include "core/hw/tegra_x1/gpu/memory_util.hpp" - -namespace hydra::hw::tegra_x1::gpu::renderer { - -TextureDecoder::TextureDecoder() {} -TextureDecoder::~TextureDecoder() {} - -void TextureDecoder::Decode(const TextureDescriptor& descriptor, u8* out_data) { - u8* in_data = reinterpret_cast(descriptor.ptr); - - // TODO: correct? - switch (descriptor.kind) { - case NvKind::Pitch: - case NvKind::PitchNoSwizzle: - std::memcpy(out_data, in_data, descriptor.GetSize()); - break; - default: - decode_generic_16bx2(descriptor.stride, - descriptor.layer_count * descriptor.depth * - descriptor.height, - descriptor.block_height_log2, in_data, out_data); - break; - } -} - -} // namespace hydra::hw::tegra_x1::gpu::renderer diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.hpp deleted file mode 100644 index 19b79f4b..00000000 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_decoder.hpp +++ /dev/null @@ -1,17 +0,0 @@ -#pragma once - -#include "core/hw/tegra_x1/gpu/renderer/const.hpp" - -namespace hydra::hw::tegra_x1::gpu::renderer { - -class TextureDecoder { - public: - TextureDecoder(); - ~TextureDecoder(); - - void Decode(const TextureDescriptor& descriptor, u8* out_data); - - private: -}; - -} // namespace hydra::hw::tegra_x1::gpu::renderer From feb5746b0ca31a18f3dea20d5ad2c072bfdf3285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Sun, 19 Apr 2026 08:54:49 +0200 Subject: [PATCH 09/17] renderer(wip): split texture and texture view --- src/core/CMakeLists.txt | 6 +- src/core/c_api.cpp | 35 ++-- src/core/c_api.h | 16 +- src/core/emulation_context.cpp | 82 +++++---- src/core/emulation_context.hpp | 12 +- src/core/horizon/display/layer.cpp | 9 +- src/core/horizon/display/layer.hpp | 4 +- src/core/hw/tegra_x1/gpu/engines/2d.cpp | 13 +- src/core/hw/tegra_x1/gpu/engines/2d.hpp | 6 +- src/core/hw/tegra_x1/gpu/engines/3d.cpp | 24 ++- src/core/hw/tegra_x1/gpu/engines/3d.hpp | 9 +- src/core/hw/tegra_x1/gpu/engines/copy.cpp | 1 - src/core/hw/tegra_x1/gpu/engines/copy.hpp | 1 - src/core/hw/tegra_x1/gpu/gpu.cpp | 8 +- src/core/hw/tegra_x1/gpu/gpu.hpp | 6 +- .../hw/tegra_x1/gpu/renderer/buffer_base.hpp | 7 +- .../hw/tegra_x1/gpu/renderer/buffer_view.hpp | 8 +- src/core/hw/tegra_x1/gpu/renderer/const.cpp | 52 +----- src/core/hw/tegra_x1/gpu/renderer/const.hpp | 119 ++++++------ .../hw/tegra_x1/gpu/renderer/metal/buffer.cpp | 30 +-- .../hw/tegra_x1/gpu/renderer/metal/buffer.hpp | 3 +- .../gpu/renderer/metal/render_pass.cpp | 8 +- .../tegra_x1/gpu/renderer/metal/renderer.cpp | 30 +-- .../tegra_x1/gpu/renderer/metal/renderer.hpp | 8 +- .../gpu/renderer/metal/surface_compositor.cpp | 10 +- .../gpu/renderer/metal/surface_compositor.hpp | 7 +- .../tegra_x1/gpu/renderer/metal/texture.cpp | 88 ++------- .../tegra_x1/gpu/renderer/metal/texture.hpp | 25 +-- .../gpu/renderer/metal/texture_view.cpp | 37 ++++ .../gpu/renderer/metal/texture_view.hpp | 22 +++ .../tegra_x1/gpu/renderer/renderer_base.hpp | 7 +- .../gpu/renderer/surface_compositor.hpp | 4 +- src/core/hw/tegra_x1/gpu/renderer/texture.hpp | 53 ++++++ .../hw/tegra_x1/gpu/renderer/texture_base.hpp | 53 ------ .../tegra_x1/gpu/renderer/texture_cache.cpp | 172 +++++++++--------- .../tegra_x1/gpu/renderer/texture_cache.hpp | 61 ++++--- .../hw/tegra_x1/gpu/renderer/texture_view.cpp | 58 ++++++ .../hw/tegra_x1/gpu/renderer/texture_view.hpp | 45 +++++ src/frontend/swiftui/Api.swift | 26 +-- .../texture_viewer/TextureListView.swift | 16 +- .../swiftui/texture_viewer/TextureView.swift | 8 +- 41 files changed, 667 insertions(+), 522 deletions(-) create mode 100644 src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp create mode 100644 src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp create mode 100644 src/core/hw/tegra_x1/gpu/renderer/texture.hpp delete mode 100644 src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp create mode 100644 src/core/hw/tegra_x1/gpu/renderer/texture_view.cpp create mode 100644 src/core/hw/tegra_x1/gpu/renderer/texture_view.hpp diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 4ef28efd..834b99d6 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -554,7 +554,9 @@ add_library(hydra-core hw/tegra_x1/gpu/renderer/buffer_view.hpp hw/tegra_x1/gpu/renderer/buffer_cache.cpp hw/tegra_x1/gpu/renderer/buffer_cache.hpp - hw/tegra_x1/gpu/renderer/texture_base.hpp + hw/tegra_x1/gpu/renderer/texture.hpp + hw/tegra_x1/gpu/renderer/texture_view.cpp + hw/tegra_x1/gpu/renderer/texture_view.hpp hw/tegra_x1/gpu/renderer/texture_cache.cpp hw/tegra_x1/gpu/renderer/texture_cache.hpp hw/tegra_x1/gpu/renderer/sampler_base.hpp @@ -584,6 +586,8 @@ add_library(hydra-core hw/tegra_x1/gpu/renderer/metal/buffer.hpp hw/tegra_x1/gpu/renderer/metal/texture.cpp hw/tegra_x1/gpu/renderer/metal/texture.hpp + hw/tegra_x1/gpu/renderer/metal/texture_view.cpp + hw/tegra_x1/gpu/renderer/metal/texture_view.hpp hw/tegra_x1/gpu/renderer/metal/sampler.cpp hw/tegra_x1/gpu/renderer/metal/sampler.hpp hw/tegra_x1/gpu/renderer/metal/render_pass.cpp diff --git a/src/core/c_api.cpp b/src/core/c_api.cpp index e0791878..fc1192bb 100644 --- a/src/core/c_api.cpp +++ b/src/core/c_api.cpp @@ -9,8 +9,7 @@ #include "core/horizon/loader/plugins/manager.hpp" #include "core/horizon/ui/handler_base.hpp" #include "core/hw/tegra_x1/gpu/gpu.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" -#include +#include "core/hw/tegra_x1/gpu/renderer/texture.hpp" #define HYDRA_EXPORT extern "C" __attribute__((visibility("default"))) @@ -1017,43 +1016,43 @@ hydra_texture_cache_get_texture_memory(uint32_t index) { // Texture memory HYDRA_EXPORT uint32_t -hydra_texture_memory_get_sparse_texture_count(const void* mem) { +hydra_texture_memory_get_texture_group_count(const void* mem) { // HACK return static_cast( static_cast(mem) - ->GetSparseTextureCount()); + ->GetTextureGroupCount()); } HYDRA_EXPORT const void* -hydra_texture_memory_get_sparse_texture(const void* mem, uint32_t index) { +hydra_texture_memory_get_texture_group(const void* mem, uint32_t index) { return &static_cast( mem) - ->GetSparseTexture(index); + ->GetTextureGroup(index); } -// Sparse texture +// Texture group HYDRA_EXPORT uint32_t -hydra_sparse_texture_get_texture_group_count(const void* sparse_tex) { +hydra_texture_group_get_texture_storage_count(const void* group) { // HACK return static_cast( - static_cast( - sparse_tex) - ->GetGroupCount()); + static_cast( + group) + ->GetStorageCount()); } HYDRA_EXPORT const void* -hydra_sparse_texture_get_texture_group(const void* sparse_tex, uint32_t index) { +hydra_texture_group_get_texture_storage(const void* group, uint32_t index) { return &static_cast< - const hydra::hw::tegra_x1::gpu::renderer::SparseTexture*>( - sparse_tex) - ->GetGroup(index); + const hydra::hw::tegra_x1::gpu::renderer::TextureGroup*>(group) + ->GetStorage(index); } -// Texture group +// Texture storage HYDRA_EXPORT const void* -hydra_texture_group_get_texture_descriptor(const void* group) { +hydra_texture_storage_get_texture_descriptor(const void* storage) { return &static_cast< - const hydra::hw::tegra_x1::gpu::renderer::TextureGroup*>(group) + const hydra::hw::tegra_x1::gpu::renderer::TextureStorage*>( + storage) ->base->GetDescriptor(); } diff --git a/src/core/c_api.h b/src/core/c_api.h index 7146e988..702e991a 100644 --- a/src/core/c_api.h +++ b/src/core/c_api.h @@ -392,17 +392,17 @@ uint32_t hydra_texture_cache_get_texture_memory_count(); const void* hydra_texture_cache_get_texture_memory(uint32_t index); // Texture memory -uint32_t hydra_texture_memory_get_sparse_texture_count(const void* mem); -const void* hydra_texture_memory_get_sparse_texture(const void* mem, - uint32_t index); - -// Sparse texture -uint32_t hydra_sparse_texture_get_texture_group_count(const void* sparse_tex); -const void* hydra_sparse_texture_get_texture_group(const void* sparse_tex, +uint32_t hydra_texture_memory_get_texture_group_count(const void* mem); +const void* hydra_texture_memory_get_texture_group(const void* mem, uint32_t index); // Texture group -const void* hydra_texture_group_get_texture_descriptor(const void* group); +uint32_t hydra_texture_group_get_texture_storage_count(const void* group); +const void* hydra_texture_group_get_texture_storage(const void* group, + uint32_t index); + +// Texture storage +const void* hydra_texture_storage_get_texture_descriptor(const void* storage); // Texture descriptor typedef enum HydraTextureType : uint32_t { diff --git a/src/core/emulation_context.cpp b/src/core/emulation_context.cpp index 9367ba3b..f85e3532 100644 --- a/src/core/emulation_context.cpp +++ b/src/core/emulation_context.cpp @@ -27,7 +27,8 @@ #include "core/hw/tegra_x1/gpu/renderer/buffer_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/command_buffer.hpp" #include "core/hw/tegra_x1/gpu/renderer/surface_compositor.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" #include "core/input/device_manager.hpp" #if HYDRA_HYPERVISOR_ENABLED @@ -47,6 +48,12 @@ constexpr auto STARTUP_MOVIE_BREAK_AFTER_FADE_IN_DURATION = 200ms; } // namespace +CombinedTextureView::~CombinedTextureView() { + // TODO: uncomment + // delete view; + // delete base; +} + EmulationContext::EmulationContext(horizon::ui::HandlerBase& ui_handler) { LOGGER_INSTANCE.SetOutput(CONFIG_INSTANCE.GetLogOutput()); @@ -279,15 +286,19 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { // Create texture const u32 stride = width * 4; const u32 size = height * stride; - hw::tegra_x1::gpu::renderer::TextureDescriptor descriptor( - 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, - hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, true, - stride, width, height, 1, 1, 1, 0x0, 0x0, 0x0, - hw::tegra_x1::gpu::renderer:: - get_texture_format_default_swizzle_channels( - hw::tegra_x1::gpu::renderer::TextureFormat:: - RGBA8Unorm)); - nintendo_logo = gpu->GetRenderer().CreateTexture(descriptor); + const auto descriptor = hw::tegra_x1::gpu::renderer:: + TextureDescriptor::CreateWithLevelCount( + 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, + hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, + true, stride, width, height, 1, 1, 1, 0x0, 0x0, 0x0); + const auto texture = gpu->GetRenderer().CreateTexture(descriptor); + + const auto view_descriptor = + hw::tegra_x1::gpu::renderer::TextureViewDescriptor( + descriptor.type, descriptor.format, Range(0, 1), + Range(0, 1)); + const auto texture_view = texture->CreateView(view_descriptor); + nintendo_logo = {texture, texture_view}; // Command buffer command_buffer = gpu->GetRenderer().CreateCommandBuffer(); @@ -297,7 +308,7 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { std::memcpy(reinterpret_cast(tmp_buffer->GetPtr()), data, size); free(data); - nintendo_logo->CopyFrom(command_buffer, tmp_buffer); + texture->CopyFrom(command_buffer, tmp_buffer); gpu->GetRenderer().FreeTemporaryBuffer(tmp_buffer); } } @@ -308,14 +319,15 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { height, frame_count)) { const u32 stride = width * 4; const u32 size = height * stride; - hw::tegra_x1::gpu::renderer::TextureDescriptor descriptor( - 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, - hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, true, - stride, width, height, 1, 1, 1, 0x0, 0x0, 0x0, - hw::tegra_x1::gpu::renderer:: - get_texture_format_default_swizzle_channels( - hw::tegra_x1::gpu::renderer::TextureFormat:: - RGBA8Unorm)); + const auto descriptor = hw::tegra_x1::gpu::renderer:: + TextureDescriptor::CreateWithLevelCount( + 0x0, hw::tegra_x1::gpu::renderer::TextureType::_2D, + hw::tegra_x1::gpu::renderer::TextureFormat::RGBA8Unorm, + true, stride, width, height, 1, 1, 1, 0x0, 0x0, 0x0); + const auto view_descriptor = + hw::tegra_x1::gpu::renderer::TextureViewDescriptor( + descriptor.type, descriptor.format, Range(0, 1), + Range(0, 1)); startup_movie.reserve(frame_count); // Command buffer @@ -324,16 +336,18 @@ void EmulationContext::LoadAndStart(horizon::loader::LoaderBase* loader) { for (u32 i = 0; i < frame_count; i++) { // Create texture - auto frame = gpu->GetRenderer().CreateTexture(descriptor); + const auto texture = + gpu->GetRenderer().CreateTexture(descriptor); + const auto texture_view = texture->CreateView(view_descriptor); // Copy data auto tmp_buffer = gpu->GetRenderer().AllocateTemporaryBuffer(size); std::memcpy(reinterpret_cast(tmp_buffer->GetPtr()), data + i * height * width, size); - frame->CopyFrom(command_buffer, tmp_buffer); + texture->CopyFrom(command_buffer, tmp_buffer); gpu->GetRenderer().FreeTemporaryBuffer(tmp_buffer); - startup_movie.push_back(frame); + startup_movie.push_back({texture, texture_view}); } free(data); @@ -500,13 +514,9 @@ void EmulationContext::ProgressFrame(u32 width, u32 height, loading = false; // Free loading assets - if (nintendo_logo) { - delete nintendo_logo; - nintendo_logo = nullptr; - } + if (nintendo_logo) + nintendo_logo = std::nullopt; if (!startup_movie.empty()) { - for (auto frame : startup_movie) - delete frame; startup_movie.clear(); startup_movie.shrink_to_fit(); startup_movie_delays.clear(); @@ -529,11 +539,12 @@ void EmulationContext::ProgressFrame(u32 width, u32 height, // Nintendo logo if (nintendo_logo) { - int2 size = {(i32)nintendo_logo->GetDescriptor().width, - (i32)nintendo_logo->GetDescriptor().height}; + const auto tex = *nintendo_logo; + int2 size = {(i32)tex.base->GetDescriptor().width, + (i32)tex.base->GetDescriptor().height}; int2 dst_offset = {32, 32}; compositor->DrawTexture( - command_buffer, nintendo_logo, IntRect2D({0, 0}, size), + command_buffer, tex.view, IntRect2D({0, 0}, size), IntRect2D(dst_offset, size), true, opacity); } @@ -548,12 +559,12 @@ void EmulationContext::ProgressFrame(u32 width, u32 height, } auto frame = startup_movie[startup_movie_frame]; - int2 size = {(i32)frame->GetDescriptor().width, - (i32)frame->GetDescriptor().height}; + int2 size = {(i32)frame.base->GetDescriptor().width, + (i32)frame.base->GetDescriptor().height}; int2 dst_offset = {(i32)width - size.x() - 32, (i32)height - size.y() - 32}; compositor->DrawTexture( - command_buffer, frame, IntRect2D({0, 0}, size), + command_buffer, frame.view, IntRect2D({0, 0}, size), IntRect2D(dst_offset, size), true, opacity); } } @@ -623,7 +634,8 @@ void EmulationContext::TakeScreenshot() { auto command_buffer = RENDERER_INSTANCE.CreateCommandBuffer(); auto buffer = RENDERER_INSTANCE.AllocateTemporaryBuffer( static_cast(rect.size.y() * rect.size.x() * 4)); - buffer->CopyFrom(command_buffer, texture, rect.origin, rect.size); + buffer->CopyFrom(command_buffer, texture, rect.origin, rect.size, + Range(0, 1), Range(0, 1)); delete command_buffer; // TODO: wait for the command buffer to finish diff --git a/src/core/emulation_context.hpp b/src/core/emulation_context.hpp index 903148d2..06cb7e13 100644 --- a/src/core/emulation_context.hpp +++ b/src/core/emulation_context.hpp @@ -11,6 +11,13 @@ namespace horizon::loader { class LoaderBase; } +struct CombinedTextureView { + hw::tegra_x1::gpu::renderer::ITexture* base; + hw::tegra_x1::gpu::renderer::ITextureView* view; + + ~CombinedTextureView(); +}; + class EmulationContext { using clock_t = std::chrono::steady_clock; @@ -50,9 +57,8 @@ class EmulationContext { horizon::OS* os; // Loading screen assets - hw::tegra_x1::gpu::renderer::TextureBase* nintendo_logo{nullptr}; - std::vector - startup_movie; // TODO: texture array? + std::optional nintendo_logo{}; + std::vector startup_movie; // TODO: texture array? std::vector startup_movie_delays; clock_t::time_point next_startup_movie_frame_time; clock_t::time_point startup_movie_fade_in_time; diff --git a/src/core/horizon/display/layer.cpp b/src/core/horizon/display/layer.cpp index ca92b97a..6bd06f5e 100644 --- a/src/core/horizon/display/layer.cpp +++ b/src/core/horizon/display/layer.cpp @@ -4,7 +4,8 @@ #include "core/horizon/os.hpp" #include "core/hw/tegra_x1/gpu/gpu.hpp" #include "core/hw/tegra_x1/gpu/renderer/surface_compositor.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" namespace hydra::horizon::display { @@ -34,12 +35,12 @@ bool Layer::AcquirePresentTexture( // HACK if (src_rect.size.x() == 0) { src_rect.size.x() = - static_cast(present_texture->GetDescriptor().width); + static_cast(present_texture->GetBase()->GetDescriptor().width); ONCE(LOG_WARN(Other, "Invalid src width")); } if (src_rect.size.y() == 0) { - src_rect.size.y() = - static_cast(present_texture->GetDescriptor().height); + src_rect.size.y() = static_cast( + present_texture->GetBase()->GetDescriptor().height); ONCE(LOG_WARN(Other, "Invalid src height")); } diff --git a/src/core/horizon/display/layer.hpp b/src/core/horizon/display/layer.hpp index 9d1efcac..410aa683 100644 --- a/src/core/horizon/display/layer.hpp +++ b/src/core/horizon/display/layer.hpp @@ -3,7 +3,7 @@ #include "core/horizon/display/binder.hpp" namespace hydra::hw::tegra_x1::gpu::renderer { -class TextureBase; +class ITextureView; class ICommandBuffer; class ISurfaceCompositor; } // namespace hydra::hw::tegra_x1::gpu::renderer @@ -40,7 +40,7 @@ class Layer { i64 z{0}; // Present - hw::tegra_x1::gpu::renderer::TextureBase* present_texture{nullptr}; + hw::tegra_x1::gpu::renderer::ITextureView* present_texture{nullptr}; IntRect2D src_rect; public: diff --git a/src/core/hw/tegra_x1/gpu/engines/2d.cpp b/src/core/hw/tegra_x1/gpu/engines/2d.cpp index 7fccec7e..e0203501 100644 --- a/src/core/hw/tegra_x1/gpu/engines/2d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/2d.cpp @@ -1,7 +1,7 @@ #include "core/hw/tegra_x1/gpu/engines/2d.hpp" #include "core/hw/tegra_x1/gpu/gpu.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::engines { @@ -38,16 +38,15 @@ void TwoD::Copy(const u32 index, const u32 pixels_from_memory_src_y0_int) { #pragma GCC diagnostic pop -renderer::TextureBase* TwoD::GetTexture(const Texture2DInfo& info, - renderer::TextureUsage usage) { +renderer::ITextureView* TwoD::GetTexture(const Texture2DInfo& info, + renderer::TextureUsage usage) { // TODO: layer - const renderer::TextureDescriptor descriptor( + const auto descriptor = renderer::TextureDescriptor::CreateWithLayerSize( tls_crnt_gmmu->UnmapAddr(info.addr), renderer::TextureType::_2D, renderer::to_texture_format(info.format), info.layout == MemoryLayout::Pitch, info.stride, info.width, - info.height, 1, 1, info.depth, 0x0, 0x0, 0x0, // HACK - renderer::get_texture_format_default_swizzle_channels( - renderer::to_texture_format(info.format))); + info.height, 1, 1, info.depth, 0x0, 0x0, 0x0 // HACK + ); return RENDERER_INSTANCE.GetTextureCache().Find(tls_crnt_command_buffer, descriptor, usage); diff --git a/src/core/hw/tegra_x1/gpu/engines/2d.hpp b/src/core/hw/tegra_x1/gpu/engines/2d.hpp index ba735711..936bc076 100644 --- a/src/core/hw/tegra_x1/gpu/engines/2d.hpp +++ b/src/core/hw/tegra_x1/gpu/engines/2d.hpp @@ -4,7 +4,7 @@ #include "core/hw/tegra_x1/gpu/renderer/const.hpp" namespace hydra::hw::tegra_x1::gpu::renderer { -class TextureBase; +class ITextureView; } namespace hydra::hw::tegra_x1::gpu::engines { @@ -78,8 +78,8 @@ class TwoD : public EngineWithRegsBase { void Copy(const u32 index, const u32 pixels_from_memory_src_y0_int); // Helpers - static renderer::TextureBase* GetTexture(const Texture2DInfo& info, - renderer::TextureUsage usage); + static renderer::ITextureView* GetTexture(const Texture2DInfo& info, + renderer::TextureUsage usage); }; } // namespace hydra::hw::tegra_x1::gpu::engines diff --git a/src/core/hw/tegra_x1/gpu/engines/3d.cpp b/src/core/hw/tegra_x1/gpu/engines/3d.cpp index f058e1c6..d69d3847 100644 --- a/src/core/hw/tegra_x1/gpu/engines/3d.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/3d.cpp @@ -8,7 +8,7 @@ #include "core/hw/tegra_x1/gpu/renderer/render_pass_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/sampler_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/shader_base.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::engines { @@ -445,7 +445,7 @@ void ThreeD::BindGroup(const u32 index, const u32 data) { #pragma GCC diagnostic pop -renderer::TextureBase* +renderer::ITextureView* ThreeD::GetColorTargetTexture(u32 render_target_index) const { const auto& render_target = regs.color_targets[render_target_index]; @@ -487,7 +487,7 @@ ThreeD::GetColorTargetTexture(u32 render_target_index) const { stride = 0; } - const renderer::TextureDescriptor descriptor( + const auto descriptor = renderer::TextureDescriptor::CreateWithLayerSize( tls_crnt_gmmu->UnmapAddr(gpu_addr), type, format, is_linear, stride, width, render_target.height, depth, layer_count, render_target.tile_mode.width, render_target.tile_mode.height, @@ -498,7 +498,7 @@ ThreeD::GetColorTargetTexture(u32 render_target_index) const { tls_crnt_command_buffer, descriptor, renderer::TextureUsage::Write); } -renderer::TextureBase* ThreeD::GetDepthStencilTargetTexture() const { +renderer::ITextureView* ThreeD::GetDepthStencilTargetTexture() const { const auto gpu_addr = u64(regs.depth_target_addr); if (gpu_addr == 0x0) { // TODO: is this really an error? @@ -510,7 +510,7 @@ renderer::TextureBase* ThreeD::GetDepthStencilTargetTexture() const { ? renderer::TextureType::_2DArray : renderer::TextureType::_2D; - const renderer::TextureDescriptor descriptor( + const auto descriptor = renderer::TextureDescriptor::CreateWithLayerSize( tls_crnt_gmmu->UnmapAddr(gpu_addr), type, renderer::to_texture_format(regs.depth_target_format), false, 0, regs.depth_target_width, regs.depth_target_height, 1, @@ -767,7 +767,7 @@ renderer::BufferView ThreeD::GetVertexBuffer(u32 vertex_array_index) const { tls_crnt_command_buffer, Range::FromSize(ptr, size)); } -renderer::TextureBase* +renderer::ITextureView* ThreeD::GetTexture(const TextureImageControl& tic) const { // HACK if (tic.hdr_version == TicHdrVersion::_1DBuffer) { @@ -810,17 +810,21 @@ ThreeD::GetTexture(const TextureImageControl& tic) const { layer_count *= 6; } - const renderer::TextureDescriptor descriptor( + const u32 level_count = tic.mip_max_levels + 1; + const auto descriptor = renderer::TextureDescriptor::CreateWithLevelCount( tls_crnt_gmmu->UnmapAddr(gpu_addr), type, format, is_linear, linear_stride, tic.width_minus_one + 1, tic.height_minus_one + 1, depth, - tic.mip_max_levels + 1, layer_count, tic.tile_width_gobs_log2, - tic.tile_height_gobs_log2, tic.tile_depth_gobs_log2, + level_count, layer_count, tic.tile_width_gobs_log2, + tic.tile_height_gobs_log2, tic.tile_depth_gobs_log2); + const renderer::TextureViewDescriptor view_descriptor( + type, format, Range(0, level_count), Range(0, layer_count), renderer::SwizzleChannels( format, tic.format_word.swizzle_x, tic.format_word.swizzle_y, tic.format_word.swizzle_z, tic.format_word.swizzle_w)); return RENDERER_INSTANCE.GetTextureCache().Find( - tls_crnt_command_buffer, descriptor, renderer::TextureUsage::Read); + tls_crnt_command_buffer, descriptor, view_descriptor, + renderer::TextureUsage::Read); } renderer::SamplerBase* diff --git a/src/core/hw/tegra_x1/gpu/engines/3d.hpp b/src/core/hw/tegra_x1/gpu/engines/3d.hpp index 1a679b98..275d68d6 100644 --- a/src/core/hw/tegra_x1/gpu/engines/3d.hpp +++ b/src/core/hw/tegra_x1/gpu/engines/3d.hpp @@ -10,7 +10,7 @@ class DriverBase; } namespace hydra::hw::tegra_x1::gpu::renderer { -class TextureBase; +class ITextureView; class SamplerBase; class RenderPassBase; class PipelineBase; @@ -610,8 +610,9 @@ class ThreeD : public EngineWithRegsBase, public InlineBase { void BindGroup(const u32 index, const u32 data); // Helpers - renderer::TextureBase* GetColorTargetTexture(u32 render_target_index) const; - renderer::TextureBase* GetDepthStencilTargetTexture() const; + renderer::ITextureView* + GetColorTargetTexture(u32 render_target_index) const; + renderer::ITextureView* GetDepthStencilTargetTexture() const; renderer::RenderPassBase* GetRenderPass() const; renderer::Viewport GetViewport(u32 index); renderer::Scissor GetScissor(u32 index); @@ -619,7 +620,7 @@ class ThreeD : public EngineWithRegsBase, public InlineBase { renderer::ShaderBase* GetShader(ShaderStage stage); renderer::PipelineBase* GetPipeline(); renderer::BufferView GetVertexBuffer(u32 vertex_array_index) const; - renderer::TextureBase* GetTexture(const TextureImageControl& tic) const; + renderer::ITextureView* GetTexture(const TextureImageControl& tic) const; renderer::SamplerBase* GetSampler(const TextureSamplerControl& tsc) const; void ConfigureShaderStage(const ShaderStage stage, diff --git a/src/core/hw/tegra_x1/gpu/engines/copy.cpp b/src/core/hw/tegra_x1/gpu/engines/copy.cpp index 95ec80b6..81a272f8 100644 --- a/src/core/hw/tegra_x1/gpu/engines/copy.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/copy.cpp @@ -3,7 +3,6 @@ #include "core/hw/tegra_x1/gpu/gpu.hpp" #include "core/hw/tegra_x1/gpu/memory_util.hpp" #include "core/hw/tegra_x1/gpu/renderer/buffer_base.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" namespace hydra::hw::tegra_x1::gpu::engines { diff --git a/src/core/hw/tegra_x1/gpu/engines/copy.hpp b/src/core/hw/tegra_x1/gpu/engines/copy.hpp index be48efbc..306350cc 100644 --- a/src/core/hw/tegra_x1/gpu/engines/copy.hpp +++ b/src/core/hw/tegra_x1/gpu/engines/copy.hpp @@ -4,7 +4,6 @@ namespace hydra::hw::tegra_x1::gpu::renderer { class BufferBase; -class TextureBase; } // namespace hydra::hw::tegra_x1::gpu::renderer namespace hydra::hw::tegra_x1::gpu::engines { diff --git a/src/core/hw/tegra_x1/gpu/gpu.cpp b/src/core/hw/tegra_x1/gpu/gpu.cpp index 47be18a8..216f0337 100644 --- a/src/core/hw/tegra_x1/gpu/gpu.cpp +++ b/src/core/hw/tegra_x1/gpu/gpu.cpp @@ -79,9 +79,9 @@ void Gpu::SubchannelMethod(u32 subchannel, u32 method, u32 arg) { GetEngineAtSubchannel(subchannel)->Method(method, arg); } -renderer::TextureBase* Gpu::GetTexture(renderer::ICommandBuffer* command_buffer, - cpu::IMmu* mmu, - const NvGraphicsBuffer& buff) { +renderer::ITextureView* +Gpu::GetTexture(renderer::ICommandBuffer* command_buffer, cpu::IMmu* mmu, + const NvGraphicsBuffer& buff) { std::lock_guard texture_cache_lock(renderer->GetTextureCache().GetMutex()); const auto& plane = buff.planes[0]; @@ -95,7 +95,7 @@ renderer::TextureBase* Gpu::GetTexture(renderer::ICommandBuffer* command_buffer, (plane.kind == NvKind::Pitch || plane.kind == NvKind::PitchNoSwizzle); // TODO: why are there more planes? - renderer::TextureDescriptor descriptor( + const auto descriptor = renderer::TextureDescriptor::CreateWithLayerSize( mmu->UnmapAddr(GetMap(static_cast(buff.nvmap_id)).addr + plane.offset), renderer::TextureType::_2D, diff --git a/src/core/hw/tegra_x1/gpu/gpu.hpp b/src/core/hw/tegra_x1/gpu/gpu.hpp index a1a17f7f..be690c61 100644 --- a/src/core/hw/tegra_x1/gpu/gpu.hpp +++ b/src/core/hw/tegra_x1/gpu/gpu.hpp @@ -94,9 +94,9 @@ class Gpu { } // Texture - renderer::TextureBase* GetTexture(renderer::ICommandBuffer* command_buffer, - cpu::IMmu* mmu, - const NvGraphicsBuffer& buff); + renderer::ITextureView* GetTexture(renderer::ICommandBuffer* command_buffer, + cpu::IMmu* mmu, + const NvGraphicsBuffer& buff); // Getters Pfifo& GetPfifo() { return pfifo; } diff --git a/src/core/hw/tegra_x1/gpu/renderer/buffer_base.hpp b/src/core/hw/tegra_x1/gpu/renderer/buffer_base.hpp index e3e1822c..0c2b4b21 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/buffer_base.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/buffer_base.hpp @@ -5,7 +5,7 @@ namespace hydra::hw::tegra_x1::gpu::renderer { class ICommandBuffer; -class TextureBase; +class ITexture; class BufferBase { public: @@ -28,9 +28,10 @@ class BufferBase { size_ = std::min(src->GetSize() - src_offset, size - dst_offset); CopyFromImpl(command_buffer, src, dst_offset, src_offset, size_); } - virtual void CopyFrom(ICommandBuffer* command_buffer, TextureBase* src, + virtual void CopyFrom(ICommandBuffer* command_buffer, ITextureView* src, const uint3 src_origin, const uint3 src_size, - u64 dst_offset = 0) = 0; + const Range src_levels, + const Range src_layers, u64 dst_offset = 0) = 0; protected: u64 size; diff --git a/src/core/hw/tegra_x1/gpu/renderer/buffer_view.hpp b/src/core/hw/tegra_x1/gpu/renderer/buffer_view.hpp index 0a8fc35f..7461d8d9 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/buffer_view.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/buffer_view.hpp @@ -29,9 +29,11 @@ struct BufferView { size_ = std::min(src.size - src.offset, size - offset); base->CopyFrom(command_buffer, src.base, offset, src.offset, size_); } - void CopyFrom(ICommandBuffer* command_buffer, TextureBase* src, - const uint3 src_origin, const uint3 src_size) { - base->CopyFrom(command_buffer, src, src_origin, src_size, offset); + void CopyFrom(ICommandBuffer* command_buffer, ITextureView* src, + const uint3 src_origin, const uint3 src_size, + const Range src_levels, const Range src_layers) { + base->CopyFrom(command_buffer, src, src_origin, src_size, src_levels, + src_layers, offset); } protected: diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.cpp b/src/core/hw/tegra_x1/gpu/renderer/const.cpp index 6f6c1787..256f789c 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.cpp @@ -616,40 +616,6 @@ SwizzleChannels::SwizzleChannels(const TextureFormat format, #undef SWIZZLE } -SwizzleChannels -get_texture_format_default_swizzle_channels(const TextureFormat format) { - if (is_texture_format_depth_or_stencil(format)) - return {ImageSwizzle::Zero, ImageSwizzle::Zero, ImageSwizzle::Zero, - ImageSwizzle::Zero}; - -#define SWIZZLE(r, g, b, a) \ - SwizzleChannels(ImageSwizzle::r, ImageSwizzle::g, ImageSwizzle::b, \ - ImageSwizzle::a) - - // TODO: implement all formats - switch (format) { - case TextureFormat::R8Unorm: - return SWIZZLE(R, Zero, Zero, OneFloat); - case TextureFormat::B5G6R5Unorm: - case TextureFormat::BC1_RGB: - return SWIZZLE(R, G, B, OneFloat); - case TextureFormat::RG8Unorm: - return SWIZZLE(R, G, Zero, OneFloat); - case TextureFormat::RGBA8Unorm: - case TextureFormat::BGRA8Unorm: - case TextureFormat::RGBA8Unorm_sRGB: - case TextureFormat::RGB10A2Unorm: - case TextureFormat::BC2_RGBA: - case TextureFormat::BC3_RGBA: - return SWIZZLE(R, G, B, A); - default: - ONCE(LOG_NOT_IMPLEMENTED(Gpu, "{} default swizzle", format)); - return SWIZZLE(R, G, B, A); - } - -#undef SWIZZLE -} - u32 TextureDescriptor::GetHash() const { HashCode hash; hash.Add(ptr); @@ -665,25 +631,27 @@ u32 TextureDescriptor::GetHash() const { hash.Add(ToTextureTypeCompatibility(type)); - // TODO: get format info from the renderer instead - hash.Add(is_texture_format_compressed(format)); - hash.Add(is_texture_format_depth_or_stencil(format)); - hash.Add(get_texture_format_stride(format, 16)); + const auto& format_info = GetTextureFormatInfo(format); + hash.Add(format_info.bytes_per_block); + hash.Add(format_info.block_width); + hash.Add(format_info.block_height); + hash.Add(format_info.is_depth_stencil); return hash.ToHashCode(); } u32 TextureViewDescriptor::GetHash() const { HashCode hash; + hash.Add(type); hash.Add(format); - hash.Add(swizzle_channels.r); - hash.Add(swizzle_channels.g); - hash.Add(swizzle_channels.b); - hash.Add(swizzle_channels.a); hash.Add(levels.GetBegin()); hash.Add(levels.GetEnd()); hash.Add(layers.GetBegin()); hash.Add(layers.GetEnd()); + hash.Add(swizzle_channels.r); + hash.Add(swizzle_channels.g); + hash.Add(swizzle_channels.b); + hash.Add(swizzle_channels.a); return hash.ToHashCode(); } diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.hpp b/src/core/hw/tegra_x1/gpu/renderer/const.hpp index 1d930aec..751e41ab 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.hpp @@ -4,7 +4,7 @@ namespace hydra::hw::tegra_x1::gpu::renderer { -class TextureBase; +class ITextureView; class ShaderBase; enum class TextureType { @@ -209,9 +209,6 @@ struct SwizzleChannels { } }; -SwizzleChannels -get_texture_format_default_swizzle_channels(const TextureFormat format); - struct TextureDescriptor { uptr ptr; TextureType type; @@ -227,46 +224,58 @@ struct TextureDescriptor { u32 block_height_log2; u32 block_depth_log2; u32 layer_size; - SwizzleChannels swizzle_channels; - TextureDescriptor(const uptr ptr_, const TextureType type_, - const TextureFormat format_, const bool is_linear_, - const u32 linear_stride_, const u32 width_, - const u32 height_, const u32 depth_, - const u32 level_count_, const u32 layer_count_, - const u32 block_width_log2_, const u32 block_height_log2_, - const u32 block_depth_log2_, - const SwizzleChannels& swizzle_channels_) - : ptr{ptr_}, type{type_}, format{format_}, is_linear{is_linear_}, - linear_stride{linear_stride_}, width{width_}, height{height_}, - depth{depth_}, level_count{level_count_}, layer_count{layer_count_}, - block_width_log2{block_width_log2_}, - block_height_log2{block_height_log2_}, - block_depth_log2{block_depth_log2_}, swizzle_channels{ - swizzle_channels_} { - layer_size = CalculateLayerSize(); + static TextureDescriptor + CreateWithLevelCount(uptr ptr, TextureType type, TextureFormat format, + bool is_linear, u32 linear_stride, u32 width, + u32 height, u32 depth, u32 level_count, + u32 layer_count, u32 block_width_log2, + u32 block_height_log2, u32 block_depth_log2) { + TextureDescriptor d; + d.ptr = ptr; + d.type = type; + d.format = format; + d.is_linear = is_linear; + d.linear_stride = linear_stride; + d.width = width; + d.height = height; + d.depth = depth; + d.level_count = level_count; + d.layer_count = layer_count; + d.block_width_log2 = block_width_log2; + d.block_height_log2 = block_height_log2; + d.block_depth_log2 = block_depth_log2; + + d.CalculateLayerSize(); + return d; } - TextureDescriptor(const uptr ptr_, const TextureType type_, - const TextureFormat format_, const bool is_linear_, - const u32 linear_stride_, const u32 width_, - const u32 height_, const u32 depth_, - const u32 layer_count_, const u32 block_width_log2_, - const u32 block_height_log2_, const u32 block_depth_log2_, - const u32 layer_size_ = 0) - : ptr{ptr_}, type{type_}, format{format_}, is_linear{is_linear_}, - linear_stride{linear_stride_}, width{width_}, height{height_}, - depth{depth_}, layer_count{layer_count_}, - block_width_log2{block_width_log2_}, - block_height_log2{block_height_log2_}, - block_depth_log2{block_depth_log2_}, layer_size{layer_size_}, - swizzle_channels{ - get_texture_format_default_swizzle_channels(format_)} { - // HACK - level_count = 1; - + static TextureDescriptor + CreateWithLayerSize(uptr ptr, TextureType type, TextureFormat format, + bool is_linear, u32 linear_stride, u32 width, + u32 height, u32 depth, u32 layer_count, + u32 block_width_log2, u32 block_height_log2, + u32 block_depth_log2, u32 layer_size = 0) { + TextureDescriptor d; + d.ptr = ptr; + d.type = type; + d.format = format; + d.is_linear = is_linear; + d.linear_stride = linear_stride; + d.width = width; + d.height = height; + d.depth = depth; + d.layer_count = layer_count; + d.block_width_log2 = block_width_log2; + d.block_height_log2 = block_height_log2; + d.block_depth_log2 = block_depth_log2; + d.layer_size = layer_size; + + d.CalculateLevelCount(); if (layer_size == 0) - layer_size = CalculateLayerSize(); + d.CalculateLayerSize(); + + return d; } u32 GetSize() const { return layer_count * layer_size; } @@ -277,28 +286,36 @@ struct TextureDescriptor { u32 GetHash() const; private: - u32 CalculateLayerSize() const { + TextureDescriptor() = default; + + void CalculateLayerSize() { // HACK if (is_linear) { - return depth * align(height, 16u) * linear_stride; + layer_size = depth * align(height, 16u) * linear_stride; } else { - return depth * align(height, 16u) * - align(get_texture_format_stride(format, width), 64u); + layer_size = depth * align(height, 16u) * + align(get_texture_format_stride(format, width), 64u); } } + + void CalculateLevelCount() { + // HACK + level_count = 1; + } }; struct TextureViewDescriptor { + TextureType type; TextureFormat format; - SwizzleChannels swizzle_channels; Range levels; Range layers; + SwizzleChannels swizzle_channels; - TextureViewDescriptor(TextureFormat format_, - SwizzleChannels swizzle_channels_, Range levels_, - Range layers_) - : format{format_}, swizzle_channels{swizzle_channels_}, levels{levels_}, - layers{layers_} {} + TextureViewDescriptor(TextureType type_, TextureFormat format_, + Range levels_, Range layers_, + SwizzleChannels swizzle_channels_ = SwizzleChannels()) + : type{type_}, format{format_}, levels{levels_}, layers{layers_}, + swizzle_channels{swizzle_channels_} {} u32 GetHash() const; }; @@ -368,7 +385,7 @@ enum class BlendFactor { }; struct RenderTargetDescriptor { - TextureBase* texture; + ITextureView* texture; bool load_action_clear = false; union { float color[4]; diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.cpp index d725fb17..c37a4180 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.cpp @@ -2,7 +2,7 @@ #include "core/hw/tegra_x1/gpu/renderer/metal/command_buffer.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp" -#include "core/hw/tegra_x1/gpu/renderer/metal/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::renderer::metal { @@ -16,24 +16,32 @@ Buffer::Buffer(MTL::Buffer* buffer_) Buffer::~Buffer() { buffer->release(); } -void Buffer::CopyFrom(ICommandBuffer* command_buffer, TextureBase* src, +void Buffer::CopyFrom(ICommandBuffer* command_buffer, ITextureView* src, const uint3 src_origin, const uint3 src_size, + const Range src_levels, const Range src_layers, u64 dst_offset) { const auto command_buffer_impl = static_cast(command_buffer); - auto src_impl = static_cast(src); + auto src_impl = static_cast(src); auto blit_encoder = command_buffer_impl->GetBlitCommandEncoder(); // TODO: bytes per image // TODO: calculate the stride for the Metal pixel format - blit_encoder->copyFromTexture( - src_impl->GetTexture(), 0, 0, - MTL::Origin::Make(src_origin.x(), src_origin.y(), src_origin.z()), - MTL::Size::Make(src_size.x(), src_size.y(), src_size.z()), buffer, - dst_offset, - get_texture_format_stride(src_impl->GetDescriptor().format, - src_size.x()), - 0); + for (u32 layer = src_layers.GetBegin(); layer < src_layers.GetEnd(); + layer++) { + for (u32 level = src_levels.GetBegin(); level < src_levels.GetEnd(); + level++) { + blit_encoder->copyFromTexture( + src_impl->GetTexture(), layer, level, + MTL::Origin::Make(src_origin.x(), src_origin.y(), + src_origin.z()), + MTL::Size::Make(src_size.x(), src_size.y(), src_size.z()), + buffer, dst_offset, + get_texture_format_stride(src_impl->GetDescriptor().format, + src_size.x()), + 0); + } + } } void Buffer::CopyFromImpl(const uptr data, u64 dst_offset, u64 size_) { diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.hpp b/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.hpp index 231106ce..81804c0f 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/buffer.hpp @@ -16,8 +16,9 @@ class Buffer final : public BufferBase { } // Copying - void CopyFrom(ICommandBuffer* command_buffer, TextureBase* src, + void CopyFrom(ICommandBuffer* command_buffer, ITextureView* src, const uint3 src_origin, const uint3 src_size, + const Range src_levels, const Range src_layers, u64 dst_offset) override; private: diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/render_pass.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/render_pass.cpp index c9bcac6b..f99ff712 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/render_pass.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/render_pass.cpp @@ -1,7 +1,7 @@ #include "core/hw/tegra_x1/gpu/renderer/metal/render_pass.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/maxwell_to_mtl.hpp" -#include "core/hw/tegra_x1/gpu/renderer/metal/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::renderer::metal { @@ -18,7 +18,7 @@ RenderPass::RenderPass(const RenderPassDescriptor& descriptor) auto color_attachment = render_pass_descriptor->colorAttachments()->object(i); color_attachment->setTexture( - static_cast(descriptor.color_targets[i].texture) + static_cast(descriptor.color_targets[i].texture) ->GetTexture()); if (color_target.load_action_clear) { color_attachment->setLoadAction(MTL::LoadActionClear); @@ -43,7 +43,7 @@ RenderPass::RenderPass(const RenderPassDescriptor& descriptor) if (format_info.has_depth) { auto depth_attachment = render_pass_descriptor->depthAttachment(); depth_attachment->setTexture( - static_cast(depth_stencil_target.texture) + static_cast(depth_stencil_target.texture) ->GetTexture()); if (depth_stencil_target.load_action_clear && depth_stencil_target.clear_data.clear_depth) { @@ -61,7 +61,7 @@ RenderPass::RenderPass(const RenderPassDescriptor& descriptor) auto stencil_attachment = render_pass_descriptor->stencilAttachment(); stencil_attachment->setTexture( - static_cast(depth_stencil_target.texture) + static_cast(depth_stencil_target.texture) ->GetTexture()); if (depth_stencil_target.load_action_clear && depth_stencil_target.clear_data.clear_stencil) { diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.cpp index 1a5b746c..d3ae999d 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.cpp @@ -12,6 +12,7 @@ #include "core/hw/tegra_x1/gpu/renderer/metal/shader.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp" // TODO: define in a separate file /* @@ -126,7 +127,7 @@ void Renderer::FreeTemporaryBuffer(BufferBase* buffer) { delete buffer_impl; } -TextureBase* Renderer::CreateTexture(const TextureDescriptor& descriptor) { +ITexture* Renderer::CreateTexture(const TextureDescriptor& descriptor) { return new Texture(descriptor); } @@ -151,9 +152,10 @@ void Renderer::ClearColor(ICommandBuffer* command_buffer, u32 render_target_id, u32 layer, u8 mask, const uint4 color) { const auto command_buffer_impl = static_cast(command_buffer); - auto texture = static_cast(state.render_pass->GetDescriptor() - .color_targets[render_target_id] - .texture); + auto texture = + static_cast(state.render_pass->GetDescriptor() + .color_targets[render_target_id] + .texture); // HACK if (!texture) { @@ -170,7 +172,8 @@ void Renderer::ClearColor(ICommandBuffer* command_buffer, u32 render_target_id, command_buffer_impl->SetRenderPipelineState( clear_color_pipeline_cache->Find( - {texture->GetPixelFormat(), render_target_id, mask})); + {to_mtl_pixel_format(texture->GetDescriptor().format), + render_target_id, mask})); // TODO: set viewport and scissor encoder->setVertexBytes(&render_target_id, sizeof(render_target_id), 0); encoder->setFragmentBytes(&color, sizeof(color), 0); @@ -182,7 +185,7 @@ void Renderer::ClearDepth(ICommandBuffer* command_buffer, u32 layer, const float value) { const auto command_buffer_impl = static_cast(command_buffer); - auto texture = static_cast( + auto texture = static_cast( state.render_pass->GetDescriptor().depth_stencil_target.texture); // HACK @@ -202,7 +205,8 @@ void Renderer::ClearDepth(ICommandBuffer* command_buffer, u32 layer, auto encoder = GetRenderCommandEncoder(command_buffer_impl); command_buffer_impl->SetRenderPipelineState( - clear_depth_pipeline_cache->Find(texture->GetPixelFormat())); + clear_depth_pipeline_cache->Find( + to_mtl_pixel_format(texture->GetDescriptor().format))); command_buffer_impl->SetDepthStencilState( depth_stencil_state_always_and_write); // TODO: set viewport and scissor @@ -261,14 +265,14 @@ void Renderer::BindUniformBuffer(const BufferView& buffer, state.uniform_buffers[u32(shader_type)][index] = buffer; } -void Renderer::BindTexture(TextureBase* texture, SamplerBase* sampler, +void Renderer::BindTexture(ITextureView* texture, SamplerBase* sampler, ShaderType shader_type, u32 index) { // HACK if (shader_type == ShaderType::Count) return; - state.textures[u32(shader_type)][index] = {static_cast(texture), - static_cast(sampler)}; + state.textures[u32(shader_type)][index] = { + static_cast(texture), static_cast(sampler)}; } void Renderer::UnbindUniformBuffers(ShaderType shader_type) { @@ -391,9 +395,9 @@ void Renderer::SetUniformBuffer(CommandBuffer* command_buffer, void Renderer::SetTexture(CommandBuffer* command_buffer, ShaderType shader_type, u32 index) { const auto texture = state.textures[u32(shader_type)][index]; - if (texture.texture) - command_buffer->SetTexture(texture.texture->GetTexture(), shader_type, - index); + if (texture.texture_view) + command_buffer->SetTexture(texture.texture_view->GetTexture(), + shader_type, index); if (texture.sampler) command_buffer->SetSampler(texture.sampler->GetSampler(), shader_type, index); diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp b/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp index 64a362bc..b35e0e58 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp @@ -14,13 +14,13 @@ namespace hydra::hw::tegra_x1::gpu::renderer::metal { class CommandBuffer; class Buffer; -class Texture; +class TextureView; class Sampler; class RenderPass; class Pipeline; struct CombinedTextureSampler { - const Texture* texture{nullptr}; + const TextureView* texture_view{nullptr}; const Sampler* sampler{nullptr}; }; @@ -58,7 +58,7 @@ class Renderer : public RendererBase { void FreeTemporaryBuffer(BufferBase* buffer) override; // Texture - TextureBase* CreateTexture(const TextureDescriptor& descriptor) override; + ITexture* CreateTexture(const TextureDescriptor& descriptor) override; // Sampler SamplerBase* CreateSampler(const SamplerDescriptor& descriptor) override; @@ -96,7 +96,7 @@ class Renderer : public RendererBase { engines::IndexType index_type) override; void BindUniformBuffer(const BufferView& buffer, ShaderType shader_type, u32 index) override; - void BindTexture(TextureBase* texture, SamplerBase* sampler, + void BindTexture(ITextureView* texture, SamplerBase* sampler, ShaderType shader_type, u32 index) override; // Resource unbinding diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.cpp index b3663c6f..5d8e2c9d 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.cpp @@ -4,6 +4,7 @@ #include "core/hw/tegra_x1/gpu/renderer/metal/command_buffer.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::renderer::metal { @@ -22,12 +23,12 @@ SurfaceCompositor::SurfaceCompositor(CA::MetalDrawable* drawable_) SurfaceCompositor::~SurfaceCompositor() { render_pass_descriptor->release(); } void SurfaceCompositor::DrawTexture(ICommandBuffer* command_buffer, - const TextureBase* texture, + const ITextureView* texture, const FloatRect2D src_rect, const FloatRect2D dst_rect, bool transparent, f32 opacity) { auto command_buffer_impl = static_cast(command_buffer); - auto texture_impl = static_cast(texture); + auto texture_impl = static_cast(texture); auto encoder = command_buffer_impl->GetRenderCommandEncoder(render_pass_descriptor); @@ -44,8 +45,9 @@ void SurfaceCompositor::DrawTexture(ICommandBuffer* command_buffer, encoder->setVertexBytes(&zero, sizeof(zero), 0); // Src rect - const auto src_width = texture->GetDescriptor().width; - const auto src_height = texture->GetDescriptor().height; + const auto& descriptor = texture->GetBase()->GetDescriptor(); + const auto src_width = descriptor.width; + const auto src_height = descriptor.height; BlitParams params = { .src_offset = {src_rect.origin.x() / src_width, src_rect.origin.y() / src_height}, diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.hpp b/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.hpp index 33894ae3..5ec0e493 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/surface_compositor.hpp @@ -12,9 +12,10 @@ class SurfaceCompositor final : public ISurfaceCompositor { SurfaceCompositor(CA::MetalDrawable* drawable_); ~SurfaceCompositor() override; - void DrawTexture(ICommandBuffer* command_buffer, const TextureBase* texture, - const FloatRect2D src_rect, const FloatRect2D dst_rect, - bool transparent, f32 opacity) override; + void DrawTexture(ICommandBuffer* command_buffer, + const ITextureView* texture, const FloatRect2D src_rect, + const FloatRect2D dst_rect, bool transparent, + f32 opacity) override; void Present(ICommandBuffer* command_buffer) override; private: diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp index 005be0f3..a6785862 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.cpp @@ -4,11 +4,11 @@ #include "core/hw/tegra_x1/gpu/renderer/metal/command_buffer.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/maxwell_to_mtl.hpp" #include "core/hw/tegra_x1/gpu/renderer/metal/renderer.hpp" +#include "core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::renderer::metal { -Texture::Texture(const TextureDescriptor& descriptor) - : TextureBase(descriptor) { +Texture::Texture(const TextureDescriptor& descriptor) : ITexture(descriptor) { const auto type = ToMtlTextureType(descriptor.type); MTL::TextureDescriptor* desc = MTL::TextureDescriptor::alloc()->init(); @@ -43,55 +43,22 @@ Texture::Texture(const TextureDescriptor& descriptor) } const auto& pixel_format_info = to_mtl_pixel_format_info(descriptor.format); - pixel_format = pixel_format_info.pixel_format; - desc->setPixelFormat(pixel_format); - - base_texture = METAL_RENDERER_INSTANCE.GetDevice()->newTexture(desc); - if (pixel_format_info.component_indices == uchar4{0, 1, 2, 3}) { - texture = base_texture; - } else { - owns_base = true; - texture = CreateViewImpl(descriptor.format, SwizzleChannels()); - } -} - -Texture::Texture(const TextureDescriptor& descriptor, - MTL::Texture* mtl_texture_) - : TextureBase(descriptor), owns_base{false}, - base_texture{mtl_texture_}, texture{mtl_texture_} {} + desc->setPixelFormat(pixel_format_info.pixel_format); -Texture::~Texture() { - if (owns_base) - base_texture->release(); - texture->release(); + texture = METAL_RENDERER_INSTANCE.GetDevice()->newTexture(desc); } -TextureBase* Texture::CreateView(const TextureViewDescriptor& descriptor) { - const auto& pixel_format_info = to_mtl_pixel_format_info(descriptor.format); +Texture::~Texture() { texture->release(); } - // Swizzle - MTL::TextureSwizzle swizzle_components[] = { - to_mtl_swizzle(descriptor.swizzle_channels.r), - to_mtl_swizzle(descriptor.swizzle_channels.g), - to_mtl_swizzle(descriptor.swizzle_channels.b), - to_mtl_swizzle(descriptor.swizzle_channels.a)}; - MTL::TextureSwizzleChannels swizzle_channels( - swizzle_components[pixel_format_info.component_indices[0]], - swizzle_components[pixel_format_info.component_indices[1]], - swizzle_components[pixel_format_info.component_indices[2]], - swizzle_components[pixel_format_info.component_indices[3]]); - - auto desc = GetDescriptor(); - desc.format = descriptor.format; - desc.swizzle_channels = descriptor.swizzle_channels; - - return new Texture( - desc, CreateViewImpl(descriptor.format, descriptor.swizzle_channels)); +ITextureView* +Texture::CreateView(const TextureViewDescriptor& view_descriptor) { + return new TextureView(this, view_descriptor); } void Texture::CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, - const uint3 dst_origin, const usize3 size, - const Range levels, const Range layers) { + const uint3 dst_origin, const usize3 dst_size, + const Range dst_levels, + const Range dst_layers) { const auto command_buffer_impl = static_cast(command_buffer); const auto mtl_src = static_cast(src)->GetBuffer(); @@ -102,20 +69,23 @@ void Texture::CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, // TODO: don't align const auto stride = align( get_texture_format_stride(descriptor.format, descriptor.width), 64u); - for (u32 layer = layers.GetBegin(); layer < layers.GetEnd(); layer++) { - for (u32 level = levels.GetBegin(); level < levels.GetEnd(); level++) { + for (u32 layer = dst_layers.GetBegin(); layer < dst_layers.GetEnd(); + layer++) { + for (u32 level = dst_levels.GetBegin(); level < dst_levels.GetEnd(); + level++) { encoder->copyFromBuffer( mtl_src, layer * descriptor.layer_size + /*descriptor.GetLevelOffset(level)*/ 0, stride, descriptor.height * stride, - MTL::Size(size.x(), size.y(), size.z()), texture, layer, level, + MTL::Size(dst_size.x(), dst_size.y(), dst_size.z()), texture, + layer, level, MTL::Origin(dst_origin.x(), dst_origin.y(), dst_origin.z())); } } } -void Texture::CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, +void Texture::CopyFrom(ICommandBuffer* command_buffer, const ITexture* src, const uint3 src_origin, const u32 src_level, const u32 src_layer, const uint3 dst_origin, const u32 dst_level, const u32 dst_layer, @@ -141,7 +111,7 @@ void Texture::CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, } } -void Texture::BlitFrom(ICommandBuffer* command_buffer, const TextureBase* src, +void Texture::BlitFrom(ICommandBuffer* command_buffer, const ITexture* src, const float3 src_origin, const usize3 src_size, const u32 src_level, const u32 src_layer, const float3 dst_origin, const usize3 dst_size, @@ -168,24 +138,4 @@ void Texture::BlitFrom(ICommandBuffer* command_buffer, const TextureBase* src, src_origin, src_size, texture, 0, dst_origin, dst_size); } -MTL::Texture* Texture::CreateViewImpl(TextureFormat format, - SwizzleChannels swizzle_channels) { - const auto& pixel_format_info = to_mtl_pixel_format_info(format); - - // Swizzle - MTL::TextureSwizzle swizzle_components[] = { - to_mtl_swizzle(swizzle_channels.r), to_mtl_swizzle(swizzle_channels.g), - to_mtl_swizzle(swizzle_channels.b), to_mtl_swizzle(swizzle_channels.a)}; - MTL::TextureSwizzleChannels swizzle_channels_mtl( - swizzle_components[pixel_format_info.component_indices[0]], - swizzle_components[pixel_format_info.component_indices[1]], - swizzle_components[pixel_format_info.component_indices[2]], - swizzle_components[pixel_format_info.component_indices[3]]); - - return base_texture->newTextureView( - to_mtl_pixel_format(format), ToMtlTextureType(this->descriptor.type), - NS::Range(0, 1), NS::Range(0, descriptor.layer_count), - swizzle_channels_mtl); -} - } // namespace hydra::hw::tegra_x1::gpu::renderer::metal diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp index 3f4f2fc5..c9800823 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture.hpp @@ -1,30 +1,31 @@ #pragma once #include "core/hw/tegra_x1/gpu/renderer/metal/const.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture.hpp" namespace hydra::hw::tegra_x1::gpu::renderer::metal { -class Texture final : public TextureBase { +class Texture final : public ITexture { public: Texture(const TextureDescriptor& descriptor); - Texture(const TextureDescriptor& descriptor, MTL::Texture* mtl_texture_); ~Texture() override; - TextureBase* CreateView(const TextureViewDescriptor& descriptor) override; + ITextureView* + CreateView(const TextureViewDescriptor& view_descriptor) override; // Copying void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, - const uint3 dst_origin, const usize3 size, - const Range levels, const Range layers) override; - void CopyFrom(ICommandBuffer* command_buffer, const TextureBase* src, + const uint3 dst_origin, const usize3 dst_size, + const Range dst_levels, + const Range dst_layers) override; + void CopyFrom(ICommandBuffer* command_buffer, const ITexture* src, const uint3 src_origin, const u32 src_level, const u32 src_layer, const uint3 dst_origin, const u32 dst_level, const u32 dst_layer, const usize3 size, const u32 level_count, const u32 layer_count) override; // Blitting - void BlitFrom(ICommandBuffer* command_buffer, const TextureBase* src, + void BlitFrom(ICommandBuffer* command_buffer, const ITexture* src, const float3 src_origin, const usize3 src_size, const u32 src_level, const u32 src_layer, const float3 dst_origin, const usize3 dst_size, @@ -32,18 +33,10 @@ class Texture final : public TextureBase { const u32 level_count, const u32 layer_count) override; private: - bool owns_base{false}; - MTL::Texture* base_texture; MTL::Texture* texture; - MTL::PixelFormat pixel_format; - - MTL::Texture* CreateViewImpl(TextureFormat format, - SwizzleChannels swizzle_channels); - public: GETTER(texture, GetTexture); - GETTER(pixel_format, GetPixelFormat); }; } // namespace hydra::hw::tegra_x1::gpu::renderer::metal diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp new file mode 100644 index 00000000..5cf74914 --- /dev/null +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp @@ -0,0 +1,37 @@ +#include "core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp" + +#include "core/hw/tegra_x1/gpu/renderer/metal/maxwell_to_mtl.hpp" +#include "core/hw/tegra_x1/gpu/renderer/metal/texture.hpp" + +namespace hydra::hw::tegra_x1::gpu::renderer::metal { + +TextureView::TextureView(Texture* base, const TextureViewDescriptor& descriptor) + : ITextureView(base, descriptor) { + const auto& pixel_format_info = to_mtl_pixel_format_info(descriptor.format); + + // Swizzle + // TODO: remove component indices + MTL::TextureSwizzle swizzle_components[] = { + to_mtl_swizzle(descriptor.swizzle_channels.r), + to_mtl_swizzle(descriptor.swizzle_channels.g), + to_mtl_swizzle(descriptor.swizzle_channels.b), + to_mtl_swizzle(descriptor.swizzle_channels.a)}; + MTL::TextureSwizzleChannels swizzle_channels_mtl( + swizzle_components[pixel_format_info.component_indices[0]], + swizzle_components[pixel_format_info.component_indices[1]], + swizzle_components[pixel_format_info.component_indices[2]], + swizzle_components[pixel_format_info.component_indices[3]]); + + // TODO: levels + texture = base->GetTexture()->newTextureView( + to_mtl_pixel_format(descriptor.format), + ToMtlTextureType(descriptor.type), + NS::Range(/*descriptor.levels.GetBegin()*/ 0, + /*descriptor.levels.GetSize()*/ 1), + NS::Range(descriptor.layers.GetBegin(), descriptor.layers.GetSize()), + swizzle_channels_mtl); +} + +TextureView::~TextureView() { texture->release(); } + +} // namespace hydra::hw::tegra_x1::gpu::renderer::metal diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp new file mode 100644 index 00000000..9898bb52 --- /dev/null +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "core/hw/tegra_x1/gpu/renderer/metal/const.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" + +namespace hydra::hw::tegra_x1::gpu::renderer::metal { + +class Texture; + +class TextureView final : public ITextureView { + public: + TextureView(Texture* base, const TextureViewDescriptor& descriptor); + ~TextureView() override; + + private: + MTL::Texture* texture; + + public: + GETTER(texture, GetTexture); +}; + +} // namespace hydra::hw::tegra_x1::gpu::renderer::metal diff --git a/src/core/hw/tegra_x1/gpu/renderer/renderer_base.hpp b/src/core/hw/tegra_x1/gpu/renderer/renderer_base.hpp index d2f70e2e..dff9d123 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/renderer_base.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/renderer_base.hpp @@ -13,7 +13,8 @@ namespace hydra::hw::tegra_x1::gpu::renderer { class ICommandBuffer; class ISurfaceCompositor; -class TextureBase; +class ITexture; +class ITextureView; class SamplerBase; class RenderPassBase; class PipelineBase; @@ -52,7 +53,7 @@ class RendererBase { virtual void FreeTemporaryBuffer(BufferBase* buffer) = 0; // Texture - virtual TextureBase* CreateTexture(const TextureDescriptor& descriptor) = 0; + virtual ITexture* CreateTexture(const TextureDescriptor& descriptor) = 0; // Sampler virtual SamplerBase* CreateSampler(const SamplerDescriptor& descriptor) = 0; @@ -93,7 +94,7 @@ class RendererBase { virtual void BindUniformBuffer(const BufferView& buffer, ShaderType shader_type, u32 index) = 0; // TODO: storage buffers - virtual void BindTexture(TextureBase* texture, SamplerBase* sampler, + virtual void BindTexture(ITextureView* texture, SamplerBase* sampler, ShaderType shader_type, u32 index) = 0; // TODO: images diff --git a/src/core/hw/tegra_x1/gpu/renderer/surface_compositor.hpp b/src/core/hw/tegra_x1/gpu/renderer/surface_compositor.hpp index 77efb005..2dc9b9ab 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/surface_compositor.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/surface_compositor.hpp @@ -5,14 +5,14 @@ namespace hydra::hw::tegra_x1::gpu::renderer { class ICommandBuffer; -class TextureBase; +class ITextureView; class ISurfaceCompositor { public: virtual ~ISurfaceCompositor() = default; virtual void DrawTexture(ICommandBuffer* command_buffer, - const TextureBase* texture, + const ITextureView* texture, const FloatRect2D src_rect, const FloatRect2D dst_rect, bool transparent, f32 opacity = 1.0f) = 0; diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture.hpp new file mode 100644 index 00000000..c8023ce8 --- /dev/null +++ b/src/core/hw/tegra_x1/gpu/renderer/texture.hpp @@ -0,0 +1,53 @@ +#pragma once + +#include "core/hw/tegra_x1/gpu/renderer/const.hpp" + +namespace hydra::hw::tegra_x1::gpu::renderer { + +class ICommandBuffer; +class BufferBase; +class ITextureView; + +class ITexture { + public: + ITexture(const TextureDescriptor& descriptor_) : descriptor{descriptor_} {} + virtual ~ITexture() = default; + + virtual ITextureView* + CreateView(const TextureViewDescriptor& view_descriptor) = 0; + + // Copying + virtual void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, + const uint3 dst_origin, const usize3 dst_size, + const Range dst_levels, + const Range dst_layers) = 0; + void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src) { + CopyFrom( + command_buffer, src, uint3({0, 0, 0}), + usize3({descriptor.width, descriptor.height, descriptor.depth}), + Range(0, descriptor.level_count), + Range(0, descriptor.layer_count)); + } + virtual void CopyFrom(ICommandBuffer* command_buffer, const ITexture* src, + const uint3 src_origin, const u32 src_level, + const u32 src_layer, const uint3 dst_origin, + const u32 dst_level, const u32 dst_layer, + const usize3 size, const u32 level_count, + const u32 layer_count) = 0; + + // Blitting + virtual void BlitFrom(ICommandBuffer* command_buffer, const ITexture* src, + const float3 src_origin, const usize3 src_size, + const u32 src_level, const u32 src_layer, + const float3 dst_origin, const usize3 dst_size, + const u32 dst_level, const u32 dst_layer, + const u32 level_count, const u32 layer_count) = 0; + + protected: + const TextureDescriptor descriptor; + + public: + CONST_REF_GETTER(descriptor, GetDescriptor); +}; + +} // namespace hydra::hw::tegra_x1::gpu::renderer diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp deleted file mode 100644 index e924c08e..00000000 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_base.hpp +++ /dev/null @@ -1,53 +0,0 @@ -#pragma once - -#include "core/hw/tegra_x1/gpu/renderer/const.hpp" - -namespace hydra::hw::tegra_x1::gpu::renderer { - -class ICommandBuffer; -class BufferBase; - -class TextureBase { - public: - TextureBase(const TextureDescriptor& descriptor_) - : descriptor{descriptor_} {} - virtual ~TextureBase() = default; - - virtual TextureBase* - CreateView(const TextureViewDescriptor& descriptor) = 0; - - // Copying - virtual void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, - const uint3 dst_origin, const usize3 size, - const Range levels, const Range layers) = 0; - void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src) { - CopyFrom( - command_buffer, src, uint3({0, 0, 0}), - usize3({descriptor.width, descriptor.height, descriptor.depth}), - Range(0, descriptor.level_count), - Range(0, descriptor.layer_count)); - } - virtual void CopyFrom(ICommandBuffer* command_buffer, - const TextureBase* src, const uint3 src_origin, - const u32 src_level, const u32 src_layer, - const uint3 dst_origin, const u32 dst_level, - const u32 dst_layer, const usize3 size, - const u32 level_count, const u32 layer_count) = 0; - - // Blitting - virtual void BlitFrom(ICommandBuffer* command_buffer, - const TextureBase* src, const float3 src_origin, - const usize3 src_size, const u32 src_level, - const u32 src_layer, const float3 dst_origin, - const usize3 dst_size, const u32 dst_level, - const u32 dst_layer, const u32 level_count, - const u32 layer_count) = 0; - - // Getters - const TextureDescriptor& GetDescriptor() const { return descriptor; } - - protected: - const TextureDescriptor descriptor; -}; - -} // namespace hydra::hw::tegra_x1::gpu::renderer diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index d0857069..93fee77b 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -4,25 +4,38 @@ #include "core/hw/tegra_x1/gpu/memory_util.hpp" #include "core/hw/tegra_x1/gpu/renderer/buffer_base.hpp" #include "core/hw/tegra_x1/gpu/renderer/const.hpp" -#include "core/hw/tegra_x1/gpu/renderer/texture_base.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture.hpp" +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" namespace hydra::hw::tegra_x1::gpu::renderer { TextureCache::~TextureCache() { for (auto& [key, mem] : entries) { - for (auto& [key, sparse_tex] : mem.cache) { - for (auto& [key, group] : sparse_tex.cache) { - delete group.base; - for (auto& [key, view] : group.view_cache) + for (auto& [key, group] : mem.cache) { + for (auto& [key, storage] : group.cache) { + delete storage.base; + for (auto& [key, view] : storage.view_cache) delete view; } } } } -TextureBase* TextureCache::Find(ICommandBuffer* command_buffer, - const TextureDescriptor& descriptor, - TextureUsage usage) { +ITextureView* TextureCache::Find(ICommandBuffer* command_buffer, + const TextureDescriptor& descriptor, + TextureUsage usage) { + return Find(command_buffer, descriptor, + TextureViewDescriptor(descriptor.type, descriptor.format, + Range(0, descriptor.level_count), + Range(0, descriptor.layer_count), + SwizzleChannels()), + usage); +} + +ITextureView* TextureCache::Find(ICommandBuffer* command_buffer, + const TextureDescriptor& descriptor, + const TextureViewDescriptor& view_descriptor, + TextureUsage usage) { const auto range = descriptor.GetRange(); // Check for containing interval @@ -32,7 +45,8 @@ TextureBase* TextureCache::Find(ICommandBuffer* command_buffer, auto& prev_mem = prev->second; if (prev_mem.range.GetEnd() >= range.GetEnd()) { // Fully contained - return AddToMemory(command_buffer, prev_mem, descriptor, usage); + return AddToMemory(command_buffer, prev_mem, descriptor, + view_descriptor, usage); } } @@ -61,7 +75,7 @@ TextureBase* TextureCache::Find(ICommandBuffer* command_buffer, // Insert merged interval auto inserted = entries.emplace(mem.range.GetBegin(), std::move(mem)); return AddToMemory(command_buffer, inserted.first->second, descriptor, - usage); + view_descriptor, usage); } void TextureCache::InvalidateMemory(Range range) { @@ -98,51 +112,60 @@ void TextureCache::MergeMemories(TextureMem& mem, TextureMem& other) { mem.cache.Add(key, std::move(tex)); } -TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, - TextureMem& mem, - const TextureDescriptor& descriptor, - TextureUsage usage) { +ITextureView* +TextureCache::AddToMemory(ICommandBuffer* command_buffer, TextureMem& mem, + const TextureDescriptor& descriptor, + const TextureViewDescriptor& view_descriptor, + TextureUsage usage) { const auto range = descriptor.GetRange(); // Check if it is a new entry - auto sparse_tex_opt = mem.cache.Find(descriptor.GetHash()); - if (!sparse_tex_opt.has_value()) { - auto& sparse_tex = mem.cache.Add(descriptor.GetHash()); - auto& group = sparse_tex.cache.Add(descriptor.ptr); - return GetTexture(command_buffer, group, mem, descriptor, usage); + auto group_opt = mem.cache.Find(descriptor.GetHash()); + if (!group_opt.has_value()) { + auto& group = mem.cache.Add(descriptor.GetHash()); + auto& storage = group.cache.Add(descriptor.ptr); + return GetTexture(command_buffer, storage, mem, descriptor, + view_descriptor, usage); } - auto& sparse_tex = **sparse_tex_opt; + auto& group = **group_opt; // Check if it is just a view with smaller layer count - auto group_opt = sparse_tex.cache.Find(descriptor.ptr); - if (group_opt) { - auto& group = **group_opt; - if (group.base->GetDescriptor().GetRange().Contains(range)) - return GetTexture(command_buffer, group, mem, descriptor, usage); + auto storage_opt = group.cache.Find(descriptor.ptr); + if (storage_opt) { + auto& storage = **storage_opt; + if (storage.base->GetDescriptor().GetRange().Contains(range)) + return GetTextureView(command_buffer, storage, mem, view_descriptor, + usage); else - sparse_tex.cache.Remove(descriptor.ptr); + group.cache.Remove(descriptor.ptr); } // Check if it is a proper layer view - for (auto& [key, group] : sparse_tex.cache) { - if (group.base->GetDescriptor().GetRange().Contains(range)) { + for (auto& [key, storage] : group.cache) { + if (storage.base->GetDescriptor().GetRange().Contains(range)) { const auto offset = static_cast( - range.GetBegin() - group.base->GetDescriptor().ptr); + range.GetBegin() - storage.base->GetDescriptor().ptr); ASSERT_ALIGNMENT_DEBUG(offset, descriptor.layer_size, Gpu, "texture view offset"); - const auto layers = Range::FromSize( - offset / descriptor.layer_size, descriptor.layer_count); + const u32 layer_offset = offset / descriptor.layer_size; return GetTextureView( - group, TextureViewDescriptor(descriptor.format, - descriptor.swizzle_channels, - Range(0, 1), layers)); + command_buffer, storage, mem, + TextureViewDescriptor( + view_descriptor.type, view_descriptor.format, + view_descriptor.levels, + Range::FromSize(layer_offset + + view_descriptor.layers.GetBegin(), + view_descriptor.layers.GetSize()), + view_descriptor.swizzle_channels), + usage); } } // HACK: create a new texture - auto& group = sparse_tex.cache.Add(descriptor.ptr); - return GetTexture(command_buffer, group, mem, descriptor, usage); + auto& storage = group.cache.Add(descriptor.ptr); + return GetTexture(command_buffer, storage, mem, descriptor, view_descriptor, + usage); /* // Create a new entry and merge it with others @@ -218,61 +241,42 @@ TextureBase* TextureCache::AddToMemory(ICommandBuffer* command_buffer, */ } -TextureBase* TextureCache::GetTexture(ICommandBuffer* command_buffer, - TextureGroup& group, TextureMem& mem, - const TextureDescriptor& descriptor, - TextureUsage usage) { - if (!group.base) - Create(command_buffer, descriptor, group); - - Update(command_buffer, group, mem, usage); - - // If the formats match and swizzle is the default swizzle, - // return base - if (descriptor.format == group.base->GetDescriptor().format && - descriptor.swizzle_channels == SwizzleChannels()) { - return group.base; +ITextureView* TextureCache::GetTexture( + ICommandBuffer* command_buffer, TextureStorage& storage, TextureMem& mem, + const TextureDescriptor& descriptor, + const TextureViewDescriptor& view_descriptor, TextureUsage usage) { + if (!storage.base) { + storage.base = RENDERER_INSTANCE.CreateTexture(descriptor); + DecodeTexture(command_buffer, storage); } - // Otherwise, get a texture view - auto view_desc = - TextureViewDescriptor(descriptor.format, descriptor.swizzle_channels, - Range(0, descriptor.level_count), - Range(0, descriptor.layer_count)); - return GetTextureView(group, view_desc); + return GetTextureView(command_buffer, storage, mem, view_descriptor, usage); } -TextureBase* -TextureCache::GetTextureView(TextureGroup& group, - const TextureViewDescriptor& descriptor) { - auto view_opt = group.view_cache.Find(descriptor.GetHash()); +ITextureView* TextureCache::GetTextureView( + ICommandBuffer* command_buffer, TextureStorage& storage, TextureMem& mem, + const TextureViewDescriptor& view_descriptor, TextureUsage usage) { + Update(command_buffer, storage, mem, usage); + + auto view_opt = storage.view_cache.Find(view_descriptor.GetHash()); if (view_opt.has_value()) return **view_opt; - auto view = group.base->CreateView(descriptor); - group.view_cache.Add(descriptor.GetHash(), view); + auto view = storage.base->CreateView(view_descriptor); + storage.view_cache.Add(view_descriptor.GetHash(), view); return view; } -void TextureCache::Create(ICommandBuffer* command_buffer, - const TextureDescriptor& descriptor, - TextureGroup& group) { - auto desc = descriptor; - desc.swizzle_channels = - get_texture_format_default_swizzle_channels(desc.format); - group.base = RENDERER_INSTANCE.CreateTexture(desc); - DecodeTexture(command_buffer, group); -} - -void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, - TextureMem& mem, TextureUsage usage) { +void TextureCache::Update(ICommandBuffer* command_buffer, + TextureStorage& storage, TextureMem& mem, + TextureUsage usage) { bool sync = false; - if (group.update_timestamp < mem.info.modified_timestamp) { + if (storage.update_timestamp < mem.info.modified_timestamp) { // If modified by the guest sync = true; - } else if (group.update_timestamp < mem.info.written_timestamp) { + } else if (storage.update_timestamp < mem.info.written_timestamp) { // Other textures in this memory changed, let's copy them - const auto base = group.base; + const auto base = storage.base; const auto& descriptor = base->GetDescriptor(); const auto range = descriptor.GetRange(); for (auto& [key, sparse_tex] : mem.cache) { @@ -374,7 +378,7 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, } } - group.MarkUpdated(); + storage.MarkUpdated(); } else if (mem.info.written_timestamp == TextureCacheTimePoint{}) { // Never written to if (usage == TextureUsage::Present) { @@ -386,7 +390,7 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, } if (sync) - DecodeTexture(command_buffer, group); + DecodeTexture(command_buffer, storage); if (usage == TextureUsage::Read) mem.info.MarkRead(); @@ -394,10 +398,10 @@ void TextureCache::Update(ICommandBuffer* command_buffer, TextureGroup& group, mem.info.MarkWritten(); if (usage == TextureUsage::Write || sync) - group.MarkUpdated(); + storage.MarkUpdated(); } -u32 TextureCache::GetDataHash(const TextureBase* texture) { +u32 TextureCache::GetDataHash(const ITexture* texture) { constexpr u32 SAMPLE_COUNT = 37; const auto& descriptor = texture->GetDescriptor(); @@ -412,8 +416,8 @@ u32 TextureCache::GetDataHash(const TextureBase* texture) { } void TextureCache::DecodeTexture(ICommandBuffer* command_buffer, - TextureGroup& group) { - const auto& descriptor = group.base->GetDescriptor(); + TextureStorage& storage) { + const auto& descriptor = storage.base->GetDescriptor(); // Align the height to 16 bytes (TODO: why 16?) auto tmp_buffer = @@ -433,7 +437,7 @@ void TextureCache::DecodeTexture(ICommandBuffer* command_buffer, descriptor.block_height_log2, in_data, out_data); } - group.base->CopyFrom(command_buffer, tmp_buffer); + storage.base->CopyFrom(command_buffer, tmp_buffer); RENDERER_INSTANCE.FreeTemporaryBuffer(tmp_buffer); } diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp index 06fd437b..7706782c 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.hpp @@ -9,28 +9,29 @@ class IMmu; namespace hydra::hw::tegra_x1::gpu::renderer { class ICommandBuffer; -class TextureBase; +class ITexture; +class ITextureView; typedef std::chrono::steady_clock TextureCacheClock; typedef TextureCacheClock::time_point TextureCacheTimePoint; -struct TextureGroup { - TextureBase* base{nullptr}; - SmallCache view_cache; +struct TextureStorage { + ITexture* base{nullptr}; + SmallCache view_cache; TextureCacheTimePoint update_timestamp{}; void MarkUpdated() { update_timestamp = TextureCacheClock::now(); } }; -struct SparseTexture { - SmallCache cache; +struct TextureGroup { + SmallCache cache; // Debug - usize GetGroupCount() const { return cache.GetCount(); } + usize GetStorageCount() const { return cache.GetCount(); } - const TextureGroup& GetGroup(u32 index) const { + const TextureStorage& GetStorage(u32 index) const { // HACK: const cast - auto it = const_cast&>(cache).begin(); + auto it = const_cast&>(cache).begin(); std::advance(it, index); return it->second; } @@ -49,14 +50,14 @@ struct TextureMemInfo { struct TextureMem { Range range; TextureMemInfo info; - SmallCache cache; + SmallCache cache; // Debug - usize GetSparseTextureCount() const { return cache.GetCount(); } + usize GetTextureGroupCount() const { return cache.GetCount(); } - const SparseTexture& GetSparseTexture(u32 index) const { + const TextureGroup& GetTextureGroup(u32 index) const { // HACK: const cast - auto it = const_cast&>(cache).begin(); + auto it = const_cast&>(cache).begin(); std::advance(it, index); return it->second; } @@ -68,8 +69,12 @@ class TextureCache { public: ~TextureCache(); - TextureBase* Find(ICommandBuffer* command_buffer, - const TextureDescriptor& descriptor, TextureUsage usage); + ITextureView* Find(ICommandBuffer* command_buffer, + const TextureDescriptor& descriptor, TextureUsage usage); + ITextureView* Find(ICommandBuffer* command_buffer, + const TextureDescriptor& descriptor, + const TextureViewDescriptor& view_descriptor, + TextureUsage usage); void InvalidateMemory(Range range); @@ -88,23 +93,25 @@ class TextureCache { std::map entries; void MergeMemories(TextureMem& mem, TextureMem& other); - TextureBase* AddToMemory(ICommandBuffer* command_buffer, TextureMem& mem, + ITextureView* AddToMemory(ICommandBuffer* command_buffer, TextureMem& mem, + const TextureDescriptor& descriptor, + const TextureViewDescriptor& view_descriptor, + TextureUsage usage); + ITextureView* GetTexture(ICommandBuffer* command_buffer, + TextureStorage& storage, TextureMem& mem, const TextureDescriptor& descriptor, + const TextureViewDescriptor& view_descriptor, TextureUsage usage); - TextureBase* GetTexture(ICommandBuffer* command_buffer, TextureGroup& group, - TextureMem& mem, - const TextureDescriptor& descriptor, - TextureUsage usage); - TextureBase* GetTextureView(TextureGroup& group, - const TextureViewDescriptor& descriptor); - void Create(ICommandBuffer* command_buffer, - const TextureDescriptor& descriptor, TextureGroup& group); - void Update(ICommandBuffer* command_buffer, TextureGroup& group, + ITextureView* GetTextureView(ICommandBuffer* command_buffer, + TextureStorage& storage, TextureMem& mem, + const TextureViewDescriptor& view_descriptor, + TextureUsage usage); + void Update(ICommandBuffer* command_buffer, TextureStorage& storage, TextureMem& mem, TextureUsage usage); // Helpers - u32 GetDataHash(const TextureBase* texture); - void DecodeTexture(ICommandBuffer* command_buffer, TextureGroup& group); + u32 GetDataHash(const ITexture* texture); + void DecodeTexture(ICommandBuffer* command_buffer, TextureStorage& storage); // TODO: encode texture public: diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_view.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_view.cpp new file mode 100644 index 00000000..1c1d0b85 --- /dev/null +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_view.cpp @@ -0,0 +1,58 @@ +#include "core/hw/tegra_x1/gpu/renderer/texture_view.hpp" + +#include "core/hw/tegra_x1/gpu/renderer/texture.hpp" + +namespace hydra::hw::tegra_x1::gpu::renderer { + +void ITextureView::CopyFrom(ICommandBuffer* command_buffer, + const BufferBase* src, const uint3 dst_origin, + const usize3 dst_size, const Range dst_levels, + const Range dst_layers) { + base->CopyFrom(command_buffer, src, dst_origin, dst_size, + Range::FromSize(descriptor.levels.GetBegin() + + dst_levels.GetBegin(), + dst_levels.GetSize()), + Range::FromSize(descriptor.layers.GetBegin() + + dst_layers.GetBegin(), + dst_layers.GetSize())); +} + +void ITextureView::CopyFrom(ICommandBuffer* command_buffer, + const BufferBase* src) { + CopyFrom(command_buffer, src, uint3({0, 0, 0}), + usize3({base->GetDescriptor().width, base->GetDescriptor().height, + base->GetDescriptor().depth}), + Range(0, descriptor.levels.GetSize()), + Range(0, descriptor.layers.GetSize())); +} + +void ITextureView::CopyFrom(ICommandBuffer* command_buffer, + const ITextureView* src, const uint3 src_origin, + const u32 src_level, const u32 src_layer, + const uint3 dst_origin, const u32 dst_level, + const u32 dst_layer, const usize3 size, + const u32 level_count, const u32 layer_count) { + base->CopyFrom(command_buffer, src->GetBase(), src_origin, + src->GetDescriptor().levels.GetBegin() + src_level, + src->GetDescriptor().layers.GetBegin() + src_layer, + dst_origin, descriptor.levels.GetBegin() + dst_level, + descriptor.layers.GetBegin() + dst_layer, size, level_count, + layer_count); +} + +void ITextureView::BlitFrom(ICommandBuffer* command_buffer, + const ITextureView* src, const float3 src_origin, + const usize3 src_size, const u32 src_level, + const u32 src_layer, const float3 dst_origin, + const usize3 dst_size, const u32 dst_level, + const u32 dst_layer, const u32 level_count, + const u32 layer_count) { + base->BlitFrom( + command_buffer, src->GetBase(), src_origin, src_size, + src->GetDescriptor().levels.GetBegin() + src_level, + src->GetDescriptor().layers.GetBegin() + src_layer, dst_origin, + dst_size, descriptor.levels.GetBegin() + dst_level, + descriptor.layers.GetBegin() + dst_layer, level_count, layer_count); +} + +} // namespace hydra::hw::tegra_x1::gpu::renderer diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_view.hpp b/src/core/hw/tegra_x1/gpu/renderer/texture_view.hpp new file mode 100644 index 00000000..88c62906 --- /dev/null +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_view.hpp @@ -0,0 +1,45 @@ +#pragma once + +#include "core/hw/tegra_x1/gpu/renderer/const.hpp" + +namespace hydra::hw::tegra_x1::gpu::renderer { + +class ICommandBuffer; +class BufferBase; +class ITexture; + +class ITextureView { + public: + ITextureView(ITexture* base_, const TextureViewDescriptor& descriptor_) + : base{base_}, descriptor{descriptor_} {} + virtual ~ITextureView() = default; + + // Copying + void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src, + const uint3 dst_origin, const usize3 dst_size, + const Range dst_levels, const Range dst_layers); + void CopyFrom(ICommandBuffer* command_buffer, const BufferBase* src); + void CopyFrom(ICommandBuffer* command_buffer, const ITextureView* src, + const uint3 src_origin, const u32 src_level, + const u32 src_layer, const uint3 dst_origin, + const u32 dst_level, const u32 dst_layer, const usize3 size, + const u32 level_count, const u32 layer_count); + + // Blitting + void BlitFrom(ICommandBuffer* command_buffer, const ITextureView* src, + const float3 src_origin, const usize3 src_size, + const u32 src_level, const u32 src_layer, + const float3 dst_origin, const usize3 dst_size, + const u32 dst_level, const u32 dst_layer, + const u32 level_count, const u32 layer_count); + + protected: + ITexture* base; + const TextureViewDescriptor descriptor; + + public: + GETTER(base, GetBase); + CONST_REF_GETTER(descriptor, GetDescriptor); +}; + +} // namespace hydra::hw::tegra_x1::gpu::renderer diff --git a/src/frontend/swiftui/Api.swift b/src/frontend/swiftui/Api.swift index d62a2523..5be7325f 100644 --- a/src/frontend/swiftui/Api.swift +++ b/src/frontend/swiftui/Api.swift @@ -1118,34 +1118,34 @@ func hydraTextureCacheGetTextureMemory(at index: Int) -> HydraTextureMemory { struct HydraTextureMemory: HandleStruct { internal let handle: UnsafeRawPointer - var sparseTextureCount: Int { - Int(hydra_texture_memory_get_sparse_texture_count(self.handle)) + var textureGroupCount: Int { + Int(hydra_texture_memory_get_texture_group_count(self.handle)) } - func getSparseTexture(at index: Int) -> HydraSparseTexture { - HydraSparseTexture(handle: hydra_texture_memory_get_sparse_texture(self.handle, UInt32(index))) + func getTextureGroup(at index: Int) -> HydraTextureGroup { + HydraTextureGroup(handle: hydra_texture_memory_get_texture_group(self.handle, UInt32(index))) } } -// Sparse texture -struct HydraSparseTexture: HandleStruct { +// Texture group +struct HydraTextureGroup: HandleStruct { internal let handle: UnsafeRawPointer - var textureGroupCount: Int { - Int(hydra_sparse_texture_get_texture_group_count(self.handle)) + var textureStorageCount: Int { + Int(hydra_texture_group_get_texture_storage_count(self.handle)) } - func getTextureGroup(at index: Int) -> HydraTextureGroup { - HydraTextureGroup(handle: hydra_sparse_texture_get_texture_group(self.handle, UInt32(index))) + func getTextureStorage(at index: Int) -> HydraTextureStorage { + HydraTextureStorage(handle: hydra_texture_group_get_texture_storage(self.handle, UInt32(index))) } } -// Texture group -struct HydraTextureGroup: HandleStruct { +// Texture storage +struct HydraTextureStorage: HandleStruct { internal let handle: UnsafeRawPointer var descriptor: HydraTextureDescriptor { - HydraTextureDescriptor(handle: hydra_texture_group_get_texture_descriptor(self.handle)) + HydraTextureDescriptor(handle: hydra_texture_storage_get_texture_descriptor(self.handle)) } } diff --git a/src/frontend/swiftui/texture_viewer/TextureListView.swift b/src/frontend/swiftui/texture_viewer/TextureListView.swift index 2dbb47b9..9d5bdfef 100644 --- a/src/frontend/swiftui/texture_viewer/TextureListView.swift +++ b/src/frontend/swiftui/texture_viewer/TextureListView.swift @@ -3,13 +3,13 @@ import SwiftUI struct TextureListView: View { @State private var refreshID = 0 - @State private var textures: [HydraTextureGroup] = [] + @State private var textures: [HydraTextureStorage] = [] var body: some View { ZStack { List { - ForEach(Array(self.textures.enumerated()), id: \.offset) { index, group in - TextureView(group: group) + ForEach(Array(self.textures.enumerated()), id: \.offset) { index, storage in + TextureView(storage: storage) .id("\(refreshID)-\(index)") // Unique ID per refresh } } @@ -45,11 +45,11 @@ struct TextureListView: View { self.textures.removeAll() for i in 0.. Date: Tue, 5 May 2026 17:26:24 +0200 Subject: [PATCH 10/17] renderer: correct buffer cache note --- src/core/hw/tegra_x1/gpu/renderer/buffer_cache.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/hw/tegra_x1/gpu/renderer/buffer_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/buffer_cache.cpp index fa11ae55..8f7e2e47 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/buffer_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/buffer_cache.cpp @@ -48,7 +48,7 @@ void BufferCache::InvalidateMemory(Range range) { entry.invalidation_range = entry.invalidation_range.value().Union(invalidation_range); } else { - // Clamp the range + // Set the range directly entry.invalidation_range = invalidation_range; } } From 9ad7d3554aa0642de0e8179b263fdbd36fe966b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Tue, 5 May 2026 18:51:33 +0200 Subject: [PATCH 11/17] metal: demote texture types from arrays if possible --- .../gpu/renderer/metal/texture_view.cpp | 23 +++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp b/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp index 5cf74914..05574e2f 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/metal/texture_view.cpp @@ -22,10 +22,29 @@ TextureView::TextureView(Texture* base, const TextureViewDescriptor& descriptor) swizzle_components[pixel_format_info.component_indices[2]], swizzle_components[pixel_format_info.component_indices[3]]); + auto type = descriptor.type; + + // Demote array types to non-array types if possible + switch (type) { + case TextureType::_1DArray: + if (descriptor.layers.GetSize() == 1) + type = TextureType::_1D; + break; + case TextureType::_2DArray: + if (descriptor.layers.GetSize() == 1) + type = TextureType::_2D; + break; + case TextureType::CubeArray: + if (descriptor.layers.GetSize() == 6) + type = TextureType::Cube; + break; + default: + break; + } + // TODO: levels texture = base->GetTexture()->newTextureView( - to_mtl_pixel_format(descriptor.format), - ToMtlTextureType(descriptor.type), + to_mtl_pixel_format(descriptor.format), ToMtlTextureType(type), NS::Range(/*descriptor.levels.GetBegin()*/ 0, /*descriptor.levels.GetSize()*/ 1), NS::Range(descriptor.layers.GetBegin(), descriptor.layers.GetSize()), From 3246bb53356e2f6e5091e629ba4d48157446055e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Wed, 6 May 2026 08:33:28 +0200 Subject: [PATCH 12/17] renderer: relax texture stride hashing rules --- src/core/hw/tegra_x1/gpu/renderer/const.cpp | 4 ++-- src/core/hw/tegra_x1/gpu/renderer/const.hpp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.cpp b/src/core/hw/tegra_x1/gpu/renderer/const.cpp index 256f789c..94e3bb09 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.cpp @@ -619,8 +619,8 @@ SwizzleChannels::SwizzleChannels(const TextureFormat format, u32 TextureDescriptor::GetHash() const { HashCode hash; hash.Add(ptr); - hash.Add(is_linear); - hash.Add(linear_stride); + if (is_linear) + hash.Add(linear_stride); hash.Add(width); hash.Add(height); hash.Add(depth); diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.hpp b/src/core/hw/tegra_x1/gpu/renderer/const.hpp index 751e41ab..40ab892b 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.hpp @@ -272,7 +272,7 @@ struct TextureDescriptor { d.layer_size = layer_size; d.CalculateLevelCount(); - if (layer_size == 0) + if (layer_size == 0 || layer_count == 1) d.CalculateLayerSize(); return d; From 16063d0d924514360fdd2eaf860b5b9d3204b7e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Wed, 6 May 2026 08:44:35 +0200 Subject: [PATCH 13/17] renderer: don't copy textures to themselves --- src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index 93fee77b..18905f59 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -279,11 +279,13 @@ void TextureCache::Update(ICommandBuffer* command_buffer, const auto base = storage.base; const auto& descriptor = base->GetDescriptor(); const auto range = descriptor.GetRange(); - for (auto& [key, sparse_tex] : mem.cache) { - // TODO: skip this sparse texture + for (auto& [key, group] : mem.cache) { + for (auto& [key, other_storage] : group.cache) { + // Skip this storage + if (&other_storage == &storage) + continue; - for (auto& [key, other_group] : sparse_tex.cache) { - const auto other_base = other_group.base; + const auto other_base = other_storage.base; const auto& other_descriptor = other_base->GetDescriptor(); const auto other_range = other_descriptor.GetRange(); From 9bee7b7afa7875be2692140f9f9e79399783e5f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Sat, 9 May 2026 08:19:40 +0200 Subject: [PATCH 14/17] swiftui: rework texture viewer --- src/core/c_api.cpp | 16 ++ src/core/c_api.h | 2 + src/frontend/CMakeLists.txt | 1 - src/frontend/swiftui/Api.swift | 185 ++++++++++++++++++ .../texture_viewer/TextureListView.swift | 27 ++- .../swiftui/texture_viewer/TextureView.swift | 35 ---- 6 files changed, 226 insertions(+), 40 deletions(-) delete mode 100644 src/frontend/swiftui/texture_viewer/TextureView.swift diff --git a/src/core/c_api.cpp b/src/core/c_api.cpp index fc1192bb..c73cf6cc 100644 --- a/src/core/c_api.cpp +++ b/src/core/c_api.cpp @@ -1106,6 +1106,22 @@ hydra_texture_descriptor_get_depth(const void* descriptor) { ->depth; } +HYDRA_EXPORT uint32_t +hydra_texture_descriptor_get_level_count(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->level_count; +} + +HYDRA_EXPORT uint32_t +hydra_texture_descriptor_get_layer_count(const void* descriptor) { + return static_cast< + const hydra::hw::tegra_x1::gpu::renderer::TextureDescriptor*>( + descriptor) + ->layer_count; +} + HYDRA_EXPORT uint64_t hydra_texture_descriptor_get_layer_size(const void* descriptor) { return static_cast< diff --git a/src/core/c_api.h b/src/core/c_api.h index 702e991a..69dca5be 100644 --- a/src/core/c_api.h +++ b/src/core/c_api.h @@ -568,6 +568,8 @@ HydraTextureFormat hydra_texture_descriptor_get_format(const void* descriptor); uint32_t hydra_texture_descriptor_get_width(const void* descriptor); uint32_t hydra_texture_descriptor_get_height(const void* descriptor); uint32_t hydra_texture_descriptor_get_depth(const void* descriptor); +uint32_t hydra_texture_descriptor_get_level_count(const void* descriptor); +uint32_t hydra_texture_descriptor_get_layer_count(const void* descriptor); uint64_t hydra_texture_descriptor_get_layer_size(const void* descriptor); uint64_t hydra_texture_descriptor_get_size(const void* descriptor); diff --git a/src/frontend/CMakeLists.txt b/src/frontend/CMakeLists.txt index fb742aed..5581691c 100644 --- a/src/frontend/CMakeLists.txt +++ b/src/frontend/CMakeLists.txt @@ -79,7 +79,6 @@ elseif (FRONTEND STREQUAL "SwiftUI") swiftui/debugger/DebuggersView.swift swiftui/texture_viewer/TextureViewer.swift swiftui/texture_viewer/TextureListView.swift - swiftui/texture_viewer/TextureView.swift ) if (CMAKE_SYSTEM_NAME STREQUAL "Darwin") diff --git a/src/frontend/swiftui/Api.swift b/src/frontend/swiftui/Api.swift index 5be7325f..75f37f37 100644 --- a/src/frontend/swiftui/Api.swift +++ b/src/frontend/swiftui/Api.swift @@ -1150,6 +1150,183 @@ struct HydraTextureStorage: HandleStruct { } // Texture descriptor +extension HydraTextureType { + var description: String { + switch self { + case HYDRA_TEXTURE_TYPE_1D: + return "1D" + case HYDRA_TEXTURE_TYPE_1D_ARRAY: + return "1D Array" + case HYDRA_TEXTURE_TYPE_1D_BUFFER: + return "1D Buffer" + case HYDRA_TEXTURE_TYPE_2D: + return "2D" + case HYDRA_TEXTURE_TYPE_2D_ARRAY: + return "2D Array" + case HYDRA_TEXTURE_TYPE_3D: + return "3D" + case HYDRA_TEXTURE_TYPE_CUBE: + return "Cube" + case HYDRA_TEXTURE_TYPE_CUBE_ARRAY: + return "Cube Array" + default: + return "Unknown \(self.rawValue)" + } + } +} + +extension HydraTextureFormat { + var description: String { + switch self { + case HYDRA_TEXTURE_FORMAT_INVALID: return "Invalid" + + case HYDRA_TEXTURE_FORMAT_R8_UNORM: return "R8 Unorm" + case HYDRA_TEXTURE_FORMAT_R8_SNORM: return "R8 Snorm" + case HYDRA_TEXTURE_FORMAT_R8_UINT: return "R8 UInt" + case HYDRA_TEXTURE_FORMAT_R8_SINT: return "R8 SInt" + case HYDRA_TEXTURE_FORMAT_R16_FLOAT: return "R16 Float" + case HYDRA_TEXTURE_FORMAT_R16_UNORM: return "R16 Unorm" + case HYDRA_TEXTURE_FORMAT_R16_SNORM: return "R16 Snorm" + case HYDRA_TEXTURE_FORMAT_R16_UINT: return "R16 UInt" + case HYDRA_TEXTURE_FORMAT_R16_SINT: return "R16 SInt" + case HYDRA_TEXTURE_FORMAT_R32_FLOAT: return "R32 Float" + case HYDRA_TEXTURE_FORMAT_R32_UINT: return "R32 UInt" + case HYDRA_TEXTURE_FORMAT_R32_SINT: return "R32 SInt" + + case HYDRA_TEXTURE_FORMAT_RG8_UNORM: return "RG8 Unorm" + case HYDRA_TEXTURE_FORMAT_RG8_SNORM: return "RG8 Snorm" + case HYDRA_TEXTURE_FORMAT_RG8_UINT: return "RG8 UInt" + case HYDRA_TEXTURE_FORMAT_RG8_SINT: return "RG8 SInt" + case HYDRA_TEXTURE_FORMAT_RG16_FLOAT: return "RG16 Float" + case HYDRA_TEXTURE_FORMAT_RG16_UNORM: return "RG16 Unorm" + case HYDRA_TEXTURE_FORMAT_RG16_SNORM: return "RG16 Snorm" + case HYDRA_TEXTURE_FORMAT_RG16_UINT: return "RG16 UInt" + case HYDRA_TEXTURE_FORMAT_RG16_SINT: return "RG16 SInt" + case HYDRA_TEXTURE_FORMAT_RG32_FLOAT: return "RG32 Float" + case HYDRA_TEXTURE_FORMAT_RG32_UINT: return "RG32 UInt" + case HYDRA_TEXTURE_FORMAT_RG32_SINT: return "RG32 SInt" + + case HYDRA_TEXTURE_FORMAT_RGB32_FLOAT: return "RGB32 Float" + case HYDRA_TEXTURE_FORMAT_RGB32_UINT: return "RGB32 UInt" + case HYDRA_TEXTURE_FORMAT_RGB32_SINT: return "RGB32 SInt" + + case HYDRA_TEXTURE_FORMAT_RGBA8_UNORM: return "RGBA8 Unorm" + case HYDRA_TEXTURE_FORMAT_RGBA8_SNORM: return "RGBA8 Snorm" + case HYDRA_TEXTURE_FORMAT_RGBA8_UINT: return "RGBA8 UInt" + case HYDRA_TEXTURE_FORMAT_RGBA8_SINT: return "RGBA8 SInt" + case HYDRA_TEXTURE_FORMAT_RGBA16_FLOAT: return "RGBA16 Float" + case HYDRA_TEXTURE_FORMAT_RGBA16_UNORM: return "RGBA16 Unorm" + case HYDRA_TEXTURE_FORMAT_RGBA16_SNORM: return "RGBA16 Snorm" + case HYDRA_TEXTURE_FORMAT_RGBA16_UINT: return "RGBA16 UInt" + case HYDRA_TEXTURE_FORMAT_RGBA16_SINT: return "RGBA16 SInt" + case HYDRA_TEXTURE_FORMAT_RGBA32_FLOAT: return "RGBA32 Float" + case HYDRA_TEXTURE_FORMAT_RGBA32_UINT: return "RGBA32 UInt" + case HYDRA_TEXTURE_FORMAT_RGBA32_SINT: return "RGBA32 SInt" + + case HYDRA_TEXTURE_FORMAT_S8_UINT: return "S8 UInt" + case HYDRA_TEXTURE_FORMAT_Z16_UNORM: return "Z16 Unorm" + case HYDRA_TEXTURE_FORMAT_Z24_UNORM_X8_UINT: return "Z24 Unorm X8 UInt" + case HYDRA_TEXTURE_FORMAT_Z32_FLOAT: return "Z32 Float" + case HYDRA_TEXTURE_FORMAT_Z24_UNORM_S8_UINT: return "Z24 Unorm S8 UInt" + case HYDRA_TEXTURE_FORMAT_Z32_FLOAT_X24_S8_UINT: return "Z32 Float X24 S8 UInt" + + case HYDRA_TEXTURE_FORMAT_RGBX8_UNORM_SRGB: return "RGBX8 Unorm sRGB" + case HYDRA_TEXTURE_FORMAT_RGBA8_UNORM_SRGB: return "RGBA8 Unorm sRGB" + case HYDRA_TEXTURE_FORMAT_RGBA4_UNORM: return "RGBA4 Unorm" + case HYDRA_TEXTURE_FORMAT_RGB5_UNORM: return "RGB5 Unorm" + case HYDRA_TEXTURE_FORMAT_RGB5A1_UNORM: return "RGB5A1 Unorm" + case HYDRA_TEXTURE_FORMAT_R5G6B5_UNORM: return "R5G6B5 Unorm" + case HYDRA_TEXTURE_FORMAT_RGB10A2_UNORM: return "RGB10A2 Unorm" + case HYDRA_TEXTURE_FORMAT_RGB10A2_UINT: return "RGB10A2 UInt" + case HYDRA_TEXTURE_FORMAT_RG11B10_FLOAT: return "RG11B10 Float" + case HYDRA_TEXTURE_FORMAT_E5BGR9_FLOAT: return "E5BGR9 Float" + + case HYDRA_TEXTURE_FORMAT_BC1_RGB: return "BC1 RGB" + case HYDRA_TEXTURE_FORMAT_BC1_RGBA: return "BC1 RGBA" + case HYDRA_TEXTURE_FORMAT_BC2_RGBA: return "BC2 RGBA" + case HYDRA_TEXTURE_FORMAT_BC3_RGBA: return "BC3 RGBA" + case HYDRA_TEXTURE_FORMAT_BC1_RGB_SRGB: return "BC1 RGB sRGB" + case HYDRA_TEXTURE_FORMAT_BC1_RGBA_SRGB: return "BC1 RGBA sRGB" + case HYDRA_TEXTURE_FORMAT_BC2_RGBA_SRGB: return "BC2 RGBA sRGB" + case HYDRA_TEXTURE_FORMAT_BC3_RGBA_SRGB: return "BC3 RGBA sRGB" + case HYDRA_TEXTURE_FORMAT_BC4_R_UNORM: return "BC4 R Unorm" + case HYDRA_TEXTURE_FORMAT_BC4_R_SNORM: return "BC4 R Snorm" + case HYDRA_TEXTURE_FORMAT_BC5_RG_UNORM: return "BC5 RG Unorm" + case HYDRA_TEXTURE_FORMAT_BC5_RG_SNORM: return "BC5 RG Snorm" + case HYDRA_TEXTURE_FORMAT_BC7_RGBA_UNORM: return "BC7 RGBA Unorm" + case HYDRA_TEXTURE_FORMAT_BC7_RGBA_UNORM_SRGB: return "BC7 RGBA Unorm sRGB" + case HYDRA_TEXTURE_FORMAT_BC6H_RGBA_SF16_FLOAT: return "BC6H SF16 Float" + case HYDRA_TEXTURE_FORMAT_BC6H_RGBA_UF16_FLOAT: return "BC6H UF16 Float" + + case HYDRA_TEXTURE_FORMAT_RGBX8_UNORM: return "RGBX8 Unorm" + case HYDRA_TEXTURE_FORMAT_RGBX8_SNORM: return "RGBX8 Snorm" + case HYDRA_TEXTURE_FORMAT_RGBX8_UINT: return "RGBX8 UInt" + case HYDRA_TEXTURE_FORMAT_RGBX8_SINT: return "RGBX8 SInt" + case HYDRA_TEXTURE_FORMAT_RGBX16_FLOAT: return "RGBX16 Float" + case HYDRA_TEXTURE_FORMAT_RGBX16_UNORM: return "RGBX16 Unorm" + case HYDRA_TEXTURE_FORMAT_RGBX16_SNORM: return "RGBX16 Snorm" + case HYDRA_TEXTURE_FORMAT_RGBX16_UINT: return "RGBX16 UInt" + case HYDRA_TEXTURE_FORMAT_RGBX16_SINT: return "RGBX16 SInt" + case HYDRA_TEXTURE_FORMAT_RGBX32_FLOAT: return "RGBX32 Float" + case HYDRA_TEXTURE_FORMAT_RGBX32_UINT: return "RGBX32 UInt" + case HYDRA_TEXTURE_FORMAT_RGBX32_SINT: return "RGBX32 SInt" + + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_4X4: return "ASTC 4x4" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X4: return "ASTC 5x4" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X5: return "ASTC 5x5" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X5: return "ASTC 6x5" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X6: return "ASTC 6x6" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X5: return "ASTC 8x5" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X6: return "ASTC 8x6" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X8: return "ASTC 8x8" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X5: return "ASTC 10x5" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X6: return "ASTC 10x6" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X8: return "ASTC 10x8" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X10: return "ASTC 10x10" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X10: return "ASTC 12x10" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X12: return "ASTC 12x12" + + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_4X4_SRGB: return "ASTC 4x4 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X4_SRGB: return "ASTC 5x4 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_5X5_SRGB: return "ASTC 5x5 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X5_SRGB: return "ASTC 6x5 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_6X6_SRGB: return "ASTC 6x6 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X5_SRGB: return "ASTC 8x5 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X6_SRGB: return "ASTC 8x6 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_8X8_SRGB: return "ASTC 8x8 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X5_SRGB: return "ASTC 10x5 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X6_SRGB: return "ASTC 10x6 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X8_SRGB: return "ASTC 10x8 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_10X10_SRGB: return "ASTC 10x10 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X10_SRGB: return "ASTC 12x10 sRGB" + case HYDRA_TEXTURE_FORMAT_ASTC_RGBA_12X12_SRGB: return "ASTC 12x12 sRGB" + + case HYDRA_TEXTURE_FORMAT_B5G6R5_UNORM: return "B5G6R5 Unorm" + case HYDRA_TEXTURE_FORMAT_BGR5_UNORM: return "BGR5 Unorm" + case HYDRA_TEXTURE_FORMAT_BGR5A1_UNORM: return "BGR5A1 Unorm" + case HYDRA_TEXTURE_FORMAT_A1BGR5_UNORM: return "A1BGR5 Unorm" + case HYDRA_TEXTURE_FORMAT_BGRX8_UNORM: return "BGRX8 Unorm" + case HYDRA_TEXTURE_FORMAT_BGRA8_UNORM: return "BGRA8 Unorm" + case HYDRA_TEXTURE_FORMAT_BGRX8_UNORM_SRGB: return "BGRX8 Unorm sRGB" + case HYDRA_TEXTURE_FORMAT_BGRA8_UNORM_SRGB: return "BGRA8 Unorm sRGB" + + case HYDRA_TEXTURE_FORMAT_ETC2_R_UNORM: return "ETC2 R Unorm" + case HYDRA_TEXTURE_FORMAT_ETC2_R_SNORM: return "ETC2 R Snorm" + case HYDRA_TEXTURE_FORMAT_ETC2_RG_UNORM: return "ETC2 RG Unorm" + case HYDRA_TEXTURE_FORMAT_ETC2_RG_SNORM: return "ETC2 RG Snorm" + case HYDRA_TEXTURE_FORMAT_ETC2_RGB: return "ETC2 RGB" + case HYDRA_TEXTURE_FORMAT_PTA_ETC2_RGB: return "PTA ETC2 RGB" + case HYDRA_TEXTURE_FORMAT_ETC2_RGBA: return "ETC2 RGBA" + case HYDRA_TEXTURE_FORMAT_ETC2_RGB_SRGB: return "ETC2 RGB sRGB" + case HYDRA_TEXTURE_FORMAT_PTA_ETC2_RGB_SRGB: return "PTA ETC2 RGB sRGB" + case HYDRA_TEXTURE_FORMAT_ETC2_RGBA_SRGB: return "ETC2 RGBA sRGB" + + default: + return "Unknown (\(self.rawValue))" + } + } +} + struct HydraTextureDescriptor: HandleStruct { internal let handle: UnsafeRawPointer @@ -1177,6 +1354,14 @@ struct HydraTextureDescriptor: HandleStruct { hydra_texture_descriptor_get_depth(self.handle) } + var levelCount: UInt32 { + hydra_texture_descriptor_get_level_count(self.handle) + } + + var layerCount: UInt32 { + hydra_texture_descriptor_get_layer_count(self.handle) + } + var layerSize: UInt64 { hydra_texture_descriptor_get_layer_size(self.handle) } diff --git a/src/frontend/swiftui/texture_viewer/TextureListView.swift b/src/frontend/swiftui/texture_viewer/TextureListView.swift index 9d5bdfef..74997dde 100644 --- a/src/frontend/swiftui/texture_viewer/TextureListView.swift +++ b/src/frontend/swiftui/texture_viewer/TextureListView.swift @@ -7,12 +7,31 @@ struct TextureListView: View { var body: some View { ZStack { - List { - ForEach(Array(self.textures.enumerated()), id: \.offset) { index, storage in - TextureView(storage: storage) - .id("\(refreshID)-\(index)") // Unique ID per refresh + // TODO: support sorting + Table(self.textures) { + TableColumn("Dimensions") { texture in + Text("\(texture.descriptor.width)x\(texture.descriptor.height)\(texture.descriptor.depth == 1 ? "" : "x\(texture.descriptor.depth)")") + } + TableColumn("Type") { texture in + Text(texture.descriptor.type.description) + } + TableColumn("Format") { texture in + Text(texture.descriptor.format.description) + } + TableColumn("Levels") { texture in + Text("\(texture.descriptor.levelCount)") + } + TableColumn("Layers") { texture in + Text("\(texture.descriptor.layerCount)") + } + TableColumn("Layer Size") { texture in + Text("\(texture.descriptor.layerSize)") + } + TableColumn("Total Size") { texture in + Text("\(texture.descriptor.size)") } } + .id("\(refreshID)") // Unique ID per refresh // TODO: add an option to refresh at regular intervals or any time a change happens? HStack { diff --git a/src/frontend/swiftui/texture_viewer/TextureView.swift b/src/frontend/swiftui/texture_viewer/TextureView.swift deleted file mode 100644 index 3b1b5a8b..00000000 --- a/src/frontend/swiftui/texture_viewer/TextureView.swift +++ /dev/null @@ -1,35 +0,0 @@ -import SwiftUI - -struct TextureView: View { - let storage: HydraTextureStorage - - private let type: HydraTextureType - private let format: HydraTextureFormat - private let width: UInt32 - private let height: UInt32 - private let depth: UInt32 - - init(storage: HydraTextureStorage) { - self.storage = storage - - let descriptor = storage.descriptor - self.type = descriptor.type - self.format = descriptor.format - self.width = descriptor.width - self.height = descriptor.height - self.depth = descriptor.depth - } - - var body: some View { - HStack { - // TODO: preview - - VStack { - Text("\(self.width)x\(self.height)\(self.depth == 1 ? "" : "x\(self.depth)")") - .bold() - Text("\(self.type.rawValue)") // TODO: .description - Text("\(self.format.rawValue)") // TODO: .description - } - } - } -} From de4cbb9e71e15c9fa84411dfd1dd9a300f60d7bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Mon, 11 May 2026 08:45:41 +0200 Subject: [PATCH 15/17] gpu: cleanup layout conversion --- src/core/hw/tegra_x1/gpu/engines/copy.cpp | 21 +++++----- src/core/hw/tegra_x1/gpu/memory_util.cpp | 39 ++++++++++--------- src/core/hw/tegra_x1/gpu/memory_util.hpp | 9 ++--- src/core/hw/tegra_x1/gpu/renderer/const.hpp | 1 + .../tegra_x1/gpu/renderer/texture_cache.cpp | 12 +++--- 5 files changed, 41 insertions(+), 41 deletions(-) diff --git a/src/core/hw/tegra_x1/gpu/engines/copy.cpp b/src/core/hw/tegra_x1/gpu/engines/copy.cpp index 81a272f8..c60137ee 100644 --- a/src/core/hw/tegra_x1/gpu/engines/copy.cpp +++ b/src/core/hw/tegra_x1/gpu/engines/copy.cpp @@ -50,22 +50,21 @@ void Copy::LaunchDMA(const u32 index, const LaunchDMAData data) { Range::FromSize(dst_ptr, regs.line_count * regs.stride_out)); } else { - // Encode as Generic 16BX2 // TODO: block size log2 can also be negative? - encode_generic_16bx2(dst_stride, regs.line_count, - static_cast(get_block_size_log2( - regs.dst.block_size.height)), - reinterpret_cast(src_ptr), - reinterpret_cast(dst_ptr)); + ConvertLinearToBlockLinear(dst_stride, regs.line_count, + static_cast(get_block_size_log2( + regs.dst.block_size.height)), + reinterpret_cast(src_ptr), + reinterpret_cast(dst_ptr)); } } else { if (data.dst_memory_layout == MemoryLayout::Pitch) { // TODO: block size log2 can also be negative? - decode_generic_16bx2(src_stride, regs.line_count, - static_cast(get_block_size_log2( - regs.src.block_size.height)), - reinterpret_cast(src_ptr), - reinterpret_cast(dst_ptr)); + ConvertBlockLinearToLinear(src_stride, regs.line_count, + static_cast(get_block_size_log2( + regs.src.block_size.height)), + reinterpret_cast(src_ptr), + reinterpret_cast(dst_ptr)); } else { LOG_NOT_IMPLEMENTED(Engines, "BlockLinear to BlockLinear"); } diff --git a/src/core/hw/tegra_x1/gpu/memory_util.cpp b/src/core/hw/tegra_x1/gpu/memory_util.cpp index 6ba8274c..21a1202c 100644 --- a/src/core/hw/tegra_x1/gpu/memory_util.cpp +++ b/src/core/hw/tegra_x1/gpu/memory_util.cpp @@ -4,9 +4,9 @@ namespace hydra::hw::tegra_x1::gpu { namespace { -template -void process_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, - u8* encoded, u8* decoded) { +template +void Convert(u32 stride, u32 rows, u32 block_height_log2, u8* block_linear, + u8* linear) { const auto block_height_gobs = 1u << block_height_log2; const auto block_height_px = 8u << block_height_log2; @@ -26,26 +26,27 @@ void process_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, const u32 x = block_x * 64; const u32 y = block_y * block_height_px + gob_y * 8; if (y < rows) { - u8* decoded_gob = (u8*)decoded + y * stride + x; + u8* decoded_gob = (u8*)linear + y * stride + x; // Reverse the 16Bx2 swizzling for each GOB for (u32 i = 0; i < BLOCK_SIZE; i++) { const u32 local_y = ((i >> 1) & 0x06) | (i & 0x01); const u32 local_x = ((i << 3) & 0x10) | ((i << 1) & 0x20); - auto decoded_data = reinterpret_cast( + auto linear_data = reinterpret_cast( decoded_gob + local_y * stride + local_x); - auto encoded_data = reinterpret_cast(encoded); - if constexpr (encode) - *encoded_data = *decoded_data; + auto block_linear_data = + reinterpret_cast(block_linear); + if constexpr (to_block_linear) + *block_linear_data = *linear_data; else - *decoded_data = *encoded_data; + *linear_data = *block_linear_data; - encoded += sizeof(u128); + block_linear += sizeof(u128); } } else { // Skip this GOB if we're past the valid height - encoded += sizeof(u128) * BLOCK_SIZE; + block_linear += sizeof(u128) * BLOCK_SIZE; } } } @@ -54,16 +55,16 @@ void process_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, } // namespace -void encode_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, - u8* in_data, u8* out_data) { - process_generic_16bx2(stride, rows, block_height_log2, out_data, - in_data); +void ConvertBlockLinearToLinear(u32 stride, u32 rows, u32 block_height_log2, + const u8* in_data, u8* out_data) { + Convert(stride, rows, block_height_log2, const_cast(in_data), + out_data); } -void decode_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, - u8* in_data, u8* out_data) { - process_generic_16bx2(stride, rows, block_height_log2, in_data, - out_data); +void ConvertLinearToBlockLinear(u32 stride, u32 rows, u32 block_height_log2, + const u8* in_data, u8* out_data) { + Convert(stride, rows, block_height_log2, out_data, + const_cast(in_data)); } } // namespace hydra::hw::tegra_x1::gpu diff --git a/src/core/hw/tegra_x1/gpu/memory_util.hpp b/src/core/hw/tegra_x1/gpu/memory_util.hpp index 3e740846..d058224d 100644 --- a/src/core/hw/tegra_x1/gpu/memory_util.hpp +++ b/src/core/hw/tegra_x1/gpu/memory_util.hpp @@ -4,10 +4,9 @@ namespace hydra::hw::tegra_x1::gpu { -void encode_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, - u8* in_data, u8* out_data); - -void decode_generic_16bx2(u32 stride, u32 rows, u32 block_height_log2, - u8* in_data, u8* out_data); +void ConvertBlockLinearToLinear(u32 stride, u32 rows, u32 block_height_log2, + const u8* in_data, u8* out_data); +void ConvertLinearToBlockLinear(u32 stride, u32 rows, u32 block_height_log2, + const u8* in_data, u8* out_data); } // namespace hydra::hw::tegra_x1::gpu diff --git a/src/core/hw/tegra_x1/gpu/renderer/const.hpp b/src/core/hw/tegra_x1/gpu/renderer/const.hpp index 40ab892b..45e5312b 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/const.hpp +++ b/src/core/hw/tegra_x1/gpu/renderer/const.hpp @@ -272,6 +272,7 @@ struct TextureDescriptor { d.layer_size = layer_size; d.CalculateLevelCount(); + // HACK: calculate layer size when layer count is 1 if (layer_size == 0 || layer_count == 1) d.CalculateLayerSize(); diff --git a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp index 18905f59..92a806b8 100644 --- a/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp +++ b/src/core/hw/tegra_x1/gpu/renderer/texture_cache.cpp @@ -431,12 +431,12 @@ void TextureCache::DecodeTexture(ICommandBuffer* command_buffer, std::memcpy(out_data, in_data, descriptor.GetSize()); } else { // HACK - decode_generic_16bx2(align(get_texture_format_stride(descriptor.format, - descriptor.width), - 64u), - descriptor.layer_count * descriptor.depth * - descriptor.height, - descriptor.block_height_log2, in_data, out_data); + ConvertBlockLinearToLinear( + align( + get_texture_format_stride(descriptor.format, descriptor.width), + 64u), + descriptor.layer_count * descriptor.depth * descriptor.height, + descriptor.block_height_log2, in_data, out_data); } storage.base->CopyFrom(command_buffer, tmp_buffer); From 042b91404764748a4288618f55f00b9ec67bcf71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Mon, 11 May 2026 09:06:05 +0200 Subject: [PATCH 16/17] swiftui: improve texture viewer readability --- src/frontend/swiftui/ContentView.swift | 2 +- .../swiftui/GameListToolbarItems.swift | 12 ++--- src/frontend/swiftui/GameListView.swift | 6 +-- .../texture_viewer/TextureListView.swift | 53 +++++++++++++++++-- 4 files changed, 57 insertions(+), 16 deletions(-) diff --git a/src/frontend/swiftui/ContentView.swift b/src/frontend/swiftui/ContentView.swift index a2356f37..8dccb93d 100644 --- a/src/frontend/swiftui/ContentView.swift +++ b/src/frontend/swiftui/ContentView.swift @@ -7,7 +7,7 @@ import SwiftUI struct ContentView: View { @EnvironmentObject var globalState: GlobalState - @AppStorage("viewMode") private var viewMode: Int = ViewMode.list.rawValue + @AppStorage("viewMode") private var viewMode: ViewMode = .list @State private var fps: Int = 0 #if os(iOS) diff --git a/src/frontend/swiftui/GameListToolbarItems.swift b/src/frontend/swiftui/GameListToolbarItems.swift index d83c4910..398aef0e 100644 --- a/src/frontend/swiftui/GameListToolbarItems.swift +++ b/src/frontend/swiftui/GameListToolbarItems.swift @@ -17,7 +17,7 @@ private let switchType = UTType(exportedAs: "com.samoz256.switch-document", conf struct GameListToolbarItems: ToolbarContent { @EnvironmentObject var globalState: GlobalState - @Binding var viewMode: Int + @Binding var viewMode: ViewMode @State private var isFirmwareFilePickerPresented = false @State private var isGameFilePickerPresented = false @@ -27,14 +27,14 @@ struct GameListToolbarItems: ToolbarContent { #if os(macOS) ToolbarItemGroup(placement: .principal) { Button("List View", systemImage: "list.bullet") { - viewMode = ViewMode.list.rawValue + viewMode = .list } - .disabled(ViewMode(rawValue: viewMode) == .list) - + .disabled(viewMode == .list) + Button("Grid View", systemImage: "rectangle.grid.3x2.fill") { - viewMode = ViewMode.grid.rawValue + viewMode = .grid } - .disabled(ViewMode(rawValue: viewMode) == .grid) + .disabled(viewMode == .grid) } #endif diff --git a/src/frontend/swiftui/GameListView.swift b/src/frontend/swiftui/GameListView.swift index 5b2228df..6041f77b 100644 --- a/src/frontend/swiftui/GameListView.swift +++ b/src/frontend/swiftui/GameListView.swift @@ -8,7 +8,7 @@ enum ViewMode: Int { struct GameListView: View { @EnvironmentObject var globalState: GlobalState - @Binding var viewMode: Int + @Binding var viewMode: ViewMode @State private var games: [Game] = [] @@ -18,7 +18,7 @@ struct GameListView: View { var body: some View { VStack { - switch ViewMode(rawValue: viewMode) { + switch viewMode { case .list: List { ForEach(games.indices, id: \.self) { index in @@ -39,8 +39,6 @@ struct GameListView: View { .padding() .frame(maxWidth: .infinity) } - case .none: - Text("ERROR") } } .onAppear { diff --git a/src/frontend/swiftui/texture_viewer/TextureListView.swift b/src/frontend/swiftui/texture_viewer/TextureListView.swift index 74997dde..8f220b8f 100644 --- a/src/frontend/swiftui/texture_viewer/TextureListView.swift +++ b/src/frontend/swiftui/texture_viewer/TextureListView.swift @@ -1,8 +1,51 @@ import SwiftUI +enum SizeFormat: Int { + case decimal, hex, byteCount + + func format(_ nb: UInt64) -> String { + switch (self) { + case .decimal: + return nb.formatted() + case .hex: + return "0x" + String(nb, radix: 16, uppercase: false) + case .byteCount: + return ByteCountFormatter.string(fromByteCount: Int64(nb), countStyle: .binary) + } + } +} + +struct TextureSizeView: View { + let size: UInt64 + @Binding var sizeFormat: SizeFormat + + var body: some View { + Text(sizeFormat.format(size)) + .font(.system(.body, design: .monospaced)) // Better for hex + .frame(maxWidth: .infinity, alignment: .trailing) + .contentShape(Rectangle()) // Clickable + .contextMenu { + Picker("Size Format", selection: self.$sizeFormat) { + Text("Decimal").tag(SizeFormat.decimal) + Text("Hex").tag(SizeFormat.hex) + Text("Byte Count").tag(SizeFormat.byteCount) + } + + Divider() + + Button("Copy Value") { + NSPasteboard.general.clearContents() + NSPasteboard.general.setString(sizeFormat.format(size), forType: .string) + } + } + } +} + struct TextureListView: View { @State private var refreshID = 0 + @AppStorage("sizeFormat") private var sizeFormat: SizeFormat = .decimal + @State private var textures: [HydraTextureStorage] = [] var body: some View { @@ -10,7 +53,7 @@ struct TextureListView: View { // TODO: support sorting Table(self.textures) { TableColumn("Dimensions") { texture in - Text("\(texture.descriptor.width)x\(texture.descriptor.height)\(texture.descriptor.depth == 1 ? "" : "x\(texture.descriptor.depth)")") + Text("\(texture.descriptor.width) x \(texture.descriptor.height)\(texture.descriptor.depth == 1 ? "" : " x \(texture.descriptor.depth)")") } TableColumn("Type") { texture in Text(texture.descriptor.type.description) @@ -19,16 +62,16 @@ struct TextureListView: View { Text(texture.descriptor.format.description) } TableColumn("Levels") { texture in - Text("\(texture.descriptor.levelCount)") + Text(String(texture.descriptor.levelCount)) } TableColumn("Layers") { texture in - Text("\(texture.descriptor.layerCount)") + Text(String(texture.descriptor.layerCount)) } TableColumn("Layer Size") { texture in - Text("\(texture.descriptor.layerSize)") + TextureSizeView(size: texture.descriptor.layerSize, sizeFormat: self.$sizeFormat) } TableColumn("Total Size") { texture in - Text("\(texture.descriptor.size)") + TextureSizeView(size: texture.descriptor.size, sizeFormat: self.$sizeFormat) } } .id("\(refreshID)") // Unique ID per refresh From dfcf8af44e921db56a98a314a2a4e7c4d3ed2d8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Samuel=20=C5=BD=C3=BAbor?= Date: Mon, 11 May 2026 09:17:13 +0200 Subject: [PATCH 17/17] swiftui: support texture sorting --- src/frontend/swiftui/Api.swift | 12 ++++++++-- .../texture_viewer/TextureListView.swift | 22 +++++++++++-------- 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/frontend/swiftui/Api.swift b/src/frontend/swiftui/Api.swift index 75f37f37..fcc679ff 100644 --- a/src/frontend/swiftui/Api.swift +++ b/src/frontend/swiftui/Api.swift @@ -1150,7 +1150,11 @@ struct HydraTextureStorage: HandleStruct { } // Texture descriptor -extension HydraTextureType { +extension HydraTextureType: Comparable { + public static func < (lhs: HydraTextureType, rhs: HydraTextureType) -> Bool { + return lhs.rawValue < rhs.rawValue + } + var description: String { switch self { case HYDRA_TEXTURE_TYPE_1D: @@ -1175,7 +1179,11 @@ extension HydraTextureType { } } -extension HydraTextureFormat { +extension HydraTextureFormat: Comparable { + public static func < (lhs: HydraTextureFormat, rhs: HydraTextureFormat) -> Bool { + return lhs.rawValue < rhs.rawValue + } + var description: String { switch self { case HYDRA_TEXTURE_FORMAT_INVALID: return "Invalid" diff --git a/src/frontend/swiftui/texture_viewer/TextureListView.swift b/src/frontend/swiftui/texture_viewer/TextureListView.swift index 8f220b8f..68fd4979 100644 --- a/src/frontend/swiftui/texture_viewer/TextureListView.swift +++ b/src/frontend/swiftui/texture_viewer/TextureListView.swift @@ -48,29 +48,33 @@ struct TextureListView: View { @State private var textures: [HydraTextureStorage] = [] + @State private var sortOrder = [KeyPathComparator(\HydraTextureStorage.descriptor.format)] + private var sortedTextures: [HydraTextureStorage] { + return textures.sorted(using: sortOrder) + } + var body: some View { ZStack { - // TODO: support sorting - Table(self.textures) { - TableColumn("Dimensions") { texture in + Table(self.sortedTextures, sortOrder: self.$sortOrder) { + TableColumn("Dimensions", value: \.descriptor.width) { texture in // TODO: use whole size as the value Text("\(texture.descriptor.width) x \(texture.descriptor.height)\(texture.descriptor.depth == 1 ? "" : " x \(texture.descriptor.depth)")") } - TableColumn("Type") { texture in + TableColumn("Type", value: \.descriptor.type) { texture in Text(texture.descriptor.type.description) } - TableColumn("Format") { texture in + TableColumn("Format", value: \.descriptor.format) { texture in Text(texture.descriptor.format.description) } - TableColumn("Levels") { texture in + TableColumn("Levels", value: \.descriptor.levelCount) { texture in Text(String(texture.descriptor.levelCount)) } - TableColumn("Layers") { texture in + TableColumn("Layers", value: \.descriptor.layerCount) { texture in Text(String(texture.descriptor.layerCount)) } - TableColumn("Layer Size") { texture in + TableColumn("Layer Size", value: \.descriptor.layerSize) { texture in TextureSizeView(size: texture.descriptor.layerSize, sizeFormat: self.$sizeFormat) } - TableColumn("Total Size") { texture in + TableColumn("Total Size", value: \.descriptor.size) { texture in TextureSizeView(size: texture.descriptor.size, sizeFormat: self.$sizeFormat) } }