Compare commits

...
Author SHA1 Message Date
yuzubot fe699b35e3 "Merge Tagged PR 4836" 2021-06-26 12:02:55 +00:00
yuzubot c39a6d1a38 "Merge Tagged PR 5896" 2021-06-26 12:02:55 +00:00
bunnei 432fab7c4f Merge pull request #6526 from bunnei/doom-update
services: Misc. minor changes for latest SDK update.
2021-06-26 01:21:55 -07:00
bunnei 36d581ec73 hle: service: hwopus: OpenHardwareOpusDecoderEx: Remove unused buffer size. 2021-06-26 00:38:08 -07:00
Ameer J d9fb6dbd37 Merge pull request #6528 from ReinUsesLisp/device-memory
vulkan_device: Make device memory match the rest of the file
2021-06-25 17:07:24 -04:00
ReinUsesLisp 99b859db55 vulkan_device: Make device memory match the rest of the file
Match the style in the file.
2021-06-25 02:38:58 -03:00
bunnei c805c0b395 Merge pull request #6496 from ameerj/astc-fixes
astc: Various robustness enhancements for the gpu decoder
2021-06-24 21:47:05 -07:00
bunnei b9c2732121 Merge pull request #6519 from Wunkolo/mem-size-literal
common: Replace common_sizes into user-literals
2021-06-24 19:09:12 -07:00
bunnei 982be246ab hle: hle_helpers: Skip data payload offset checks on TIPC requests.
- TIPC does not use this.
2021-06-24 18:39:43 -07:00
bunnei 3565e32f4d hle: service: hwopus: Implement GetWorkBufferSizeEx and OpenHardwareOpusDecoderEx.
- This is used by the latest update of Doom Eternal.
2021-06-24 18:25:37 -07:00
bunnei d1ba4a2db2 hle: service: aoc: Stub GetAddOnContentListChangedEventWithProcessId.
- This is used by the latest update of Doom Eternal.
2021-06-24 18:22:53 -07:00
bunnei 50d0cc2716 audio_core: common: Bump audio revision to 9.
- This is used in fw 12.x.x games.
2021-06-24 18:22:10 -07:00
Wunkolo 4569f39c7c common: Replace common_sizes into user-literals
Removes common_sizes.h in favor of having `_KiB`, `_MiB`, `_GiB`, etc
user-literals within literals.h.

To keep the global namespace clean, users will have to use:

```
using namespace Common::Literals;
```

to access these literals.
2021-06-24 09:27:40 -07:00
bunnei 4dc2f5a341 Merge pull request #6522 from Morph1984/pragma
general: Add missing #pragma once directives
2021-06-24 08:53:27 -07:00
Morph eed0d1f33b general: Add missing #pragma once directives 2021-06-24 07:20:57 -04:00
ameerj 851c76233d util_shaders: Specify ASTC decoder memory barrier bits 2021-06-19 11:16:25 -04:00
ameerj ace20ba4a4 astc_decoder.comp: Remove unnecessary LUT SSBOs
We can move them to instead be compile time constants within the shader.
2021-06-19 10:56:13 -04:00
ameerj 31b125ef57 astc: Various robustness enhancements for the gpu decoder
These changes should help in reducing crashes/drivers panics that may
occur due to synchronization issues between the shader completion and
later access of the decoded texture.
2021-06-19 09:00:33 -04:00
59 changed files with 954 additions and 527 deletions

No files matched your search

