Compare commits

..

26 commits

Author SHA1 Message Date
85434536ee [dynarmic] fix exception posix handler
Some checks failed
eden-license / license-header (pull_request) Failing after 38s
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
004bddf35a [dynarmic] use better boost::visitor
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
9682d47297 [dynarmic] regalloc use scratchimpl that uses all instead of iteraiting
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
67dd4933ba [dynarmic] Implement constant folding for CountLeadingZeros, add readXX constnat folding for A64
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
9716d39ff4 [dynarmic] unconditional branches always take
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
5164fe9b4a [dynarmic] fix hardcoded AVX512 registers, use xmm0 instead of xmm16 to align with spec
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
b82107b71a [dynarmic] checked code alignment
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
15137d33f5 [dynarmic] remove use of mcl reverse iterator
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
213a7fedd6 [dynarmic, docs] fastmem docs
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
4aec22966a [dynarmic, cmake][ remove unusd frontends var
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
2ff96eba3f [dynarmic] fix android
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
616ba96ec2 [dynarmic] use ARCHITECTURE_ macros instead of MCL ones
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
cf46cd9d44 [dynarmic] add back encoding names (for print_info)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
896d3ac794 [dynarmic] fix ASIMD execution
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
bb8e985ae7 [dynarmic] fix tests
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
4681238047 [dynarmic] reduce matcher table noise and cache misses
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
f8d35408d6 [dynarmic] (prolly makes MSVC crash) - use 128MiB code cache
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
0a9e7f7ac0 [docs] fastmem draft
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
e57f46d985 [dynarmic] fix tests_reader and tests_generator
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
5d8d094aaa [dynarmic] reduce use 2 bits for LRU and 4 bits for clog2 of bit size
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
3753f7d64b [dynarmic] use small vector experiment
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
a98968768c Fix license headers 2025-09-17 18:28:08 +02:00
8806242173 [dynarmic] reduce opt pass latency
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 18:28:08 +02:00
8ac495acee
[fs] Remove remaining files from NCA bypass and fix some asserts (#2502)
Reviewed-on: #2502
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: MaranBr <maranbr@outlook.com>
Co-committed-by: MaranBr <maranbr@outlook.com>
2025-09-17 17:45:52 +02:00
cda6958111
[host_memory] decrease latency of mapping on linux (#232)
Signed-off-by: lizzie <lizzie@eden-emu.dev>
Reviewed-on: #232
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
2025-09-17 02:31:44 +02:00
dac2efc4c8
[Shader Recompiler] Caching optimization for Texture_Pass (#481)
Add Caching per texture_pass and optimize sorting to single pass.
Use Logical shift instead of arithmetic shift.

Reviewed-on: #481
Reviewed-by: Shinmegumi <shinmegumi@eden-emu.dev>
Reviewed-by: crueter <crueter@eden-emu.dev>
Co-authored-by: wildcard <wildcard@eden-emu.dev>
Co-committed-by: wildcard <wildcard@eden-emu.dev>
2025-09-17 02:27:03 +02:00
7 changed files with 127 additions and 69 deletions

View file

@ -598,12 +598,17 @@ public:
bool ClearBackingRegion(size_t physical_offset, size_t length) { bool ClearBackingRegion(size_t physical_offset, size_t length) {
#ifdef __linux__ #ifdef __linux__
// Set MADV_REMOVE on backing map to destroy it instantly. // Only incur syscall cost IF memset would be slower (theshold = 16MiB)
// This also deletes the area from the backing file. // TODO(lizzie): Smarter way to dynamically get this threshold (broadwell != raptor lake) for example
int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE); if (length >= 2097152UL * 8) {
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno)); // Set MADV_REMOVE on backing map to destroy it instantly.
// This also deletes the area from the backing file.
return true; int ret = madvise(backing_base + physical_offset, length, MADV_REMOVE);
ASSERT_MSG(ret == 0, "madvise failed: {}", strerror(errno));
return true;
} else {
return false;
}
#else #else
return false; return false;
#endif #endif

View file

@ -107,7 +107,6 @@ add_library(core STATIC
file_sys/fssystem/fssystem_nca_header.cpp file_sys/fssystem/fssystem_nca_header.cpp
file_sys/fssystem/fssystem_nca_header.h file_sys/fssystem/fssystem_nca_header.h
file_sys/fssystem/fssystem_nca_reader.cpp file_sys/fssystem/fssystem_nca_reader.cpp
file_sys/fssystem/fssystem_passthrough_storage.h
file_sys/fssystem/fssystem_pooled_buffer.cpp file_sys/fssystem/fssystem_pooled_buffer.cpp
file_sys/fssystem/fssystem_pooled_buffer.h file_sys/fssystem/fssystem_pooled_buffer.h
file_sys/fssystem/fssystem_sparse_storage.cpp file_sys/fssystem/fssystem_sparse_storage.cpp

View file

@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/file_sys/errors.h" #include "core/file_sys/errors.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree.h" #include "core/file_sys/fssystem/fssystem_bucket_tree.h"
#include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h" #include "core/file_sys/fssystem/fssystem_bucket_tree_utils.h"

View file

@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h" #include "core/file_sys/fssystem/fssystem_aes_ctr_counter_extended_storage.h"
#include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h" #include "core/file_sys/fssystem/fssystem_aes_ctr_storage.h"
#include "core/file_sys/fssystem/fssystem_aes_xts_storage.h" #include "core/file_sys/fssystem/fssystem_aes_xts_storage.h"
@ -14,7 +13,6 @@
#include "core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h" #include "core/file_sys/fssystem/fssystem_hierarchical_sha256_storage.h"
#include "core/file_sys/fssystem/fssystem_indirect_storage.h" #include "core/file_sys/fssystem/fssystem_indirect_storage.h"
#include "core/file_sys/fssystem/fssystem_integrity_romfs_storage.h" #include "core/file_sys/fssystem/fssystem_integrity_romfs_storage.h"
#include "core/file_sys/fssystem/fssystem_passthrough_storage.h"
#include "core/file_sys/fssystem/fssystem_memory_resource_buffer_hold_storage.h" #include "core/file_sys/fssystem/fssystem_memory_resource_buffer_hold_storage.h"
#include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h" #include "core/file_sys/fssystem/fssystem_nca_file_system_driver.h"
#include "core/file_sys/fssystem/fssystem_sparse_storage.h" #include "core/file_sys/fssystem/fssystem_sparse_storage.h"

View file

@ -13,13 +13,11 @@ u8 NcaHeader::GetProperKeyGeneration() const {
} }
bool NcaPatchInfo::HasIndirectTable() const { bool NcaPatchInfo::HasIndirectTable() const {
static constexpr unsigned char BKTR[4] = {'B', 'K', 'T', 'R'}; return this->indirect_size != 0;
return std::memcmp(indirect_header.data(), BKTR, sizeof(BKTR)) == 0;
} }
bool NcaPatchInfo::HasAesCtrExTable() const { bool NcaPatchInfo::HasAesCtrExTable() const {
static constexpr unsigned char BKTR[4] = {'B', 'K', 'T', 'R'}; return this->aes_ctr_ex_size != 0;
return std::memcmp(aes_ctr_ex_header.data(), BKTR, sizeof(BKTR)) == 0;
} }
} // namespace FileSys } // namespace FileSys

View file

@ -1,32 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/file_sys/fssystem/fs_i_storage.h"
#include "core/file_sys/vfs/vfs.h"
namespace FileSys {
//TODO: No integrity verification.
class PassthroughStorage final : public IReadOnlyStorage {
YUZU_NON_COPYABLE(PassthroughStorage);
YUZU_NON_MOVEABLE(PassthroughStorage);
public:
explicit PassthroughStorage(VirtualFile base) : base_(std::move(base)) {}
~PassthroughStorage() override = default;
size_t Read(u8* buffer, size_t size, size_t offset) const override {
if (!base_ || size == 0)
return 0;
return base_->Read(buffer, size, offset);
}
size_t GetSize() const override {
return base_ ? base_->GetSize() : 0;
}
private:
VirtualFile base_{};
};
} // namespace FileSys

View file

@ -7,7 +7,9 @@
#include <algorithm> #include <algorithm>
#include <bit> #include <bit>
#include <optional> #include <optional>
#include <unordered_map>
#include <tuple>
#include <limits>
#include <boost/container/small_vector.hpp> #include <boost/container/small_vector.hpp>
#include "shader_recompiler/environment.h" #include "shader_recompiler/environment.h"
@ -177,6 +179,93 @@ bool IsBindless(const IR::Inst& inst) {
bool IsTextureInstruction(const IR::Inst& inst) { bool IsTextureInstruction(const IR::Inst& inst) {
return IndexedInstruction(inst) != IR::Opcode::Void; return IndexedInstruction(inst) != IR::Opcode::Void;
} }
// Per-pass caches
struct CbufWordKey {
u32 index;
u32 offset;
bool operator==(const CbufWordKey& o) const noexcept {
return index == o.index && offset == o.offset;
}
};
struct CbufWordKeyHash {
size_t operator()(const CbufWordKey& k) const noexcept {
return (static_cast<size_t>(k.index) << 32) ^ k.offset;
}
};
struct HandleKey {
u32 index, offset, shift_left;
u32 sec_index, sec_offset, sec_shift_left;
bool has_secondary;
bool operator==(const HandleKey& o) const noexcept {
return std::tie(index, offset, shift_left,
sec_index, sec_offset, sec_shift_left, has_secondary)
== std::tie(o.index, o.offset, o.shift_left,
o.sec_index, o.sec_offset, o.sec_shift_left, o.has_secondary);
}
};
struct HandleKeyHash {
size_t operator()(const HandleKey& k) const noexcept {
size_t h = (static_cast<size_t>(k.index) << 32) ^ k.offset;
h ^= (static_cast<size_t>(k.shift_left) << 1);
h ^= (static_cast<size_t>(k.sec_index) << 33) ^ (static_cast<size_t>(k.sec_offset) << 2);
h ^= (static_cast<size_t>(k.sec_shift_left) << 3);
h ^= k.has_secondary ? 0x9e3779b97f4a7c15ULL : 0ULL;
return h;
}
};
// Thread-local(may implement multithreading in future *wink*)
thread_local std::unordered_map<CbufWordKey, u32, CbufWordKeyHash> g_cbuf_word_cache;
thread_local std::unordered_map<HandleKey, u32, HandleKeyHash> g_handle_cache;
thread_local std::unordered_map<const IR::Inst*, ConstBufferAddr> g_track_cache;
static inline u32 ReadCbufCached(Environment& env, u32 index, u32 offset) {
const CbufWordKey k{index, offset};
if (auto it = g_cbuf_word_cache.find(k); it != g_cbuf_word_cache.end()) return it->second;
const u32 v = env.ReadCbufValue(index, offset);
g_cbuf_word_cache.emplace(k, v);
return v;
}
static inline u32 GetTextureHandleCached(Environment& env, const ConstBufferAddr& cbuf) {
const u32 sec_idx = cbuf.has_secondary ? cbuf.secondary_index : cbuf.index;
const u32 sec_off = cbuf.has_secondary ? cbuf.secondary_offset : cbuf.offset;
const HandleKey hk{cbuf.index, cbuf.offset, cbuf.shift_left,
sec_idx, sec_off, cbuf.secondary_shift_left, cbuf.has_secondary};
if (auto it = g_handle_cache.find(hk); it != g_handle_cache.end()) return it->second;
const u32 lhs = ReadCbufCached(env, cbuf.index, cbuf.offset) << cbuf.shift_left;
const u32 rhs = ReadCbufCached(env, sec_idx, sec_off) << cbuf.secondary_shift_left;
const u32 handle = lhs | rhs;
g_handle_cache.emplace(hk, handle);
return handle;
}
// Cached variants of existing helpers
static inline TextureType ReadTextureTypeCached(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTextureType(GetTextureHandleCached(env, cbuf));
}
static inline TexturePixelFormat ReadTexturePixelFormatCached(Environment& env,
const ConstBufferAddr& cbuf) {
return env.ReadTexturePixelFormat(GetTextureHandleCached(env, cbuf));
}
static inline bool IsTexturePixelFormatIntegerCached(Environment& env,
const ConstBufferAddr& cbuf) {
return env.IsTexturePixelFormatInteger(GetTextureHandleCached(env, cbuf));
}
std::optional<ConstBufferAddr> Track(const IR::Value& value, Environment& env);
static inline std::optional<ConstBufferAddr> TrackCached(const IR::Value& v, Environment& env) {
if (const IR::Inst* key = v.InstRecursive()) {
if (auto it = g_track_cache.find(key); it != g_track_cache.end()) return it->second;
auto found = Track(v, env);
if (found) g_track_cache.emplace(key, *found);
return found;
}
return Track(v, env);
}
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env); std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env);
@ -203,7 +292,7 @@ std::optional<u32> TryGetConstant(IR::Value& value, Environment& env) {
return std::nullopt; return std::nullopt;
} }
const auto offset_number = offset.U32(); const auto offset_number = offset.U32();
return env.ReadCbufValue(index_number, offset_number); return ReadCbufCached(env, index_number, offset_number);
} }
std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env) { std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environment& env) {
@ -211,8 +300,8 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
default: default:
return std::nullopt; return std::nullopt;
case IR::Opcode::BitwiseOr32: { case IR::Opcode::BitwiseOr32: {
std::optional lhs{Track(inst->Arg(0), env)}; std::optional lhs{TrackCached(inst->Arg(0), env)};
std::optional rhs{Track(inst->Arg(1), env)}; std::optional rhs{TrackCached(inst->Arg(1), env)};
if (!lhs || !rhs) { if (!lhs || !rhs) {
return std::nullopt; return std::nullopt;
} }
@ -242,7 +331,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
if (!shift.IsImmediate()) { if (!shift.IsImmediate()) {
return std::nullopt; return std::nullopt;
} }
std::optional lhs{Track(inst->Arg(0), env)}; std::optional lhs{TrackCached(inst->Arg(0), env)};
if (lhs) { if (lhs) {
lhs->shift_left = shift.U32(); lhs->shift_left = shift.U32();
} }
@ -271,7 +360,7 @@ std::optional<ConstBufferAddr> TryGetConstBuffer(const IR::Inst* inst, Environme
return std::nullopt; return std::nullopt;
} while (false); } while (false);
} }
std::optional lhs{Track(op1, env)}; std::optional lhs{TrackCached(op1, env)};
if (lhs) { if (lhs) {
lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32())); lhs->shift_left = static_cast<u32>(std::countr_zero(op2.U32()));
} }
@ -346,7 +435,7 @@ static ConstBufferAddr last_valid_addr = ConstBufferAddr{
TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) { TextureInst MakeInst(Environment& env, IR::Block* block, IR::Inst& inst) {
ConstBufferAddr addr; ConstBufferAddr addr;
if (IsBindless(inst)) { if (IsBindless(inst)) {
const std::optional<ConstBufferAddr> track_addr{Track(inst.Arg(0), env)}; const std::optional<ConstBufferAddr> track_addr{TrackCached(inst.Arg(0), env)};
if (!track_addr) { if (!track_addr) {
//throw NotImplementedException("Failed to track bindless texture constant buffer"); //throw NotImplementedException("Failed to track bindless texture constant buffer");
@ -384,15 +473,15 @@ u32 GetTextureHandle(Environment& env, const ConstBufferAddr& cbuf) {
return lhs_raw | rhs_raw; return lhs_raw | rhs_raw;
} }
TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) { [[maybe_unused]]TextureType ReadTextureType(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTextureType(GetTextureHandle(env, cbuf)); return env.ReadTextureType(GetTextureHandle(env, cbuf));
} }
TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) { [[maybe_unused]]TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAddr& cbuf) {
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
} }
bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) { [[maybe_unused]]bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf)); return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
} }
@ -543,6 +632,10 @@ void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_
} // Anonymous namespace } // Anonymous namespace
void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info) { void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info) {
// reset per-pass caches
g_cbuf_word_cache.clear();
g_handle_cache.clear();
g_track_cache.clear();
TextureInstVector to_replace; TextureInstVector to_replace;
for (IR::Block* const block : program.post_order_blocks) { for (IR::Block* const block : program.post_order_blocks) {
for (IR::Inst& inst : block->Instructions()) { for (IR::Inst& inst : block->Instructions()) {
@ -553,11 +646,9 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
} }
} }
// Sort instructions to visit textures by constant buffer index, then by offset // Sort instructions to visit textures by constant buffer index, then by offset
std::ranges::sort(to_replace, [](const auto& lhs, const auto& rhs) { std::ranges::sort(to_replace, [](const auto& a, const auto& b) {
return lhs.cbuf.offset < rhs.cbuf.offset; if (a.cbuf.index != b.cbuf.index) return a.cbuf.index < b.cbuf.index;
}); return a.cbuf.offset < b.cbuf.offset;
std::stable_sort(to_replace.begin(), to_replace.end(), [](const auto& lhs, const auto& rhs) {
return lhs.cbuf.index < rhs.cbuf.index;
}); });
Descriptors descriptors{ Descriptors descriptors{
program.info.texture_buffer_descriptors, program.info.texture_buffer_descriptors,
@ -575,14 +666,14 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
bool is_multisample{false}; bool is_multisample{false};
switch (inst->GetOpcode()) { switch (inst->GetOpcode()) {
case IR::Opcode::ImageQueryDimensions: case IR::Opcode::ImageQueryDimensions:
flags.type.Assign(ReadTextureType(env, cbuf)); flags.type.Assign(ReadTextureTypeCached(env, cbuf));
inst->SetFlags(flags); inst->SetFlags(flags);
break; break;
case IR::Opcode::ImageSampleImplicitLod: case IR::Opcode::ImageSampleImplicitLod:
if (flags.type != TextureType::Color2D) { if (flags.type != TextureType::Color2D) {
break; break;
} }
if (ReadTextureType(env, cbuf) == TextureType::Color2DRect) { if (ReadTextureTypeCached(env, cbuf) == TextureType::Color2DRect) {
PatchImageSampleImplicitLod(*texture_inst.block, *texture_inst.inst); PatchImageSampleImplicitLod(*texture_inst.block, *texture_inst.inst);
} }
break; break;
@ -596,7 +687,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (flags.type != TextureType::Color1D) { if (flags.type != TextureType::Color1D) {
break; break;
} }
if (ReadTextureType(env, cbuf) == TextureType::Buffer) { if (ReadTextureTypeCached(env, cbuf) == TextureType::Buffer) {
// Replace with the bound texture type only when it's a texture buffer // Replace with the bound texture type only when it's a texture buffer
// If the instruction is 1D and the bound type is 2D, don't change the code and let // If the instruction is 1D and the bound type is 2D, don't change the code and let
// the rasterizer robustness handle it // the rasterizer robustness handle it
@ -627,7 +718,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
} }
const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)}; const bool is_integer{IsTexturePixelFormatIntegerCached(env, cbuf)};
if (flags.type == TextureType::Buffer) { if (flags.type == TextureType::Buffer) {
index = descriptors.Add(ImageBufferDescriptor{ index = descriptors.Add(ImageBufferDescriptor{
.format = flags.image_format, .format = flags.image_format,
@ -691,16 +782,16 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (cbuf.count > 1) { if (cbuf.count > 1) {
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)}; const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
IR::IREmitter ir{*texture_inst.block, insert_point}; IR::IREmitter ir{*texture_inst.block, insert_point};
const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))}; const IR::U32 shift{ir.Imm32(DESCRIPTOR_SIZE_SHIFT)};
inst->SetArg(0, ir.UMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift), inst->SetArg(0, ir.UMin(ir.ShiftRightLogical(cbuf.dynamic_offset, shift),
ir.Imm32(DESCRIPTOR_SIZE - 1))); ir.Imm32(DESCRIPTOR_SIZE - 1)));
} else { } else {
inst->SetArg(0, IR::Value{}); inst->SetArg(0, IR::Value{});
} }
if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch &&
flags.type == TextureType::Buffer) { flags.type == TextureType::Buffer) {
const auto pixel_format = ReadTexturePixelFormat(env, cbuf); const auto pixel_format = ReadTexturePixelFormatCached(env, cbuf);
if (IsPixelFormatSNorm(pixel_format)) { if (IsPixelFormatSNorm(pixel_format)) {
PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format);
} }