+1 -1
View File
@@ -15,7 +15,7 @@ constexpr ResultCode ERR_INVALID_PARAMETERS{ErrorModule::Audio, 41};
constexpr ResultCode ERR_SPLITTER_SORT_FAILED{ErrorModule::Audio, 43};
} // namespace Audren
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '8');
constexpr u32_le CURRENT_PROCESS_REVISION = Common::MakeMagic('R', 'E', 'V', '9');
constexpr std::size_t MAX_MIX_BUFFERS = 24;
constexpr std::size_t MAX_BIQUAD_FILTERS = 2;
constexpr std::size_t MAX_CHANNEL_COUNT = 6;
+1 -1
View File
@@ -110,7 +110,6 @@ add_library(common STATIC
cityhash.cpp
cityhash.h
common_funcs.h
common_sizes.h
common_types.h
concepts.h
div_ceil.h
@@ -134,6 +133,7 @@ add_library(common STATIC
host_memory.cpp
host_memory.h
intrusive_red_black_tree.h
literals.h
logging/backend.cpp
logging/backend.h
logging/filter.cpp
-44
View File
@@ -1,44 +0,0 @@
// Copyright 2021 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <limits>
#include "common/common_types.h"
namespace Common {
enum : u64 {
Size_1_KB = 0x400ULL,
Size_64_KB = 64ULL * Size_1_KB,
Size_128_KB = 128ULL * Size_1_KB,
Size_1_MB = 0x100000ULL,
Size_2_MB = 2ULL * Size_1_MB,
Size_4_MB = 4ULL * Size_1_MB,
Size_5_MB = 5ULL * Size_1_MB,
Size_14_MB = 14ULL * Size_1_MB,
Size_32_MB = 32ULL * Size_1_MB,
Size_33_MB = 33ULL * Size_1_MB,
Size_128_MB = 128ULL * Size_1_MB,
Size_448_MB = 448ULL * Size_1_MB,
Size_507_MB = 507ULL * Size_1_MB,
Size_512_MB = 512ULL * Size_1_MB,
Size_562_MB = 562ULL * Size_1_MB,
Size_1554_MB = 1554ULL * Size_1_MB,
Size_2048_MB = 2048ULL * Size_1_MB,
Size_2193_MB = 2193ULL * Size_1_MB,
Size_3285_MB = 3285ULL * Size_1_MB,
Size_4916_MB = 4916ULL * Size_1_MB,
Size_1_GB = 0x40000000ULL,
Size_2_GB = 2ULL * Size_1_GB,
Size_4_GB = 4ULL * Size_1_GB,
Size_6_GB = 6ULL * Size_1_GB,
Size_8_GB = 8ULL * Size_1_GB,
Size_64_GB = 64ULL * Size_1_GB,
Size_512_GB = 512ULL * Size_1_GB,
Size_Invalid = std::numeric_limits<u64>::max(),
};
} // namespace Common
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2021 yuzu emulator team
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
namespace Common::Literals {
constexpr u64 operator""_KiB(unsigned long long int x) {
return 1024ULL * x;
}
constexpr u64 operator""_MiB(unsigned long long int x) {
return 1024_KiB * x;
}
constexpr u64 operator""_GiB(unsigned long long int x) {
return 1024_MiB * x;
}
constexpr u64 operator""_TiB(unsigned long long int x) {
return 1024_GiB * x;
}
constexpr u64 operator""_PiB(unsigned long long int x) {
return 1024_TiB * x;
}
} // namespace Common::Literals
+7 -4
View File
@@ -19,6 +19,8 @@
#include "common/assert.h"
#include "common/fs/file.h"
#include "common/fs/fs.h"
#include "common/literals.h"
#include "common/logging/backend.h"
#include "common/logging/log.h"
#include "common/logging/text_formatter.h"
@@ -98,8 +100,8 @@ private:
write_logs(entry);
}
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a case
// where a system is repeatedly spamming logs even on close.
// Drain the logging queue. Only writes out up to MAX_LOGS_TO_WRITE to prevent a
// case where a system is repeatedly spamming logs even on close.
const int MAX_LOGS_TO_WRITE = filter.IsDebug() ? INT_MAX : 100;
int logs_written = 0;
while (logs_written++ < MAX_LOGS_TO_WRITE && message_queue.Pop(entry)) {
@@ -169,10 +171,11 @@ FileBackend::FileBackend(const std::filesystem::path& filename) {
FileBackend::~FileBackend() = default;
void FileBackend::Write(const Entry& entry) {
using namespace Common::Literals;
// prevent logs from going over the maximum size (in case its spamming and the user doesn't
// know)
constexpr std::size_t MAX_BYTES_WRITTEN = 100 * 1024 * 1024;
constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1024 * 1024 * 1024;
constexpr std::size_t MAX_BYTES_WRITTEN = 100_MiB;
constexpr std::size_t MAX_BYTES_WRITTEN_EXTENDED = 1_GiB;
if (!file->IsOpen()) {
return;
+2
View File
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <chrono>
#include "common/common_types.h"
+5 -2
View File
@@ -8,6 +8,7 @@
#include <dynarmic/interface/A32/config.h>
#include <dynarmic/interface/A32/context.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
@@ -22,6 +23,8 @@
namespace Core {
using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public:
explicit DynarmicCallbacks32(ARM_Dynarmic_32& parent_)
@@ -143,8 +146,8 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 400 * 1024 * 1024;
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Safe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
+4 -2
View File
@@ -7,6 +7,7 @@
#include <dynarmic/interface/A64/a64.h>
#include <dynarmic/interface/A64/config.h>
#include "common/assert.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
@@ -24,6 +25,7 @@
namespace Core {
using Vector = Dynarmic::A64::Vector;
using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public:
@@ -184,8 +186,8 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
config.wall_clock_cntpct = uses_wall_clock;
// Code cache size
config.code_cache_size = 512 * 1024 * 1024;
config.far_code_offset = 400 * 1024 * 1024;
config.code_cache_size = 512_MiB;
config.far_code_offset = 400_MiB;
// Safe optimizations
if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::DebugMode) {
+2
View File
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common/common_types.h"
// This file contains yuzu's HLE API version constants.
+6 -2
View File
@@ -345,8 +345,12 @@ public:
explicit RequestParser(u32* command_buffer) : RequestHelperBase(command_buffer) {}
explicit RequestParser(Kernel::HLERequestContext& ctx) : RequestHelperBase(ctx) {
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
Skip(ctx.GetDataPayloadOffset(), false);
// TIPC does not have data payload offset
if (!ctx.IsTipc()) {
ASSERT_MSG(ctx.GetDataPayloadOffset(), "context is incomplete");
Skip(ctx.GetDataPayloadOffset(), false);
}
// Skip the u64 command id, it's already stored in the context
static constexpr u32 CommandIdSize = 2;
Skip(CommandIdSize, false);
@@ -4,7 +4,8 @@
#include <random>
#include "common/common_sizes.h"
#include "common/literals.h"
#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/hle/kernel/board/nintendo/nx/secure_monitor.h"
#include "core/hle/kernel/k_trace.h"
@@ -25,6 +26,8 @@ constexpr const std::size_t RequiredNonSecureSystemMemorySize =
namespace {
using namespace Common::Literals;
u32 GetMemoryModeForInit() {
return 0x01;
}
@@ -57,11 +60,11 @@ size_t KSystemControl::Init::GetIntendedMemorySize() {
switch (GetMemorySizeForInit()) {
case Smc::MemorySize_4GB:
default: // All invalid modes should go to 4GB.
return Common::Size_4_GB;
return 4_GiB;
case Smc::MemorySize_6GB:
return Common::Size_6_GB;
return 6_GiB;
case Smc::MemorySize_8GB:
return Common::Size_8_GB;
return 8_GiB;
}
}
@@ -79,17 +82,17 @@ std::size_t KSystemControl::Init::GetApplicationPoolSize() {
switch (GetMemoryArrangeForInit()) {
case Smc::MemoryArrangement_4GB:
default:
return Common::Size_3285_MB;
return 3285_MiB;
case Smc::MemoryArrangement_4GBForAppletDev:
return Common::Size_2048_MB;
return 2048_MiB;
case Smc::MemoryArrangement_4GBForSystemDev:
return Common::Size_3285_MB;
return 3285_MiB;
case Smc::MemoryArrangement_6GB:
return Common::Size_4916_MB;
return 4916_MiB;
case Smc::MemoryArrangement_6GBForAppletDev:
return Common::Size_3285_MB;
return 3285_MiB;
case Smc::MemoryArrangement_8GB:
return Common::Size_4916_MB;
return 4916_MiB;
}
}();
@@ -103,22 +106,22 @@ size_t KSystemControl::Init::GetAppletPoolSize() {
switch (GetMemoryArrangeForInit()) {
case Smc::MemoryArrangement_4GB:
default:
return Common::Size_507_MB;
return 507_MiB;
case Smc::MemoryArrangement_4GBForAppletDev:
return Common::Size_1554_MB;
return 1554_MiB;
case Smc::MemoryArrangement_4GBForSystemDev:
return Common::Size_448_MB;
return 448_MiB;
case Smc::MemoryArrangement_6GB:
return Common::Size_562_MB;
return 562_MiB;
case Smc::MemoryArrangement_6GBForAppletDev:
return Common::Size_2193_MB;
return 2193_MiB;
case Smc::MemoryArrangement_8GB:
return Common::Size_2193_MB;
return 2193_MiB;
}
}();
// Return (possibly) adjusted size.
constexpr size_t ExtraSystemMemoryForAtmosphere = Common::Size_33_MB;
constexpr size_t ExtraSystemMemoryForAtmosphere = 33_MiB;
return base_pool_size - ExtraSystemMemoryForAtmosphere - KTraceBufferSize;
}
+19 -16
View File
@@ -5,34 +5,37 @@
#include <array>
#include "common/assert.h"
#include "common/common_sizes.h"
#include "common/literals.h"
#include "core/hle/kernel/k_address_space_info.h"
namespace Kernel {
namespace {
using namespace Common::Literals;
constexpr u64 Size_Invalid = UINT64_MAX;
// clang-format off
constexpr std::array<KAddressSpaceInfo, 13> AddressSpaceInfos{{
{ .bit_width = 32, .address = Common::Size_2_MB , .size = Common::Size_1_GB - Common::Size_2_MB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = Common::Size_1_GB , .size = Common::Size_4_GB - Common::Size_1_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 32, .address = Common::Size_Invalid, .size = Common::Size_1_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Common::Size_128_MB , .size = Common::Size_2_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = Common::Size_2_GB , .size = Common::Size_64_GB - Common::Size_2_GB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Common::Size_128_MB , .size = Common::Size_512_GB - Common::Size_128_MB, .type = KAddressSpaceInfo::Type::Map39Bit, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_6_GB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_64_GB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Common::Size_Invalid, .size = Common::Size_2_GB , .type = KAddressSpaceInfo::Type::Stack, },
{ .bit_width = 32, .address = 2_MiB , .size = 1_GiB - 2_MiB , .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 32, .address = 1_GiB , .size = 4_GiB - 1_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 32, .address = Size_Invalid, .size = 1_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = 128_MiB , .size = 2_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::MapSmall, },
{ .bit_width = 36, .address = 2_GiB , .size = 64_GiB - 2_GiB , .type = KAddressSpaceInfo::Type::MapLarge, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 36, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = 128_MiB , .size = 512_GiB - 128_MiB, .type = KAddressSpaceInfo::Type::Map39Bit, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::MapSmall },
{ .bit_width = 39, .address = Size_Invalid, .size = 6_GiB , .type = KAddressSpaceInfo::Type::Heap, },
{ .bit_width = 39, .address = Size_Invalid, .size = 64_GiB , .type = KAddressSpaceInfo::Type::Alias, },
{ .bit_width = 39, .address = Size_Invalid, .size = 2_GiB , .type = KAddressSpaceInfo::Type::Stack, },
}};
// clang-format on
constexpr bool IsAllowedIndexForAddress(std::size_t index) {
return index < AddressSpaceInfos.size() &&
AddressSpaceInfos[index].address != Common::Size_Invalid;
return index < AddressSpaceInfos.size() && AddressSpaceInfos[index].address != Size_Invalid;
}
using IndexArray =
@@ -3,6 +3,7 @@
// Refer to the license.txt file included.
#include "common/alignment.h"
#include "common/literals.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_system_control.h"
@@ -12,8 +13,10 @@ namespace Kernel {
namespace {
using namespace Common::Literals;
constexpr size_t CarveoutAlignment = 0x20000;
constexpr size_t CarveoutSizeMax = (512ULL * 1024 * 1024) - CarveoutAlignment;
constexpr size_t CarveoutSizeMax = (512_MiB) - CarveoutAlignment;
bool SetupPowerManagementControllerMemoryRegion(KMemoryLayout& memory_layout) {
// Above firmware 2.0.0, the PMC is not mappable.
+14 -13
View File
@@ -7,8 +7,7 @@
#include <utility>
#include "common/alignment.h"
#include "common/common_sizes.h"
#include "common/common_types.h"
#include "common/literals.h"
#include "core/device_memory.h"
#include "core/hle/kernel/k_memory_region.h"
#include "core/hle/kernel/k_memory_region_type.h"
@@ -16,20 +15,22 @@
namespace Kernel {
constexpr std::size_t L1BlockSize = Common::Size_1_GB;
constexpr std::size_t L2BlockSize = Common::Size_2_MB;
using namespace Common::Literals;
constexpr std::size_t L1BlockSize = 1_GiB;
constexpr std::size_t L2BlockSize = 2_MiB;
constexpr std::size_t GetMaximumOverheadSize(std::size_t size) {
return (Common::DivideUp(size, L1BlockSize) + Common::DivideUp(size, L2BlockSize)) * PageSize;
}
constexpr std::size_t MainMemorySize = Common::Size_4_GB;
constexpr std::size_t MainMemorySizeMax = Common::Size_8_GB;
constexpr std::size_t MainMemorySize = 4_GiB;
constexpr std::size_t MainMemorySizeMax = 8_GiB;
constexpr std::size_t ReservedEarlyDramSize = 0x60000;
constexpr std::size_t ReservedEarlyDramSize = 384_KiB;
constexpr std::size_t DramPhysicalAddress = 0x80000000;
constexpr std::size_t KernelAslrAlignment = Common::Size_2_MB;
constexpr std::size_t KernelAslrAlignment = 2_MiB;
constexpr std::size_t KernelVirtualAddressSpaceWidth = 1ULL << 39;
constexpr std::size_t KernelPhysicalAddressSpaceWidth = 1ULL << 48;
@@ -40,7 +41,7 @@ constexpr std::size_t KernelVirtualAddressSpaceLast = KernelVirtualAddressSpaceE
constexpr std::size_t KernelVirtualAddressSpaceSize =
KernelVirtualAddressSpaceEnd - KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeBase = KernelVirtualAddressSpaceBase;
constexpr std::size_t KernelVirtualAddressCodeSize = 0x62000;
constexpr std::size_t KernelVirtualAddressCodeSize = 392_KiB;
constexpr std::size_t KernelVirtualAddressCodeEnd =
KernelVirtualAddressCodeBase + KernelVirtualAddressCodeSize;
@@ -53,14 +54,14 @@ constexpr std::size_t KernelPhysicalAddressSpaceSize =
constexpr std::size_t KernelPhysicalAddressCodeBase = DramPhysicalAddress + ReservedEarlyDramSize;
constexpr std::size_t KernelPageTableHeapSize = GetMaximumOverheadSize(MainMemorySizeMax);
constexpr std::size_t KernelInitialPageHeapSize = Common::Size_128_KB;
constexpr std::size_t KernelInitialPageHeapSize = 128_KiB;
constexpr std::size_t KernelSlabHeapDataSize = Common::Size_5_MB;
constexpr std::size_t KernelSlabHeapGapsSize = Common::Size_2_MB - Common::Size_64_KB;
constexpr std::size_t KernelSlabHeapDataSize = 5_MiB;
constexpr std::size_t KernelSlabHeapGapsSize = 2_MiB - 64_KiB;
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSize;
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000ULL;
constexpr std::size_t KernelSlabHeapAdditionalSize = 416_KiB;
constexpr std::size_t KernelResourceSize =
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
+4 -1
View File
@@ -4,6 +4,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/literals.h"
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/kernel/k_address_space_info.h"
@@ -23,6 +24,8 @@ namespace Kernel {
namespace {
using namespace Common::Literals;
constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceType as_type) {
switch (as_type) {
case FileSys::ProgramAddressSpaceType::Is32Bit:
@@ -89,7 +92,7 @@ ResultCode KPageTable::InitializeForProcess(FileSys::ProgramAddressSpaceType as_
}
// Set code regions and determine remaining
constexpr std::size_t RegionAlignment{2 * 1024 * 1024};
constexpr std::size_t RegionAlignment{2_MiB};
VAddr process_code_start{};
VAddr process_code_end{};
std::size_t stack_region_size{};
+5 -1
View File
@@ -4,9 +4,13 @@
#pragma once
#include "common/common_funcs.h"
namespace Kernel {
using namespace Common::Literals;
constexpr bool IsKTraceEnabled = false;
constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16 * 1024 * 1024 : 0;
constexpr std::size_t KTraceBufferSize = IsKTraceEnabled ? 16_MiB : 0;
} // namespace Kernel
+8 -9
View File
@@ -12,7 +12,6 @@
#include <utility>
#include "common/assert.h"
#include "common/common_sizes.h"
#include "common/logging/log.h"
#include "common/microprofile.h"
#include "common/thread.h"
@@ -180,7 +179,7 @@ struct KernelCore::Impl {
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
// Reserve secure applet memory, introduced in firmware 5.0.0
constexpr u64 secure_applet_memory_size{Common::Size_4_MB};
constexpr u64 secure_applet_memory_size{4_MiB};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size));
@@ -320,8 +319,8 @@ struct KernelCore::Impl {
const VAddr code_end_virt_addr = KernelVirtualAddressCodeEnd;
// Setup the containing kernel region.
constexpr size_t KernelRegionSize = Common::Size_1_GB;
constexpr size_t KernelRegionAlign = Common::Size_1_GB;
constexpr size_t KernelRegionSize = 1_GiB;
constexpr size_t KernelRegionAlign = 1_GiB;
constexpr VAddr kernel_region_start =
Common::AlignDown(code_start_virt_addr, KernelRegionAlign);
size_t kernel_region_size = KernelRegionSize;
@@ -368,7 +367,7 @@ struct KernelCore::Impl {
// Decide on the actual size for the misc region.
constexpr size_t MiscRegionAlign = KernelAslrAlignment;
constexpr size_t MiscRegionMinimumSize = Common::Size_32_MB;
constexpr size_t MiscRegionMinimumSize = 32_MiB;
const size_t misc_region_size = Common::AlignUp(
std::max(misc_region_needed_size, MiscRegionMinimumSize), MiscRegionAlign);
ASSERT(misc_region_size > 0);
@@ -381,7 +380,7 @@ struct KernelCore::Impl {
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
// Setup the stack region.
constexpr size_t StackRegionSize = Common::Size_14_MB;
constexpr size_t StackRegionSize = 14_MiB;
constexpr size_t StackRegionAlign = KernelAslrAlignment;
const VAddr stack_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
@@ -414,7 +413,7 @@ struct KernelCore::Impl {
slab_region_start, slab_region_size, KMemoryRegionType_KernelSlab));
// Setup the temp region.
constexpr size_t TempRegionSize = Common::Size_128_MB;
constexpr size_t TempRegionSize = 128_MiB;
constexpr size_t TempRegionAlign = KernelAslrAlignment;
const VAddr temp_region_start =
memory_layout.GetVirtualMemoryRegionTree().GetRandomAlignedRegion(
@@ -470,7 +469,7 @@ struct KernelCore::Impl {
// Determine size available for kernel page table heaps, requiring > 8 MB.
const PAddr resource_end_phys_addr = slab_start_phys_addr + resource_region_size;
const size_t page_table_heap_size = resource_end_phys_addr - slab_end_phys_addr;
ASSERT(page_table_heap_size / Common::Size_4_MB > 2);
ASSERT(page_table_heap_size / 4_MiB > 2);
// Insert a physical region for the kernel page table heap region
ASSERT(memory_layout.GetPhysicalMemoryRegionTree().Insert(
@@ -495,7 +494,7 @@ struct KernelCore::Impl {
ASSERT(linear_extents.GetEndAddress() != 0);
// Setup the linear mapping region.
constexpr size_t LinearRegionAlign = Common::Size_1_GB;
constexpr size_t LinearRegionAlign = 1_GiB;
const PAddr aligned_linear_phys_start =
Common::AlignDown(linear_extents.GetAddress(), LinearRegionAlign);
const size_t linear_region_size =
+9 -1
View File
@@ -117,7 +117,7 @@ AOC_U::AOC_U(Core::System& system_)
{7, &AOC_U::PrepareAddOnContent, "PrepareAddOnContent"},
{8, &AOC_U::GetAddOnContentListChangedEvent, "GetAddOnContentListChangedEvent"},
{9, nullptr, "GetAddOnContentLostErrorCode"},
{10, nullptr, "GetAddOnContentListChangedEventWithProcessId"},
{10, &AOC_U::GetAddOnContentListChangedEventWithProcessId, "GetAddOnContentListChangedEventWithProcessId"},
{100, &AOC_U::CreateEcPurchasedEventManager, "CreateEcPurchasedEventManager"},
{101, &AOC_U::CreatePermanentEcPurchasedEventManager, "CreatePermanentEcPurchasedEventManager"},
{110, nullptr, "CreateContentsServiceManager"},
@@ -257,6 +257,14 @@ void AOC_U::GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx) {
rb.PushCopyObjects(aoc_change_event.GetReadableEvent());
}
void AOC_U::GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(aoc_change_event.GetReadableEvent());
}
void AOC_U::CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AOC, "(STUBBED) called");
+1
View File
@@ -28,6 +28,7 @@ private:
void GetAddOnContentBaseId(Kernel::HLERequestContext& ctx);
void PrepareAddOnContent(Kernel::HLERequestContext& ctx);
void GetAddOnContentListChangedEvent(Kernel::HLERequestContext& ctx);
void GetAddOnContentListChangedEventWithProcessId(Kernel::HLERequestContext& ctx);
void CreateEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
void CreatePermanentEcPurchasedEventManager(Kernel::HLERequestContext& ctx);
+41 -4
View File
@@ -253,7 +253,11 @@ void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) {
rb.Push<u32>(worker_buffer_sz);
}
void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
void HwOpus::GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx) {
GetWorkBufferSize(ctx);
}
void HwOpus::OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
@@ -291,14 +295,47 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
}
void HwOpus::OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto sample_rate = rp.Pop<u32>();
const auto channel_count = rp.Pop<u32>();
LOG_CRITICAL(Audio, "called sample_rate={}, channel_count={}", sample_rate, channel_count);
ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 ||
sample_rate == 12000 || sample_rate == 8000,
"Invalid sample rate");
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
const int num_stereo_streams = channel_count == 2 ? 1 : 0;
const auto mapping_table = CreateMappingTable(channel_count);
int error = 0;
OpusDecoderPtr decoder{
opus_multistream_decoder_create(sample_rate, static_cast<int>(channel_count), 1,
num_stereo_streams, mapping_table.data(), &error)};
if (error != OPUS_OK || decoder == nullptr) {
LOG_ERROR(Audio, "Failed to create Opus decoder (error={}).", error);
IPC::ResponseBuilder rb{ctx, 2};
// TODO(ogniK): Use correct error code
rb.Push(ResultUnknown);
return;
}
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IHardwareOpusDecoderManager>(
system, OpusDecoderState{std::move(decoder), sample_rate, channel_count});
}
HwOpus::HwOpus(Core::System& system_) : ServiceFramework{system_, "hwopus"} {
static const FunctionInfo functions[] = {
{0, &HwOpus::OpenOpusDecoder, "OpenOpusDecoder"},
{0, &HwOpus::OpenHardwareOpusDecoder, "OpenHardwareOpusDecoder"},
{1, &HwOpus::GetWorkBufferSize, "GetWorkBufferSize"},
{2, nullptr, "OpenOpusDecoderForMultiStream"},
{3, nullptr, "GetWorkBufferSizeForMultiStream"},
{4, nullptr, "OpenHardwareOpusDecoderEx"},
{5, nullptr, "GetWorkBufferSizeEx"},
{4, &HwOpus::OpenHardwareOpusDecoderEx, "OpenHardwareOpusDecoderEx"},
{5, &HwOpus::GetWorkBufferSizeEx, "GetWorkBufferSizeEx"},
{6, nullptr, "OpenHardwareOpusDecoderForMultiStreamEx"},
{7, nullptr, "GetWorkBufferSizeForMultiStreamEx"},
};
+3 -1
View File
@@ -18,8 +18,10 @@ public:
~HwOpus() override;
private:
void OpenOpusDecoder(Kernel::HLERequestContext& ctx);
void OpenHardwareOpusDecoder(Kernel::HLERequestContext& ctx);
void OpenHardwareOpusDecoderEx(Kernel::HLERequestContext& ctx);
void GetWorkBufferSize(Kernel::HLERequestContext& ctx);
void GetWorkBufferSizeEx(Kernel::HLERequestContext& ctx);
};
} // namespace Service::Audio
@@ -68,6 +68,7 @@ void nvhost_nvdec::OnOpen(DeviceFD fd) {}
void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
system.GPU().ClearCdmaInstance();
system.GPU().MemoryManager().InvalidateQueuedCaches();
}
} // namespace Service::Nvidia::Devices
@@ -198,7 +198,13 @@ NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vec
return NvResult::InvalidState;
}
if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
if (vic_device) {
// UnmapVicFrame defers texture_cache invalidation of the frame address until
// the stream is over
gpu.MemoryManager().UnmapVicFrame(object->dma_map_addr, *size);
} else {
gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
}
} else {
// This occurs quite frequently, however does not seem to impact functionality
LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
@@ -160,6 +160,7 @@ protected:
s32_le nvmap_fd{};
u32_le submit_timeout{};
bool vic_device{};
std::shared_ptr<nvmap> nvmap_dev;
SyncpointManager& syncpoint_manager;
std::array<u32, MaxSyncPoints> device_syncpoints{};
@@ -12,8 +12,9 @@
namespace Service::Nvidia::Devices {
nvhost_vic::nvhost_vic(Core::System& system_, std::shared_ptr<nvmap> nvmap_dev_,
SyncpointManager& syncpoint_manager_)
: nvhost_nvdec_common{system_, std::move(nvmap_dev_), syncpoint_manager_} {}
: nvhost_nvdec_common(system_, std::move(nvmap_dev_), syncpoint_manager_) {
vic_device = true;
}
nvhost_vic::~nvhost_vic() = default;
NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
+2
View File
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "core/hle/result.h"
namespace Service::SPL {
+2
View File
@@ -2,6 +2,8 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <span>
#include "common/bit_field.h"
+3 -1
View File
@@ -5,11 +5,13 @@
#include <catch2/catch.hpp>
#include "common/host_memory.h"
#include "common/literals.h"
using Common::HostMemory;
using namespace Common::Literals;
static constexpr size_t VIRTUAL_SIZE = 1ULL << 39;
static constexpr size_t BACKING_SIZE = 4ULL * 1024 * 1024 * 1024;
static constexpr size_t BACKING_SIZE = 4_GiB;
TEST_CASE("HostMemory: Initialize and deinitialize", "[common]") {
{ HostMemory mem(BACKING_SIZE, VIRTUAL_SIZE); }
+7 -4
View File
@@ -16,9 +16,9 @@
#include <boost/container/small_vector.hpp>
#include "common/common_sizes.h"
#include "common/common_types.h"
#include "common/div_ceil.h"
#include "common/literals.h"
#include "common/microprofile.h"
#include "common/scope_exit.h"
#include "common/settings.h"
@@ -48,8 +48,11 @@ constexpr u32 NUM_COMPUTE_UNIFORM_BUFFERS = 8;
constexpr u32 NUM_STORAGE_BUFFERS = 16;
constexpr u32 NUM_STAGES = 5;
using namespace Common::Literals;
template <typename P>
class BufferCache {
// Page size for caching purposes.
// This is unrelated to the CPU page size and it can be changed as it seems optimal.
static constexpr u32 PAGE_BITS = 16;
@@ -66,8 +69,8 @@ class BufferCache {
static constexpr BufferId NULL_BUFFER_ID{0};
static constexpr u64 EXPECTED_MEMORY = Common::Size_512_MB;
static constexpr u64 CRITICAL_MEMORY = Common::Size_1_GB;
static constexpr u64 EXPECTED_MEMORY = 512_MiB;
static constexpr u64 CRITICAL_MEMORY = 1_GiB;
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
@@ -96,7 +99,7 @@ class BufferCache {
};
public:
static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = 4096;
static constexpr u32 DEFAULT_SKIP_CACHE_SIZE = 4_KiB;
explicit BufferCache(VideoCore::RasterizerInterface& rasterizer_,
Tegra::Engines::Maxwell3D& maxwell3d_,
+4
View File
@@ -1785,6 +1785,8 @@ public:
SSY,
SYNC,
BRK,
CAL,
RET,
DEPBAR,
VOTE,
VOTE_VTG,
@@ -2108,6 +2110,8 @@ private:
INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
INST("111000110100----", Id::BRK, Type::Flow, "BRK"),
INST("111000110000----", Id::EXIT, Type::Flow, "EXIT"),
INST("111000100110----", Id::CAL, Type::Flow, "CAL"),
INST("111000110010----", Id::RET, Type::Flow, "RET"),
INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
INST("0101000011011---", Id::VOTE, Type::Warp, "VOTE"),
INST("0101000011100---", Id::VOTE_VTG, Type::Warp, "VOTE_VTG"),
+20 -26
View File
@@ -11,12 +11,8 @@
#define UNIFORM(n)
#define BINDING_INPUT_BUFFER 0
#define BINDING_ENC_BUFFER 1
#define BINDING_6_TO_8_BUFFER 2
#define BINDING_7_TO_8_BUFFER 3
#define BINDING_8_TO_8_BUFFER 4
#define BINDING_BYTE_TO_16_BUFFER 5
#define BINDING_SWIZZLE_BUFFER 6
#define BINDING_OUTPUT_IMAGE 7
#define BINDING_SWIZZLE_BUFFER 2
#define BINDING_OUTPUT_IMAGE 3
#else // ^^^ Vulkan ^^^ // vvv OpenGL vvv
@@ -26,10 +22,6 @@
#define BINDING_SWIZZLE_BUFFER 0
#define BINDING_INPUT_BUFFER 1
#define BINDING_ENC_BUFFER 2
#define BINDING_6_TO_8_BUFFER 3
#define BINDING_7_TO_8_BUFFER 4
#define BINDING_8_TO_8_BUFFER 5
#define BINDING_BYTE_TO_16_BUFFER 6
#define BINDING_OUTPUT_IMAGE 0
#endif
@@ -76,19 +68,6 @@ layout(binding = BINDING_INPUT_BUFFER, std430) readonly buffer InputBufferU32 {
layout(binding = BINDING_ENC_BUFFER, std430) readonly buffer EncodingsValues {
EncodingData encoding_values[];
};
// ASTC Precompiled tables
layout(binding = BINDING_6_TO_8_BUFFER, std430) readonly buffer REPLICATE_6_BIT_TO_8 {
uint REPLICATE_6_BIT_TO_8_TABLE[];
};
layout(binding = BINDING_7_TO_8_BUFFER, std430) readonly buffer REPLICATE_7_BIT_TO_8 {
uint REPLICATE_7_BIT_TO_8_TABLE[];
};
layout(binding = BINDING_8_TO_8_BUFFER, std430) readonly buffer REPLICATE_8_BIT_TO_8 {
uint REPLICATE_8_BIT_TO_8_TABLE[];
};
layout(binding = BINDING_BYTE_TO_16_BUFFER, std430) readonly buffer REPLICATE_BYTE_TO_16 {
uint REPLICATE_BYTE_TO_16_TABLE[];
};
layout(binding = BINDING_OUTPUT_IMAGE, rgba8) uniform writeonly image2DArray dest_image;
@@ -139,6 +118,19 @@ const uint REPLICATE_4_BIT_TO_6_TABLE[16] =
const uint REPLICATE_5_BIT_TO_6_TABLE[32] =
uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 33, 35, 37, 39, 41, 43, 45,
47, 49, 51, 53, 55, 57, 59, 61, 63);
const uint REPLICATE_6_BIT_TO_8_TABLE[64] =
uint[](0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60, 65, 69, 73, 77, 81, 85, 89,
93, 97, 101, 105, 109, 113, 117, 121, 125, 130, 134, 138, 142, 146, 150, 154, 158, 162,
166, 170, 174, 178, 182, 186, 190, 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235,
239, 243, 247, 251, 255);
const uint REPLICATE_7_BIT_TO_8_TABLE[128] =
uint[](0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44,
46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88,
90, 92, 94, 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126,
129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159, 161, 163,
165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191, 193, 195, 197, 199,
201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223, 225, 227, 229, 231, 233, 235,
237, 239, 241, 243, 245, 247, 249, 251, 253, 255);
// Input ASTC texture globals
uint current_index = 0;
@@ -207,8 +199,7 @@ uint Replicate(uint val, uint num_bits, uint to_bit) {
}
uvec4 ReplicateByteTo16(uvec4 value) {
return uvec4(REPLICATE_BYTE_TO_16_TABLE[value.x], REPLICATE_BYTE_TO_16_TABLE[value.y],
REPLICATE_BYTE_TO_16_TABLE[value.z], REPLICATE_BYTE_TO_16_TABLE[value.w]);
return value * 0x101;
}
uint ReplicateBitTo7(uint value) {
@@ -236,7 +227,7 @@ uint FastReplicateTo8(uint value, uint num_bits) {
case 7:
return REPLICATE_7_BIT_TO_8_TABLE[value];
case 8:
return REPLICATE_8_BIT_TO_8_TABLE[value];
return value;
}
return Replicate(value, num_bits, 8);
}
@@ -1327,6 +1318,9 @@ void main() {
offset += swizzle;
const ivec3 coord = ivec3(gl_GlobalInvocationID * uvec3(block_dims, 1));
if (any(greaterThanEqual(coord, imageSize(dest_image)))) {
return;
}
uint block_index =
pos.z * gl_WorkGroupSize.x * gl_WorkGroupSize.y + pos.y * gl_WorkGroupSize.x + pos.x;
+19
View File
@@ -114,6 +114,25 @@ void MemoryManager::TryUnlockPage(PageEntry page_entry, std::size_t size) {
.IsSuccess());
}
void MemoryManager::UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size) {
if (!size) {
return;
}
const std::optional<VAddr> cpu_addr = GpuToCpuAddress(gpu_addr);
ASSERT(cpu_addr);
rasterizer->InvalidateExceptTextureCache(*cpu_addr, size);
cache_invalidate_queue.push_back({*cpu_addr, size});
UpdateRange(gpu_addr, PageEntry::State::Unmapped, size);
}
void MemoryManager::InvalidateQueuedCaches() {
for (const auto& entry : cache_invalidate_queue) {
rasterizer->InvalidateTextureCache(entry.first, entry.second);
}
cache_invalidate_queue.clear();
}
PageEntry MemoryManager::GetPageEntry(GPUVAddr gpu_addr) const {
return page_table[PageEntryIndex(gpu_addr)];
}
+8
View File
@@ -123,6 +123,14 @@ public:
[[nodiscard]] GPUVAddr Allocate(std::size_t size, std::size_t align);
void Unmap(GPUVAddr gpu_addr, std::size_t size);
/**
* Some Decoded NVDEC frames require that texture cache does not get invalidated.
* UnmapVicFrame defers the texture cache invalidation until the stream ends
* by invoking InvalidateQueuedCaches to invalidate all frame texture caches.
*/
void UnmapVicFrame(GPUVAddr gpu_addr, std::size_t size);
void InvalidateQueuedCaches();
private:
[[nodiscard]] PageEntry GetPageEntry(GPUVAddr gpu_addr) const;
void SetPageEntry(GPUVAddr gpu_addr, PageEntry page_entry, std::size_t size = page_size);
+6
View File
@@ -72,6 +72,12 @@ public:
/// Notify rasterizer that any caches of the specified region should be flushed to Switch memory
virtual void FlushRegion(VAddr addr, u64 size) = 0;
/// Notify rasterizer to flush the texture cache to Switch memory
virtual void InvalidateExceptTextureCache(VAddr addr, u64 size) = 0;
/// Notify rasterizer to invalidate the texture cache
virtual void InvalidateTextureCache(VAddr addr, u64 size) = 0;
/// Check if the the specified memory area requires flushing to CPU Memory.
virtual bool MustFlushRegion(VAddr addr, u64 size) = 0;
@@ -491,6 +491,9 @@ private:
const Registry& registry;
const ShaderType stage;
std::shared_ptr<ShaderFunctionIR> context_func;
u32 ast_var_base{};
std::size_t num_temporaries = 0;
std::size_t max_temporaries = 0;
@@ -807,13 +810,33 @@ ARBDecompiler::ARBDecompiler(const Device& device_, const ShaderIR& ir_, const R
: device{device_}, ir{ir_}, registry{registry_}, stage{stage_} {
DefineGlobalMemory();
context_func = ir.GetMainFunction();
ast_var_base = 0;
AddLine("TEMP RC;");
AddLine("TEMP FSWZA[4];");
AddLine("TEMP FSWZB[4];");
if (ir.IsDecompiled()) {
InitializeVariables();
AddLine("main:");
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
AddLine("RET;");
}
const auto& subfunctions = ir.GetSubFunctions();
auto it = subfunctions.begin();
while (it != subfunctions.end()) {
context_func = *it;
AddLine("func_{}:", context_func->GetId());
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
AddLine("RET;");
}
it++;
}
AddLine("END");
@@ -1060,41 +1083,38 @@ void ARBDecompiler::InitializeVariables() {
}
void ARBDecompiler::DecompileAST() {
const u32 num_flow_variables = ir.GetASTNumVariables();
const u32 num_flow_variables = context_func->GetASTNumVariables();
for (u32 i = 0; i < num_flow_variables; ++i) {
AddLine("TEMP F{};", i);
AddLine("TEMP F{};", i + ast_var_base);
}
for (u32 i = 0; i < num_flow_variables; ++i) {
AddLine("MOV.U F{}, {{0, 0, 0, 0}};", i);
AddLine("MOV.U F{}, {{0, 0, 0, 0}};", i + ast_var_base);
}
InitializeVariables();
VisitAST(ir.GetASTProgram());
VisitAST(context_func->GetASTProgram());
ast_var_base += num_flow_variables;
}
void ARBDecompiler::DecompileBranchMode() {
static constexpr u32 FLOW_STACK_SIZE = 20;
if (!ir.IsFlowStackDisabled()) {
if (!context_func->IsFlowStackDisabled()) {
AddLine("TEMP SSY[{}];", FLOW_STACK_SIZE);
AddLine("TEMP PBK[{}];", FLOW_STACK_SIZE);
AddLine("TEMP SSY_TOP;");
AddLine("TEMP PBK_TOP;");
}
AddLine("TEMP PC;");
AddLine("TEMP PC{};", context_func->GetId());
if (!ir.IsFlowStackDisabled()) {
if (!context_func->IsFlowStackDisabled()) {
AddLine("MOV.U SSY_TOP.x, 0;");
AddLine("MOV.U PBK_TOP.x, 0;");
}
InitializeVariables();
const auto basic_block_end = ir.GetBasicBlocks().end();
auto basic_block_it = ir.GetBasicBlocks().begin();
const auto basic_block_end = context_func->GetBasicBlocks().end();
auto basic_block_it = context_func->GetBasicBlocks().begin();
const u32 first_address = basic_block_it->first;
AddLine("MOV.U PC.x, {};", first_address);
AddLine("MOV.U PC{}.x, {};", context_func->GetId(), first_address);
AddLine("REP;");
@@ -1103,7 +1123,7 @@ void ARBDecompiler::DecompileBranchMode() {
const auto& [address, bb] = *basic_block_it;
++num_blocks;
AddLine("SEQ.S.CC RC.x, PC.x, {};", address);
AddLine("SEQ.S.CC RC.x, PC{}.x, {};", context_func->GetId(), address);
AddLine("IF NE.x;");
VisitBlock(bb);
@@ -1114,7 +1134,7 @@ void ARBDecompiler::DecompileBranchMode() {
const auto op = std::get_if<OperationNode>(&*bb[bb.size() - 1]);
if (!op || op->GetCode() != OperationCode::Branch) {
const u32 next_address = basic_block_it->first;
AddLine("MOV.U PC.x, {};", next_address);
AddLine("MOV.U PC{}.x, {};", context_func->GetId(), next_address);
AddLine("CONT;");
}
}
@@ -1152,7 +1172,8 @@ void ARBDecompiler::VisitAST(const ASTNode& node) {
} else if (const auto decoded = std::get_if<ASTBlockDecoded>(&*node->GetInnerData())) {
VisitBlock(decoded->nodes);
} else if (const auto var_set = std::get_if<ASTVarSet>(&*node->GetInnerData())) {
AddLine("MOV.U F{}, {};", var_set->index, VisitExpression(var_set->condition));
AddLine("MOV.U F{}, {};", var_set->index + ast_var_base,
VisitExpression(var_set->condition));
ResetTemporaries();
} else if (const auto do_while = std::get_if<ASTDoWhile>(&*node->GetInnerData())) {
const std::string condition = VisitExpression(do_while->condition);
@@ -1172,7 +1193,11 @@ void ARBDecompiler::VisitAST(const ASTNode& node) {
ResetTemporaries();
}
if (ast_return->kills) {
AddLine("KIL TR;");
if (stage == ShaderType::Fragment) {
AddLine("KIL TR;");
} else {
AddLine("RET;");
}
} else {
Exit();
}
@@ -1219,7 +1244,7 @@ std::string ARBDecompiler::VisitExpression(const Expr& node) {
return Visit(ir.GetConditionCode(expr->cc));
}
if (const auto expr = std::get_if<ExprVar>(&*node)) {
return fmt::format("F{}.x", expr->var_index);
return fmt::format("F{}.x", expr->var_index + ast_var_base);
}
if (const auto expr = std::get_if<ExprBoolean>(&*node)) {
return expr->value ? "0xffffffff" : "0";
@@ -1406,6 +1431,11 @@ std::string ARBDecompiler::Visit(const Node& node) {
return {};
}
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
AddLine("CAL func_{};", func_call->GetFuncId());
return {};
}
if ([[maybe_unused]] const auto cmt = std::get_if<CommentNode>(&*node)) {
// Uncommenting this will generate invalid code. GLASM lacks comments.
// AddLine("// {}", cmt->GetText());
@@ -1479,7 +1509,7 @@ std::string ARBDecompiler::GlobalMemoryPointer(const GmemNode& gmem) {
}
void ARBDecompiler::Exit() {
if (stage != ShaderType::Fragment) {
if (!context_func->IsMain() || stage != ShaderType::Fragment) {
AddLine("RET;");
return;
}
@@ -2021,13 +2051,13 @@ std::string ARBDecompiler::ImageStore(Operation operation) {
std::string ARBDecompiler::Branch(Operation operation) {
const auto target = std::get<ImmediateNode>(*operation[0]);
AddLine("MOV.U PC.x, {};", target.GetValue());
AddLine("MOV.U PC{}.x, {};", context_func->GetId(), target.GetValue());
AddLine("CONT;");
return {};
}
std::string ARBDecompiler::BranchIndirect(Operation operation) {
AddLine("MOV.U PC.x, {};", Visit(operation[0]));
AddLine("MOV.U PC{}.x, {};", context_func->GetId(), Visit(operation[0]));
AddLine("CONT;");
return {};
}
@@ -2045,7 +2075,7 @@ std::string ARBDecompiler::PopFlowStack(Operation operation) {
const auto stack = std::get<MetaStackClass>(operation.GetMeta());
const std::string_view stack_name = StackName(stack);
AddLine("SUB.S {}_TOP.x, {}_TOP.x, 1;", stack_name, stack_name);
AddLine("MOV.U PC.x, {}[{}_TOP.x].x;", stack_name, stack_name);
AddLine("MOV.U PC{}.x, {}[{}_TOP.x].x;", context_func->GetId(), stack_name, stack_name);
AddLine("CONT;");
return {};
}
@@ -2056,6 +2086,10 @@ std::string ARBDecompiler::Exit(Operation) {
}
std::string ARBDecompiler::Discard(Operation) {
if (stage != ShaderType::Fragment) {
AddLine("RET;");
return {};
}
AddLine("KIL TR;");
return {};
}
@@ -548,6 +548,26 @@ void RasterizerOpenGL::FlushRegion(VAddr addr, u64 size) {
query_cache.FlushRegion(addr, size);
}
void RasterizerOpenGL::InvalidateExceptTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
shader_cache.InvalidateRegion(addr, size);
{
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.WriteMemory(addr, size);
}
query_cache.InvalidateRegion(addr, size);
}
void RasterizerOpenGL::InvalidateTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
std::scoped_lock lock{texture_cache.mutex};
texture_cache.UnmapMemory(addr, size);
}
bool RasterizerOpenGL::MustFlushRegion(VAddr addr, u64 size) {
std::scoped_lock lock{buffer_cache.mutex, texture_cache.mutex};
if (!Settings::IsGPULevelHigh()) {
@@ -75,6 +75,8 @@ public:
void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
void InvalidateExceptTextureCache(VAddr addr, u64 size) override;
void InvalidateTextureCache(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override;
void OnCPUWrite(VAddr addr, u64 size) override;
@@ -435,6 +435,27 @@ public:
DeclareCustomVariables();
DeclarePhysicalAttributeReader();
const auto& subfunctions = ir.GetSubFunctions();
auto it = subfunctions.rbegin();
while (it != subfunctions.rend()) {
context_func = *it;
code.AddLine("void func_{}() {{", context_func->GetId());
++code.scope;
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
}
--code.scope;
code.AddLine("}}");
it++;
}
context_func = ir.GetMainFunction();
code.AddLine("void main() {{");
++code.scope;
@@ -442,7 +463,7 @@ public:
code.AddLine("gl_Position = vec4(0.0f, 0.0f, 0.0f, 1.0f);");
}
if (ir.IsDecompiled()) {
if (context_func->IsDecompiled()) {
DecompileAST();
} else {
DecompileBranchMode();
@@ -462,13 +483,13 @@ private:
void DecompileBranchMode() {
// VM's program counter
const auto first_address = ir.GetBasicBlocks().begin()->first;
const auto first_address = context_func->GetBasicBlocks().begin()->first;
code.AddLine("uint jmp_to = {}U;", first_address);
// TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
// unlikely that shaders will use 20 nested SSYs and PBKs.
constexpr u32 FLOW_STACK_SIZE = 20;
if (!ir.IsFlowStackDisabled()) {
if (!context_func->IsFlowStackDisabled()) {
for (const auto stack : std::array{MetaStackClass::Ssy, MetaStackClass::Pbk}) {
code.AddLine("uint {}[{}];", FlowStackName(stack), FLOW_STACK_SIZE);
code.AddLine("uint {} = 0U;", FlowStackTopName(stack));
@@ -480,7 +501,7 @@ private:
code.AddLine("switch (jmp_to) {{");
for (const auto& pair : ir.GetBasicBlocks()) {
for (const auto& pair : context_func->GetBasicBlocks()) {
const auto& [address, bb] = pair;
code.AddLine("case 0x{:X}U: {{", address);
++code.scope;
@@ -1131,6 +1152,11 @@ private:
return {};
}
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
code.AddLine("func_{}();", func_call->GetFuncId());
return {};
}
if (const auto comment = std::get_if<CommentNode>(&*node)) {
code.AddLine("// " + comment->GetText());
return {};
@@ -2267,7 +2293,9 @@ private:
}
Expression Exit(Operation operation) {
PreExit();
if (context_func->IsMain()) {
PreExit();
}
code.AddLine("return;");
return {};
}
@@ -2277,7 +2305,11 @@ private:
// about unexecuted instructions that may follow this.
code.AddLine("if (true) {{");
++code.scope;
code.AddLine("discard;");
if (stage != ShaderType::Fragment) {
code.AddLine("return;");
} else {
code.AddLine("discard;");
}
--code.scope;
code.AddLine("}}");
return {};
@@ -2388,7 +2420,7 @@ private:
}
Expression Barrier(Operation) {
if (!ir.IsDecompiled()) {
if (!context_func->IsDecompiled()) {
LOG_ERROR(Render_OpenGL, "barrier() used but shader is not decompiled");
return {};
}
@@ -2755,6 +2787,8 @@ private:
const Header header;
std::unordered_map<u8, VaryingTFB> transform_feedback;
std::shared_ptr<ShaderFunctionIR> context_func;
ShaderWriter code;
std::optional<u32> max_input_vertices;
@@ -2902,9 +2936,15 @@ public:
decomp.code.scope++;
}
if (ast.kills) {
decomp.code.AddLine("discard;");
if (decomp.stage != ShaderType::Fragment) {
decomp.code.AddLine("return;");
} else {
decomp.code.AddLine("discard;");
}
} else {
decomp.PreExit();
if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.code.AddLine("return;");
}
if (!is_true) {
@@ -2937,13 +2977,13 @@ private:
};
void GLSLDecompiler::DecompileAST() {
const u32 num_flow_variables = ir.GetASTNumVariables();
const u32 num_flow_variables = context_func->GetASTNumVariables();
for (u32 i = 0; i < num_flow_variables; i++) {
code.AddLine("bool {} = false;", GetFlowVariable(i));
}
ASTDecompiler decompiler{*this};
decompiler.Visit(ir.GetASTProgram());
decompiler.Visit(context_func->GetASTProgram());
}
} // Anonymous namespace
@@ -12,12 +12,15 @@
#include <glad/glad.h>
#include "common/common_types.h"
#include "common/literals.h"
#include "video_core/renderer_opengl/gl_resource_manager.h"
namespace OpenGL {
using namespace Common::Literals;
class StreamBuffer {
static constexpr size_t STREAM_BUFFER_SIZE = 64 * 1024 * 1024;
static constexpr size_t STREAM_BUFFER_SIZE = 64_MiB;
static constexpr size_t NUM_SYNCS = 16;
static constexpr size_t REGION_SIZE = STREAM_BUFFER_SIZE / NUM_SYNCS;
static constexpr size_t MAX_ALIGNMENT = 256;
@@ -69,7 +69,8 @@ UtilShaders::UtilShaders(ProgramManager& program_manager_)
swizzle_table_buffer.Create();
astc_buffer.Create();
glNamedBufferStorage(swizzle_table_buffer.handle, sizeof(swizzle_table), &swizzle_table, 0);
glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_BUFFER_DATA), &ASTC_BUFFER_DATA, 0);
glNamedBufferStorage(astc_buffer.handle, sizeof(ASTC_ENCODINGS_VALUES), &ASTC_ENCODINGS_VALUES,
0);
}
UtilShaders::~UtilShaders() = default;
@@ -79,12 +80,6 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
static constexpr GLuint BINDING_SWIZZLE_BUFFER = 0;
static constexpr GLuint BINDING_INPUT_BUFFER = 1;
static constexpr GLuint BINDING_ENC_BUFFER = 2;
static constexpr GLuint BINDING_6_TO_8_BUFFER = 3;
static constexpr GLuint BINDING_7_TO_8_BUFFER = 4;
static constexpr GLuint BINDING_8_TO_8_BUFFER = 5;
static constexpr GLuint BINDING_BYTE_TO_16_BUFFER = 6;
static constexpr GLuint BINDING_OUTPUT_IMAGE = 0;
const Extent2D tile_size{
@@ -93,21 +88,7 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
};
program_manager.BindHostCompute(astc_decoder_program.handle);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_SWIZZLE_BUFFER, swizzle_table_buffer.handle);
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, encoding_values),
sizeof(AstcBufferData::encoding_values));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_6_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_6_to_8),
sizeof(AstcBufferData::replicate_6_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_7_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_7_to_8),
sizeof(AstcBufferData::replicate_7_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_8_TO_8_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_8_to_8),
sizeof(AstcBufferData::replicate_8_to_8));
glBindBufferRange(GL_SHADER_STORAGE_BUFFER, BINDING_BYTE_TO_16_BUFFER, astc_buffer.handle,
offsetof(AstcBufferData, replicate_byte_to_16),
sizeof(AstcBufferData::replicate_byte_to_16));
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, BINDING_ENC_BUFFER, astc_buffer.handle);
glFlushMappedNamedBufferRange(map.buffer, map.offset, image.guest_size_bytes);
glUniform2ui(1, tile_size.width, tile_size.height);
@@ -137,6 +118,12 @@ void UtilShaders::ASTCDecode(Image& image, const ImageBufferMap& map,
glDispatchCompute(num_dispatches_x, num_dispatches_y, image.info.resources.layers);
}
// Precautionary barrier to ensure the compute shader is done decoding prior to texture access.
// GL_TEXTURE_FETCH_BARRIER_BIT and GL_SHADER_IMAGE_ACCESS_BARRIER_BIT are used in a separate
// glMemoryBarrier call by the texture cache runtime
glMemoryBarrier(GL_UNIFORM_BARRIER_BIT | GL_COMMAND_BARRIER_BIT | GL_PIXEL_BUFFER_BARRIER_BIT |
GL_TEXTURE_UPDATE_BARRIER_BIT | GL_BUFFER_UPDATE_BARRIER_BIT |
GL_SHADER_STORAGE_BARRIER_BIT | GL_CLIENT_MAPPED_BUFFER_BARRIER_BIT);
program_manager.RestoreGuestCompute();
}
@@ -30,19 +30,16 @@
namespace Vulkan {
using Tegra::Texture::SWIZZLE_TABLE;
using Tegra::Texture::ASTC::EncodingsValues;
using Tegra::Texture::ASTC::ASTC_ENCODINGS_VALUES;
using namespace Tegra::Texture::ASTC;
namespace {
constexpr u32 ASTC_BINDING_INPUT_BUFFER = 0;
constexpr u32 ASTC_BINDING_ENC_BUFFER = 1;
constexpr u32 ASTC_BINDING_6_TO_8_BUFFER = 2;
constexpr u32 ASTC_BINDING_7_TO_8_BUFFER = 3;
constexpr u32 ASTC_BINDING_8_TO_8_BUFFER = 4;
constexpr u32 ASTC_BINDING_BYTE_TO_16_BUFFER = 5;
constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 6;
constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 7;
constexpr u32 ASTC_BINDING_SWIZZLE_BUFFER = 2;
constexpr u32 ASTC_BINDING_OUTPUT_IMAGE = 3;
constexpr size_t ASTC_NUM_BINDINGS = 4;
VkPushConstantRange BuildComputePushConstantRange(std::size_t size) {
return {
@@ -71,7 +68,7 @@ std::array<VkDescriptorSetLayoutBinding, 2> BuildInputOutputDescriptorSetBinding
}};
}
std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
std::array<VkDescriptorSetLayoutBinding, ASTC_NUM_BINDINGS> BuildASTCDescriptorSetBindings() {
return {{
{
.binding = ASTC_BINDING_INPUT_BUFFER,
@@ -87,34 +84,6 @@ std::array<VkDescriptorSetLayoutBinding, 8> BuildASTCDescriptorSetBindings() {
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_6_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_7_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_8_TO_8_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_BYTE_TO_16_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.descriptorCount = 1,
.stageFlags = VK_SHADER_STAGE_COMPUTE_BIT,
.pImmutableSamplers = nullptr,
},
{
.binding = ASTC_BINDING_SWIZZLE_BUFFER,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
@@ -143,7 +112,8 @@ VkDescriptorUpdateTemplateEntryKHR BuildInputOutputDescriptorUpdateTemplate() {
};
}
std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateTemplateEntry() {
std::array<VkDescriptorUpdateTemplateEntryKHR, ASTC_NUM_BINDINGS>
BuildASTCPassDescriptorUpdateTemplateEntry() {
return {{
{
.dstBinding = ASTC_BINDING_INPUT_BUFFER,
@@ -161,38 +131,6 @@ std::array<VkDescriptorUpdateTemplateEntryKHR, 8> BuildASTCPassDescriptorUpdateT
.offset = ASTC_BINDING_ENC_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_6_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_6_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_7_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_7_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_8_TO_8_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_8_TO_8_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_BYTE_TO_16_BUFFER,
.dstArrayElement = 0,
.descriptorCount = 1,
.descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_BUFFER,
.offset = ASTC_BINDING_BYTE_TO_16_BUFFER * sizeof(DescriptorUpdateEntry),
.stride = sizeof(DescriptorUpdateEntry),
},
{
.dstBinding = ASTC_BINDING_SWIZZLE_BUFFER,
.dstArrayElement = 0,
@@ -222,15 +160,6 @@ struct AstcPushConstants {
u32 block_height_mask;
};
struct AstcBufferData {
decltype(SWIZZLE_TABLE) swizzle_table_buffer = SWIZZLE_TABLE;
decltype(EncodingsValues) encoding_values = EncodingsValues;
decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
} constexpr ASTC_BUFFER_DATA;
} // Anonymous namespace
VKComputePass::VKComputePass(const Device& device, VKDescriptorPool& descriptor_pool,
@@ -423,7 +352,7 @@ ASTCDecoderPass::ASTCDecoderPass(const Device& device_, VKScheduler& scheduler_,
ASTCDecoderPass::~ASTCDecoderPass() = default;
void ASTCDecoderPass::MakeDataBuffer() {
constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_BUFFER_DATA) + sizeof(SWIZZLE_TABLE);
constexpr size_t TOTAL_BUFFER_SIZE = sizeof(ASTC_ENCODINGS_VALUES) + sizeof(SWIZZLE_TABLE);
data_buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr,
@@ -437,9 +366,10 @@ void ASTCDecoderPass::MakeDataBuffer() {
data_buffer_commit = memory_allocator.Commit(data_buffer, MemoryUsage::Upload);
const auto staging_ref = staging_buffer_pool.Request(TOTAL_BUFFER_SIZE, MemoryUsage::Upload);
std::memcpy(staging_ref.mapped_span.data(), &ASTC_BUFFER_DATA, sizeof(ASTC_BUFFER_DATA));
std::memcpy(staging_ref.mapped_span.data(), &ASTC_ENCODINGS_VALUES,
sizeof(ASTC_ENCODINGS_VALUES));
// Tack on the swizzle table at the end of the buffer
std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_BUFFER_DATA), &SWIZZLE_TABLE,
std::memcpy(staging_ref.mapped_span.data() + sizeof(ASTC_ENCODINGS_VALUES), &SWIZZLE_TABLE,
sizeof(SWIZZLE_TABLE));
scheduler.Record([src = staging_ref.buffer, offset = staging_ref.offset, dst = *data_buffer,
@@ -509,18 +439,8 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
update_descriptor_queue.Acquire();
update_descriptor_queue.AddBuffer(map.buffer, input_offset,
image.guest_size_bytes - swizzle.buffer_offset);
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, encoding_values),
sizeof(AstcBufferData::encoding_values));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_6_to_8),
sizeof(AstcBufferData::replicate_6_to_8));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_7_to_8),
sizeof(AstcBufferData::replicate_7_to_8));
update_descriptor_queue.AddBuffer(*data_buffer, offsetof(AstcBufferData, replicate_8_to_8),
sizeof(AstcBufferData::replicate_8_to_8));
update_descriptor_queue.AddBuffer(*data_buffer,
offsetof(AstcBufferData, replicate_byte_to_16),
sizeof(AstcBufferData::replicate_byte_to_16));
update_descriptor_queue.AddBuffer(*data_buffer, sizeof(AstcBufferData),
update_descriptor_queue.AddBuffer(*data_buffer, 0, sizeof(ASTC_ENCODINGS_VALUES));
update_descriptor_queue.AddBuffer(*data_buffer, sizeof(ASTC_ENCODINGS_VALUES),
sizeof(SWIZZLE_TABLE));
update_descriptor_queue.AddImage(image.StorageImageView(swizzle.level));
@@ -569,6 +489,7 @@ void ASTCDecoderPass::Assemble(Image& image, const StagingBufferRef& map,
cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT,
VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, 0, image_barrier);
});
scheduler.Finish();
}
} // namespace Vulkan
@@ -497,6 +497,26 @@ void RasterizerVulkan::FlushRegion(VAddr addr, u64 size) {
query_cache.FlushRegion(addr, size);
}
void Vulkan::RasterizerVulkan::InvalidateExceptTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
pipeline_cache.InvalidateRegion(addr, size);
{
std::scoped_lock lock{buffer_cache.mutex};
buffer_cache.WriteMemory(addr, size);
}
query_cache.InvalidateRegion(addr, size);
}
void Vulkan::RasterizerVulkan::InvalidateTextureCache(VAddr addr, u64 size) {
if (addr == 0 || size == 0) {
return;
}
std::scoped_lock lock{texture_cache.mutex};
texture_cache.UnmapMemory(addr, size);
}
bool RasterizerVulkan::MustFlushRegion(VAddr addr, u64 size) {
std::scoped_lock lock{texture_cache.mutex, buffer_cache.mutex};
if (!Settings::IsGPULevelHigh()) {
@@ -67,6 +67,8 @@ public:
void DisableGraphicsUniformBuffer(size_t stage, u32 index) override;
void FlushAll() override;
void FlushRegion(VAddr addr, u64 size) override;
void InvalidateExceptTextureCache(VAddr addr, u64 size) override;
void InvalidateTextureCache(VAddr addr, u64 size) override;
bool MustFlushRegion(VAddr addr, u64 size) override;
void InvalidateRegion(VAddr addr, u64 size) override;
void OnCPUWrite(VAddr addr, u64 size) override;
@@ -406,10 +406,38 @@ private:
binding = DeclareStorageTexels(binding);
binding = DeclareImages(binding);
const auto& subfunctions = ir.GetSubFunctions();
labels.resize(subfunctions.size() + 1);
other_functions.resize(subfunctions.size());
auto it = subfunctions.rbegin();
while (it != subfunctions.rend()) {
context_func = *it;
other_functions[context_func->GetId() - 1] =
OpFunction(t_void, {}, TypeFunction(t_void));
AddLabel();
if (context_func->IsDecompiled()) {
DeclareFlowVariables();
DecompileAST();
} else {
AllocateLabels();
DecompileBranchMode();
}
OpReturn();
OpFunctionEnd();
it++;
}
context_func = ir.GetMainFunction();
const Id main = OpFunction(t_void, {}, TypeFunction(t_void));
AddLabel();
if (ir.IsDecompiled()) {
if (context_func->IsDecompiled()) {
DeclareFlowVariables();
DecompileAST();
} else {
@@ -441,16 +469,18 @@ private:
void DecompileAST();
void DecompileBranchMode() {
const u32 first_address = ir.GetBasicBlocks().begin()->first;
const Id loop_label = OpLabel("loop");
const Id merge_label = OpLabel("merge");
const u32 first_address = context_func->GetBasicBlocks().begin()->first;
const u32 func_id = context_func->GetId();
const std::string func_id_msg = std::to_string(func_id);
const Id loop_label = OpLabel("loop_" + func_id_msg);
const Id merge_label = OpLabel("merge_" + func_id_msg);
const Id dummy_label = OpLabel();
const Id jump_label = OpLabel();
continue_label = OpLabel("continue");
continue_label = OpLabel("continue_" + func_id_msg);
std::vector<Sirit::Literal> literals;
std::vector<Id> branch_labels;
for (const auto& [literal, label] : labels) {
for (const auto& [literal, label] : labels[func_id]) {
literals.push_back(literal);
branch_labels.push_back(label);
}
@@ -462,11 +492,11 @@ private:
std::tie(ssy_flow_stack, ssy_flow_stack_top) = CreateFlowStack();
std::tie(pbk_flow_stack, pbk_flow_stack_top) = CreateFlowStack();
Name(jmp_to, "jmp_to");
Name(ssy_flow_stack, "ssy_flow_stack");
Name(ssy_flow_stack_top, "ssy_flow_stack_top");
Name(pbk_flow_stack, "pbk_flow_stack");
Name(pbk_flow_stack_top, "pbk_flow_stack_top");
Name(jmp_to, "jmp_to_" + func_id_msg);
Name(ssy_flow_stack, "ssy_flow_stack_" + func_id_msg);
Name(ssy_flow_stack_top, "ssy_flow_stack_top_" + func_id_msg);
Name(pbk_flow_stack, "pbk_flow_stack_" + func_id_msg);
Name(pbk_flow_stack_top, "pbk_flow_stack_top_" + func_id_msg);
DefinePrologue();
@@ -484,13 +514,14 @@ private:
AddLabel(default_branch);
OpReturn();
for (const auto& [address, bb] : ir.GetBasicBlocks()) {
AddLabel(labels.at(address));
for (const auto& [address, bb] : context_func->GetBasicBlocks()) {
AddLabel(labels[func_id].at(address));
VisitBasicBlock(bb);
const auto next_it = labels.lower_bound(address + 1);
const Id next_label = next_it != labels.end() ? next_it->second : default_branch;
const auto next_it = labels[func_id].lower_bound(address + 1);
const Id next_label =
next_it != labels[func_id].end() ? next_it->second : default_branch;
OpBranch(next_label);
}
@@ -508,9 +539,10 @@ private:
static constexpr auto INTERNAL_FLAGS_COUNT = static_cast<std::size_t>(InternalFlag::Amount);
void AllocateLabels() {
for (const auto& pair : ir.GetBasicBlocks()) {
const u32 func_id = context_func->GetId();
for (const auto& pair : context_func->GetBasicBlocks()) {
const u32 address = pair.first;
labels.emplace(address, OpLabel(fmt::format("label_0x{:x}", address)));
labels[func_id].emplace(address, OpLabel(fmt::format("label_0x{:x}", address)));
}
}
@@ -589,6 +621,14 @@ private:
DeclareOutputVertex();
}
void SafeKill() {
if (stage != ShaderType::Fragment) {
OpReturn();
return;
}
OpKill();
}
void DeclareFragment() {
if (stage != ShaderType::Fragment) {
return;
@@ -656,7 +696,7 @@ private:
}
void DeclareFlowVariables() {
for (u32 i = 0; i < ir.GetASTNumVariables(); i++) {
for (u32 i = 0; i < context_func->GetASTNumVariables(); i++) {
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
Name(id, fmt::format("flow_var_{}", static_cast<u32>(i)));
flow_variables.emplace(i, AddGlobalVariable(id));
@@ -1333,6 +1373,12 @@ private:
return {};
}
if (const auto func_call = std::get_if<FunctionCallNode>(&*node)) {
const u32 func_id = func_call->GetFuncId();
OpFunctionCall(t_void, other_functions[func_id - 1]);
return {};
}
if (const auto comment = std::get_if<CommentNode>(&*node)) {
if (device.HasDebuggingToolAttached()) {
// We should insert comments with OpString instead of using named variables
@@ -2124,7 +2170,7 @@ private:
OpBranchConditional(condition, true_label, discard_label);
AddLabel(discard_label);
OpKill();
SafeKill();
AddLabel(true_label);
}
@@ -2175,7 +2221,9 @@ private:
}
Expression Exit(Operation operation) {
PreExit();
if (context_func->IsMain()) {
PreExit();
}
inside_branch = true;
if (conditional_branch_set) {
OpReturn();
@@ -2192,12 +2240,12 @@ private:
Expression Discard(Operation operation) {
inside_branch = true;
if (conditional_branch_set) {
OpKill();
SafeKill();
} else {
const Id dummy = OpLabel();
OpBranch(dummy);
AddLabel(dummy);
OpKill();
SafeKill();
AddLabel();
}
return {};
@@ -2276,7 +2324,7 @@ private:
}
Expression Barrier(Operation) {
if (!ir.IsDecompiled()) {
if (!context_func->IsDecompiled()) {
LOG_ERROR(Render_Vulkan, "OpBarrier used by shader is not decompiled");
return {};
}
@@ -2770,6 +2818,8 @@ private:
const Specialization& specialization;
std::unordered_map<u8, VaryingTFB> transform_feedback;
std::shared_ptr<ShaderFunctionIR> context_func;
const Id t_void = Name(TypeVoid(), "void");
const Id t_bool = Name(TypeBool(), "bool");
@@ -2896,7 +2946,8 @@ private:
Id ssy_flow_stack{};
Id pbk_flow_stack{};
Id continue_label{};
std::map<u32, Id> labels;
std::vector<std::map<u32, Id>> labels;
std::vector<Id> other_functions;
bool conditional_branch_set{};
bool inside_branch{};
@@ -3047,9 +3098,11 @@ public:
decomp.OpBranchConditional(condition, then_label, endif_label);
decomp.AddLabel(then_label);
if (ast.kills) {
decomp.OpKill();
decomp.SafeKill();
} else {
decomp.PreExit();
if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.OpReturn();
}
decomp.AddLabel(endif_label);
@@ -3058,9 +3111,11 @@ public:
decomp.OpBranch(next_block);
decomp.AddLabel(next_block);
if (ast.kills) {
decomp.OpKill();
decomp.SafeKill();
} else {
decomp.PreExit();
if (decomp.context_func->IsMain()) {
decomp.PreExit();
}
decomp.OpReturn();
}
decomp.AddLabel(decomp.OpLabel());
@@ -3097,7 +3152,7 @@ private:
};
void SPIRVDecompiler::DecompileAST() {
const u32 num_flow_variables = ir.GetASTNumVariables();
const u32 num_flow_variables = context_func->GetASTNumVariables();
for (u32 i = 0; i < num_flow_variables; i++) {
const Id id = OpVariable(t_prv_bool, spv::StorageClass::Private, v_false);
Name(id, fmt::format("flow_var_{}", i));
@@ -3106,7 +3161,7 @@ void SPIRVDecompiler::DecompileAST() {
DefinePrologue();
const ASTNode program = ir.GetASTProgram();
const ASTNode program = context_func->GetASTProgram();
ASTDecompiler decompiler{*this};
decompiler.Visit(program);
@@ -12,6 +12,7 @@
#include "common/assert.h"
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_staging_buffer_pool.h"
#include "video_core/vulkan_common/vulkan_device.h"
@@ -19,12 +20,15 @@
namespace Vulkan {
namespace {
using namespace Common::Literals;
// Maximum potential alignment of a Vulkan buffer
constexpr VkDeviceSize MAX_ALIGNMENT = 256;
// Maximum size to put elements in the stream buffer
constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8 * 1024 * 1024;
constexpr VkDeviceSize MAX_STREAM_BUFFER_REQUEST_SIZE = 8_MiB;
// Stream buffer size in bytes
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128 * 1024 * 1024;
constexpr VkDeviceSize STREAM_BUFFER_SIZE = 128_MiB;
constexpr VkDeviceSize REGION_SIZE = STREAM_BUFFER_SIZE / StagingBufferPool::NUM_SYNCS;
constexpr VkMemoryPropertyFlags HOST_FLAGS =
@@ -10,6 +10,7 @@
#include "common/alignment.h"
#include "common/assert.h"
#include "common/literals.h"
#include "video_core/renderer_vulkan/vk_scheduler.h"
#include "video_core/renderer_vulkan/vk_stream_buffer.h"
#include "video_core/vulkan_common/vulkan_device.h"
@@ -19,6 +20,8 @@ namespace Vulkan {
namespace {
using namespace Common::Literals;
constexpr VkBufferUsageFlags BUFFER_USAGE =
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT |
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_BUFFER_BIT;
@@ -26,7 +29,7 @@ constexpr VkBufferUsageFlags BUFFER_USAGE =
constexpr u64 WATCHES_INITIAL_RESERVE = 0x4000;
constexpr u64 WATCHES_RESERVE_CHUNK = 0x1000;
constexpr u64 PREFERRED_STREAM_BUFFER_SIZE = 256 * 1024 * 1024;
constexpr u64 PREFERRED_STREAM_BUFFER_SIZE = 256_MiB;
/// Find a memory type with the passed requirements
std::optional<u32> FindMemoryType(const VkPhysicalDeviceMemoryProperties& properties,
+109 -52
View File
@@ -7,6 +7,7 @@
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "common/assert.h"
@@ -26,17 +27,29 @@ using Tegra::Shader::OpCode;
constexpr s32 unassigned_branch = -2;
enum class JumpLabel : u32 {
SSYClass = 0,
PBKClass = 1,
};
struct JumpItem {
JumpLabel type;
u32 address;
bool operator==(const JumpItem& other) const {
return std::tie(type, address) == std::tie(other.type, other.address);
}
};
struct Query {
u32 address{};
std::stack<u32> ssy_stack{};
std::stack<u32> pbk_stack{};
std::stack<JumpItem> stack{};
};
struct BlockStack {
BlockStack() = default;
explicit BlockStack(const Query& q) : ssy_stack{q.ssy_stack}, pbk_stack{q.pbk_stack} {}
std::stack<u32> ssy_stack{};
std::stack<u32> pbk_stack{};
explicit BlockStack(const Query& q) : stack{q.stack} {}
std::stack<JumpItem> stack{};
};
template <typename T, typename... Args>
@@ -65,20 +78,36 @@ struct BlockInfo {
}
};
struct CFGRebuildState {
explicit CFGRebuildState(const ProgramCode& program_code_, u32 start_, Registry& registry_)
: program_code{program_code_}, registry{registry_}, start{start_} {}
struct ProgramControl {
std::unordered_set<u32> found_functions{};
std::list<u32> pending_functions{};
void RegisterFunction(u32 address) {
if (found_functions.count(address) != 0) {
return;
}
found_functions.insert(address);
pending_functions.emplace_back(address);
}
};
struct CFGRebuildState {
explicit CFGRebuildState(ProgramControl& control_, const ProgramCode& program_code_, u32 start_,
u32 base_start_, Registry& registry_)
: control{control_}, program_code{program_code_}, registry{registry_}, start{start_},
base_start{base_start_} {}
ProgramControl& control;
const ProgramCode& program_code;
Registry& registry;
u32 start{};
u32 base_start{};
std::vector<BlockInfo> block_info;
std::list<u32> inspect_queries;
std::list<Query> queries;
std::unordered_map<u32, u32> registered;
std::set<u32> labels;
std::map<u32, u32> ssy_labels;
std::map<u32, u32> pbk_labels;
std::map<u32, JumpItem> jump_labels;
std::unordered_map<u32, BlockStack> stacks;
ASTManager* manager{};
};
@@ -153,7 +182,7 @@ template <typename Result, typename TestCallable, typename PackCallable>
std::optional<Result> TrackInstruction(const CFGRebuildState& state, u32& pos, TestCallable test,
PackCallable pack) {
for (; pos >= state.start; --pos) {
if (IsSchedInstruction(pos, state.start)) {
if (IsSchedInstruction(pos, state.base_start)) {
continue;
}
const Instruction instr = state.program_code[pos];
@@ -262,7 +291,7 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
single_branch.ignore = true;
break;
}
if (IsSchedInstruction(offset, state.start)) {
if (IsSchedInstruction(offset, state.base_start)) {
offset++;
continue;
}
@@ -274,6 +303,7 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
}
switch (opcode->get().GetId()) {
case OpCode::Id::RET:
case OpCode::Id::EXIT: {
const auto pred_index = static_cast<u32>(instr.pred.pred_index);
single_branch.condition.predicate = GetPredicate(pred_index, instr.negate_pred != 0);
@@ -411,13 +441,20 @@ std::pair<ParseResult, ParseInfo> ParseCode(CFGRebuildState& state, u32 address)
case OpCode::Id::SSY: {
const u32 target = offset + instr.bra.GetBranchTarget();
insert_label(state, target);
state.ssy_labels.emplace(offset, target);
JumpItem it = {JumpLabel::SSYClass, target};
state.jump_labels.emplace(offset, it);
break;
}
case OpCode::Id::PBK: {
const u32 target = offset + instr.bra.GetBranchTarget();
insert_label(state, target);
state.pbk_labels.emplace(offset, target);
JumpItem it = {JumpLabel::PBKClass, target};
state.jump_labels.emplace(offset, it);
break;
}
case OpCode::Id::CAL: {
const u32 target = offset + instr.bra.GetBranchTarget();
state.control.RegisterFunction(target);
break;
}
case OpCode::Id::BRX: {
@@ -513,7 +550,7 @@ bool TryInspectAddress(CFGRebuildState& state) {
}
bool TryQuery(CFGRebuildState& state) {
const auto gather_labels = [](std::stack<u32>& cc, std::map<u32, u32>& labels,
const auto gather_labels = [](std::stack<JumpItem>& cc, std::map<u32, JumpItem>& labels,
BlockInfo& block) {
auto gather_start = labels.lower_bound(block.start);
const auto gather_end = labels.upper_bound(block.end);
@@ -522,6 +559,19 @@ bool TryQuery(CFGRebuildState& state) {
++gather_start;
}
};
const auto pop_labels = [](JumpLabel type, SingleBranch* branch, Query& query) -> bool {
while (!query.stack.empty() && query.stack.top().type != type) {
query.stack.pop();
}
if (query.stack.empty()) {
return false;
}
if (branch->address == unassigned_branch) {
branch->address = query.stack.top().address;
}
query.stack.pop();
return true;
};
if (state.queries.empty()) {
return false;
}
@@ -534,8 +584,7 @@ bool TryQuery(CFGRebuildState& state) {
// consumes a label. Schedule new queries accordingly
if (block.visited) {
BlockStack& stack = state.stacks[q.address];
const bool all_okay = (stack.ssy_stack.empty() || q.ssy_stack == stack.ssy_stack) &&
(stack.pbk_stack.empty() || q.pbk_stack == stack.pbk_stack);
const bool all_okay = (stack.stack.empty() || q.stack == stack.stack);
state.queries.pop_front();
return all_okay;
}
@@ -544,8 +593,7 @@ bool TryQuery(CFGRebuildState& state) {
Query q2(q);
state.queries.pop_front();
gather_labels(q2.ssy_stack, state.ssy_labels, block);
gather_labels(q2.pbk_stack, state.pbk_labels, block);
gather_labels(q2.stack, state.jump_labels, block);
if (std::holds_alternative<SingleBranch>(*block.branch)) {
auto* branch = std::get_if<SingleBranch>(block.branch.get());
if (!branch->condition.IsUnconditional()) {
@@ -555,16 +603,10 @@ bool TryQuery(CFGRebuildState& state) {
auto& conditional_query = state.queries.emplace_back(q2);
if (branch->is_sync) {
if (branch->address == unassigned_branch) {
branch->address = conditional_query.ssy_stack.top();
}
conditional_query.ssy_stack.pop();
pop_labels(JumpLabel::SSYClass, branch, conditional_query);
}
if (branch->is_brk) {
if (branch->address == unassigned_branch) {
branch->address = conditional_query.pbk_stack.top();
}
conditional_query.pbk_stack.pop();
pop_labels(JumpLabel::PBKClass, branch, conditional_query);
}
conditional_query.address = branch->address;
return true;
@@ -646,25 +688,23 @@ void DecompileShader(CFGRebuildState& state) {
state.manager->Decompile();
}
} // Anonymous namespace
std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings,
Registry& registry) {
auto result_out = std::make_unique<ShaderCharacteristics>();
ShaderFunction ScanFunction(ProgramControl& control, const ProgramCode& program_code,
u32 start_address, u32 base_start, const CompilerSettings& settings,
Registry& registry) {
ShaderFunction result_out{};
if (settings.depth == CompileDepth::BruteForce) {
result_out->settings.depth = CompileDepth::BruteForce;
result_out.settings.depth = CompileDepth::BruteForce;
return result_out;
}
CFGRebuildState state{program_code, start_address, registry};
CFGRebuildState state{control, program_code, start_address, base_start, registry};
// Inspect Code and generate blocks
state.labels.clear();
state.labels.emplace(start_address);
state.inspect_queries.push_back(state.start);
while (!state.inspect_queries.empty()) {
if (!TryInspectAddress(state)) {
result_out->settings.depth = CompileDepth::BruteForce;
result_out.settings.depth = CompileDepth::BruteForce;
return result_out;
}
}
@@ -675,7 +715,7 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
if (settings.depth != CompileDepth::FlowStack) {
// Decompile Stacks
state.queries.push_back(Query{state.start, {}, {}});
state.queries.push_back(Query{state.start, {}});
decompiled = true;
while (!state.queries.empty()) {
if (!TryQuery(state)) {
@@ -705,19 +745,18 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
state.manager->ShowCurrentState("Of Shader");
state.manager->Clear();
} else {
auto characteristics = std::make_unique<ShaderCharacteristics>();
characteristics->start = start_address;
characteristics->settings.depth = settings.depth;
characteristics->manager = std::move(manager);
characteristics->end = state.block_info.back().end + 1;
return characteristics;
result_out.start = start_address;
result_out.settings.depth = settings.depth;
result_out.manager = std::move(manager);
result_out.end = state.block_info.back().end + 1;
return result_out;
}
}
result_out->start = start_address;
result_out->settings.depth =
result_out.start = start_address;
result_out.settings.depth =
use_flow_stack ? CompileDepth::FlowStack : CompileDepth::NoFlowStack;
result_out->blocks.clear();
result_out.blocks.clear();
for (auto& block : state.block_info) {
ShaderBlock new_block{};
new_block.start = block.start;
@@ -726,20 +765,20 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
if (!new_block.ignore_branch) {
new_block.branch = block.branch;
}
result_out->end = std::max(result_out->end, block.end);
result_out->blocks.push_back(new_block);
result_out.end = std::max(result_out.end, block.end);
result_out.blocks.push_back(new_block);
}
if (!use_flow_stack) {
result_out->labels = std::move(state.labels);
result_out.labels = std::move(state.labels);
return result_out;
}
auto back = result_out->blocks.begin();
auto back = result_out.blocks.begin();
auto next = std::next(back);
while (next != result_out->blocks.end()) {
while (next != result_out.blocks.end()) {
if (!state.labels.contains(next->start) && next->start == back->end + 1) {
back->end = next->end;
next = result_out->blocks.erase(next);
next = result_out.blocks.erase(next);
continue;
}
back = next;
@@ -748,4 +787,22 @@ std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code,
return result_out;
}
} // Anonymous namespace
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings, Registry& registry) {
ProgramControl control{};
auto result_out = std::make_unique<ShaderProgram>();
result_out->main =
ScanFunction(control, program_code, start_address, start_address, settings, registry);
while (!control.pending_functions.empty()) {
u32 address = control.pending_functions.front();
auto fun = ScanFunction(control, program_code, address, start_address, settings, registry);
result_out->subfunctions.emplace(address, std::move(fun));
control.pending_functions.pop_front();
}
return result_out;
}
} // namespace VideoCommon::Shader
+9 -4
View File
@@ -5,6 +5,7 @@
#pragma once
#include <list>
#include <map>
#include <optional>
#include <set>
#include <variant>
@@ -101,7 +102,7 @@ struct ShaderBlock {
}
};
struct ShaderCharacteristics {
struct ShaderFunction {
std::list<ShaderBlock> blocks{};
std::set<u32> labels{};
u32 start{};
@@ -110,8 +111,12 @@ struct ShaderCharacteristics {
CompilerSettings settings{};
};
std::unique_ptr<ShaderCharacteristics> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings,
Registry& registry);
struct ShaderProgram {
ShaderFunction main;
std::map<u32, ShaderFunction> subfunctions;
};
std::unique_ptr<ShaderProgram> ScanFlow(const ProgramCode& program_code, u32 start_address,
const CompilerSettings& settings, Registry& registry);
} // namespace VideoCommon::Shader
+157 -68
View File
@@ -64,9 +64,52 @@ std::optional<u32> TryDeduceSamplerSize(const SamplerEntry& sampler_to_deduce,
} // Anonymous namespace
class ExprDecoder {
public:
explicit ExprDecoder(ShaderIR& ir_) : ir(ir_) {}
void operator()(const ExprAnd& expr) {
Visit(expr.operand1);
Visit(expr.operand2);
}
void operator()(const ExprOr& expr) {
Visit(expr.operand1);
Visit(expr.operand2);
}
void operator()(const ExprNot& expr) {
Visit(expr.operand1);
}
void operator()(const ExprPredicate& expr) {
const auto pred = static_cast<Tegra::Shader::Pred>(expr.predicate);
if (pred != Pred::UnusedIndex && pred != Pred::NeverExecute) {
ir.used_predicates.insert(pred);
}
}
void operator()(const ExprCondCode& expr) {}
void operator()(const ExprVar& expr) {}
void operator()(const ExprBoolean& expr) {}
void operator()(const ExprGprEqual& expr) {
ir.used_registers.insert(expr.gpr);
}
void Visit(const Expr& node) {
return std::visit(*this, *node);
}
private:
ShaderIR& ir;
};
class ASTDecoder {
public:
explicit ASTDecoder(ShaderIR& ir_) : ir(ir_) {}
explicit ASTDecoder(ShaderIR& ir_) : ir(ir_), decoder(ir_) {}
void operator()(ASTProgram& ast) {
ASTNode current = ast.nodes.GetFirst();
@@ -77,6 +120,7 @@ public:
}
void operator()(ASTIfThen& ast) {
decoder.Visit(ast.condition);
ASTNode current = ast.nodes.GetFirst();
while (current) {
Visit(current);
@@ -96,13 +140,18 @@ public:
void operator()(ASTBlockDecoded& ast) {}
void operator()(ASTVarSet& ast) {}
void operator()(ASTVarSet& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTLabel& ast) {}
void operator()(ASTGoto& ast) {}
void operator()(ASTGoto& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTDoWhile& ast) {
decoder.Visit(ast.condition);
ASTNode current = ast.nodes.GetFirst();
while (current) {
Visit(current);
@@ -110,9 +159,13 @@ public:
}
}
void operator()(ASTReturn& ast) {}
void operator()(ASTReturn& ast) {
decoder.Visit(ast.condition);
}
void operator()(ASTBreak& ast) {}
void operator()(ASTBreak& ast) {
decoder.Visit(ast.condition);
}
void Visit(ASTNode& node) {
std::visit(*this, *node->GetInnerData());
@@ -125,77 +178,113 @@ public:
private:
ShaderIR& ir;
ExprDecoder decoder;
};
void ShaderIR::Decode() {
const auto decode_function = ([this](ShaderFunction& shader_info) {
coverage_end = std::max<u32>(0, shader_info.end);
switch (shader_info.settings.depth) {
case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) {
basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
}
break;
}
case CompileDepth::NoFlowStack: {
disable_flow_stack = true;
const auto insert_block = [this](NodeBlock& nodes, u32 label) {
if (label == static_cast<u32>(exit_branch)) {
return;
}
basic_blocks.insert({label, nodes});
};
const auto& blocks = shader_info.blocks;
NodeBlock current_block;
u32 current_label = static_cast<u32>(exit_branch);
for (const auto& block : blocks) {
if (shader_info.labels.contains(block.start)) {
insert_block(current_block, current_label);
current_block.clear();
current_label = block.start;
}
if (!block.ignore_branch) {
DecodeRangeInner(current_block, block.start, block.end);
InsertControlFlow(current_block, block);
} else {
DecodeRangeInner(current_block, block.start, block.end + 1);
}
}
insert_block(current_block, current_label);
break;
}
case CompileDepth::DecompileBackwards:
case CompileDepth::FullDecompile: {
program_manager = std::move(shader_info.manager);
disable_flow_stack = true;
decompiled = true;
ASTDecoder decoder{*this};
ASTNode program = program_manager.GetProgram();
decoder.Visit(program);
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
[[fallthrough]];
case CompileDepth::BruteForce: {
const auto shader_end = static_cast<u32>(program_code.size());
coverage_begin = main_offset;
coverage_end = shader_end;
for (u32 label = main_offset; label < shader_end; ++label) {
basic_blocks.insert({label, DecodeRange(label, label + 1)});
}
break;
}
}
if (settings.depth != shader_info.settings.depth) {
LOG_WARNING(
HW_GPU,
"Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
CompileDepthAsString(settings.depth),
CompileDepthAsString(shader_info.settings.depth));
}
});
const auto gen_function =
([this](ShaderFunction& shader_info, u32 id) -> std::shared_ptr<ShaderFunctionIR> {
std::shared_ptr<ShaderFunctionIR> result;
if (decompiled) {
result = std::make_shared<ShaderFunctionIR>(std::move(program_manager), id,
shader_info.start, shader_info.end);
} else {
result =
std::make_shared<ShaderFunctionIR>(std::move(basic_blocks), disable_flow_stack,
id, shader_info.start, shader_info.end);
}
decompiled = false;
disable_flow_stack = false;
basic_blocks.clear();
program_manager.Clear();
return result;
});
std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header));
decompiled = false;
auto info = ScanFlow(program_code, main_offset, settings, registry);
auto& shader_info = *info;
coverage_begin = shader_info.start;
coverage_end = shader_info.end;
switch (shader_info.settings.depth) {
case CompileDepth::FlowStack: {
for (const auto& block : shader_info.blocks) {
basic_blocks.insert({block.start, DecodeRange(block.start, block.end + 1)});
}
break;
u32 id_start = 1;
for (auto& pair : info->subfunctions) {
func_map.emplace(pair.first, id_start);
id_start++;
}
case CompileDepth::NoFlowStack: {
disable_flow_stack = true;
const auto insert_block = [this](NodeBlock& nodes, u32 label) {
if (label == static_cast<u32>(exit_branch)) {
return;
}
basic_blocks.insert({label, nodes});
};
const auto& blocks = shader_info.blocks;
NodeBlock current_block;
u32 current_label = static_cast<u32>(exit_branch);
for (const auto& block : blocks) {
if (shader_info.labels.contains(block.start)) {
insert_block(current_block, current_label);
current_block.clear();
current_label = block.start;
}
if (!block.ignore_branch) {
DecodeRangeInner(current_block, block.start, block.end);
InsertControlFlow(current_block, block);
} else {
DecodeRangeInner(current_block, block.start, block.end + 1);
}
}
insert_block(current_block, current_label);
break;
}
case CompileDepth::DecompileBackwards:
case CompileDepth::FullDecompile: {
program_manager = std::move(shader_info.manager);
disable_flow_stack = true;
decompiled = true;
ASTDecoder decoder{*this};
ASTNode program = GetASTProgram();
decoder.Visit(program);
break;
}
default:
LOG_CRITICAL(HW_GPU, "Unknown decompilation mode!");
[[fallthrough]];
case CompileDepth::BruteForce: {
const auto shader_end = static_cast<u32>(program_code.size());
coverage_begin = main_offset;
coverage_end = shader_end;
for (u32 label = main_offset; label < shader_end; ++label) {
basic_blocks.insert({label, DecodeRange(label, label + 1)});
}
break;
}
}
if (settings.depth != shader_info.settings.depth) {
LOG_WARNING(
HW_GPU, "Decompiling to this setting \"{}\" failed, downgrading to this setting \"{}\"",
CompileDepthAsString(settings.depth), CompileDepthAsString(shader_info.settings.depth));
coverage_begin = info->main.start;
coverage_end = 0;
decode_function(info->main);
main_function = gen_function(info->main, 0);
subfunctions.resize(info->subfunctions.size());
for (auto& pair : info->subfunctions) {
auto& func_info = pair.second;
decode_function(func_info);
u32 id = func_map[pair.first];
subfunctions[id - 1] = gen_function(func_info, id);
}
}
+11
View File
@@ -33,6 +33,7 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
// With the previous preconditions, this instruction is a no-operation.
break;
}
case OpCode::Id::RET:
case OpCode::Id::EXIT: {
const ConditionCode cc = instr.flow_condition_code;
UNIMPLEMENTED_IF_MSG(cc != ConditionCode::T, "EXIT condition code used: {}", cc);
@@ -312,6 +313,16 @@ u32 ShaderIR::DecodeOther(NodeBlock& bb, u32 pc) {
LOG_DEBUG(HW_GPU, "DEPBAR instruction is stubbed");
break;
}
case OpCode::Id::CAL: {
const u32 target = pc + instr.bra.GetBranchTarget();
const auto it = func_map.find(target);
if (it == func_map.end()) {
UNREACHABLE();
break;
}
bb.push_back(FunctionCall(it->second));
break;
}
default:
UNIMPLEMENTED_MSG("Unhandled instruction: {}", opcode->get().GetName());
}
+14 -1
View File
@@ -267,10 +267,11 @@ class PatchNode;
class SmemNode;
class GmemNode;
class CommentNode;
class FunctionCallNode;
using NodeData = std::variant<OperationNode, ConditionalNode, GprNode, CustomVarNode, ImmediateNode,
InternalFlagNode, PredicateNode, AbufNode, PatchNode, CbufNode,
LmemNode, SmemNode, GmemNode, CommentNode>;
LmemNode, SmemNode, GmemNode, FunctionCallNode, CommentNode>;
using Node = std::shared_ptr<NodeData>;
using Node4 = std::array<Node, 4>;
using NodeBlock = std::vector<Node>;
@@ -494,6 +495,18 @@ private:
std::vector<Node> code; ///< Code to execute
};
class FunctionCallNode final : public AmendNode {
public:
explicit FunctionCallNode(u32 func_id_) : func_id{func_id_} {}
[[nodiscard]] u32 GetFuncId() const {
return func_id;
}
private:
u32 func_id; ///< Id of the function to call
};
/// A general purpose register
class GprNode final {
public:
+5
View File
@@ -19,6 +19,11 @@ Node Comment(std::string text) {
return MakeNode<CommentNode>(std::move(text));
}
/// Creates a function call
Node FunctionCall(u32 func_id) {
return MakeNode<FunctionCallNode>(func_id);
}
Node Immediate(u32 value) {
return MakeNode<ImmediateNode>(value);
}
+3
View File
@@ -27,6 +27,9 @@ Node Conditional(Node condition, std::vector<Node> code);
/// Creates a commentary node
Node Comment(std::string text);
/// Creates a function call
Node FunctionCall(u32 func_id);
/// Creates an u32 immediate
Node Immediate(u32 value);
+70 -25
View File
@@ -26,7 +26,7 @@ namespace VideoCommon::Shader {
struct ShaderBlock;
constexpr u32 MAX_PROGRAM_LENGTH = 0x1000;
constexpr u32 MAX_PROGRAM_LENGTH = 0x2000;
struct ConstBuffer {
constexpr explicit ConstBuffer(u32 max_offset_, bool is_indirect_)
@@ -64,16 +64,68 @@ struct GlobalMemoryUsage {
bool is_written{};
};
class ShaderFunctionIR final {
public:
explicit ShaderFunctionIR(std::map<u32, NodeBlock>&& basic_blocks_, bool disable_flow_stack_,
u32 id_, u32 coverage_begin_, u32 coverage_end_)
: basic_blocks{std::move(basic_blocks_)}, decompiled{false},
disable_flow_stack{disable_flow_stack_}, id{id_}, coverage_begin{coverage_begin_},
coverage_end{coverage_end_} {}
explicit ShaderFunctionIR(ASTManager&& program_manager_, u32 id_, u32 coverage_begin_,
u32 coverage_end_)
: program_manager{std::move(program_manager_)}, decompiled{true}, disable_flow_stack{true},
id{id_}, coverage_begin{coverage_begin_}, coverage_end{coverage_end_} {}
const std::map<u32, NodeBlock>& GetBasicBlocks() const {
return basic_blocks;
}
[[nodiscard]] bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
[[nodiscard]] bool IsDecompiled() const {
return decompiled;
}
const ASTManager& GetASTManager() const {
return program_manager;
}
[[nodiscard]] ASTNode GetASTProgram() const {
return program_manager.GetProgram();
}
[[nodiscard]] u32 GetASTNumVariables() const {
return program_manager.GetVariables();
}
[[nodiscard]] bool IsMain() const {
return id == 0;
}
[[nodiscard]] u32 GetId() const {
return id;
}
private:
std::map<u32, NodeBlock> basic_blocks;
ASTManager program_manager{true, true};
bool decompiled{};
bool disable_flow_stack{};
u32 id{};
u32 coverage_begin{};
u32 coverage_end{};
};
class ShaderIR final {
public:
explicit ShaderIR(const ProgramCode& program_code_, u32 main_offset_,
CompilerSettings settings_, Registry& registry_);
~ShaderIR();
const std::map<u32, NodeBlock>& GetBasicBlocks() const {
return basic_blocks;
}
const std::set<u32>& GetRegisters() const {
return used_registers;
}
@@ -155,26 +207,6 @@ public:
return header;
}
bool IsFlowStackDisabled() const {
return disable_flow_stack;
}
bool IsDecompiled() const {
return decompiled;
}
const ASTManager& GetASTManager() const {
return program_manager;
}
ASTNode GetASTProgram() const {
return program_manager.GetProgram();
}
u32 GetASTNumVariables() const {
return program_manager.GetVariables();
}
u32 ConvertAddressToNvidiaSpace(u32 address) const {
return (address - main_offset) * static_cast<u32>(sizeof(Tegra::Shader::Instruction));
}
@@ -190,7 +222,16 @@ public:
return num_custom_variables;
}
std::shared_ptr<ShaderFunctionIR> GetMainFunction() const {
return main_function;
}
const std::vector<std::shared_ptr<ShaderFunctionIR>>& GetSubFunctions() const {
return subfunctions;
}
private:
friend class ExprDecoder;
friend class ASTDecoder;
struct SamplerInfo {
@@ -453,6 +494,10 @@ private:
std::vector<Node> amend_code;
u32 num_custom_variables{};
std::shared_ptr<ShaderFunctionIR> main_function;
std::vector<std::shared_ptr<ShaderFunctionIR>> subfunctions;
std::unordered_map<u32, u32> func_map;
std::set<u32> used_registers;
std::set<Tegra::Shader::Pred> used_predicates;
std::set<Tegra::Shader::Attribute::Index> used_input_attributes;
+6 -6
View File
@@ -19,9 +19,8 @@
#include <boost/container/small_vector.hpp>
#include "common/alignment.h"
#include "common/common_funcs.h"
#include "common/common_sizes.h"
#include "common/common_types.h"
#include "common/literals.h"
#include "common/logging/log.h"
#include "common/settings.h"
#include "video_core/compatible_formats.h"
@@ -59,6 +58,7 @@ using VideoCore::Surface::PixelFormat;
using VideoCore::Surface::PixelFormatFromDepthFormat;
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
using VideoCore::Surface::SurfaceType;
using namespace Common::Literals;
template <class P>
class TextureCache {
@@ -79,8 +79,8 @@ class TextureCache {
/// Sampler ID for bugged sampler ids
static constexpr SamplerId NULL_SAMPLER_ID{0};
static constexpr u64 DEFAULT_EXPECTED_MEMORY = Common::Size_1_GB;
static constexpr u64 DEFAULT_CRITICAL_MEMORY = Common::Size_2_GB;
static constexpr u64 DEFAULT_EXPECTED_MEMORY = 1_GiB;
static constexpr u64 DEFAULT_CRITICAL_MEMORY = 2_GiB;
using Runtime = typename P::Runtime;
using Image = typename P::Image;
@@ -400,8 +400,8 @@ TextureCache<P>::TextureCache(Runtime& runtime_, VideoCore::RasterizerInterface&
minimum_memory = 0;
} else {
// on OGL we can be more conservatives as the driver takes care.
expected_memory = DEFAULT_EXPECTED_MEMORY + Common::Size_512_MB;
critical_memory = DEFAULT_CRITICAL_MEMORY + Common::Size_1_GB;
expected_memory = DEFAULT_EXPECTED_MEMORY + 512_MiB;
critical_memory = DEFAULT_CRITICAL_MEMORY + 1_GiB;
minimum_memory = expected_memory;
}
}
+6 -4
View File
@@ -269,7 +269,7 @@ static void DecodeQuintBlock(InputBitStream& bits, IntegerEncodedVector& result,
static void DecodeIntegerSequence(IntegerEncodedVector& result, InputBitStream& bits, u32 maxRange,
u32 nValues) {
// Determine encoding parameters
IntegerEncodedValue val = EncodingsValues[maxRange];
IntegerEncodedValue val = ASTC_ENCODINGS_VALUES[maxRange];
// Start decoding
u32 nValsDecoded = 0;
@@ -310,7 +310,7 @@ struct TexelWeightParams {
nIdxs *= 2;
}
return EncodingsValues[m_MaxWeight].GetBitLength(nIdxs);
return ASTC_ENCODINGS_VALUES[m_MaxWeight].GetBitLength(nIdxs);
}
u32 GetNumWeightValues() const {
@@ -551,6 +551,8 @@ static void FillError(std::span<u32> outBuf, u32 blockWidth, u32 blockHeight) {
}
}
}
static constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
static constexpr u32 ReplicateByteTo16(std::size_t value) {
return REPLICATE_BYTE_TO_16_TABLE[value];
}
@@ -753,12 +755,12 @@ static void DecodeColorValues(u32* out, std::span<u8> data, const u32* modes, co
// figure out the max value for each of them...
u32 range = 256;
while (--range > 0) {
IntegerEncodedValue val = EncodingsValues[range];
IntegerEncodedValue val = ASTC_ENCODINGS_VALUES[range];
u32 bitLength = val.GetBitLength(nValues);
if (bitLength <= nBitsForColorData) {
// Find the smallest possible range that matches the given encoding
while (--range > 0) {
IntegerEncodedValue newval = EncodingsValues[range];
IntegerEncodedValue newval = ASTC_ENCODINGS_VALUES[range];
if (!newval.MatchesEncoding(val)) {
break;
}
+1 -10
View File
@@ -77,7 +77,7 @@ constexpr std::array<IntegerEncodedValue, 256> MakeEncodedValues() {
return encodings;
}
constexpr std::array<IntegerEncodedValue, 256> EncodingsValues = MakeEncodedValues();
constexpr std::array<IntegerEncodedValue, 256> ASTC_ENCODINGS_VALUES = MakeEncodedValues();
// Replicates low num_bits such that [(to_bit - 1):(to_bit - 1 - from_bit)]
// is the same as [(num_bits - 1):0] and repeats all the way down.
@@ -116,19 +116,10 @@ constexpr auto MakeReplicateTable() {
return table;
}
constexpr auto REPLICATE_BYTE_TO_16_TABLE = MakeReplicateTable<u32, 8, 16>();
constexpr auto REPLICATE_6_BIT_TO_8_TABLE = MakeReplicateTable<u32, 6, 8>();
constexpr auto REPLICATE_7_BIT_TO_8_TABLE = MakeReplicateTable<u32, 7, 8>();
constexpr auto REPLICATE_8_BIT_TO_8_TABLE = MakeReplicateTable<u32, 8, 8>();
struct AstcBufferData {
decltype(EncodingsValues) encoding_values = EncodingsValues;
decltype(REPLICATE_6_BIT_TO_8_TABLE) replicate_6_to_8 = REPLICATE_6_BIT_TO_8_TABLE;
decltype(REPLICATE_7_BIT_TO_8_TABLE) replicate_7_to_8 = REPLICATE_7_BIT_TO_8_TABLE;
decltype(REPLICATE_8_BIT_TO_8_TABLE) replicate_8_to_8 = REPLICATE_8_BIT_TO_8_TABLE;
decltype(REPLICATE_BYTE_TO_16_TABLE) replicate_byte_to_16 = REPLICATE_BYTE_TO_16_TABLE;
} constexpr ASTC_BUFFER_DATA;
void Decompress(std::span<const uint8_t> data, uint32_t width, uint32_t height, uint32_t depth,
uint32_t block_width, uint32_t block_height, std::span<uint8_t> output);
@@ -821,9 +821,9 @@ void Device::CollectTelemetryParameters() {
void Device::CollectPhysicalMemoryInfo() {
const auto mem_properties = physical.GetMemoryProperties();
const std::size_t num_properties = mem_properties.memoryHeapCount;
const size_t num_properties = mem_properties.memoryHeapCount;
device_access_memory = 0;
for (std::size_t element = 0; element < num_properties; element++) {
for (size_t element = 0; element < num_properties; ++element) {
if ((mem_properties.memoryHeaps[element].flags & VK_MEMORY_HEAP_DEVICE_LOCAL_BIT) != 0) {
device_access_memory += mem_properties.memoryHeaps[element].size;
}
+16 -17
View File
@@ -264,21 +264,22 @@ private:
bool IsFormatSupported(VkFormat wanted_format, VkFormatFeatureFlags wanted_usage,
FormatType format_type) const;
VkInstance instance; ///< Vulkan instance.
vk::DeviceDispatch dld; ///< Device function pointers.
vk::PhysicalDevice physical; ///< Physical device.
VkPhysicalDeviceProperties properties; ///< Device properties.
vk::Device logical; ///< Logical device.
vk::Queue graphics_queue; ///< Main graphics queue.
vk::Queue present_queue; ///< Main present queue.
u32 instance_version{}; ///< Vulkan onstance version.
u32 graphics_family{}; ///< Main graphics queue family index.
u32 present_family{}; ///< Main present queue family index.
VkDriverIdKHR driver_id{}; ///< Driver ID.
VkShaderStageFlags guest_warp_stages{}; ///< Stages where the guest warp size can be forced.ed
bool is_optimal_astc_supported{}; ///< Support for native ASTC.
bool is_float16_supported{}; ///< Support for float16 arithmetics.
bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
VkInstance instance; ///< Vulkan instance.
vk::DeviceDispatch dld; ///< Device function pointers.
vk::PhysicalDevice physical; ///< Physical device.
VkPhysicalDeviceProperties properties; ///< Device properties.
vk::Device logical; ///< Logical device.
vk::Queue graphics_queue; ///< Main graphics queue.
vk::Queue present_queue; ///< Main present queue.
u32 instance_version{}; ///< Vulkan onstance version.
u32 graphics_family{}; ///< Main graphics queue family index.
u32 present_family{}; ///< Main present queue family index.
VkDriverIdKHR driver_id{}; ///< Driver ID.
VkShaderStageFlags guest_warp_stages{}; ///< Stages where the guest warp size can be forced.
u64 device_access_memory{}; ///< Total size of device local memory in bytes.
bool is_optimal_astc_supported{}; ///< Support for native ASTC.
bool is_float16_supported{}; ///< Support for float16 arithmetics.
bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest.
bool is_formatless_image_load_supported{}; ///< Support for shader image read without format.
bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images.
bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil.
@@ -309,8 +310,6 @@ private:
/// Nsight Aftermath GPU crash tracker
std::unique_ptr<NsightAftermathTracker> nsight_aftermath_tracker;
u64 device_access_memory;
};
} // namespace Vulkan