Compare commits
4 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2d2ef05d8c | ||
|
|
8f183a47dd | ||
|
|
97d425c304 | ||
|
|
e20db909ee |
@@ -143,7 +143,7 @@ struct AuxInfo {
|
||||
std::array<u8, 24> output_mix_buffers;
|
||||
u32_le mix_buffer_count;
|
||||
u32_le sample_rate; // Stored in the aux buffer currently
|
||||
u32_le sample_count;
|
||||
u32_le sampe_count;
|
||||
u64_le send_buffer_info;
|
||||
u64_le send_buffer_base;
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include "audio_core/stream.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/core_timing_util.h"
|
||||
#include "core/settings.h"
|
||||
@@ -103,7 +104,10 @@ void Stream::PlayNextBuffer() {
|
||||
CoreTiming::ScheduleEventThreadsafe(GetBufferReleaseCycles(*active_buffer), release_event, {});
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(AudioOutput, "Audio", "ReleaseActiveBuffer", MP_RGB(100, 100, 255));
|
||||
|
||||
void Stream::ReleaseActiveBuffer() {
|
||||
MICROPROFILE_SCOPE(AudioOutput);
|
||||
ASSERT(active_buffer);
|
||||
released_buffers.push(std::move(active_buffer));
|
||||
release_callback();
|
||||
|
||||
@@ -12,8 +12,7 @@
|
||||
#include <thread>
|
||||
#include <vector>
|
||||
#ifdef _WIN32
|
||||
#include <share.h> // For _SH_DENYWR
|
||||
#include <windows.h> // For OutputDebugStringA
|
||||
#include <share.h> // For _SH_DENYWR
|
||||
#else
|
||||
#define _SH_DENYWR 0
|
||||
#endif
|
||||
@@ -140,18 +139,12 @@ void FileBackend::Write(const Entry& entry) {
|
||||
if (!file.IsOpen() || bytes_written > MAX_BYTES_WRITTEN) {
|
||||
return;
|
||||
}
|
||||
bytes_written += file.WriteString(FormatLogMessage(entry).append(1, '\n'));
|
||||
bytes_written += file.WriteString(FormatLogMessage(entry) + '\n');
|
||||
if (entry.log_level >= Level::Error) {
|
||||
file.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
void DebuggerBackend::Write(const Entry& entry) {
|
||||
#ifdef _WIN32
|
||||
::OutputDebugStringA(FormatLogMessage(entry).append(1, '\n').c_str());
|
||||
#endif
|
||||
}
|
||||
|
||||
/// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
|
||||
#define ALL_LOG_CLASSES() \
|
||||
CLS(Log) \
|
||||
|
||||
@@ -103,20 +103,6 @@ private:
|
||||
std::size_t bytes_written;
|
||||
};
|
||||
|
||||
/**
|
||||
* Backend that writes to Visual Studio's output window
|
||||
*/
|
||||
class DebuggerBackend : public Backend {
|
||||
public:
|
||||
static const char* Name() {
|
||||
return "debugger";
|
||||
}
|
||||
const char* GetName() const override {
|
||||
return Name();
|
||||
}
|
||||
void Write(const Entry& entry) override;
|
||||
};
|
||||
|
||||
void AddBackend(std::unique_ptr<Backend> backend);
|
||||
|
||||
void RemoveBackend(std::string_view backend_name);
|
||||
|
||||
@@ -153,7 +153,6 @@ struct VisitorInterface : NonCopyable {
|
||||
|
||||
/// Completion method, called once all fields have been visited
|
||||
virtual void Complete() = 0;
|
||||
virtual bool SubmitTestcase() = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -179,9 +178,6 @@ struct NullVisitor : public VisitorInterface {
|
||||
void Visit(const Field<std::chrono::microseconds>& /*field*/) override {}
|
||||
|
||||
void Complete() override {}
|
||||
bool SubmitTestcase() override {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// Appends build-specific information to the given FieldCollection,
|
||||
|
||||
@@ -176,7 +176,7 @@ Loader::ResultStatus XCI::AddNCAFromPartition(XCIPartition part) {
|
||||
for (const VirtualFile& file : partitions[static_cast<std::size_t>(part)]->GetFiles()) {
|
||||
if (file->GetExtension() != "nca")
|
||||
continue;
|
||||
auto nca = std::make_shared<NCA>(file);
|
||||
auto nca = std::make_shared<NCA>(file, nullptr, 0, keys);
|
||||
// TODO(DarkLordZach): Add proper Rev1+ Support
|
||||
if (nca->IsUpdate())
|
||||
continue;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace Loader {
|
||||
@@ -107,5 +108,7 @@ private:
|
||||
std::shared_ptr<NSP> secure_partition;
|
||||
std::shared_ptr<NCA> program;
|
||||
std::vector<std::shared_ptr<NCA>> ncas;
|
||||
|
||||
Core::Crypto::KeyManager keys;
|
||||
};
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -101,8 +101,9 @@ static bool IsValidNCA(const NCAHeader& header) {
|
||||
return header.magic == Common::MakeMagic('N', 'C', 'A', '3');
|
||||
}
|
||||
|
||||
NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset)
|
||||
: file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)) {
|
||||
NCA::NCA(VirtualFile file_, VirtualFile bktr_base_romfs_, u64 bktr_base_ivfc_offset,
|
||||
Core::Crypto::KeyManager keys_)
|
||||
: file(std::move(file_)), bktr_base_romfs(std::move(bktr_base_romfs_)), keys(std::move(keys_)) {
|
||||
if (file == nullptr) {
|
||||
status = Loader::ResultStatus::ErrorNullFile;
|
||||
return;
|
||||
|
||||
@@ -79,7 +79,8 @@ inline bool IsDirectoryExeFS(const std::shared_ptr<VfsDirectory>& pfs) {
|
||||
class NCA : public ReadOnlyVfsDirectory {
|
||||
public:
|
||||
explicit NCA(VirtualFile file, VirtualFile bktr_base_romfs = nullptr,
|
||||
u64 bktr_base_ivfc_offset = 0);
|
||||
u64 bktr_base_ivfc_offset = 0,
|
||||
Core::Crypto::KeyManager keys = Core::Crypto::KeyManager());
|
||||
~NCA() override;
|
||||
|
||||
Loader::ResultStatus GetStatus() const;
|
||||
|
||||
@@ -66,10 +66,4 @@ std::string NACP::GetVersionString() const {
|
||||
return Common::StringFromFixedZeroTerminatedBuffer(raw->version_string.data(),
|
||||
raw->version_string.size());
|
||||
}
|
||||
|
||||
std::vector<u8> NACP::GetRawBytes() const {
|
||||
std::vector<u8> out(sizeof(RawNACP));
|
||||
std::memcpy(out.data(), raw.get(), sizeof(RawNACP));
|
||||
return out;
|
||||
}
|
||||
} // namespace FileSys
|
||||
|
||||
@@ -81,7 +81,6 @@ public:
|
||||
u64 GetTitleId() const;
|
||||
u64 GetDLCBaseTitleId() const;
|
||||
std::string GetVersionString() const;
|
||||
std::vector<u8> GetRawBytes() const;
|
||||
|
||||
private:
|
||||
std::unique_ptr<RawNACP> raw;
|
||||
|
||||
@@ -106,9 +106,12 @@ static ContentRecordType GetCRTypeFromNCAType(NCAContentType type) {
|
||||
|
||||
VirtualFile RegisteredCache::OpenFileOrDirectoryConcat(const VirtualDir& dir,
|
||||
std::string_view path) const {
|
||||
if (dir->GetFileRelative(path) != nullptr)
|
||||
return dir->GetFileRelative(path);
|
||||
if (dir->GetDirectoryRelative(path) != nullptr) {
|
||||
const auto file = dir->GetFileRelative(path);
|
||||
if (file != nullptr)
|
||||
return file;
|
||||
|
||||
const auto nca_dir = dir->GetDirectoryRelative(path);
|
||||
if (nca_dir != nullptr) {
|
||||
const auto nca_dir = dir->GetDirectoryRelative(path);
|
||||
VirtualFile file = nullptr;
|
||||
|
||||
@@ -225,7 +228,7 @@ void RegisteredCache::ProcessFiles(const std::vector<NcaID>& ids) {
|
||||
|
||||
if (file == nullptr)
|
||||
continue;
|
||||
const auto nca = std::make_shared<NCA>(parser(file, id));
|
||||
const auto nca = std::make_shared<NCA>(parser(file, id), nullptr, 0, keys);
|
||||
if (nca->GetStatus() != Loader::ResultStatus::Success ||
|
||||
nca->GetType() != NCAContentType::Meta) {
|
||||
continue;
|
||||
@@ -315,7 +318,7 @@ std::unique_ptr<NCA> RegisteredCache::GetEntry(u64 title_id, ContentRecordType t
|
||||
const auto raw = GetEntryRaw(title_id, type);
|
||||
if (raw == nullptr)
|
||||
return nullptr;
|
||||
return std::make_unique<NCA>(raw);
|
||||
return std::make_unique<NCA>(raw, nullptr, 0, keys);
|
||||
}
|
||||
|
||||
std::unique_ptr<NCA> RegisteredCache::GetEntry(RegisteredCacheEntry entry) const {
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <vector>
|
||||
#include <boost/container/flat_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
@@ -133,6 +134,8 @@ private:
|
||||
|
||||
VirtualDir dir;
|
||||
RegisteredCacheParsingFunction parser;
|
||||
Core::Crypto::KeyManager keys;
|
||||
|
||||
// maps tid -> NcaID of meta
|
||||
boost::container::flat_map<u64, NcaID> meta_id;
|
||||
// maps tid -> meta
|
||||
|
||||
@@ -83,24 +83,6 @@ ResultVal<VirtualDir> SaveDataFactory::Open(SaveDataSpaceId space, SaveDataDescr
|
||||
return MakeResult<VirtualDir>(std::move(out));
|
||||
}
|
||||
|
||||
VirtualDir SaveDataFactory::GetSaveDataSpaceDirectory(SaveDataSpaceId space) const {
|
||||
return dir->GetDirectoryRelative(GetSaveDataSpaceIdPath(space));
|
||||
}
|
||||
|
||||
std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
|
||||
switch (space) {
|
||||
case SaveDataSpaceId::NandSystem:
|
||||
return "/system/";
|
||||
case SaveDataSpaceId::NandUser:
|
||||
return "/user/";
|
||||
case SaveDataSpaceId::TemporaryStorage:
|
||||
return "/temp/";
|
||||
default:
|
||||
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
|
||||
return "/unrecognized/"; ///< To prevent corruption when ignoring asserts.
|
||||
}
|
||||
}
|
||||
|
||||
std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
||||
u128 user_id, u64 save_id) {
|
||||
// According to switchbrew, if a save is of type SaveData and the title id field is 0, it should
|
||||
@@ -108,7 +90,21 @@ std::string SaveDataFactory::GetFullPath(SaveDataSpaceId space, SaveDataType typ
|
||||
if (type == SaveDataType::SaveData && title_id == 0)
|
||||
title_id = Core::CurrentProcess()->GetTitleID();
|
||||
|
||||
std::string out = GetSaveDataSpaceIdPath(space);
|
||||
std::string out;
|
||||
|
||||
switch (space) {
|
||||
case SaveDataSpaceId::NandSystem:
|
||||
out = "/system/";
|
||||
break;
|
||||
case SaveDataSpaceId::NandUser:
|
||||
out = "/user/";
|
||||
break;
|
||||
case SaveDataSpaceId::TemporaryStorage:
|
||||
out = "/temp/";
|
||||
break;
|
||||
default:
|
||||
ASSERT_MSG(false, "Unrecognized SaveDataSpaceId: {:02X}", static_cast<u8>(space));
|
||||
}
|
||||
|
||||
switch (type) {
|
||||
case SaveDataType::SystemSaveData:
|
||||
|
||||
@@ -52,9 +52,6 @@ public:
|
||||
|
||||
ResultVal<VirtualDir> Open(SaveDataSpaceId space, SaveDataDescriptor meta);
|
||||
|
||||
VirtualDir GetSaveDataSpaceDirectory(SaveDataSpaceId space) const;
|
||||
|
||||
static std::string GetSaveDataSpaceIdPath(SaveDataSpaceId space);
|
||||
static std::string GetFullPath(SaveDataSpaceId space, SaveDataType type, u64 title_id,
|
||||
u128 user_id, u64 save_id);
|
||||
|
||||
|
||||
@@ -252,7 +252,7 @@ void NSP::ReadNCAs(const std::vector<VirtualFile>& files) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto next_nca = std::make_shared<NCA>(next_file);
|
||||
auto next_nca = std::make_shared<NCA>(next_file, nullptr, 0, keys);
|
||||
if (next_nca->GetType() == NCAContentType::Program)
|
||||
program_status[cnmt.GetTitleID()] = next_nca->GetStatus();
|
||||
if (next_nca->GetStatus() == Loader::ResultStatus::Success ||
|
||||
|
||||
@@ -70,6 +70,8 @@ private:
|
||||
std::map<u64, std::map<ContentRecordType, std::shared_ptr<NCA>>> ncas;
|
||||
std::vector<VirtualFile> ticket_files;
|
||||
|
||||
Core::Crypto::KeyManager keys;
|
||||
|
||||
VirtualFile romfs;
|
||||
VirtualDir exefs;
|
||||
};
|
||||
|
||||
@@ -5,9 +5,11 @@
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/program_metadata.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
@@ -15,7 +17,6 @@
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
@@ -34,11 +35,6 @@ SharedPtr<Process> Process::Create(KernelCore& kernel, std::string&& name) {
|
||||
process->process_id = kernel.CreateNewProcessID();
|
||||
process->svc_access_mask.set();
|
||||
|
||||
std::mt19937 rng(Settings::values.rng_seed.value_or(0));
|
||||
std::uniform_int_distribution<u64> distribution;
|
||||
std::generate(process->random_entropy.begin(), process->random_entropy.end(),
|
||||
[&] { return distribution(rng); });
|
||||
|
||||
kernel.AppendNewProcess(process);
|
||||
return process;
|
||||
}
|
||||
@@ -245,15 +241,83 @@ void Process::LoadModule(CodeSet module_, VAddr base_addr) {
|
||||
}
|
||||
|
||||
ResultVal<VAddr> Process::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
|
||||
return vm_manager.HeapAllocate(target, size, perms);
|
||||
if (target < vm_manager.GetHeapRegionBaseAddress() ||
|
||||
target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (heap_memory == nullptr) {
|
||||
// Initialize heap
|
||||
heap_memory = std::make_shared<std::vector<u8>>();
|
||||
heap_start = heap_end = target;
|
||||
} else {
|
||||
vm_manager.UnmapRange(heap_start, heap_end - heap_start);
|
||||
}
|
||||
|
||||
// If necessary, expand backing vector to cover new heap extents.
|
||||
if (target < heap_start) {
|
||||
heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
|
||||
heap_start = target;
|
||||
vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
|
||||
}
|
||||
if (target + size > heap_end) {
|
||||
heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
|
||||
heap_end = target + size;
|
||||
vm_manager.RefreshMemoryBlockMappings(heap_memory.get());
|
||||
}
|
||||
ASSERT(heap_end - heap_start == heap_memory->size());
|
||||
|
||||
CASCADE_RESULT(auto vma, vm_manager.MapMemoryBlock(target, heap_memory, target - heap_start,
|
||||
size, MemoryState::Heap));
|
||||
vm_manager.Reprotect(vma, perms);
|
||||
|
||||
heap_used = size;
|
||||
|
||||
return MakeResult<VAddr>(heap_end - size);
|
||||
}
|
||||
|
||||
ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||
return vm_manager.HeapFree(target, size);
|
||||
if (target < vm_manager.GetHeapRegionBaseAddress() ||
|
||||
target + size > vm_manager.GetHeapRegionEndAddress() || target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||
if (result.IsError())
|
||||
return result;
|
||||
|
||||
heap_used -= size;
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode Process::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
return vm_manager.MirrorMemory(dst_addr, src_addr, size);
|
||||
auto vma = vm_manager.FindVMA(src_addr);
|
||||
|
||||
ASSERT_MSG(vma != vm_manager.vma_map.end(), "Invalid memory address");
|
||||
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
|
||||
|
||||
// The returned VMA might be a bigger one encompassing the desired address.
|
||||
auto vma_offset = src_addr - vma->first;
|
||||
ASSERT_MSG(vma_offset + size <= vma->second.size,
|
||||
"Shared memory exceeds bounds of mapped block");
|
||||
|
||||
const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
|
||||
std::size_t backing_block_offset = vma->second.offset + vma_offset;
|
||||
|
||||
CASCADE_RESULT(auto new_vma,
|
||||
vm_manager.MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
|
||||
MemoryState::Mapped));
|
||||
// Protect mirror with permissions from old region
|
||||
vm_manager.Reprotect(new_vma, vma->second.permissions);
|
||||
// Remove permissions from old region
|
||||
vm_manager.Reprotect(vma, VMAPermission::None);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode Process::UnmapMemory(VAddr dst_addr, VAddr /*src_addr*/, u64 size) {
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <bitset>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <random>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
@@ -120,8 +119,6 @@ struct CodeSet final {
|
||||
|
||||
class Process final : public Object {
|
||||
public:
|
||||
static constexpr std::size_t RANDOM_ENTROPY_SIZE = 4;
|
||||
|
||||
static SharedPtr<Process> Create(KernelCore& kernel, std::string&& name);
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
@@ -215,11 +212,6 @@ public:
|
||||
total_process_running_time_ticks += ticks;
|
||||
}
|
||||
|
||||
/// Gets 8 bytes of random data for svcGetInfo RandomEntropy
|
||||
u64 GetRandomEntropy(std::size_t index) const {
|
||||
return random_entropy.at(index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads process-specifics configuration info with metadata provided
|
||||
* by an executable.
|
||||
@@ -300,6 +292,17 @@ private:
|
||||
u32 allowed_thread_priority_mask = 0xFFFFFFFF;
|
||||
u32 is_virtual_address_memory_enabled = 0;
|
||||
|
||||
// Memory used to back the allocations in the regular heap. A single vector is used to cover
|
||||
// the entire virtual address space extents that bound the allocations, including any holes.
|
||||
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
||||
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
|
||||
std::shared_ptr<std::vector<u8>> heap_memory;
|
||||
|
||||
// The left/right bounds of the address space covered by heap_memory.
|
||||
VAddr heap_start = 0;
|
||||
VAddr heap_end = 0;
|
||||
u64 heap_used = 0;
|
||||
|
||||
/// The Thread Local Storage area is allocated as processes create threads,
|
||||
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
|
||||
/// holds the TLS for a specific thread. This vector contains which parts are in use for each
|
||||
@@ -318,9 +321,6 @@ private:
|
||||
/// Per-process handle table for storing created object handles in.
|
||||
HandleTable handle_table;
|
||||
|
||||
/// Random values for svcGetInfo RandomEntropy
|
||||
std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy;
|
||||
|
||||
std::string name;
|
||||
};
|
||||
|
||||
|
||||
@@ -34,7 +34,6 @@
|
||||
#include "core/hle/lock.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Kernel {
|
||||
namespace {
|
||||
@@ -396,42 +395,16 @@ struct BreakReason {
|
||||
/// Break program execution
|
||||
static void Break(u32 reason, u64 info1, u64 info2) {
|
||||
BreakReason break_reason{reason};
|
||||
bool has_dumped_buffer{};
|
||||
|
||||
const auto handle_debug_buffer = [&](VAddr addr, u64 sz) {
|
||||
if (sz == 0 || addr == 0 || has_dumped_buffer) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This typically is an error code so we're going to assume this is the case
|
||||
if (sz == sizeof(u32)) {
|
||||
LOG_CRITICAL(Debug_Emulated, "debug_buffer_err_code={:X}", Memory::Read32(addr));
|
||||
} else {
|
||||
// We don't know what's in here so we'll hexdump it
|
||||
std::vector<u8> debug_buffer(sz);
|
||||
Memory::ReadBlock(addr, debug_buffer.data(), sz);
|
||||
std::string hexdump;
|
||||
for (std::size_t i = 0; i < debug_buffer.size(); i++) {
|
||||
hexdump += fmt::format("{:02X} ", debug_buffer[i]);
|
||||
if (i != 0 && i % 16 == 0) {
|
||||
hexdump += '\n';
|
||||
}
|
||||
}
|
||||
LOG_CRITICAL(Debug_Emulated, "debug_buffer=\n{}", hexdump);
|
||||
}
|
||||
has_dumped_buffer = true;
|
||||
};
|
||||
switch (break_reason.break_type) {
|
||||
case BreakType::Panic:
|
||||
LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}",
|
||||
info1, info2);
|
||||
handle_debug_buffer(info1, info2);
|
||||
break;
|
||||
case BreakType::AssertionFailed:
|
||||
LOG_CRITICAL(Debug_Emulated,
|
||||
"Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
|
||||
info1, info2);
|
||||
handle_debug_buffer(info1, info2);
|
||||
break;
|
||||
case BreakType::PreNROLoad:
|
||||
LOG_WARNING(
|
||||
@@ -460,7 +433,6 @@ static void Break(u32 reason, u64 info1, u64 info2) {
|
||||
Debug_Emulated,
|
||||
"Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}",
|
||||
static_cast<u32>(break_reason.break_type.Value()), info1, info2);
|
||||
handle_debug_buffer(info1, info2);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -469,7 +441,6 @@ static void Break(u32 reason, u64 info1, u64 info2) {
|
||||
Debug_Emulated,
|
||||
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
|
||||
reason, info1, info2);
|
||||
handle_debug_buffer(info1, info2);
|
||||
ASSERT(false);
|
||||
|
||||
Core::CurrentProcess()->PrepareForTermination();
|
||||
@@ -559,16 +530,7 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id)
|
||||
*result = 0;
|
||||
break;
|
||||
case GetInfoType::RandomEntropy:
|
||||
if (handle != 0) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) {
|
||||
return ERR_INVALID_COMBINATION_KERNEL;
|
||||
}
|
||||
|
||||
*result = current_process->GetRandomEntropy(info_sub_id);
|
||||
return RESULT_SUCCESS;
|
||||
*result = 0;
|
||||
break;
|
||||
case GetInfoType::ASLRRegionBaseAddr:
|
||||
*result = vm_manager.GetASLRRegionBaseAddress();
|
||||
|
||||
@@ -243,85 +243,6 @@ ResultCode VMManager::ReprotectRange(VAddr target, u64 size, VMAPermission new_p
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultVal<VAddr> VMManager::HeapAllocate(VAddr target, u64 size, VMAPermission perms) {
|
||||
if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
|
||||
target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (heap_memory == nullptr) {
|
||||
// Initialize heap
|
||||
heap_memory = std::make_shared<std::vector<u8>>();
|
||||
heap_start = heap_end = target;
|
||||
} else {
|
||||
UnmapRange(heap_start, heap_end - heap_start);
|
||||
}
|
||||
|
||||
// If necessary, expand backing vector to cover new heap extents.
|
||||
if (target < heap_start) {
|
||||
heap_memory->insert(begin(*heap_memory), heap_start - target, 0);
|
||||
heap_start = target;
|
||||
RefreshMemoryBlockMappings(heap_memory.get());
|
||||
}
|
||||
if (target + size > heap_end) {
|
||||
heap_memory->insert(end(*heap_memory), (target + size) - heap_end, 0);
|
||||
heap_end = target + size;
|
||||
RefreshMemoryBlockMappings(heap_memory.get());
|
||||
}
|
||||
ASSERT(heap_end - heap_start == heap_memory->size());
|
||||
|
||||
CASCADE_RESULT(auto vma, MapMemoryBlock(target, heap_memory, target - heap_start, size,
|
||||
MemoryState::Heap));
|
||||
Reprotect(vma, perms);
|
||||
|
||||
heap_used = size;
|
||||
|
||||
return MakeResult<VAddr>(heap_end - size);
|
||||
}
|
||||
|
||||
ResultCode VMManager::HeapFree(VAddr target, u64 size) {
|
||||
if (target < GetHeapRegionBaseAddress() || target + size > GetHeapRegionEndAddress() ||
|
||||
target + size < target) {
|
||||
return ERR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
const ResultCode result = UnmapRange(target, size);
|
||||
if (result.IsError()) {
|
||||
return result;
|
||||
}
|
||||
|
||||
heap_used -= size;
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
ResultCode VMManager::MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size) {
|
||||
const auto vma = FindVMA(src_addr);
|
||||
|
||||
ASSERT_MSG(vma != vma_map.end(), "Invalid memory address");
|
||||
ASSERT_MSG(vma->second.backing_block, "Backing block doesn't exist for address");
|
||||
|
||||
// The returned VMA might be a bigger one encompassing the desired address.
|
||||
const auto vma_offset = src_addr - vma->first;
|
||||
ASSERT_MSG(vma_offset + size <= vma->second.size,
|
||||
"Shared memory exceeds bounds of mapped block");
|
||||
|
||||
const std::shared_ptr<std::vector<u8>>& backing_block = vma->second.backing_block;
|
||||
const std::size_t backing_block_offset = vma->second.offset + vma_offset;
|
||||
|
||||
CASCADE_RESULT(auto new_vma, MapMemoryBlock(dst_addr, backing_block, backing_block_offset, size,
|
||||
MemoryState::Mapped));
|
||||
// Protect mirror with permissions from old region
|
||||
Reprotect(new_vma, vma->second.permissions);
|
||||
// Remove permissions from old region
|
||||
Reprotect(vma, VMAPermission::None);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
}
|
||||
|
||||
void VMManager::RefreshMemoryBlockMappings(const std::vector<u8>* block) {
|
||||
// If this ever proves to have a noticeable performance impact, allow users of the function to
|
||||
// specify a specific range of addresses to limit the scan to.
|
||||
@@ -574,7 +495,8 @@ u64 VMManager::GetTotalMemoryUsage() const {
|
||||
}
|
||||
|
||||
u64 VMManager::GetTotalHeapUsage() const {
|
||||
return heap_used;
|
||||
LOG_WARNING(Kernel, "(STUBBED) called");
|
||||
return 0x0;
|
||||
}
|
||||
|
||||
VAddr VMManager::GetAddressSpaceBaseAddress() const {
|
||||
|
||||
@@ -186,11 +186,6 @@ public:
|
||||
/// Changes the permissions of a range of addresses, splitting VMAs as necessary.
|
||||
ResultCode ReprotectRange(VAddr target, u64 size, VMAPermission new_perms);
|
||||
|
||||
ResultVal<VAddr> HeapAllocate(VAddr target, u64 size, VMAPermission perms);
|
||||
ResultCode HeapFree(VAddr target, u64 size);
|
||||
|
||||
ResultCode MirrorMemory(VAddr dst_addr, VAddr src_addr, u64 size);
|
||||
|
||||
/**
|
||||
* Scans all VMAs and updates the page table range of any that use the given vector as backing
|
||||
* memory. This should be called after any operation that causes reallocation of the vector.
|
||||
@@ -348,15 +343,5 @@ private:
|
||||
|
||||
VAddr tls_io_region_base = 0;
|
||||
VAddr tls_io_region_end = 0;
|
||||
|
||||
// Memory used to back the allocations in the regular heap. A single vector is used to cover
|
||||
// the entire virtual address space extents that bound the allocations, including any holes.
|
||||
// This makes deallocation and reallocation of holes fast and keeps process memory contiguous
|
||||
// in the emulator address space, allowing Memory::GetPointer to be reasonably safe.
|
||||
std::shared_ptr<std::vector<u8>> heap_memory;
|
||||
// The left/right bounds of the address space covered by heap_memory.
|
||||
VAddr heap_start = 0;
|
||||
VAddr heap_end = 0;
|
||||
u64 heap_used = 0;
|
||||
};
|
||||
} // namespace Kernel
|
||||
|
||||
@@ -242,28 +242,6 @@ void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestCo
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_ACC, "called");
|
||||
// A u8 is passed into this function which we can safely ignore. It's to determine if we have
|
||||
// access to use the network or not by the looks of it
|
||||
IPC::ResponseBuilder rb{ctx, 6};
|
||||
if (profile_manager->GetUserCount() != 1) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u128>(INVALID_UUID);
|
||||
return;
|
||||
}
|
||||
auto user_list = profile_manager->GetAllUsers();
|
||||
if (user_list.empty()) {
|
||||
rb.Push(ResultCode(-1)); // TODO(ogniK): Find the correct error code
|
||||
rb.PushRaw<u128>(INVALID_UUID);
|
||||
return;
|
||||
}
|
||||
|
||||
// Select the first user we have
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module,
|
||||
std::shared_ptr<ProfileManager> profile_manager, const char* name)
|
||||
: ServiceFramework(name), module(std::move(module)),
|
||||
|
||||
@@ -27,7 +27,6 @@ public:
|
||||
void InitializeApplicationInfo(Kernel::HLERequestContext& ctx);
|
||||
void GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx);
|
||||
void IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx);
|
||||
void TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> module;
|
||||
|
||||
@@ -17,7 +17,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{5, &ACC_SU::GetProfile, "GetProfile"},
|
||||
{6, nullptr, "GetProfileDigest"},
|
||||
{50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{51, nullptr, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{100, nullptr, "GetUserRegistrationNotifier"},
|
||||
{101, nullptr, "GetUserStateChangeNotifier"},
|
||||
|
||||
@@ -17,7 +17,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{5, &ACC_U0::GetProfile, "GetProfile"},
|
||||
{6, nullptr, "GetProfileDigest"},
|
||||
{50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{51, nullptr, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"},
|
||||
{101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"},
|
||||
|
||||
@@ -17,7 +17,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p
|
||||
{5, &ACC_U1::GetProfile, "GetProfile"},
|
||||
{6, nullptr, "GetProfileDigest"},
|
||||
{50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"},
|
||||
{51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"},
|
||||
{51, nullptr, "TrySelectUserWithoutInteraction"},
|
||||
{60, nullptr, "ListOpenContextStoredUsers"},
|
||||
{100, nullptr, "GetUserRegistrationNotifier"},
|
||||
{101, nullptr, "GetUserStateChangeNotifier"},
|
||||
|
||||
@@ -2,11 +2,8 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include <random>
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "common/file_util.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "core/settings.h"
|
||||
@@ -42,19 +39,6 @@ UUID UUID::Generate() {
|
||||
return UUID{distribution(gen), distribution(gen)};
|
||||
}
|
||||
|
||||
std::string UUID::Format() const {
|
||||
return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
|
||||
}
|
||||
|
||||
std::string UUID::FormatSwitch() const {
|
||||
std::array<u8, 16> s{};
|
||||
std::memcpy(s.data(), uuid.data(), sizeof(u128));
|
||||
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
|
||||
":02x}{:02x}{:02x}{:02x}{:02x}",
|
||||
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
|
||||
s[12], s[13], s[14], s[15]);
|
||||
}
|
||||
|
||||
ProfileManager::ProfileManager() {
|
||||
ParseUserSaveFile();
|
||||
|
||||
@@ -341,12 +325,11 @@ void ProfileManager::ParseUserSaveFile() {
|
||||
return;
|
||||
}
|
||||
|
||||
for (const auto& user : data.users) {
|
||||
if (user.uuid == UUID(INVALID_UUID)) {
|
||||
continue;
|
||||
}
|
||||
for (std::size_t i = 0; i < MAX_USERS; ++i) {
|
||||
const auto& user = data.users[i];
|
||||
|
||||
AddUser({user.uuid, user.username, user.timestamp, {}, false});
|
||||
if (user.uuid != UUID(INVALID_UUID))
|
||||
AddUser({user.uuid, user.username, user.timestamp, {}, false});
|
||||
}
|
||||
|
||||
std::stable_partition(profiles.begin(), profiles.end(),
|
||||
|
||||
@@ -42,14 +42,22 @@ struct UUID {
|
||||
void Invalidate() {
|
||||
uuid = INVALID_UUID;
|
||||
}
|
||||
std::string Format() const {
|
||||
return fmt::format("0x{:016X}{:016X}", uuid[1], uuid[0]);
|
||||
}
|
||||
|
||||
std::string Format() const;
|
||||
std::string FormatSwitch() const;
|
||||
std::string FormatSwitch() const {
|
||||
std::array<u8, 16> s{};
|
||||
std::memcpy(s.data(), uuid.data(), sizeof(u128));
|
||||
return fmt::format("{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{"
|
||||
":02x}{:02x}{:02x}{:02x}{:02x}",
|
||||
s[0], s[1], s[2], s[3], s[4], s[5], s[6], s[7], s[8], s[9], s[10], s[11],
|
||||
s[12], s[13], s[14], s[15]);
|
||||
}
|
||||
};
|
||||
static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
|
||||
|
||||
constexpr std::size_t profile_username_size = 32;
|
||||
using ProfileUsername = std::array<u8, profile_username_size>;
|
||||
using ProfileUsername = std::array<u8, 0x20>;
|
||||
using ProfileData = std::array<u8, MAX_DATA>;
|
||||
using UserIDArray = std::array<UUID, MAX_USERS>;
|
||||
|
||||
|
||||
@@ -338,54 +338,7 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessageQueue() {
|
||||
auto& kernel = Core::System::GetInstance().Kernel();
|
||||
on_new_message = Kernel::Event::Create(kernel, Kernel::ResetType::Sticky,
|
||||
"AMMessageQueue:OnMessageRecieved");
|
||||
on_operation_mode_changed = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot,
|
||||
"AMMessageQueue:OperationModeChanged");
|
||||
}
|
||||
|
||||
AppletMessageQueue::~AppletMessageQueue() = default;
|
||||
|
||||
const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetMesssageRecieveEvent() const {
|
||||
return on_new_message;
|
||||
}
|
||||
|
||||
const Kernel::SharedPtr<Kernel::Event>& AppletMessageQueue::GetOperationModeChangedEvent() const {
|
||||
return on_operation_mode_changed;
|
||||
}
|
||||
|
||||
void AppletMessageQueue::PushMessage(AppletMessage msg) {
|
||||
messages.push(msg);
|
||||
on_new_message->Signal();
|
||||
}
|
||||
|
||||
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
|
||||
if (messages.empty()) {
|
||||
on_new_message->Clear();
|
||||
return AppletMessage::NoMessage;
|
||||
}
|
||||
auto msg = messages.front();
|
||||
messages.pop();
|
||||
if (messages.empty()) {
|
||||
on_new_message->Clear();
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
std::size_t AppletMessageQueue::GetMessageCount() const {
|
||||
return messages.size();
|
||||
}
|
||||
|
||||
void AppletMessageQueue::OperationModeChanged() {
|
||||
PushMessage(AppletMessage::OperationModeChanged);
|
||||
PushMessage(AppletMessage::PerformanceModeChanged);
|
||||
on_operation_mode_changed->Signal();
|
||||
}
|
||||
|
||||
ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("ICommonStateGetter"), msg_queue(std::move(msg_queue)) {
|
||||
ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
|
||||
@@ -435,19 +388,21 @@ void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) {
|
||||
event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent());
|
||||
rb.PushCopyObjects(event);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage());
|
||||
rb.Push<u32>(15);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
|
||||
@@ -459,11 +414,13 @@ void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) {
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) {
|
||||
event->Signal();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent());
|
||||
rb.PushCopyObjects(event);
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) {
|
||||
@@ -487,7 +444,7 @@ void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
|
||||
@@ -497,7 +454,7 @@ void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) {
|
||||
rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked
|
||||
: APM::PerformanceMode::Handheld));
|
||||
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
}
|
||||
|
||||
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
|
||||
@@ -883,12 +840,8 @@ void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager,
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger) {
|
||||
auto message_queue = std::make_shared<AppletMessageQueue>();
|
||||
message_queue->PushMessage(
|
||||
AppletMessageQueue::AppletMessage::FocusStateChanged); // Needed on game boot
|
||||
|
||||
std::make_shared<AppletAE>(nvflinger, message_queue)->InstallAsService(service_manager);
|
||||
std::make_shared<AppletOE>(nvflinger, message_queue)->InstallAsService(service_manager);
|
||||
std::make_shared<AppletAE>(nvflinger)->InstallAsService(service_manager);
|
||||
std::make_shared<AppletOE>(nvflinger)->InstallAsService(service_manager);
|
||||
std::make_shared<IdleSys>()->InstallAsService(service_manager);
|
||||
std::make_shared<OMM>()->InstallAsService(service_manager);
|
||||
std::make_shared<SPSM>()->InstallAsService(service_manager);
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Kernel {
|
||||
@@ -40,31 +39,6 @@ enum SystemLanguage {
|
||||
TraditionalChinese = 16,
|
||||
};
|
||||
|
||||
class AppletMessageQueue {
|
||||
public:
|
||||
enum class AppletMessage : u32 {
|
||||
NoMessage = 0,
|
||||
FocusStateChanged = 15,
|
||||
OperationModeChanged = 30,
|
||||
PerformanceModeChanged = 31,
|
||||
};
|
||||
|
||||
AppletMessageQueue();
|
||||
~AppletMessageQueue();
|
||||
|
||||
const Kernel::SharedPtr<Kernel::Event>& GetMesssageRecieveEvent() const;
|
||||
const Kernel::SharedPtr<Kernel::Event>& GetOperationModeChangedEvent() const;
|
||||
void PushMessage(AppletMessage msg);
|
||||
AppletMessage PopMessage();
|
||||
std::size_t GetMessageCount() const;
|
||||
void OperationModeChanged();
|
||||
|
||||
private:
|
||||
std::queue<AppletMessage> messages;
|
||||
Kernel::SharedPtr<Kernel::Event> on_new_message;
|
||||
Kernel::SharedPtr<Kernel::Event> on_operation_mode_changed;
|
||||
};
|
||||
|
||||
class IWindowController final : public ServiceFramework<IWindowController> {
|
||||
public:
|
||||
IWindowController();
|
||||
@@ -128,7 +102,7 @@ private:
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
public:
|
||||
explicit ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_queue);
|
||||
ICommonStateGetter();
|
||||
~ICommonStateGetter() override;
|
||||
|
||||
private:
|
||||
@@ -152,7 +126,6 @@ private:
|
||||
void GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx);
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> event;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
|
||||
|
||||
@@ -12,10 +12,8 @@ namespace Service::AM {
|
||||
|
||||
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
|
||||
public:
|
||||
explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
explicit ILibraryAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("ILibraryAppletProxy"), nvflinger(std::move(nvflinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ILibraryAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ILibraryAppletProxy::GetSelfController, "GetSelfController"},
|
||||
@@ -34,7 +32,7 @@ private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
rb.PushIpcInterface<ICommonStateGetter>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
@@ -95,15 +93,12 @@ private:
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
|
||||
public:
|
||||
explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
explicit ISystemAppletProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("ISystemAppletProxy"), nvflinger(std::move(nvflinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISystemAppletProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
{1, &ISystemAppletProxy::GetSelfController, "GetSelfController"},
|
||||
@@ -124,7 +119,7 @@ private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
rb.PushIpcInterface<ICommonStateGetter>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
@@ -191,34 +186,31 @@ private:
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue);
|
||||
rb.PushIpcInterface<ISystemAppletProxy>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue);
|
||||
rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
|
||||
@@ -236,8 +228,4 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
|
||||
AppletAE::~AppletAE() = default;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& AppletAE::GetMessageQueue() const {
|
||||
return msg_queue;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -17,19 +17,15 @@ namespace AM {
|
||||
|
||||
class AppletAE final : public ServiceFramework<AppletAE> {
|
||||
public:
|
||||
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue);
|
||||
explicit AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
~AppletAE() override;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
|
||||
|
||||
private:
|
||||
void OpenSystemAppletProxy(Kernel::HLERequestContext& ctx);
|
||||
void OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx);
|
||||
void OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
|
||||
@@ -12,10 +12,8 @@ namespace Service::AM {
|
||||
|
||||
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
|
||||
public:
|
||||
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
|
||||
@@ -72,7 +70,7 @@ private:
|
||||
void GetCommonStateGetter(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ICommonStateGetter>(msg_queue);
|
||||
rb.PushIpcInterface<ICommonStateGetter>();
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
@@ -91,20 +89,17 @@ private:
|
||||
}
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue);
|
||||
rb.PushIpcInterface<IApplicationProxy>(nvflinger);
|
||||
LOG_DEBUG(Service_AM, "called");
|
||||
}
|
||||
|
||||
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue)
|
||||
: ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)),
|
||||
msg_queue(std::move(msg_queue)) {
|
||||
AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
|
||||
: ServiceFramework("appletOE"), nvflinger(std::move(nvflinger)) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &AppletOE::OpenApplicationProxy, "OpenApplicationProxy"},
|
||||
};
|
||||
@@ -113,8 +108,4 @@ AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
|
||||
AppletOE::~AppletOE() = default;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& AppletOE::GetMessageQueue() const {
|
||||
return msg_queue;
|
||||
}
|
||||
|
||||
} // namespace Service::AM
|
||||
|
||||
@@ -17,17 +17,13 @@ namespace AM {
|
||||
|
||||
class AppletOE final : public ServiceFramework<AppletOE> {
|
||||
public:
|
||||
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger,
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue);
|
||||
explicit AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger);
|
||||
~AppletOE() override;
|
||||
|
||||
const std::shared_ptr<AppletMessageQueue>& GetMessageQueue() const;
|
||||
|
||||
private:
|
||||
void OpenApplicationProxy(Kernel::HLERequestContext& ctx);
|
||||
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
std::shared_ptr<AppletMessageQueue> msg_queue;
|
||||
};
|
||||
|
||||
} // namespace AM
|
||||
|
||||
@@ -32,8 +32,8 @@ public:
|
||||
{5, &IAudioRenderer::Start, "Start"},
|
||||
{6, &IAudioRenderer::Stop, "Stop"},
|
||||
{7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"},
|
||||
{8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"},
|
||||
{9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"},
|
||||
{8, nullptr, "SetRenderingTimeLimit"},
|
||||
{9, nullptr, "GetRenderingTimeLimit"},
|
||||
{10, nullptr, "RequestUpdateAuto"},
|
||||
{11, nullptr, "ExecuteAudioRendererRendering"},
|
||||
};
|
||||
@@ -110,29 +110,8 @@ private:
|
||||
LOG_WARNING(Service_Audio, "(STUBBED) called");
|
||||
}
|
||||
|
||||
void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
rendering_time_limit_percent = rp.Pop<u32>();
|
||||
ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}",
|
||||
rendering_time_limit_percent);
|
||||
}
|
||||
|
||||
void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Audio, "called");
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push(rendering_time_limit_percent);
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> system_event;
|
||||
std::unique_ptr<AudioCore::AudioRenderer> renderer;
|
||||
u32 rendering_time_limit_percent = 100;
|
||||
};
|
||||
|
||||
class IAudioDevice final : public ServiceFramework<IAudioDevice> {
|
||||
|
||||
@@ -161,7 +161,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) {
|
||||
ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count");
|
||||
|
||||
std::size_t worker_sz = WorkerBufferSize(channel_count);
|
||||
ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large");
|
||||
ASSERT_MSG(buffer_sz < worker_sz, "Worker buffer too large");
|
||||
std::unique_ptr<OpusDecoder, OpusDeleter> decoder{
|
||||
static_cast<OpusDecoder*>(operator new(worker_sz))};
|
||||
if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) {
|
||||
|
||||
@@ -309,16 +309,6 @@ ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
return save_data_factory->Open(space, save_struct);
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) {
|
||||
LOG_TRACE(Service_FS, "Opening Save Data Space for space_id={:01X}", static_cast<u8>(space));
|
||||
|
||||
if (save_data_factory == nullptr) {
|
||||
return ResultCode(ErrorModule::FS, FileSys::ErrCodes::TitleNotFound);
|
||||
}
|
||||
|
||||
return MakeResult(save_data_factory->GetSaveDataSpaceDirectory(space));
|
||||
}
|
||||
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||
LOG_TRACE(Service_FS, "Opening SDMC");
|
||||
|
||||
@@ -329,9 +319,16 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() {
|
||||
return sdmc_factory->Open();
|
||||
}
|
||||
|
||||
std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
|
||||
return std::make_unique<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
|
||||
GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> registered_cache_union;
|
||||
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() {
|
||||
if (registered_cache_union == nullptr) {
|
||||
registered_cache_union =
|
||||
std::make_shared<FileSys::RegisteredCacheUnion>(std::vector<FileSys::RegisteredCache*>{
|
||||
GetSystemNANDContents(), GetUserNANDContents(), GetSDMCContents()});
|
||||
}
|
||||
|
||||
return registered_cache_union;
|
||||
}
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents() {
|
||||
|
||||
@@ -45,10 +45,9 @@ ResultVal<FileSys::VirtualFile> OpenRomFS(u64 title_id, FileSys::StorageId stora
|
||||
FileSys::ContentRecordType type);
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveData(FileSys::SaveDataSpaceId space,
|
||||
FileSys::SaveDataDescriptor save_struct);
|
||||
ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space);
|
||||
ResultVal<FileSys::VirtualDir> OpenSDMC();
|
||||
|
||||
std::unique_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
|
||||
std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
|
||||
|
||||
FileSys::RegisteredCache* GetSystemNANDContents();
|
||||
FileSys::RegisteredCache* GetUserNANDContents();
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/file_sys/directory.h"
|
||||
@@ -452,147 +451,7 @@ private:
|
||||
VfsDirectoryServiceWrapper backend;
|
||||
};
|
||||
|
||||
class ISaveDataInfoReader final : public ServiceFramework<ISaveDataInfoReader> {
|
||||
public:
|
||||
explicit ISaveDataInfoReader(FileSys::SaveDataSpaceId space)
|
||||
: ServiceFramework("ISaveDataInfoReader") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &ISaveDataInfoReader::ReadSaveDataInfo, "ReadSaveDataInfo"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
FindAllSaves(space);
|
||||
}
|
||||
|
||||
void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) {
|
||||
// Calculate how many entries we can fit in the output buffer
|
||||
const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo);
|
||||
|
||||
// Cap at total number of entries.
|
||||
const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index);
|
||||
|
||||
// Determine data start and end
|
||||
const auto* begin = reinterpret_cast<u8*>(info.data() + next_entry_index);
|
||||
const auto* end = reinterpret_cast<u8*>(info.data() + next_entry_index + actual_entries);
|
||||
const auto range_size = static_cast<std::size_t>(std::distance(begin, end));
|
||||
|
||||
next_entry_index += actual_entries;
|
||||
|
||||
// Write the data to memory
|
||||
ctx.WriteBuffer(begin, range_size);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(actual_entries));
|
||||
}
|
||||
|
||||
private:
|
||||
static u64 stoull_be(std::string_view str) {
|
||||
if (str.size() != 16)
|
||||
return 0;
|
||||
|
||||
const auto bytes = Common::HexStringToArray<0x8>(str);
|
||||
u64 out{};
|
||||
std::memcpy(&out, bytes.data(), sizeof(u64));
|
||||
|
||||
return Common::swap64(out);
|
||||
}
|
||||
|
||||
void FindAllSaves(FileSys::SaveDataSpaceId space) {
|
||||
const auto save_root = OpenSaveDataSpace(space);
|
||||
ASSERT(save_root.Succeeded());
|
||||
|
||||
for (const auto& type : (*save_root)->GetSubdirectories()) {
|
||||
if (type->GetName() == "save") {
|
||||
for (const auto& save_id : type->GetSubdirectories()) {
|
||||
for (const auto& user_id : save_id->GetSubdirectories()) {
|
||||
const auto save_id_numeric = stoull_be(save_id->GetName());
|
||||
auto user_id_numeric = Common::HexStringToArray<0x10>(user_id->GetName());
|
||||
std::reverse(user_id_numeric.begin(), user_id_numeric.end());
|
||||
|
||||
if (save_id_numeric != 0) {
|
||||
// System Save Data
|
||||
info.emplace_back(SaveDataInfo{
|
||||
0,
|
||||
space,
|
||||
FileSys::SaveDataType::SystemSaveData,
|
||||
{},
|
||||
user_id_numeric,
|
||||
save_id_numeric,
|
||||
0,
|
||||
user_id->GetSize(),
|
||||
{},
|
||||
});
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const auto& title_id : user_id->GetSubdirectories()) {
|
||||
const auto device =
|
||||
std::all_of(user_id_numeric.begin(), user_id_numeric.end(),
|
||||
[](u8 val) { return val == 0; });
|
||||
info.emplace_back(SaveDataInfo{
|
||||
0,
|
||||
space,
|
||||
device ? FileSys::SaveDataType::DeviceSaveData
|
||||
: FileSys::SaveDataType::SaveData,
|
||||
{},
|
||||
user_id_numeric,
|
||||
save_id_numeric,
|
||||
stoull_be(title_id->GetName()),
|
||||
title_id->GetSize(),
|
||||
{},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (space == FileSys::SaveDataSpaceId::TemporaryStorage) {
|
||||
// Temporary Storage
|
||||
for (const auto& user_id : type->GetSubdirectories()) {
|
||||
for (const auto& title_id : user_id->GetSubdirectories()) {
|
||||
if (!title_id->GetFiles().empty() ||
|
||||
!title_id->GetSubdirectories().empty()) {
|
||||
auto user_id_numeric =
|
||||
Common::HexStringToArray<0x10>(user_id->GetName());
|
||||
std::reverse(user_id_numeric.begin(), user_id_numeric.end());
|
||||
|
||||
info.emplace_back(SaveDataInfo{
|
||||
0,
|
||||
space,
|
||||
FileSys::SaveDataType::TemporaryStorage,
|
||||
{},
|
||||
user_id_numeric,
|
||||
stoull_be(type->GetName()),
|
||||
stoull_be(title_id->GetName()),
|
||||
title_id->GetSize(),
|
||||
{},
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SaveDataInfo {
|
||||
u64_le save_id_unknown;
|
||||
FileSys::SaveDataSpaceId space;
|
||||
FileSys::SaveDataType type;
|
||||
INSERT_PADDING_BYTES(0x6);
|
||||
std::array<u8, 0x10> user_id;
|
||||
u64_le save_id;
|
||||
u64_le title_id;
|
||||
u64_le save_image_size;
|
||||
INSERT_PADDING_BYTES(0x28);
|
||||
};
|
||||
static_assert(sizeof(SaveDataInfo) == 0x60, "SaveDataInfo has incorrect size.");
|
||||
|
||||
std::vector<SaveDataInfo> info;
|
||||
u64 next_entry_index = 0;
|
||||
};
|
||||
|
||||
FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "MountContent"},
|
||||
{1, &FSP_SRV::Initialize, "Initialize"},
|
||||
@@ -626,7 +485,7 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
|
||||
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
|
||||
{60, nullptr, "OpenSaveDataInfoReader"},
|
||||
{61, &FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
|
||||
{61, nullptr, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
|
||||
{62, nullptr, "OpenCacheStorageList"},
|
||||
{64, nullptr, "OpenSaveDataInternalStorageFileSystem"},
|
||||
{65, nullptr, "UpdateSaveDataMacForDebug"},
|
||||
@@ -685,7 +544,6 @@ FSP_SRV::FSP_SRV() : ServiceFramework("fsp-srv") {
|
||||
{1009, nullptr, "GetAndClearMemoryReportInfo"},
|
||||
{1100, nullptr, "OverrideSaveDataTransferTokenSignVerificationKey"},
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
@@ -760,15 +618,6 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) {
|
||||
MountSaveData(ctx);
|
||||
}
|
||||
|
||||
void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>();
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<ISaveDataInfoReader>(std::make_shared<ISaveDataInfoReader>(space));
|
||||
}
|
||||
|
||||
void FSP_SRV::GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_FS, "(STUBBED) called");
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@ private:
|
||||
void CreateSaveData(Kernel::HLERequestContext& ctx);
|
||||
void MountSaveData(Kernel::HLERequestContext& ctx);
|
||||
void OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx);
|
||||
void OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx);
|
||||
void GetGlobalAccessLogMode(Kernel::HLERequestContext& ctx);
|
||||
void OpenDataStorageByCurrentProcess(Kernel::HLERequestContext& ctx);
|
||||
void OpenDataStorageByDataId(Kernel::HLERequestContext& ctx);
|
||||
|
||||
@@ -392,10 +392,8 @@ std::size_t Controller_NPad::GetSupportedNPadIdTypesSize() const {
|
||||
}
|
||||
|
||||
void Controller_NPad::SetHoldType(NpadHoldType joy_hold_type) {
|
||||
styleset_changed_event->Signal();
|
||||
hold_type = joy_hold_type;
|
||||
}
|
||||
|
||||
Controller_NPad::NpadHoldType Controller_NPad::GetHoldType() const {
|
||||
return hold_type;
|
||||
}
|
||||
@@ -429,9 +427,6 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
|
||||
}
|
||||
|
||||
Kernel::SharedPtr<Kernel::Event> Controller_NPad::GetStyleSetChangedEvent() const {
|
||||
// TODO(ogniK): Figure out the best time to signal this event. This event seems that it should
|
||||
// be signalled at least once, and signaled after a new controller is connected?
|
||||
styleset_changed_event->Signal();
|
||||
return styleset_changed_event;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,8 +96,6 @@ public:
|
||||
// TODO(shinyquagsire23): Other update callbacks? (accel, gyro?)
|
||||
|
||||
CoreTiming::ScheduleEvent(pad_update_ticks, pad_update_event);
|
||||
|
||||
ReloadInputDevices();
|
||||
}
|
||||
|
||||
void ActivateController(HidController controller) {
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
@@ -121,7 +118,7 @@ public:
|
||||
{305, nullptr, "TerminateSystemApplet"},
|
||||
{306, nullptr, "LaunchOverlayApplet"},
|
||||
{307, nullptr, "TerminateOverlayApplet"},
|
||||
{400, &IApplicationManagerInterface::GetApplicationControlData, "GetApplicationControlData"},
|
||||
{400, nullptr, "GetApplicationControlData"},
|
||||
{401, nullptr, "InvalidateAllApplicationControlCache"},
|
||||
{402, nullptr, "RequestDownloadApplicationControlData"},
|
||||
{403, nullptr, "GetMaxApplicationControlCacheCount"},
|
||||
@@ -246,65 +243,6 @@ public:
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
void GetApplicationControlData(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto flag = rp.PopRaw<u64>();
|
||||
LOG_DEBUG(Service_NS, "called with flag={:016X}", flag);
|
||||
|
||||
const auto title_id = rp.PopRaw<u64>();
|
||||
|
||||
const auto size = ctx.GetWriteBufferSize();
|
||||
|
||||
const FileSys::PatchManager pm{title_id};
|
||||
const auto control = pm.GetControlMetadata();
|
||||
|
||||
std::vector<u8> out;
|
||||
|
||||
if (control.first != nullptr) {
|
||||
if (size < 0x4000) {
|
||||
LOG_ERROR(Service_NS,
|
||||
"output buffer is too small! (actual={:016X}, expected_min=0x4000)",
|
||||
size);
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(DarkLordZach): Find a better error code for this.
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
out.resize(0x4000);
|
||||
const auto bytes = control.first->GetRawBytes();
|
||||
std::memcpy(out.data(), bytes.data(), bytes.size());
|
||||
} else {
|
||||
LOG_WARNING(Service_NS, "missing NACP data for title_id={:016X}, defaulting to zeros.",
|
||||
title_id);
|
||||
out.resize(std::min<u64>(0x4000, size));
|
||||
}
|
||||
|
||||
if (control.second != nullptr) {
|
||||
if (size < 0x4000 + control.second->GetSize()) {
|
||||
LOG_ERROR(Service_NS,
|
||||
"output buffer is too small! (actual={:016X}, expected_min={:016X})",
|
||||
size, 0x4000 + control.second->GetSize());
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
// TODO(DarkLordZach): Find a better error code for this.
|
||||
rb.Push(ResultCode(-1));
|
||||
return;
|
||||
}
|
||||
|
||||
out.resize(0x4000 + control.second->GetSize());
|
||||
control.second->Read(out.data() + 0x4000, control.second->GetSize());
|
||||
} else {
|
||||
LOG_WARNING(Service_NS, "missing icon data for title_id={:016X}, defaulting to zeros.",
|
||||
title_id);
|
||||
}
|
||||
|
||||
ctx.WriteBuffer(out);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.Push<u32>(static_cast<u32>(out.size()));
|
||||
}
|
||||
};
|
||||
|
||||
class IApplicationVersionInterface final : public ServiceFramework<IApplicationVersionInterface> {
|
||||
|
||||
@@ -58,9 +58,9 @@ public:
|
||||
/// Rotate source image 90 degrees clockwise
|
||||
Rotate90 = 0x04,
|
||||
/// Rotate source image 180 degrees
|
||||
Rotate180 = 0x03,
|
||||
Roate180 = 0x03,
|
||||
/// Rotate source image 270 degrees clockwise
|
||||
Rotate270 = 0x07,
|
||||
Roate270 = 0x07,
|
||||
};
|
||||
|
||||
struct Buffer {
|
||||
|
||||
@@ -3,23 +3,18 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <ctime>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/spl/csrng.h"
|
||||
#include "core/hle/service/spl/module.h"
|
||||
#include "core/hle/service/spl/spl.h"
|
||||
#include "core/settings.h"
|
||||
|
||||
namespace Service::SPL {
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
: ServiceFramework(name), module(std::move(module)),
|
||||
rng(Settings::values.rng_seed.value_or(std::time(nullptr))) {}
|
||||
: ServiceFramework(name), module(std::move(module)) {}
|
||||
|
||||
Module::Interface::~Interface() = default;
|
||||
|
||||
@@ -29,7 +24,7 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
|
||||
std::size_t size = ctx.GetWriteBufferSize();
|
||||
|
||||
std::vector<u8> data(size);
|
||||
std::generate(data.begin(), data.end(), rng);
|
||||
std::generate(data.begin(), data.end(), std::rand);
|
||||
|
||||
ctx.WriteBuffer(data);
|
||||
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <random>
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::SPL {
|
||||
@@ -20,9 +19,6 @@ public:
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> module;
|
||||
|
||||
private:
|
||||
std::mt19937 rng;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,7 @@ Time::Time(std::shared_ptr<Module> time, const char* name)
|
||||
{102, nullptr, "GetStandardUserSystemClockInitialYear"},
|
||||
{200, nullptr, "IsStandardNetworkSystemClockAccuracySufficient"},
|
||||
{300, nullptr, "CalculateMonotonicSystemClockBaseTimePoint"},
|
||||
{400, &Time::GetClockSnapshot, "GetClockSnapshot"},
|
||||
{400, nullptr, "GetClockSnapshot"},
|
||||
{401, nullptr, "GetClockSnapshotFromSystemClockContext"},
|
||||
{500, nullptr, "CalculateStandardUserSystemClockDifferenceByUser"},
|
||||
{501, nullptr, "CalculateSpanBetween"},
|
||||
|
||||
@@ -15,44 +15,6 @@
|
||||
|
||||
namespace Service::Time {
|
||||
|
||||
static void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
|
||||
CalendarAdditionalInfo& additional_info,
|
||||
[[maybe_unused]] const TimeZoneRule& /*rule*/) {
|
||||
const std::time_t time(posix_time);
|
||||
const std::tm* tm = std::localtime(&time);
|
||||
if (tm == nullptr) {
|
||||
calendar_time = {};
|
||||
additional_info = {};
|
||||
return;
|
||||
}
|
||||
calendar_time.year = tm->tm_year + 1900;
|
||||
calendar_time.month = tm->tm_mon + 1;
|
||||
calendar_time.day = tm->tm_mday;
|
||||
calendar_time.hour = tm->tm_hour;
|
||||
calendar_time.minute = tm->tm_min;
|
||||
calendar_time.second = tm->tm_sec;
|
||||
|
||||
additional_info.day_of_week = tm->tm_wday;
|
||||
additional_info.day_of_year = tm->tm_yday;
|
||||
std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
|
||||
additional_info.utc_offset = 0;
|
||||
}
|
||||
|
||||
static u64 CalendarToPosix(const CalendarTime& calendar_time,
|
||||
[[maybe_unused]] const TimeZoneRule& /*rule*/) {
|
||||
std::tm time{};
|
||||
time.tm_year = calendar_time.year - 1900;
|
||||
time.tm_mon = calendar_time.month - 1;
|
||||
time.tm_mday = calendar_time.day;
|
||||
|
||||
time.tm_hour = calendar_time.hour;
|
||||
time.tm_min = calendar_time.minute;
|
||||
time.tm_sec = calendar_time.second;
|
||||
|
||||
std::time_t epoch_time = std::mktime(&time);
|
||||
return static_cast<u64>(epoch_time);
|
||||
}
|
||||
|
||||
class ISystemClock final : public ServiceFramework<ISystemClock> {
|
||||
public:
|
||||
ISystemClock() : ServiceFramework("ISystemClock") {
|
||||
@@ -118,8 +80,8 @@ public:
|
||||
{5, nullptr, "GetTimeZoneRuleVersion"},
|
||||
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
|
||||
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
||||
{201, &ITimeZoneService::ToPosixTime, "ToPosixTime"},
|
||||
{202, &ITimeZoneService::ToPosixTimeWithMyRule, "ToPosixTimeWithMyRule"},
|
||||
{201, nullptr, "ToPosixTime"},
|
||||
{202, nullptr, "ToPosixTimeWithMyRule"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
@@ -189,29 +151,24 @@ private:
|
||||
rb.PushRaw(additional_info);
|
||||
}
|
||||
|
||||
void ToPosixTime(Kernel::HLERequestContext& ctx) {
|
||||
// TODO(ogniK): Figure out how to handle multiple times
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar_time = rp.PopRaw<CalendarTime>();
|
||||
auto posix_time = CalendarToPosix(calendar_time, {});
|
||||
void PosixToCalendar(u64 posix_time, CalendarTime& calendar_time,
|
||||
CalendarAdditionalInfo& additional_info, const TimeZoneRule& /*rule*/) {
|
||||
std::time_t t(posix_time);
|
||||
std::tm* tm = std::localtime(&t);
|
||||
if (!tm) {
|
||||
return;
|
||||
}
|
||||
calendar_time.year = tm->tm_year + 1900;
|
||||
calendar_time.month = tm->tm_mon + 1;
|
||||
calendar_time.day = tm->tm_mday;
|
||||
calendar_time.hour = tm->tm_hour;
|
||||
calendar_time.minute = tm->tm_min;
|
||||
calendar_time.second = tm->tm_sec;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(1); // Amount of times we're returning
|
||||
ctx.WriteBuffer(&posix_time, sizeof(u64));
|
||||
}
|
||||
|
||||
void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto calendar_time = rp.PopRaw<CalendarTime>();
|
||||
auto posix_time = CalendarToPosix(calendar_time, {});
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw<u32>(1); // Amount of times we're returning
|
||||
ctx.WriteBuffer(&posix_time, sizeof(u64));
|
||||
additional_info.day_of_week = tm->tm_wday;
|
||||
additional_info.day_of_year = tm->tm_yday;
|
||||
std::memcpy(additional_info.name.data(), "UTC", sizeof("UTC"));
|
||||
additional_info.utc_offset = 0;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -250,55 +207,6 @@ void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& c
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
}
|
||||
|
||||
void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
|
||||
LOG_DEBUG(Service_Time, "called");
|
||||
|
||||
IPC::RequestParser rp{ctx};
|
||||
auto unknown_u8 = rp.PopRaw<u8>();
|
||||
|
||||
ClockSnapshot clock_snapshot{};
|
||||
|
||||
const s64 time_since_epoch{std::chrono::duration_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::now().time_since_epoch())
|
||||
.count()};
|
||||
CalendarTime calendar_time{};
|
||||
const std::time_t time(time_since_epoch);
|
||||
const std::tm* tm = std::localtime(&time);
|
||||
if (tm == nullptr) {
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code
|
||||
return;
|
||||
}
|
||||
SteadyClockTimePoint steady_clock_time_point{CoreTiming::cyclesToMs(CoreTiming::GetTicks()) /
|
||||
1000};
|
||||
|
||||
LocationName location_name{"UTC"};
|
||||
calendar_time.year = tm->tm_year + 1900;
|
||||
calendar_time.month = tm->tm_mon + 1;
|
||||
calendar_time.day = tm->tm_mday;
|
||||
calendar_time.hour = tm->tm_hour;
|
||||
calendar_time.minute = tm->tm_min;
|
||||
calendar_time.second = tm->tm_sec;
|
||||
clock_snapshot.system_posix_time = time_since_epoch;
|
||||
clock_snapshot.network_posix_time = time_since_epoch;
|
||||
clock_snapshot.system_calendar_time = calendar_time;
|
||||
clock_snapshot.network_calendar_time = calendar_time;
|
||||
|
||||
CalendarAdditionalInfo additional_info{};
|
||||
PosixToCalendar(time_since_epoch, calendar_time, additional_info, {});
|
||||
|
||||
clock_snapshot.system_calendar_info = additional_info;
|
||||
clock_snapshot.network_calendar_info = additional_info;
|
||||
|
||||
clock_snapshot.steady_clock_timepoint = steady_clock_time_point;
|
||||
clock_snapshot.location_name = location_name;
|
||||
clock_snapshot.clock_auto_adjustment_enabled = 1;
|
||||
clock_snapshot.ipc_u8 = unknown_u8;
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
ctx.WriteBuffer(&clock_snapshot, sizeof(ClockSnapshot));
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> time, const char* name)
|
||||
: ServiceFramework(name), time(std::move(time)) {}
|
||||
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "common/common_funcs.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::Time {
|
||||
@@ -54,23 +53,6 @@ struct SystemClockContext {
|
||||
static_assert(sizeof(SystemClockContext) == 0x20,
|
||||
"SystemClockContext structure has incorrect size");
|
||||
|
||||
struct ClockSnapshot {
|
||||
SystemClockContext user_clock_context;
|
||||
SystemClockContext network_clock_context;
|
||||
s64_le system_posix_time;
|
||||
s64_le network_posix_time;
|
||||
CalendarTime system_calendar_time;
|
||||
CalendarTime network_calendar_time;
|
||||
CalendarAdditionalInfo system_calendar_info;
|
||||
CalendarAdditionalInfo network_calendar_info;
|
||||
SteadyClockTimePoint steady_clock_timepoint;
|
||||
LocationName location_name;
|
||||
u8 clock_auto_adjustment_enabled;
|
||||
u8 ipc_u8;
|
||||
INSERT_PADDING_BYTES(2);
|
||||
};
|
||||
static_assert(sizeof(ClockSnapshot) == 0xd0, "ClockSnapshot is an invalid size");
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
@@ -83,7 +65,6 @@ public:
|
||||
void GetStandardSteadyClock(Kernel::HLERequestContext& ctx);
|
||||
void GetTimeZoneService(Kernel::HLERequestContext& ctx);
|
||||
void GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx);
|
||||
void GetClockSnapshot(Kernel::HLERequestContext& ctx);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> time;
|
||||
|
||||
@@ -132,11 +132,11 @@ public:
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "BindNoticeEvent"},
|
||||
{1, nullptr, "UnbindNoticeEvent"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "GetStatus"},
|
||||
{3, nullptr, "GetNotice"},
|
||||
{4, nullptr, "EnablePowerRequestNotice"},
|
||||
{5, nullptr, "DisablePowerRequestNotice"},
|
||||
{4, nullptr, "Unknown2"},
|
||||
{5, nullptr, "Unknown3"},
|
||||
{6, nullptr, "ReplyPowerRequest"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -12,12 +12,10 @@
|
||||
#include "common/swap.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/romfs_factory.h"
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/loader/nro.h"
|
||||
#include "core/loader/nso.h"
|
||||
#include "core/memory.h"
|
||||
@@ -210,9 +208,6 @@ ResultStatus AppLoader_NRO::Load(Kernel::Process& process) {
|
||||
return ResultStatus::ErrorLoadingNRO;
|
||||
}
|
||||
|
||||
if (romfs != nullptr)
|
||||
Service::FileSystem::RegisterRomFS(std::make_unique<FileSys::RomFSFactory>(*this));
|
||||
|
||||
process.Run(base_address, Kernel::THREADPRIO_DEFAULT, Memory::DEFAULT_STACK_SIZE);
|
||||
|
||||
is_loaded = true;
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include "common/common_types.h"
|
||||
|
||||
@@ -115,9 +114,8 @@ struct Values {
|
||||
// System
|
||||
bool use_docked_mode;
|
||||
bool enable_nfc;
|
||||
std::optional<u32> rng_seed;
|
||||
s32 current_user;
|
||||
s32 language_index;
|
||||
int current_user;
|
||||
int language_index;
|
||||
|
||||
// Controls
|
||||
std::array<std::string, NativeButton::NumButtons> buttons;
|
||||
|
||||
@@ -184,13 +184,4 @@ TelemetrySession::~TelemetrySession() {
|
||||
backend = nullptr;
|
||||
}
|
||||
|
||||
bool TelemetrySession::SubmitTestcase() {
|
||||
#ifdef ENABLE_WEB_SERVICE
|
||||
field_collection.Accept(*backend);
|
||||
return backend->SubmitTestcase();
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
@@ -31,12 +31,6 @@ public:
|
||||
field_collection.AddField(type, name, std::move(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* Submits a Testcase.
|
||||
* @returns A bool indicating whether the submission succeeded
|
||||
*/
|
||||
bool SubmitTestcase();
|
||||
|
||||
private:
|
||||
Telemetry::FieldCollection field_collection; ///< Tracks all added fields for the session
|
||||
std::unique_ptr<Telemetry::VisitorInterface> backend; ///< Backend interface that logs fields
|
||||
|
||||
@@ -21,7 +21,6 @@ add_library(video_core STATIC
|
||||
macro_interpreter.h
|
||||
memory_manager.cpp
|
||||
memory_manager.h
|
||||
rasterizer_cache.cpp
|
||||
rasterizer_cache.h
|
||||
rasterizer_interface.h
|
||||
renderer_base.cpp
|
||||
@@ -34,7 +33,6 @@ add_library(video_core STATIC
|
||||
renderer_opengl/gl_rasterizer.h
|
||||
renderer_opengl/gl_rasterizer_cache.cpp
|
||||
renderer_opengl/gl_rasterizer_cache.h
|
||||
renderer_opengl/gl_resource_manager.cpp
|
||||
renderer_opengl/gl_resource_manager.h
|
||||
renderer_opengl/gl_shader_cache.cpp
|
||||
renderer_opengl/gl_shader_cache.h
|
||||
@@ -55,8 +53,6 @@ add_library(video_core STATIC
|
||||
renderer_opengl/renderer_opengl.h
|
||||
renderer_opengl/utils.cpp
|
||||
renderer_opengl/utils.h
|
||||
surface.cpp
|
||||
surface.h
|
||||
textures/astc.cpp
|
||||
textures/astc.h
|
||||
textures/decoders.cpp
|
||||
|
||||
@@ -37,52 +37,21 @@ void Maxwell3D::InitializeRegisterDefaults() {
|
||||
regs.viewport[viewport].depth_range_near = 0.0f;
|
||||
regs.viewport[viewport].depth_range_far = 1.0f;
|
||||
}
|
||||
// Doom and Bomberman seems to use the uninitialized registers and just enable blend
|
||||
// so initialize blend registers with sane values
|
||||
regs.blend.equation_rgb = Regs::Blend::Equation::Add;
|
||||
regs.blend.factor_source_rgb = Regs::Blend::Factor::One;
|
||||
regs.blend.factor_dest_rgb = Regs::Blend::Factor::Zero;
|
||||
regs.blend.equation_a = Regs::Blend::Equation::Add;
|
||||
regs.blend.factor_source_a = Regs::Blend::Factor::One;
|
||||
regs.blend.factor_dest_a = Regs::Blend::Factor::Zero;
|
||||
for (std::size_t blend_index = 0; blend_index < Regs::NumRenderTargets; blend_index++) {
|
||||
regs.independent_blend[blend_index].equation_rgb = Regs::Blend::Equation::Add;
|
||||
regs.independent_blend[blend_index].factor_source_rgb = Regs::Blend::Factor::One;
|
||||
regs.independent_blend[blend_index].factor_dest_rgb = Regs::Blend::Factor::Zero;
|
||||
regs.independent_blend[blend_index].equation_a = Regs::Blend::Equation::Add;
|
||||
regs.independent_blend[blend_index].factor_source_a = Regs::Blend::Factor::One;
|
||||
regs.independent_blend[blend_index].factor_dest_a = Regs::Blend::Factor::Zero;
|
||||
}
|
||||
regs.stencil_front_op_fail = Regs::StencilOp::Keep;
|
||||
regs.stencil_front_op_zfail = Regs::StencilOp::Keep;
|
||||
regs.stencil_front_op_zpass = Regs::StencilOp::Keep;
|
||||
regs.stencil_front_func_func = Regs::ComparisonOp::Always;
|
||||
regs.stencil_front_func_mask = 0xFFFFFFFF;
|
||||
regs.stencil_front_mask = 0xFFFFFFFF;
|
||||
regs.stencil_two_side_enable = 1;
|
||||
regs.stencil_back_op_fail = Regs::StencilOp::Keep;
|
||||
regs.stencil_back_op_zfail = Regs::StencilOp::Keep;
|
||||
regs.stencil_back_op_zpass = Regs::StencilOp::Keep;
|
||||
regs.stencil_back_func_func = Regs::ComparisonOp::Always;
|
||||
regs.stencil_back_func_mask = 0xFFFFFFFF;
|
||||
regs.stencil_back_mask = 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) {
|
||||
// Reset the current macro.
|
||||
executing_macro = 0;
|
||||
|
||||
// Lookup the macro offset
|
||||
const u32 entry{(method - MacroRegistersStart) >> 1};
|
||||
const auto& search{macro_offsets.find(entry)};
|
||||
if (search == macro_offsets.end()) {
|
||||
LOG_CRITICAL(HW_GPU, "macro not found for method 0x{:X}!", method);
|
||||
UNREACHABLE();
|
||||
// The requested macro must have been uploaded already.
|
||||
auto macro_code = uploaded_macros.find(method);
|
||||
if (macro_code == uploaded_macros.end()) {
|
||||
LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method);
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute the current macro.
|
||||
macro_interpreter.Execute(search->second, std::move(parameters));
|
||||
macro_interpreter.Execute(macro_code->second, std::move(parameters));
|
||||
}
|
||||
|
||||
void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||
@@ -121,23 +90,13 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||
debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr);
|
||||
}
|
||||
|
||||
if (regs.reg_array[method] != value) {
|
||||
regs.reg_array[method] = value;
|
||||
if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) &&
|
||||
method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) {
|
||||
dirty_flags.vertex_attrib_format = true;
|
||||
}
|
||||
}
|
||||
regs.reg_array[method] = value;
|
||||
|
||||
switch (method) {
|
||||
case MAXWELL3D_REG_INDEX(macros.data): {
|
||||
ProcessMacroUpload(value);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(macros.bind): {
|
||||
ProcessMacroBind(value);
|
||||
break;
|
||||
}
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
|
||||
case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
|
||||
@@ -199,13 +158,9 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) {
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessMacroUpload(u32 data) {
|
||||
ASSERT_MSG(regs.macros.upload_address < macro_memory.size(),
|
||||
"upload_address exceeded macro_memory size!");
|
||||
macro_memory[regs.macros.upload_address++] = data;
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessMacroBind(u32 data) {
|
||||
macro_offsets[regs.macros.entry] = data;
|
||||
// Store the uploaded macro code to interpret them when they're called.
|
||||
auto& macro = uploaded_macros[regs.macros.entry * 2 + MacroRegistersStart];
|
||||
macro.push_back(data);
|
||||
}
|
||||
|
||||
void Maxwell3D::ProcessQueryGet() {
|
||||
|
||||
@@ -345,14 +345,6 @@ public:
|
||||
Invert = 6,
|
||||
IncrWrap = 7,
|
||||
DecrWrap = 8,
|
||||
KeepOGL = 0x1E00,
|
||||
ZeroOGL = 0,
|
||||
ReplaceOGL = 0x1E01,
|
||||
IncrOGL = 0x1E02,
|
||||
DecrOGL = 0x1E03,
|
||||
InvertOGL = 0x150A,
|
||||
IncrWrapOGL = 0x8507,
|
||||
DecrWrapOGL = 0x8508,
|
||||
};
|
||||
|
||||
enum class MemoryLayout : u32 {
|
||||
@@ -470,16 +462,6 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
struct ColorMask {
|
||||
union {
|
||||
u32 raw;
|
||||
BitField<0, 4, u32> R;
|
||||
BitField<4, 4, u32> G;
|
||||
BitField<8, 4, u32> B;
|
||||
BitField<12, 4, u32> A;
|
||||
};
|
||||
};
|
||||
|
||||
bool IsShaderConfigEnabled(std::size_t index) const {
|
||||
// The VertexB is always enabled.
|
||||
if (index == static_cast<std::size_t>(Regs::ShaderProgram::VertexB)) {
|
||||
@@ -493,13 +475,12 @@ public:
|
||||
INSERT_PADDING_WORDS(0x45);
|
||||
|
||||
struct {
|
||||
u32 upload_address;
|
||||
INSERT_PADDING_WORDS(1);
|
||||
u32 data;
|
||||
u32 entry;
|
||||
u32 bind;
|
||||
} macros;
|
||||
|
||||
INSERT_PADDING_WORDS(0x188);
|
||||
INSERT_PADDING_WORDS(0x189);
|
||||
|
||||
u32 tfb_enabled;
|
||||
|
||||
@@ -589,11 +570,7 @@ public:
|
||||
u32 stencil_back_mask;
|
||||
u32 stencil_back_func_mask;
|
||||
|
||||
INSERT_PADDING_WORDS(0xC);
|
||||
|
||||
u32 color_mask_common;
|
||||
|
||||
INSERT_PADDING_WORDS(0x6);
|
||||
INSERT_PADDING_WORDS(0x13);
|
||||
|
||||
u32 rt_separate_frag_data;
|
||||
|
||||
@@ -668,14 +645,8 @@ public:
|
||||
ComparisonOp depth_test_func;
|
||||
float alpha_test_ref;
|
||||
ComparisonOp alpha_test_func;
|
||||
u32 draw_tfb_stride;
|
||||
struct {
|
||||
float r;
|
||||
float g;
|
||||
float b;
|
||||
float a;
|
||||
} blend_color;
|
||||
INSERT_PADDING_WORDS(0x4);
|
||||
|
||||
INSERT_PADDING_WORDS(0x9);
|
||||
|
||||
struct {
|
||||
u32 separate_alpha;
|
||||
@@ -869,9 +840,8 @@ public:
|
||||
BitField<6, 4, u32> RT;
|
||||
BitField<10, 11, u32> layer;
|
||||
} clear_buffers;
|
||||
INSERT_PADDING_WORDS(0xB);
|
||||
std::array<ColorMask, NumRenderTargets> color_mask;
|
||||
INSERT_PADDING_WORDS(0x38);
|
||||
|
||||
INSERT_PADDING_WORDS(0x4B);
|
||||
|
||||
struct {
|
||||
u32 query_address_high;
|
||||
@@ -1012,12 +982,6 @@ public:
|
||||
State state{};
|
||||
MemoryManager& memory_manager;
|
||||
|
||||
struct DirtyFlags {
|
||||
bool vertex_attrib_format = true;
|
||||
};
|
||||
|
||||
DirtyFlags dirty_flags;
|
||||
|
||||
/// Reads a register value located at the input method address
|
||||
u32 GetRegisterValue(u32 method) const;
|
||||
|
||||
@@ -1030,25 +994,12 @@ public:
|
||||
/// Returns the texture information for a specific texture in a specific shader stage.
|
||||
Texture::FullTextureInfo GetStageTexture(Regs::ShaderStage stage, std::size_t offset) const;
|
||||
|
||||
/// Memory for macro code - it's undetermined how big this is, however 1MB is much larger than
|
||||
/// we've seen used.
|
||||
using MacroMemory = std::array<u32, 0x40000>;
|
||||
|
||||
/// Gets a reference to macro memory.
|
||||
const MacroMemory& GetMacroMemory() const {
|
||||
return macro_memory;
|
||||
}
|
||||
|
||||
private:
|
||||
void InitializeRegisterDefaults();
|
||||
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
|
||||
/// Start offsets of each macro in macro_memory
|
||||
std::unordered_map<u32, u32> macro_offsets;
|
||||
|
||||
/// Memory for macro code
|
||||
MacroMemory macro_memory;
|
||||
std::unordered_map<u32, std::vector<u32>> uploaded_macros;
|
||||
|
||||
/// Macro method that is currently being executed / being fed parameters.
|
||||
u32 executing_macro = 0;
|
||||
@@ -1071,12 +1022,9 @@ private:
|
||||
*/
|
||||
void CallMacroMethod(u32 method, std::vector<u32> parameters);
|
||||
|
||||
/// Handles writes to the macro uploading register.
|
||||
/// Handles writes to the macro uploading registers.
|
||||
void ProcessMacroUpload(u32 data);
|
||||
|
||||
/// Handles writes to the macro bind register.
|
||||
void ProcessMacroBind(u32 data);
|
||||
|
||||
/// Handles a write to the CLEAR_BUFFERS register.
|
||||
void ProcessClearBuffers();
|
||||
|
||||
@@ -1110,7 +1058,6 @@ ASSERT_REG_POSITION(scissor_test, 0x380);
|
||||
ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
|
||||
ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
|
||||
ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
|
||||
ASSERT_REG_POSITION(color_mask_common, 0x3E4);
|
||||
ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
|
||||
ASSERT_REG_POSITION(zeta, 0x3F8);
|
||||
ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
|
||||
@@ -1123,10 +1070,6 @@ ASSERT_REG_POSITION(depth_write_enabled, 0x4BA);
|
||||
ASSERT_REG_POSITION(alpha_test_enabled, 0x4BB);
|
||||
ASSERT_REG_POSITION(d3d_cull_mode, 0x4C2);
|
||||
ASSERT_REG_POSITION(depth_test_func, 0x4C3);
|
||||
ASSERT_REG_POSITION(alpha_test_ref, 0x4C4);
|
||||
ASSERT_REG_POSITION(alpha_test_func, 0x4C5);
|
||||
ASSERT_REG_POSITION(draw_tfb_stride, 0x4C6);
|
||||
ASSERT_REG_POSITION(blend_color, 0x4C7);
|
||||
ASSERT_REG_POSITION(blend, 0x4CF);
|
||||
ASSERT_REG_POSITION(stencil_enable, 0x4E0);
|
||||
ASSERT_REG_POSITION(stencil_front_op_fail, 0x4E1);
|
||||
@@ -1157,7 +1100,6 @@ ASSERT_REG_POSITION(instanced_arrays, 0x620);
|
||||
ASSERT_REG_POSITION(cull, 0x646);
|
||||
ASSERT_REG_POSITION(logic_op, 0x671);
|
||||
ASSERT_REG_POSITION(clear_buffers, 0x674);
|
||||
ASSERT_REG_POSITION(color_mask, 0x680);
|
||||
ASSERT_REG_POSITION(query, 0x6C0);
|
||||
ASSERT_REG_POSITION(vertex_array[0], 0x700);
|
||||
ASSERT_REG_POSITION(independent_blend, 0x780);
|
||||
|
||||
@@ -577,10 +577,6 @@ union Instruction {
|
||||
BitField<55, 1, u64> saturate;
|
||||
} fmul32;
|
||||
|
||||
union {
|
||||
BitField<52, 1, u64> generates_cc;
|
||||
} op_32;
|
||||
|
||||
union {
|
||||
BitField<48, 1, u64> is_signed;
|
||||
} shift;
|
||||
@@ -1235,7 +1231,6 @@ union Instruction {
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
BitField<20, 24, s64> smem_imm;
|
||||
BitField<0, 5, ControlCode> flow_control_code;
|
||||
|
||||
Attribute attribute;
|
||||
Sampler sampler;
|
||||
@@ -1663,4 +1658,4 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Tegra::Shader
|
||||
} // namespace Tegra::Shader
|
||||
@@ -11,7 +11,7 @@ namespace Tegra {
|
||||
|
||||
MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d) : maxwell3d(maxwell3d) {}
|
||||
|
||||
void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
|
||||
void MacroInterpreter::Execute(const std::vector<u32>& code, std::vector<u32> parameters) {
|
||||
Reset();
|
||||
registers[1] = parameters[0];
|
||||
this->parameters = std::move(parameters);
|
||||
@@ -19,7 +19,7 @@ void MacroInterpreter::Execute(u32 offset, std::vector<u32> parameters) {
|
||||
// Execute the code until we hit an exit condition.
|
||||
bool keep_executing = true;
|
||||
while (keep_executing) {
|
||||
keep_executing = Step(offset, false);
|
||||
keep_executing = Step(code, false);
|
||||
}
|
||||
|
||||
// Assert the the macro used all the input parameters
|
||||
@@ -37,10 +37,10 @@ void MacroInterpreter::Reset() {
|
||||
next_parameter_index = 1;
|
||||
}
|
||||
|
||||
bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
|
||||
bool MacroInterpreter::Step(const std::vector<u32>& code, bool is_delay_slot) {
|
||||
u32 base_address = pc;
|
||||
|
||||
Opcode opcode = GetOpcode(offset);
|
||||
Opcode opcode = GetOpcode(code);
|
||||
pc += 4;
|
||||
|
||||
// Update the program counter if we were delayed
|
||||
@@ -108,7 +108,7 @@ bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
|
||||
|
||||
delayed_pc = base_address + opcode.GetBranchTarget();
|
||||
// Execute one more instruction due to the delay slot.
|
||||
return Step(offset, true);
|
||||
return Step(code, true);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -121,18 +121,17 @@ bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) {
|
||||
// Exit has a delay slot, execute the next instruction
|
||||
// Note: Executing an exit during a branch delay slot will cause the instruction at the
|
||||
// branch target to be executed before exiting.
|
||||
Step(offset, true);
|
||||
Step(code, true);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const {
|
||||
const auto& macro_memory{maxwell3d.GetMacroMemory()};
|
||||
MacroInterpreter::Opcode MacroInterpreter::GetOpcode(const std::vector<u32>& code) const {
|
||||
ASSERT((pc % sizeof(u32)) == 0);
|
||||
ASSERT((pc + offset) < macro_memory.size() * sizeof(u32));
|
||||
return {macro_memory[offset + pc / sizeof(u32)]};
|
||||
ASSERT(pc < code.size() * sizeof(u32));
|
||||
return {code[pc / sizeof(u32)]};
|
||||
}
|
||||
|
||||
u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const {
|
||||
|
||||
@@ -22,10 +22,10 @@ public:
|
||||
|
||||
/**
|
||||
* Executes the macro code with the specified input parameters.
|
||||
* @param offset Offset to start execution at.
|
||||
* @param parameters The parameters of the macro.
|
||||
* @param code The macro byte code to execute
|
||||
* @param parameters The parameters of the macro
|
||||
*/
|
||||
void Execute(u32 offset, std::vector<u32> parameters);
|
||||
void Execute(const std::vector<u32>& code, std::vector<u32> parameters);
|
||||
|
||||
private:
|
||||
enum class Operation : u32 {
|
||||
@@ -110,11 +110,11 @@ private:
|
||||
/**
|
||||
* Executes a single macro instruction located at the current program counter. Returns whether
|
||||
* the interpreter should keep running.
|
||||
* @param offset Offset to start execution at.
|
||||
* @param code The macro code to execute.
|
||||
* @param is_delay_slot Whether the current step is being executed due to a delay slot in a
|
||||
* previous instruction.
|
||||
*/
|
||||
bool Step(u32 offset, bool is_delay_slot);
|
||||
bool Step(const std::vector<u32>& code, bool is_delay_slot);
|
||||
|
||||
/// Calculates the result of an ALU operation. src_a OP src_b;
|
||||
u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const;
|
||||
@@ -127,7 +127,7 @@ private:
|
||||
bool EvaluateBranchCondition(BranchCondition cond, u32 value) const;
|
||||
|
||||
/// Reads an opcode at the current program counter location.
|
||||
Opcode GetOpcode(u32 offset) const;
|
||||
Opcode GetOpcode(const std::vector<u32>& code) const;
|
||||
|
||||
/// Returns the specified register's value. Register 0 is hardcoded to always return 0.
|
||||
u32 GetRegister(u32 register_id) const;
|
||||
|
||||
@@ -4,21 +4,18 @@
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/memory_manager.h"
|
||||
|
||||
namespace Tegra {
|
||||
|
||||
GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
|
||||
const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)};
|
||||
std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, align);
|
||||
ASSERT(gpu_addr);
|
||||
|
||||
ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
|
||||
|
||||
for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot{PageSlot(*gpu_addr + offset)};
|
||||
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot = PageSlot(*gpu_addr + offset);
|
||||
|
||||
ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
|
||||
|
||||
slot = static_cast<u64>(PageStatus::Allocated);
|
||||
}
|
||||
|
||||
@@ -26,11 +23,10 @@ GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) {
|
||||
}
|
||||
|
||||
GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
|
||||
for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot{PageSlot(gpu_addr + offset)};
|
||||
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot = PageSlot(gpu_addr + offset);
|
||||
|
||||
ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
|
||||
|
||||
slot = static_cast<u64>(PageStatus::Allocated);
|
||||
}
|
||||
|
||||
@@ -38,19 +34,17 @@ GPUVAddr MemoryManager::AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align) {
|
||||
}
|
||||
|
||||
GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
|
||||
const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, PAGE_SIZE, PageStatus::Unmapped)};
|
||||
std::optional<GPUVAddr> gpu_addr = FindFreeBlock(size, PAGE_SIZE);
|
||||
ASSERT(gpu_addr);
|
||||
|
||||
ASSERT_MSG(gpu_addr, "unable to find available GPU memory");
|
||||
|
||||
for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot{PageSlot(*gpu_addr + offset)};
|
||||
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot = PageSlot(*gpu_addr + offset);
|
||||
|
||||
ASSERT(slot == static_cast<u64>(PageStatus::Unmapped));
|
||||
|
||||
slot = cpu_addr + offset;
|
||||
}
|
||||
|
||||
const MappedRegion region{cpu_addr, *gpu_addr, size};
|
||||
MappedRegion region{cpu_addr, *gpu_addr, size};
|
||||
mapped_regions.push_back(region);
|
||||
|
||||
return *gpu_addr;
|
||||
@@ -59,31 +53,14 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, u64 size) {
|
||||
GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size) {
|
||||
ASSERT((gpu_addr & PAGE_MASK) == 0);
|
||||
|
||||
if (PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Allocated)) {
|
||||
// Page has been already mapped. In this case, we must find a new area of memory to use that
|
||||
// is different than the specified one. Super Mario Odyssey hits this scenario when changing
|
||||
// areas, but we do not want to overwrite the old pages.
|
||||
// TODO(bunnei): We need to write a hardware test to confirm this behavior.
|
||||
|
||||
LOG_ERROR(HW_GPU, "attempting to map addr 0x{:016X}, which is not available!", gpu_addr);
|
||||
|
||||
const std::optional<GPUVAddr> new_gpu_addr{
|
||||
FindFreeBlock(gpu_addr, size, PAGE_SIZE, PageStatus::Allocated)};
|
||||
|
||||
ASSERT_MSG(new_gpu_addr, "unable to find available GPU memory");
|
||||
|
||||
gpu_addr = *new_gpu_addr;
|
||||
}
|
||||
|
||||
for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot{PageSlot(gpu_addr + offset)};
|
||||
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot = PageSlot(gpu_addr + offset);
|
||||
|
||||
ASSERT(slot == static_cast<u64>(PageStatus::Allocated));
|
||||
|
||||
slot = cpu_addr + offset;
|
||||
}
|
||||
|
||||
const MappedRegion region{cpu_addr, gpu_addr, size};
|
||||
MappedRegion region{cpu_addr, gpu_addr, size};
|
||||
mapped_regions.push_back(region);
|
||||
|
||||
return gpu_addr;
|
||||
@@ -92,12 +69,11 @@ GPUVAddr MemoryManager::MapBufferEx(VAddr cpu_addr, GPUVAddr gpu_addr, u64 size)
|
||||
GPUVAddr MemoryManager::UnmapBuffer(GPUVAddr gpu_addr, u64 size) {
|
||||
ASSERT((gpu_addr & PAGE_MASK) == 0);
|
||||
|
||||
for (u64 offset{}; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot{PageSlot(gpu_addr + offset)};
|
||||
for (u64 offset = 0; offset < size; offset += PAGE_SIZE) {
|
||||
VAddr& slot = PageSlot(gpu_addr + offset);
|
||||
|
||||
ASSERT(slot != static_cast<u64>(PageStatus::Allocated) &&
|
||||
slot != static_cast<u64>(PageStatus::Unmapped));
|
||||
|
||||
slot = static_cast<u64>(PageStatus::Unmapped);
|
||||
}
|
||||
|
||||
@@ -121,14 +97,13 @@ GPUVAddr MemoryManager::GetRegionEnd(GPUVAddr region_start) const {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::optional<GPUVAddr> MemoryManager::FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
|
||||
PageStatus status) {
|
||||
GPUVAddr gpu_addr{region_start};
|
||||
u64 free_space{};
|
||||
std::optional<GPUVAddr> MemoryManager::FindFreeBlock(u64 size, u64 align) {
|
||||
GPUVAddr gpu_addr = 0;
|
||||
u64 free_space = 0;
|
||||
align = (align + PAGE_MASK) & ~PAGE_MASK;
|
||||
|
||||
while (gpu_addr + free_space < MAX_ADDRESS) {
|
||||
if (PageSlot(gpu_addr + free_space) == static_cast<u64>(status)) {
|
||||
if (!IsPageMapped(gpu_addr + free_space)) {
|
||||
free_space += PAGE_SIZE;
|
||||
if (free_space >= size) {
|
||||
return gpu_addr;
|
||||
@@ -144,7 +119,7 @@ std::optional<GPUVAddr> MemoryManager::FindFreeBlock(GPUVAddr region_start, u64
|
||||
}
|
||||
|
||||
std::optional<VAddr> MemoryManager::GpuToCpuAddress(GPUVAddr gpu_addr) {
|
||||
const VAddr base_addr{PageSlot(gpu_addr)};
|
||||
VAddr base_addr = PageSlot(gpu_addr);
|
||||
|
||||
if (base_addr == static_cast<u64>(PageStatus::Allocated) ||
|
||||
base_addr == static_cast<u64>(PageStatus::Unmapped)) {
|
||||
@@ -158,15 +133,19 @@ std::vector<GPUVAddr> MemoryManager::CpuToGpuAddress(VAddr cpu_addr) const {
|
||||
std::vector<GPUVAddr> results;
|
||||
for (const auto& region : mapped_regions) {
|
||||
if (cpu_addr >= region.cpu_addr && cpu_addr < (region.cpu_addr + region.size)) {
|
||||
const u64 offset{cpu_addr - region.cpu_addr};
|
||||
u64 offset = cpu_addr - region.cpu_addr;
|
||||
results.push_back(region.gpu_addr + offset);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
bool MemoryManager::IsPageMapped(GPUVAddr gpu_addr) {
|
||||
return PageSlot(gpu_addr) != static_cast<u64>(PageStatus::Unmapped);
|
||||
}
|
||||
|
||||
VAddr& MemoryManager::PageSlot(GPUVAddr gpu_addr) {
|
||||
auto& block{page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK]};
|
||||
auto& block = page_table[(gpu_addr >> (PAGE_BITS + PAGE_TABLE_BITS)) & PAGE_TABLE_MASK];
|
||||
if (!block) {
|
||||
block = std::make_unique<PageBlock>();
|
||||
block->fill(static_cast<VAddr>(PageStatus::Unmapped));
|
||||
|
||||
@@ -34,15 +34,15 @@ public:
|
||||
static constexpr u64 PAGE_MASK = PAGE_SIZE - 1;
|
||||
|
||||
private:
|
||||
std::optional<GPUVAddr> FindFreeBlock(u64 size, u64 align = 1);
|
||||
bool IsPageMapped(GPUVAddr gpu_addr);
|
||||
VAddr& PageSlot(GPUVAddr gpu_addr);
|
||||
|
||||
enum class PageStatus : u64 {
|
||||
Unmapped = 0xFFFFFFFFFFFFFFFFULL,
|
||||
Allocated = 0xFFFFFFFFFFFFFFFEULL,
|
||||
};
|
||||
|
||||
std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align,
|
||||
PageStatus status);
|
||||
VAddr& PageSlot(GPUVAddr gpu_addr);
|
||||
|
||||
static constexpr u64 MAX_ADDRESS{0x10000000000ULL};
|
||||
static constexpr u64 PAGE_TABLE_BITS{10};
|
||||
static constexpr u64 PAGE_TABLE_SIZE{1 << PAGE_TABLE_BITS};
|
||||
|
||||
@@ -1,7 +0,0 @@
|
||||
// Copyright 2018 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "video_core/rasterizer_cache.h"
|
||||
|
||||
RasterizerCacheObject::~RasterizerCacheObject() = default;
|
||||
@@ -10,13 +10,13 @@
|
||||
#include <boost/range/iterator_range_core.hpp>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/rasterizer_interface.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
|
||||
class RasterizerCacheObject {
|
||||
public:
|
||||
virtual ~RasterizerCacheObject();
|
||||
|
||||
/// Gets the address of the shader in guest memory, required for cache management
|
||||
virtual VAddr GetAddr() const = 0;
|
||||
|
||||
@@ -64,8 +64,6 @@ class RasterizerCache : NonCopyable {
|
||||
friend class RasterizerCacheObject;
|
||||
|
||||
public:
|
||||
explicit RasterizerCache(VideoCore::RasterizerInterface& rasterizer) : rasterizer{rasterizer} {}
|
||||
|
||||
/// Write any cached resources overlapping the specified region back to memory
|
||||
void FlushRegion(Tegra::GPUVAddr addr, size_t size) {
|
||||
const auto& objects{GetSortedObjectsFromRegion(addr, size)};
|
||||
@@ -111,12 +109,14 @@ protected:
|
||||
void Register(const T& object) {
|
||||
object->SetIsRegistered(true);
|
||||
object_cache.add({GetInterval(object), ObjectSet{object}});
|
||||
auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
|
||||
rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), 1);
|
||||
}
|
||||
|
||||
/// Unregisters an object from the cache
|
||||
void Unregister(const T& object) {
|
||||
object->SetIsRegistered(false);
|
||||
auto& rasterizer = Core::System::GetInstance().Renderer().Rasterizer();
|
||||
rasterizer.UpdatePagesCachedCount(object->GetAddr(), object->GetSizeInBytes(), -1);
|
||||
|
||||
// Only flush if use_accurate_gpu_emulation is enabled, as it incurs a performance hit
|
||||
@@ -177,5 +177,4 @@ private:
|
||||
|
||||
ObjectCache object_cache; ///< Cache of objects
|
||||
u64 modified_ticks{}; ///< Counter of cache state ticks, used for in-order flushing
|
||||
VideoCore::RasterizerInterface& rasterizer;
|
||||
};
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "core/frontend/emu_window.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
|
||||
namespace VideoCore {
|
||||
|
||||
|
||||
@@ -9,12 +9,10 @@
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size)
|
||||
: RasterizerCache{rasterizer}, stream_buffer(GL_ARRAY_BUFFER, size) {}
|
||||
OGLBufferCache::OGLBufferCache(std::size_t size) : stream_buffer(GL_ARRAY_BUFFER, size) {}
|
||||
|
||||
GLintptr OGLBufferCache::UploadMemory(Tegra::GPUVAddr gpu_addr, std::size_t size,
|
||||
std::size_t alignment, bool cache) {
|
||||
|
||||
@@ -15,8 +15,6 @@
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class RasterizerOpenGL;
|
||||
|
||||
struct CachedBufferEntry final : public RasterizerCacheObject {
|
||||
VAddr GetAddr() const override {
|
||||
return addr;
|
||||
@@ -37,7 +35,7 @@ struct CachedBufferEntry final : public RasterizerCacheObject {
|
||||
|
||||
class OGLBufferCache final : public RasterizerCache<std::shared_ptr<CachedBufferEntry>> {
|
||||
public:
|
||||
explicit OGLBufferCache(RasterizerOpenGL& rasterizer, std::size_t size);
|
||||
explicit OGLBufferCache(std::size_t size);
|
||||
|
||||
/// Uploads data from a guest GPU address. Returns host's buffer offset where it's been
|
||||
/// allocated.
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
#include <array>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_primitive_assembler.h"
|
||||
|
||||
@@ -30,11 +30,10 @@
|
||||
namespace OpenGL {
|
||||
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
using PixelFormat = VideoCore::Surface::PixelFormat;
|
||||
using SurfaceType = VideoCore::Surface::SurfaceType;
|
||||
using PixelFormat = SurfaceParams::PixelFormat;
|
||||
using SurfaceType = SurfaceParams::SurfaceType;
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Format Setup", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_VB, "OpenGL", "Vertex Buffer Setup", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_VAO, "OpenGL", "Vertex Array Setup", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_Shader, "OpenGL", "Shader Setup", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_UBO, "OpenGL", "Const Buffer Setup", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_Index, "OpenGL", "Index Buffer Setup", MP_RGB(128, 128, 192));
|
||||
@@ -80,8 +79,7 @@ struct DrawParameters {
|
||||
};
|
||||
|
||||
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo& info)
|
||||
: res_cache{*this}, shader_cache{*this}, emu_window{window}, screen_info{info},
|
||||
buffer_cache(*this, STREAM_BUFFER_SIZE) {
|
||||
: emu_window{window}, screen_info{info}, buffer_cache(STREAM_BUFFER_SIZE) {
|
||||
// Create sampler objects
|
||||
for (std::size_t i = 0; i < texture_samplers.size(); ++i) {
|
||||
texture_samplers[i].Create();
|
||||
@@ -106,7 +104,7 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||
}
|
||||
|
||||
ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported");
|
||||
OpenGLState::ApplyDefaultState();
|
||||
|
||||
// Clipping plane 0 is always enabled for PICA fixed clip plane z <= 0
|
||||
state.clip_distance[0] = true;
|
||||
|
||||
@@ -117,6 +115,8 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||
state.draw.shader_program = 0;
|
||||
state.Apply();
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment);
|
||||
|
||||
LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!");
|
||||
@@ -124,15 +124,10 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo
|
||||
|
||||
RasterizerOpenGL::~RasterizerOpenGL() {}
|
||||
|
||||
void RasterizerOpenGL::SetupVertexFormat() {
|
||||
auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
|
||||
const auto& regs = gpu.regs;
|
||||
|
||||
if (!gpu.dirty_flags.vertex_attrib_format)
|
||||
return;
|
||||
gpu.dirty_flags.vertex_attrib_format = false;
|
||||
|
||||
void RasterizerOpenGL::SetupVertexArrays() {
|
||||
MICROPROFILE_SCOPE(OpenGL_VAO);
|
||||
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
|
||||
const auto& regs = gpu.regs;
|
||||
|
||||
auto [iter, is_cache_miss] = vertex_array_cache.try_emplace(regs.vertex_attrib_format);
|
||||
auto& VAO = iter->second;
|
||||
@@ -140,7 +135,7 @@ void RasterizerOpenGL::SetupVertexFormat() {
|
||||
if (is_cache_miss) {
|
||||
VAO.Create();
|
||||
state.draw.vertex_array = VAO.handle;
|
||||
state.ApplyVertexBufferState();
|
||||
state.Apply();
|
||||
|
||||
// The index buffer binding is stored within the VAO. Stupid OpenGL, but easy to work
|
||||
// around.
|
||||
@@ -182,13 +177,8 @@ void RasterizerOpenGL::SetupVertexFormat() {
|
||||
}
|
||||
}
|
||||
state.draw.vertex_array = VAO.handle;
|
||||
state.ApplyVertexBufferState();
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SetupVertexBuffer() {
|
||||
MICROPROFILE_SCOPE(OpenGL_VB);
|
||||
const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D();
|
||||
const auto& regs = gpu.regs;
|
||||
state.draw.vertex_buffer = buffer_cache.GetHandle();
|
||||
state.Apply();
|
||||
|
||||
// Upload all guest vertex arrays sequentially to our buffer
|
||||
for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) {
|
||||
@@ -215,9 +205,6 @@ void RasterizerOpenGL::SetupVertexBuffer() {
|
||||
glVertexBindingDivisor(index, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// Implicit set by glBindVertexBuffer. Stupid glstate handling...
|
||||
state.draw.vertex_buffer = buffer_cache.GetHandle();
|
||||
}
|
||||
|
||||
DrawParameters RasterizerOpenGL::SetupDraw() {
|
||||
@@ -342,6 +329,8 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
std::size_t RasterizerOpenGL::CalculateVertexArraysSize() const {
|
||||
@@ -410,8 +399,8 @@ void RasterizerOpenGL::UpdatePagesCachedCount(VAddr addr, u64 size, int delta) {
|
||||
cached_pages.add({pages_interval, delta});
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool using_color_fb,
|
||||
bool using_depth_fb, bool preserve_contents,
|
||||
void RasterizerOpenGL::ConfigureFramebuffers(bool using_color_fb, bool using_depth_fb,
|
||||
bool preserve_contents,
|
||||
std::optional<std::size_t> single_color_target) {
|
||||
MICROPROFILE_SCOPE(OpenGL_Framebuffer);
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
@@ -427,9 +416,9 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
|
||||
ASSERT_MSG(regs.rt_separate_frag_data == 0, "Unimplemented");
|
||||
|
||||
// Bind the framebuffer surfaces
|
||||
current_state.draw.draw_framebuffer = framebuffer.handle;
|
||||
current_state.ApplyFramebufferState();
|
||||
current_state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
|
||||
state.draw.draw_framebuffer = framebuffer.handle;
|
||||
state.Apply();
|
||||
state.framebuffer_srgb.enabled = regs.framebuffer_srgb != 0;
|
||||
|
||||
if (using_color_fb) {
|
||||
if (single_color_target) {
|
||||
@@ -507,7 +496,10 @@ void RasterizerOpenGL::ConfigureFramebuffers(OpenGLState& current_state, bool us
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D, 0,
|
||||
0);
|
||||
}
|
||||
SyncViewport(current_state);
|
||||
|
||||
SyncViewport();
|
||||
|
||||
state.Apply();
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::Clear() {
|
||||
@@ -520,23 +512,22 @@ void RasterizerOpenGL::Clear() {
|
||||
bool use_stencil{};
|
||||
|
||||
OpenGLState clear_state;
|
||||
clear_state.draw.draw_framebuffer = framebuffer.handle;
|
||||
clear_state.color_mask.red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask.green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask.blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask.alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
|
||||
|
||||
if (regs.clear_buffers.R || regs.clear_buffers.G || regs.clear_buffers.B ||
|
||||
regs.clear_buffers.A) {
|
||||
use_color = true;
|
||||
}
|
||||
if (use_color) {
|
||||
clear_state.color_mask[0].red_enabled = regs.clear_buffers.R ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask[0].green_enabled = regs.clear_buffers.G ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask[0].blue_enabled = regs.clear_buffers.B ? GL_TRUE : GL_FALSE;
|
||||
clear_state.color_mask[0].alpha_enabled = regs.clear_buffers.A ? GL_TRUE : GL_FALSE;
|
||||
}
|
||||
if (regs.clear_buffers.Z) {
|
||||
ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear Z but buffer is not enabled!");
|
||||
use_depth = true;
|
||||
|
||||
// Always enable the depth write when clearing the depth buffer. The depth write mask is
|
||||
// ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to
|
||||
// true.
|
||||
// ignored when clearing the buffer in the Switch, but OpenGL obeys it so we set it to true.
|
||||
clear_state.depth.test_enabled = true;
|
||||
clear_state.depth.test_func = GL_ALWAYS;
|
||||
}
|
||||
@@ -553,8 +544,11 @@ void RasterizerOpenGL::Clear() {
|
||||
|
||||
ScopeAcquireGLContext acquire_context{emu_window};
|
||||
|
||||
ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false,
|
||||
ConfigureFramebuffers(use_color, use_depth || use_stencil, false,
|
||||
regs.clear_buffers.RT.Value());
|
||||
// Copy the sRGB setting to the clear state to avoid problem with
|
||||
// specific driver implementations
|
||||
clear_state.framebuffer_srgb.enabled = state.framebuffer_srgb.enabled;
|
||||
clear_state.Apply();
|
||||
|
||||
if (use_color) {
|
||||
@@ -580,14 +574,15 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
|
||||
ScopeAcquireGLContext acquire_context{emu_window};
|
||||
|
||||
ConfigureFramebuffers(state);
|
||||
SyncColorMask();
|
||||
ConfigureFramebuffers();
|
||||
|
||||
SyncDepthTestState();
|
||||
SyncStencilTestState();
|
||||
SyncBlendState();
|
||||
SyncLogicOpState();
|
||||
SyncCullMode();
|
||||
SyncPrimitiveRestart();
|
||||
SyncDepthRange();
|
||||
SyncScissorTest();
|
||||
// Alpha Testing is synced on shaders.
|
||||
SyncTransformFeedback();
|
||||
@@ -601,7 +596,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
const bool is_indexed = accelerate_draw == AccelDraw::Indexed;
|
||||
|
||||
state.draw.vertex_buffer = buffer_cache.GetHandle();
|
||||
state.ApplyVertexBufferState();
|
||||
state.Apply();
|
||||
|
||||
std::size_t buffer_size = CalculateVertexArraysSize();
|
||||
|
||||
@@ -628,8 +623,7 @@ void RasterizerOpenGL::DrawArrays() {
|
||||
|
||||
buffer_cache.Map(buffer_size);
|
||||
|
||||
SetupVertexFormat();
|
||||
SetupVertexBuffer();
|
||||
SetupVertexArrays();
|
||||
DrawParameters params = SetupDraw();
|
||||
SetupShaders(params.primitive_mode);
|
||||
|
||||
@@ -709,8 +703,7 @@ bool RasterizerOpenGL::AccelerateDisplay(const Tegra::FramebufferConfig& config,
|
||||
|
||||
// Verify that the cached surface is the same size and format as the requested framebuffer
|
||||
const auto& params{surface->GetSurfaceParams()};
|
||||
const auto& pixel_format{
|
||||
VideoCore::Surface::PixelFormatFromGPUPixelFormat(config.pixel_format)};
|
||||
const auto& pixel_format{SurfaceParams::PixelFormatFromGPUPixelFormat(config.pixel_format)};
|
||||
ASSERT_MSG(params.width == config.width, "Framebuffer width is different");
|
||||
ASSERT_MSG(params.height == config.height, "Framebuffer height is different");
|
||||
ASSERT_MSG(params.pixel_format == pixel_format, "Framebuffer pixel_format is different");
|
||||
@@ -733,9 +726,9 @@ void RasterizerOpenGL::SamplerInfo::Create() {
|
||||
glSamplerParameteri(sampler.handle, GL_TEXTURE_COMPARE_FUNC, GL_NEVER);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTextureInfo& info) {
|
||||
void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntry& config) {
|
||||
const GLuint s = sampler.handle;
|
||||
const Tegra::Texture::TSCEntry& config = info.tsc;
|
||||
|
||||
if (mag_filter != config.mag_filter) {
|
||||
mag_filter = config.mag_filter;
|
||||
glSamplerParameteri(
|
||||
@@ -786,22 +779,6 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::FullTex
|
||||
glSamplerParameterfv(s, GL_TEXTURE_BORDER_COLOR, border_color.data());
|
||||
}
|
||||
}
|
||||
if (info.tic.use_header_opt_control == 0) {
|
||||
if (GLAD_GL_ARB_texture_filter_anisotropic) {
|
||||
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY,
|
||||
static_cast<float>(1 << info.tic.max_anisotropy.Value()));
|
||||
} else if (GLAD_GL_EXT_texture_filter_anisotropic) {
|
||||
glSamplerParameterf(s, GL_TEXTURE_MAX_ANISOTROPY_EXT,
|
||||
static_cast<float>(1 << info.tic.max_anisotropy.Value()));
|
||||
}
|
||||
glSamplerParameterf(s, GL_TEXTURE_MIN_LOD,
|
||||
static_cast<float>(info.tic.res_min_mip_level.Value()));
|
||||
glSamplerParameterf(s, GL_TEXTURE_MAX_LOD,
|
||||
static_cast<float>(info.tic.res_max_mip_level.Value() == 0
|
||||
? 16
|
||||
: info.tic.res_max_mip_level.Value()));
|
||||
glSamplerParameterf(s, GL_TEXTURE_LOD_BIAS, info.tic.mip_lod_bias.Value() / 256.f);
|
||||
}
|
||||
}
|
||||
|
||||
u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, Shader& shader,
|
||||
@@ -899,7 +876,7 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||
continue;
|
||||
}
|
||||
|
||||
texture_samplers[current_bindpoint].SyncWithConfig(texture);
|
||||
texture_samplers[current_bindpoint].SyncWithConfig(texture.tsc);
|
||||
Surface surface = res_cache.GetTextureSurface(texture, entry);
|
||||
if (surface != nullptr) {
|
||||
state.texture_units[current_bindpoint].texture = surface->Texture().handle;
|
||||
@@ -921,18 +898,14 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader,
|
||||
return current_unit + static_cast<u32>(entries.size());
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) {
|
||||
void RasterizerOpenGL::SyncViewport() {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()};
|
||||
auto& viewport = current_state.viewports[i];
|
||||
viewport.x = viewport_rect.left;
|
||||
viewport.y = viewport_rect.bottom;
|
||||
viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth());
|
||||
viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight());
|
||||
viewport.depth_range_far = regs.viewport[i].depth_range_far;
|
||||
viewport.depth_range_near = regs.viewport[i].depth_range_near;
|
||||
}
|
||||
const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()};
|
||||
|
||||
state.viewport.x = viewport_rect.left;
|
||||
state.viewport.y = viewport_rect.bottom;
|
||||
state.viewport.width = static_cast<GLsizei>(viewport_rect.GetWidth());
|
||||
state.viewport.height = static_cast<GLsizei>(viewport_rect.GetHeight());
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncClipEnabled() {
|
||||
@@ -974,6 +947,13 @@ void RasterizerOpenGL::SyncPrimitiveRestart() {
|
||||
state.primitive_restart.index = regs.primitive_restart.index;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncDepthRange() {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
|
||||
state.depth.depth_range_near = regs.viewport->depth_range_near;
|
||||
state.depth.depth_range_far = regs.viewport->depth_range_far;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncDepthTestState() {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
|
||||
@@ -994,6 +974,9 @@ void RasterizerOpenGL::SyncStencilTestState() {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO(bunnei): Verify behavior when this is not set
|
||||
ASSERT(regs.stencil_two_side_enable);
|
||||
|
||||
state.stencil.front.test_func = MaxwellToGL::ComparisonOp(regs.stencil_front_func_func);
|
||||
state.stencil.front.test_ref = regs.stencil_front_func_ref;
|
||||
state.stencil.front.test_mask = regs.stencil_front_func_mask;
|
||||
@@ -1001,79 +984,36 @@ void RasterizerOpenGL::SyncStencilTestState() {
|
||||
state.stencil.front.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_front_op_zfail);
|
||||
state.stencil.front.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_front_op_zpass);
|
||||
state.stencil.front.write_mask = regs.stencil_front_mask;
|
||||
if (regs.stencil_two_side_enable) {
|
||||
state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func);
|
||||
state.stencil.back.test_ref = regs.stencil_back_func_ref;
|
||||
state.stencil.back.test_mask = regs.stencil_back_func_mask;
|
||||
state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail);
|
||||
state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail);
|
||||
state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass);
|
||||
state.stencil.back.write_mask = regs.stencil_back_mask;
|
||||
} else {
|
||||
state.stencil.back.test_func = GL_ALWAYS;
|
||||
state.stencil.back.test_ref = 0;
|
||||
state.stencil.back.test_mask = 0xFFFFFFFF;
|
||||
state.stencil.back.write_mask = 0xFFFFFFFF;
|
||||
state.stencil.back.action_stencil_fail = GL_KEEP;
|
||||
state.stencil.back.action_depth_fail = GL_KEEP;
|
||||
state.stencil.back.action_depth_pass = GL_KEEP;
|
||||
}
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncColorMask() {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||
const auto& source = regs.color_mask[regs.color_mask_common ? 0 : i];
|
||||
auto& dest = state.color_mask[i];
|
||||
dest.red_enabled = (source.R == 0) ? GL_FALSE : GL_TRUE;
|
||||
dest.green_enabled = (source.G == 0) ? GL_FALSE : GL_TRUE;
|
||||
dest.blue_enabled = (source.B == 0) ? GL_FALSE : GL_TRUE;
|
||||
dest.alpha_enabled = (source.A == 0) ? GL_FALSE : GL_TRUE;
|
||||
}
|
||||
state.stencil.back.test_func = MaxwellToGL::ComparisonOp(regs.stencil_back_func_func);
|
||||
state.stencil.back.test_ref = regs.stencil_back_func_ref;
|
||||
state.stencil.back.test_mask = regs.stencil_back_func_mask;
|
||||
state.stencil.back.action_stencil_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_fail);
|
||||
state.stencil.back.action_depth_fail = MaxwellToGL::StencilOp(regs.stencil_back_op_zfail);
|
||||
state.stencil.back.action_depth_pass = MaxwellToGL::StencilOp(regs.stencil_back_op_zpass);
|
||||
state.stencil.back.write_mask = regs.stencil_back_mask;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncBlendState() {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
|
||||
state.blend_color.red = regs.blend_color.r;
|
||||
state.blend_color.green = regs.blend_color.g;
|
||||
state.blend_color.blue = regs.blend_color.b;
|
||||
state.blend_color.alpha = regs.blend_color.a;
|
||||
// TODO(Subv): Support more than just render target 0.
|
||||
state.blend.enabled = regs.blend.enable[0] != 0;
|
||||
|
||||
state.independant_blend.enabled = regs.independent_blend_enable;
|
||||
if (!state.independant_blend.enabled) {
|
||||
auto& blend = state.blend[0];
|
||||
blend.enabled = regs.blend.enable[0] != 0;
|
||||
blend.separate_alpha = regs.blend.separate_alpha;
|
||||
blend.rgb_equation = MaxwellToGL::BlendEquation(regs.blend.equation_rgb);
|
||||
blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_rgb);
|
||||
blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_rgb);
|
||||
if (blend.separate_alpha) {
|
||||
blend.a_equation = MaxwellToGL::BlendEquation(regs.blend.equation_a);
|
||||
blend.src_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_source_a);
|
||||
blend.dst_a_func = MaxwellToGL::BlendFunc(regs.blend.factor_dest_a);
|
||||
}
|
||||
for (size_t i = 1; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||
state.blend[i].enabled = false;
|
||||
}
|
||||
if (!state.blend.enabled)
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||
auto& blend = state.blend[i];
|
||||
blend.enabled = regs.blend.enable[i] != 0;
|
||||
if (!blend.enabled)
|
||||
continue;
|
||||
blend.separate_alpha = regs.independent_blend[i].separate_alpha;
|
||||
blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_rgb);
|
||||
blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_rgb);
|
||||
blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_rgb);
|
||||
if (blend.separate_alpha) {
|
||||
blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[i].equation_a);
|
||||
blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_source_a);
|
||||
blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[i].factor_dest_a);
|
||||
}
|
||||
}
|
||||
ASSERT_MSG(regs.logic_op.enable == 0,
|
||||
"Blending and logic op can't be enabled at the same time.");
|
||||
|
||||
ASSERT_MSG(regs.independent_blend_enable == 1, "Only independent blending is implemented");
|
||||
ASSERT_MSG(!regs.independent_blend[0].separate_alpha, "Unimplemented");
|
||||
state.blend.rgb_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_rgb);
|
||||
state.blend.src_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_rgb);
|
||||
state.blend.dst_rgb_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_rgb);
|
||||
state.blend.a_equation = MaxwellToGL::BlendEquation(regs.independent_blend[0].equation_a);
|
||||
state.blend.src_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_source_a);
|
||||
state.blend.dst_a_func = MaxwellToGL::BlendFunc(regs.independent_blend[0].factor_dest_a);
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncLogicOpState() {
|
||||
@@ -1092,19 +1032,19 @@ void RasterizerOpenGL::SyncLogicOpState() {
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncScissorTest() {
|
||||
// TODO: what is the correct behavior here, a single scissor for all targets
|
||||
// or scissor disabled for the rest of the targets?
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
|
||||
state.scissor.enabled = (regs.scissor_test.enable != 0);
|
||||
if (regs.scissor_test.enable == 0) {
|
||||
return;
|
||||
// TODO(Blinkhawk): Figure if the hardware supports scissor testing per viewport and how it's
|
||||
// implemented.
|
||||
if (regs.scissor_test.enable != 0) {
|
||||
const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
|
||||
const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
|
||||
state.scissor.x = regs.scissor_test.min_x;
|
||||
state.scissor.y = regs.scissor_test.min_y;
|
||||
state.scissor.width = width;
|
||||
state.scissor.height = height;
|
||||
}
|
||||
const u32 width = regs.scissor_test.max_x - regs.scissor_test.min_x;
|
||||
const u32 height = regs.scissor_test.max_y - regs.scissor_test.min_y;
|
||||
state.scissor.x = regs.scissor_test.min_x;
|
||||
state.scissor.y = regs.scissor_test.min_y;
|
||||
state.scissor.width = width;
|
||||
state.scissor.height = height;
|
||||
}
|
||||
|
||||
void RasterizerOpenGL::SyncTransformFeedback() {
|
||||
@@ -1129,8 +1069,9 @@ void RasterizerOpenGL::CheckAlphaTests() {
|
||||
const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
|
||||
|
||||
if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) {
|
||||
LOG_CRITICAL(Render_OpenGL, "Alpha Testing is enabled with Multiple Render Targets, "
|
||||
"this behavior is undefined.");
|
||||
LOG_CRITICAL(
|
||||
Render_OpenGL,
|
||||
"Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined.");
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,7 +88,7 @@ private:
|
||||
/// SamplerInfo struct.
|
||||
void Create();
|
||||
/// Syncs the sampler object with the config, updating any necessary state.
|
||||
void SyncWithConfig(const Tegra::Texture::FullTextureInfo& info);
|
||||
void SyncWithConfig(const Tegra::Texture::TSCEntry& config);
|
||||
|
||||
private:
|
||||
Tegra::Texture::TextureFilter mag_filter;
|
||||
@@ -109,8 +109,8 @@ private:
|
||||
* @param preserve_contents If true, tries to preserve data from a previously used framebuffer.
|
||||
* @param single_color_target Specifies if a single color buffer target should be used.
|
||||
*/
|
||||
void ConfigureFramebuffers(OpenGLState& current_state, bool use_color_fb = true,
|
||||
bool using_depth_fb = true, bool preserve_contents = true,
|
||||
void ConfigureFramebuffers(bool use_color_fb = true, bool using_depth_fb = true,
|
||||
bool preserve_contents = true,
|
||||
std::optional<std::size_t> single_color_target = {});
|
||||
|
||||
/*
|
||||
@@ -133,8 +133,8 @@ private:
|
||||
u32 SetupTextures(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, Shader& shader,
|
||||
GLenum primitive_mode, u32 current_unit);
|
||||
|
||||
/// Syncs the viewport and depth range to match the guest state
|
||||
void SyncViewport(OpenGLState& current_state);
|
||||
/// Syncs the viewport to match the guest state
|
||||
void SyncViewport();
|
||||
|
||||
/// Syncs the clip enabled status to match the guest state
|
||||
void SyncClipEnabled();
|
||||
@@ -148,6 +148,9 @@ private:
|
||||
/// Syncs the primitve restart to match the guest state
|
||||
void SyncPrimitiveRestart();
|
||||
|
||||
/// Syncs the depth range to match the guest state
|
||||
void SyncDepthRange();
|
||||
|
||||
/// Syncs the depth test state to match the guest state
|
||||
void SyncDepthTestState();
|
||||
|
||||
@@ -169,9 +172,6 @@ private:
|
||||
/// Syncs the point state to match the guest state
|
||||
void SyncPointState();
|
||||
|
||||
/// Syncs Color Mask
|
||||
void SyncColorMask();
|
||||
|
||||
/// Check asserts for alpha testing.
|
||||
void CheckAlphaTests();
|
||||
|
||||
@@ -207,8 +207,7 @@ private:
|
||||
|
||||
std::size_t CalculateIndexBufferSize() const;
|
||||
|
||||
void SetupVertexFormat();
|
||||
void SetupVertexBuffer();
|
||||
void SetupVertexArrays();
|
||||
|
||||
DrawParameters SetupDraw();
|
||||
|
||||
|
||||
@@ -15,24 +15,17 @@
|
||||
#include "core/memory.h"
|
||||
#include "core/settings.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/utils.h"
|
||||
#include "video_core/surface.h"
|
||||
#include "video_core/textures/astc.h"
|
||||
#include "video_core/textures/decoders.h"
|
||||
#include "video_core/utils.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
using VideoCore::Surface::ComponentTypeFromDepthFormat;
|
||||
using VideoCore::Surface::ComponentTypeFromRenderTarget;
|
||||
using VideoCore::Surface::ComponentTypeFromTexture;
|
||||
using VideoCore::Surface::PixelFormatFromDepthFormat;
|
||||
using VideoCore::Surface::PixelFormatFromRenderTargetFormat;
|
||||
using VideoCore::Surface::PixelFormatFromTextureFormat;
|
||||
using VideoCore::Surface::SurfaceTargetFromTextureType;
|
||||
using SurfaceType = SurfaceParams::SurfaceType;
|
||||
using PixelFormat = SurfaceParams::PixelFormat;
|
||||
using ComponentType = SurfaceParams::ComponentType;
|
||||
|
||||
struct FormatTuple {
|
||||
GLint internal_format;
|
||||
@@ -42,6 +35,46 @@ struct FormatTuple {
|
||||
bool compressed;
|
||||
};
|
||||
|
||||
static bool IsPixelFormatASTC(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::ASTC_2D_4X4:
|
||||
case PixelFormat::ASTC_2D_5X4:
|
||||
case PixelFormat::ASTC_2D_8X8:
|
||||
case PixelFormat::ASTC_2D_8X5:
|
||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::ASTC_2D_4X4:
|
||||
return {4, 4};
|
||||
case PixelFormat::ASTC_2D_5X4:
|
||||
return {5, 4};
|
||||
case PixelFormat::ASTC_2D_8X8:
|
||||
return {8, 8};
|
||||
case PixelFormat::ASTC_2D_8X5:
|
||||
return {8, 5};
|
||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||
return {4, 4};
|
||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||
return {5, 4};
|
||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||
return {8, 8};
|
||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||
return {8, 5};
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled format: {}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
|
||||
auto& memory_manager{Core::System::GetInstance().GPU().MemoryManager()};
|
||||
const auto cpu_addr{memory_manager.GpuToCpuAddress(gpu_addr_)};
|
||||
@@ -60,14 +93,16 @@ void SurfaceParams::InitCacheParameters(Tegra::GPUVAddr gpu_addr_) {
|
||||
|
||||
std::size_t SurfaceParams::InnerMipmapMemorySize(u32 mip_level, bool force_gl, bool layer_only,
|
||||
bool uncompressed) const {
|
||||
const u32 tile_x{GetDefaultBlockWidth(pixel_format)};
|
||||
const u32 tile_y{GetDefaultBlockHeight(pixel_format)};
|
||||
const u32 compression_factor{GetCompressionFactor(pixel_format)};
|
||||
const u32 bytes_per_pixel{GetBytesPerPixel(pixel_format)};
|
||||
u32 m_depth = (layer_only ? 1U : depth);
|
||||
u32 m_width = MipWidth(mip_level);
|
||||
u32 m_height = MipHeight(mip_level);
|
||||
m_width = uncompressed ? m_width : std::max(1U, (m_width + tile_x - 1) / tile_x);
|
||||
m_height = uncompressed ? m_height : std::max(1U, (m_height + tile_y - 1) / tile_y);
|
||||
m_width = uncompressed ? m_width
|
||||
: std::max(1U, (m_width + compression_factor - 1) / compression_factor);
|
||||
m_height = uncompressed
|
||||
? m_height
|
||||
: std::max(1U, (m_height + compression_factor - 1) / compression_factor);
|
||||
m_depth = std::max(1U, m_depth >> mip_level);
|
||||
u32 m_block_height = MipBlockHeight(mip_level);
|
||||
u32 m_block_depth = MipBlockDepth(mip_level);
|
||||
@@ -128,13 +163,6 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
|
||||
params.target = SurfaceTarget::Texture2D;
|
||||
}
|
||||
break;
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
params.depth = config.tic.Depth() * 6;
|
||||
if (!entry.IsArray()) {
|
||||
ASSERT(params.depth == 6);
|
||||
params.target = SurfaceTarget::TextureCubemap;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unknown depth for target={}", static_cast<u32>(params.target));
|
||||
UNREACHABLE();
|
||||
@@ -239,7 +267,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only,
|
||||
return params;
|
||||
}
|
||||
|
||||
static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex_format_tuples = {{
|
||||
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, ComponentType::UNorm, false}, // ABGR8U
|
||||
{GL_RGBA8, GL_RGBA, GL_BYTE, ComponentType::SNorm, false}, // ABGR8S
|
||||
{GL_RGBA8UI, GL_RGBA_INTEGER, GL_UNSIGNED_BYTE, ComponentType::UInt, false}, // ABGR8UI
|
||||
@@ -312,10 +340,6 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X4_SRGB
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_5X5_SRGB
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8
|
||||
{GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_10X8_SRGB
|
||||
|
||||
// Depth formats
|
||||
{GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT, ComponentType::Float, false}, // Z32F
|
||||
@@ -331,22 +355,20 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex
|
||||
ComponentType::Float, false}, // Z32FS8
|
||||
}};
|
||||
|
||||
static GLenum SurfaceTargetToGL(SurfaceTarget target) {
|
||||
static GLenum SurfaceTargetToGL(SurfaceParams::SurfaceTarget target) {
|
||||
switch (target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||
return GL_TEXTURE_1D;
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
return GL_TEXTURE_2D;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
return GL_TEXTURE_3D;
|
||||
case SurfaceTarget::Texture1DArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture1DArray:
|
||||
return GL_TEXTURE_1D_ARRAY;
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
return GL_TEXTURE_2D_ARRAY;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||
return GL_TEXTURE_CUBE_MAP;
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
return GL_TEXTURE_CUBE_MAP_ARRAY_ARB;
|
||||
}
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
@@ -370,32 +392,50 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const {
|
||||
return {0, actual_height, MipWidth(mip_level), 0};
|
||||
}
|
||||
|
||||
/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
|
||||
static bool IsFormatBCn(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::DXT1:
|
||||
case PixelFormat::DXT23:
|
||||
case PixelFormat::DXT45:
|
||||
case PixelFormat::DXN1:
|
||||
case PixelFormat::DXN2SNORM:
|
||||
case PixelFormat::DXN2UNORM:
|
||||
case PixelFormat::BC7U:
|
||||
case PixelFormat::BC6H_UF16:
|
||||
case PixelFormat::BC6H_SF16:
|
||||
case PixelFormat::DXT1_SRGB:
|
||||
case PixelFormat::DXT23_SRGB:
|
||||
case PixelFormat::DXT45_SRGB:
|
||||
case PixelFormat::BC7U_SRGB:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <bool morton_to_gl, PixelFormat format>
|
||||
void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer,
|
||||
std::size_t gl_buffer_size, VAddr addr) {
|
||||
constexpr u32 bytes_per_pixel = GetBytesPerPixel(format);
|
||||
constexpr u32 bytes_per_pixel = SurfaceParams::GetBytesPerPixel(format);
|
||||
|
||||
// With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual
|
||||
// pixel values.
|
||||
const u32 tile_size_x{GetDefaultBlockWidth(format)};
|
||||
const u32 tile_size_y{GetDefaultBlockHeight(format)};
|
||||
const u32 tile_size{IsFormatBCn(format) ? 4U : 1U};
|
||||
|
||||
if (morton_to_gl) {
|
||||
const std::vector<u8> data =
|
||||
Tegra::Texture::UnswizzleTexture(addr, tile_size_x, tile_size_y, bytes_per_pixel,
|
||||
stride, height, depth, block_height, block_depth);
|
||||
const std::vector<u8> data = Tegra::Texture::UnswizzleTexture(
|
||||
addr, tile_size, bytes_per_pixel, stride, height, depth, block_height, block_depth);
|
||||
const std::size_t size_to_copy{std::min(gl_buffer_size, data.size())};
|
||||
memcpy(gl_buffer, data.data(), size_to_copy);
|
||||
} else {
|
||||
Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x,
|
||||
(height + tile_size_y - 1) / tile_size_y, depth,
|
||||
Tegra::Texture::CopySwizzledData(stride / tile_size, height / tile_size, depth,
|
||||
bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr),
|
||||
gl_buffer, false, block_height, block_depth);
|
||||
}
|
||||
}
|
||||
|
||||
using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
|
||||
VideoCore::Surface::MaxPixelFormat>;
|
||||
SurfaceParams::MaxPixelFormat>;
|
||||
|
||||
static constexpr GLConversionArray morton_to_gl_fns = {
|
||||
// clang-format off
|
||||
@@ -456,10 +496,6 @@ static constexpr GLConversionArray morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_5X5>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_10X8>,
|
||||
MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>,
|
||||
MortonCopy<true, PixelFormat::Z32F>,
|
||||
MortonCopy<true, PixelFormat::Z16>,
|
||||
MortonCopy<true, PixelFormat::Z24S8>,
|
||||
@@ -528,10 +564,6 @@ static constexpr GLConversionArray gl_to_morton_fns = {
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
MortonCopy<false, PixelFormat::Z32F>,
|
||||
MortonCopy<false, PixelFormat::Z16>,
|
||||
MortonCopy<false, PixelFormat::Z24S8>,
|
||||
@@ -543,7 +575,7 @@ static constexpr GLConversionArray gl_to_morton_fns = {
|
||||
void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params,
|
||||
std::vector<u8>& gl_buffer, u32 mip_level) {
|
||||
u32 depth = params.MipDepth(mip_level);
|
||||
if (params.target == SurfaceTarget::Texture2D) {
|
||||
if (params.target == SurfaceParams::SurfaceTarget::Texture2D) {
|
||||
// TODO(Blinkhawk): Eliminate this condition once all texture types are implemented.
|
||||
depth = 1U;
|
||||
}
|
||||
@@ -569,11 +601,9 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params
|
||||
}
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_BlitSurface, "OpenGL", "BlitSurface", MP_RGB(128, 192, 64));
|
||||
static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
GLuint read_fb_handle, GLuint draw_fb_handle, GLenum src_attachment = 0,
|
||||
GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
|
||||
MICROPROFILE_SCOPE(OpenGL_BlitSurface);
|
||||
|
||||
const auto& src_params{src_surface->GetSurfaceParams()};
|
||||
const auto& dst_params{dst_surface->GetSurfaceParams()};
|
||||
@@ -586,19 +616,19 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
state.draw.draw_framebuffer = draw_fb_handle;
|
||||
// Set sRGB enabled if the destination surfaces need it
|
||||
state.framebuffer_srgb.enabled = dst_params.srgb_conversion;
|
||||
state.ApplyFramebufferState();
|
||||
state.Apply();
|
||||
|
||||
u32 buffers{};
|
||||
|
||||
if (src_params.type == SurfaceType::ColorTexture) {
|
||||
switch (src_params.target) {
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||
GL_TEXTURE_2D, src_surface->Texture().handle, 0);
|
||||
glFramebufferTexture2D(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||
0, 0);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||
glFramebufferTexture2D(
|
||||
GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
|
||||
@@ -607,12 +637,12 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
|
||||
break;
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||
src_surface->Texture().handle, 0, 0);
|
||||
glFramebufferTextureLayer(GL_READ_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
|
||||
break;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
glFramebufferTexture3D(GL_READ_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + src_attachment,
|
||||
SurfaceTargetToGL(src_params.target),
|
||||
src_surface->Texture().handle, 0, 0);
|
||||
@@ -628,13 +658,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
}
|
||||
|
||||
switch (dst_params.target) {
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||
GL_TEXTURE_2D, dst_surface->Texture().handle, 0);
|
||||
glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_TEXTURE_2D,
|
||||
0, 0);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||
glFramebufferTexture2D(
|
||||
GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face),
|
||||
@@ -643,13 +673,13 @@ static bool BlitSurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT,
|
||||
static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + cubemap_face), 0, 0);
|
||||
break;
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||
dst_surface->Texture().handle, 0, 0);
|
||||
glFramebufferTextureLayer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, 0, 0, 0);
|
||||
break;
|
||||
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
glFramebufferTexture3D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + dst_attachment,
|
||||
SurfaceTargetToGL(dst_params.target),
|
||||
dst_surface->Texture().handle, 0, 0);
|
||||
@@ -713,20 +743,18 @@ static void FastCopySurface(const Surface& src_surface, const Surface& dst_surfa
|
||||
0, 0, width, height, 1);
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_CopySurface, "OpenGL", "CopySurface", MP_RGB(128, 192, 64));
|
||||
static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
const GLuint copy_pbo_handle, const GLenum src_attachment = 0,
|
||||
const GLenum dst_attachment = 0, const std::size_t cubemap_face = 0) {
|
||||
MICROPROFILE_SCOPE(OpenGL_CopySurface);
|
||||
GLuint copy_pbo_handle, GLenum src_attachment = 0,
|
||||
GLenum dst_attachment = 0, std::size_t cubemap_face = 0) {
|
||||
ASSERT_MSG(dst_attachment == 0, "Unimplemented");
|
||||
|
||||
const auto& src_params{src_surface->GetSurfaceParams()};
|
||||
const auto& dst_params{dst_surface->GetSurfaceParams()};
|
||||
|
||||
const auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type);
|
||||
const auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type);
|
||||
auto source_format = GetFormatTuple(src_params.pixel_format, src_params.component_type);
|
||||
auto dest_format = GetFormatTuple(dst_params.pixel_format, dst_params.component_type);
|
||||
|
||||
const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
|
||||
std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes);
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle);
|
||||
glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB);
|
||||
@@ -750,10 +778,13 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
LOG_DEBUG(HW_GPU, "Trying to upload extra texture data from the CPU during "
|
||||
"reinterpretation but the texture is tiled.");
|
||||
}
|
||||
const std::size_t remaining_size = dst_params.size_in_bytes - src_params.size_in_bytes;
|
||||
std::size_t remaining_size = dst_params.size_in_bytes - src_params.size_in_bytes;
|
||||
std::vector<u8> data(remaining_size);
|
||||
std::memcpy(data.data(), Memory::GetPointer(dst_params.addr + src_params.size_in_bytes),
|
||||
data.size());
|
||||
|
||||
glBufferSubData(GL_PIXEL_PACK_BUFFER, src_params.size_in_bytes, remaining_size,
|
||||
Memory::GetPointer(dst_params.addr + src_params.size_in_bytes));
|
||||
data.data());
|
||||
}
|
||||
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
@@ -769,22 +800,21 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface,
|
||||
UNREACHABLE();
|
||||
} else {
|
||||
switch (dst_params.target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||
glTextureSubImage1D(dst_surface->Texture().handle, 0, 0, width, dest_format.format,
|
||||
dest_format.type, nullptr);
|
||||
break;
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
glTextureSubImage2D(dst_surface->Texture().handle, 0, 0, 0, width, height,
|
||||
dest_format.format, dest_format.type, nullptr);
|
||||
break;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0, 0, width, height,
|
||||
static_cast<GLsizei>(dst_params.depth), dest_format.format,
|
||||
dest_format.type, nullptr);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||
glTextureSubImage3D(dst_surface->Texture().handle, 0, 0, 0,
|
||||
static_cast<GLint>(cubemap_face), width, height, 1,
|
||||
dest_format.format, dest_format.type, nullptr);
|
||||
@@ -821,18 +851,17 @@ CachedSurface::CachedSurface(const SurfaceParams& params)
|
||||
if (!format_tuple.compressed) {
|
||||
// Only pre-create the texture for non-compressed textures.
|
||||
switch (params.target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||
glTexStorage1D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
||||
format_tuple.internal_format, rect.GetWidth());
|
||||
break;
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||
glTexStorage2D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
||||
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight());
|
||||
break;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
glTexStorage3D(SurfaceTargetToGL(params.target), params.max_mip_level,
|
||||
format_tuple.internal_format, rect.GetWidth(), rect.GetHeight(),
|
||||
params.depth);
|
||||
@@ -887,7 +916,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
|
||||
|
||||
S8Z24 s8z24_pixel{};
|
||||
Z24S8 z24s8_pixel{};
|
||||
constexpr auto bpp{GetBytesPerPixel(PixelFormat::S8Z24)};
|
||||
constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::S8Z24)};
|
||||
for (std::size_t y = 0; y < height; ++y) {
|
||||
for (std::size_t x = 0; x < width; ++x) {
|
||||
const std::size_t offset{bpp * (y * width + x)};
|
||||
@@ -907,7 +936,7 @@ static void ConvertS8Z24ToZ24S8(std::vector<u8>& data, u32 width, u32 height, bo
|
||||
}
|
||||
|
||||
static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
|
||||
constexpr auto bpp{GetBytesPerPixel(PixelFormat::G8R8U)};
|
||||
constexpr auto bpp{SurfaceParams::GetBytesPerPixel(PixelFormat::G8R8U)};
|
||||
for (std::size_t y = 0; y < height; ++y) {
|
||||
for (std::size_t x = 0; x < width; ++x) {
|
||||
const std::size_t offset{bpp * (y * width + x)};
|
||||
@@ -924,26 +953,21 @@ static void ConvertG8R8ToR8G8(std::vector<u8>& data, u32 width, u32 height) {
|
||||
* typical desktop GPUs.
|
||||
*/
|
||||
static void ConvertFormatAsNeeded_LoadGLBuffer(std::vector<u8>& data, PixelFormat pixel_format,
|
||||
u32 width, u32 height, u32 depth) {
|
||||
u32 width, u32 height) {
|
||||
switch (pixel_format) {
|
||||
case PixelFormat::ASTC_2D_4X4:
|
||||
case PixelFormat::ASTC_2D_8X8:
|
||||
case PixelFormat::ASTC_2D_8X5:
|
||||
case PixelFormat::ASTC_2D_5X4:
|
||||
case PixelFormat::ASTC_2D_5X5:
|
||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_5X5_SRGB:
|
||||
case PixelFormat::ASTC_2D_10X8:
|
||||
case PixelFormat::ASTC_2D_10X8_SRGB: {
|
||||
case PixelFormat::ASTC_2D_5X4_SRGB: {
|
||||
// Convert ASTC pixel formats to RGBA8, as most desktop GPUs do not support ASTC.
|
||||
u32 block_width{};
|
||||
u32 block_height{};
|
||||
std::tie(block_width, block_height) = GetASTCBlockSize(pixel_format);
|
||||
data =
|
||||
Tegra::Texture::ASTC::Decompress(data, width, height, depth, block_width, block_height);
|
||||
data = Tegra::Texture::ASTC::Decompress(data, width, height, block_width, block_height);
|
||||
break;
|
||||
}
|
||||
case PixelFormat::S8Z24:
|
||||
@@ -972,11 +996,7 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
|
||||
case PixelFormat::ASTC_2D_4X4:
|
||||
case PixelFormat::ASTC_2D_8X8:
|
||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||
case PixelFormat::ASTC_2D_5X5:
|
||||
case PixelFormat::ASTC_2D_5X5_SRGB:
|
||||
case PixelFormat::ASTC_2D_10X8:
|
||||
case PixelFormat::ASTC_2D_10X8_SRGB: {
|
||||
case PixelFormat::ASTC_2D_8X8_SRGB: {
|
||||
LOG_CRITICAL(HW_GPU, "Conversion of format {} after texture flushing is not implemented",
|
||||
static_cast<u32>(pixel_format));
|
||||
UNREACHABLE();
|
||||
@@ -989,7 +1009,7 @@ static void ConvertFormatAsNeeded_FlushGLBuffer(std::vector<u8>& data, PixelForm
|
||||
}
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 192, 64));
|
||||
MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64, 192));
|
||||
void CachedSurface::LoadGLBuffer() {
|
||||
MICROPROFILE_SCOPE(OpenGL_SurfaceLoad);
|
||||
gl_buffer.resize(params.max_mip_level);
|
||||
@@ -1007,7 +1027,7 @@ void CachedSurface::LoadGLBuffer() {
|
||||
}
|
||||
for (u32 i = 0; i < params.max_mip_level; i++)
|
||||
ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer[i], params.pixel_format, params.MipWidth(i),
|
||||
params.MipHeight(i), params.MipDepth(i));
|
||||
params.MipHeight(i));
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
||||
@@ -1022,7 +1042,7 @@ void CachedSurface::FlushGLBuffer() {
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||
ASSERT(params.width * GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
||||
ASSERT(params.width * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
||||
glPixelStorei(GL_PACK_ROW_LENGTH, static_cast<GLint>(params.width));
|
||||
ASSERT(!tuple.compressed);
|
||||
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
|
||||
@@ -1054,7 +1074,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||
std::size_t buffer_offset =
|
||||
static_cast<std::size_t>(static_cast<std::size_t>(y0) * params.MipWidth(mip_map) +
|
||||
static_cast<std::size_t>(x0)) *
|
||||
GetBytesPerPixel(params.pixel_format);
|
||||
SurfaceParams::GetBytesPerPixel(params.pixel_format);
|
||||
|
||||
const FormatTuple& tuple = GetFormatTuple(params.pixel_format, params.component_type);
|
||||
const GLuint target_tex = texture.handle;
|
||||
@@ -1070,35 +1090,35 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||
cur_state.Apply();
|
||||
|
||||
// Ensure no bad interactions with GL_UNPACK_ALIGNMENT
|
||||
ASSERT(params.MipWidth(mip_map) * GetBytesPerPixel(params.pixel_format) % 4 == 0);
|
||||
ASSERT(params.MipWidth(mip_map) * SurfaceParams::GetBytesPerPixel(params.pixel_format) % 4 ==
|
||||
0);
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, static_cast<GLint>(params.MipWidth(mip_map)));
|
||||
|
||||
GLsizei image_size = static_cast<GLsizei>(params.GetMipmapSizeGL(mip_map, false));
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
if (tuple.compressed) {
|
||||
switch (params.target) {
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
glCompressedTexImage2D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||
static_cast<GLsizei>(params.MipHeight(mip_map)), 0, image_size,
|
||||
&gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
||||
static_cast<GLsizei>(params.MipDepth(mip_map)), 0, image_size,
|
||||
&gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
glCompressedTexImage3D(SurfaceTargetToGL(params.target), mip_map, tuple.internal_format,
|
||||
static_cast<GLsizei>(params.MipWidth(mip_map)),
|
||||
static_cast<GLsizei>(params.MipHeight(mip_map)),
|
||||
static_cast<GLsizei>(params.depth), 0, image_size,
|
||||
&gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap: {
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap: {
|
||||
GLsizei layer_size = static_cast<GLsizei>(params.LayerSizeGL(mip_map));
|
||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||
glCompressedTexImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face),
|
||||
@@ -1123,31 +1143,30 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||
} else {
|
||||
|
||||
switch (params.target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
case SurfaceParams::SurfaceTarget::Texture1D:
|
||||
glTexSubImage1D(SurfaceTargetToGL(params.target), mip_map, x0,
|
||||
static_cast<GLsizei>(rect.GetWidth()), tuple.format, tuple.type,
|
||||
&gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
glTexSubImage2D(SurfaceTargetToGL(params.target), mip_map, x0, y0,
|
||||
static_cast<GLsizei>(rect.GetWidth()),
|
||||
static_cast<GLsizei>(rect.GetHeight()), tuple.format, tuple.type,
|
||||
&gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
||||
static_cast<GLsizei>(rect.GetWidth()),
|
||||
static_cast<GLsizei>(rect.GetHeight()), params.MipDepth(mip_map),
|
||||
tuple.format, tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
case SurfaceParams::SurfaceTarget::Texture2DArray:
|
||||
glTexSubImage3D(SurfaceTargetToGL(params.target), mip_map, x0, y0, 0,
|
||||
static_cast<GLsizei>(rect.GetWidth()),
|
||||
static_cast<GLsizei>(rect.GetHeight()), params.depth, tuple.format,
|
||||
tuple.type, &gl_buffer[mip_map][buffer_offset]);
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap: {
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap: {
|
||||
std::size_t start = buffer_offset;
|
||||
for (std::size_t face = 0; face < params.depth; ++face) {
|
||||
glTexSubImage2D(static_cast<GLenum>(GL_TEXTURE_CUBE_MAP_POSITIVE_X + face), mip_map,
|
||||
@@ -1171,7 +1190,7 @@ void CachedSurface::UploadGLMipmapTexture(u32 mip_map, GLuint read_fb_handle,
|
||||
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
|
||||
}
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 192, 64));
|
||||
MICROPROFILE_DEFINE(OpenGL_TextureUL, "OpenGL", "Texture Upload", MP_RGB(128, 64, 192));
|
||||
void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle) {
|
||||
if (params.type == SurfaceType::Fill)
|
||||
return;
|
||||
@@ -1182,8 +1201,7 @@ void CachedSurface::UploadGLTexture(GLuint read_fb_handle, GLuint draw_fb_handle
|
||||
UploadGLMipmapTexture(i, read_fb_handle, draw_fb_handle);
|
||||
}
|
||||
|
||||
RasterizerCacheOpenGL::RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer)
|
||||
: RasterizerCache{rasterizer} {
|
||||
RasterizerCacheOpenGL::RasterizerCacheOpenGL() {
|
||||
read_framebuffer.Create();
|
||||
draw_framebuffer.Create();
|
||||
copy_pbo.Create();
|
||||
@@ -1323,7 +1341,8 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||
// For compatible surfaces, we can just do fast glCopyImageSubData based copy
|
||||
if (old_params.target == new_params.target && old_params.type == new_params.type &&
|
||||
old_params.depth == new_params.depth && old_params.depth == 1 &&
|
||||
GetFormatBpp(old_params.pixel_format) == GetFormatBpp(new_params.pixel_format)) {
|
||||
SurfaceParams::GetFormatBpp(old_params.pixel_format) ==
|
||||
SurfaceParams::GetFormatBpp(new_params.pixel_format)) {
|
||||
FastCopySurface(old_surface, new_surface);
|
||||
return new_surface;
|
||||
}
|
||||
@@ -1336,17 +1355,15 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||
const bool is_blit{old_params.pixel_format == new_params.pixel_format};
|
||||
|
||||
switch (new_params.target) {
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceParams::SurfaceTarget::Texture2D:
|
||||
if (is_blit) {
|
||||
BlitSurface(old_surface, new_surface, read_framebuffer.handle, draw_framebuffer.handle);
|
||||
} else {
|
||||
CopySurface(old_surface, new_surface, copy_pbo.handle);
|
||||
}
|
||||
break;
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceTarget::Texture3D:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
case SurfaceParams::SurfaceTarget::TextureCubemap:
|
||||
case SurfaceParams::SurfaceTarget::Texture3D:
|
||||
AccurateCopySurface(old_surface, new_surface);
|
||||
break;
|
||||
default:
|
||||
@@ -1356,7 +1373,7 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface,
|
||||
}
|
||||
|
||||
return new_surface;
|
||||
}
|
||||
} // namespace OpenGL
|
||||
|
||||
Surface RasterizerCacheOpenGL::TryFindFramebufferSurface(VAddr addr) const {
|
||||
return TryGet(addr);
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "common/alignment.h"
|
||||
@@ -19,7 +18,6 @@
|
||||
#include "video_core/rasterizer_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||
#include "video_core/surface.h"
|
||||
#include "video_core/textures/decoders.h"
|
||||
#include "video_core/textures/texture.h"
|
||||
|
||||
@@ -29,12 +27,135 @@ class CachedSurface;
|
||||
using Surface = std::shared_ptr<CachedSurface>;
|
||||
using SurfaceSurfaceRect_Tuple = std::tuple<Surface, Surface, MathUtil::Rectangle<u32>>;
|
||||
|
||||
using SurfaceTarget = VideoCore::Surface::SurfaceTarget;
|
||||
using SurfaceType = VideoCore::Surface::SurfaceType;
|
||||
using PixelFormat = VideoCore::Surface::PixelFormat;
|
||||
using ComponentType = VideoCore::Surface::ComponentType;
|
||||
|
||||
struct SurfaceParams {
|
||||
enum class PixelFormat {
|
||||
ABGR8U = 0,
|
||||
ABGR8S = 1,
|
||||
ABGR8UI = 2,
|
||||
B5G6R5U = 3,
|
||||
A2B10G10R10U = 4,
|
||||
A1B5G5R5U = 5,
|
||||
R8U = 6,
|
||||
R8UI = 7,
|
||||
RGBA16F = 8,
|
||||
RGBA16U = 9,
|
||||
RGBA16UI = 10,
|
||||
R11FG11FB10F = 11,
|
||||
RGBA32UI = 12,
|
||||
DXT1 = 13,
|
||||
DXT23 = 14,
|
||||
DXT45 = 15,
|
||||
DXN1 = 16, // This is also known as BC4
|
||||
DXN2UNORM = 17,
|
||||
DXN2SNORM = 18,
|
||||
BC7U = 19,
|
||||
BC6H_UF16 = 20,
|
||||
BC6H_SF16 = 21,
|
||||
ASTC_2D_4X4 = 22,
|
||||
G8R8U = 23,
|
||||
G8R8S = 24,
|
||||
BGRA8 = 25,
|
||||
RGBA32F = 26,
|
||||
RG32F = 27,
|
||||
R32F = 28,
|
||||
R16F = 29,
|
||||
R16U = 30,
|
||||
R16S = 31,
|
||||
R16UI = 32,
|
||||
R16I = 33,
|
||||
RG16 = 34,
|
||||
RG16F = 35,
|
||||
RG16UI = 36,
|
||||
RG16I = 37,
|
||||
RG16S = 38,
|
||||
RGB32F = 39,
|
||||
RGBA8_SRGB = 40,
|
||||
RG8U = 41,
|
||||
RG8S = 42,
|
||||
RG32UI = 43,
|
||||
R32UI = 44,
|
||||
ASTC_2D_8X8 = 45,
|
||||
ASTC_2D_8X5 = 46,
|
||||
ASTC_2D_5X4 = 47,
|
||||
BGRA8_SRGB = 48,
|
||||
DXT1_SRGB = 49,
|
||||
DXT23_SRGB = 50,
|
||||
DXT45_SRGB = 51,
|
||||
BC7U_SRGB = 52,
|
||||
ASTC_2D_4X4_SRGB = 53,
|
||||
ASTC_2D_8X8_SRGB = 54,
|
||||
ASTC_2D_8X5_SRGB = 55,
|
||||
ASTC_2D_5X4_SRGB = 56,
|
||||
|
||||
MaxColorFormat,
|
||||
|
||||
// Depth formats
|
||||
Z32F = 57,
|
||||
Z16 = 58,
|
||||
|
||||
MaxDepthFormat,
|
||||
|
||||
// DepthStencil formats
|
||||
Z24S8 = 59,
|
||||
S8Z24 = 60,
|
||||
Z32FS8 = 61,
|
||||
|
||||
MaxDepthStencilFormat,
|
||||
|
||||
Max = MaxDepthStencilFormat,
|
||||
Invalid = 255,
|
||||
};
|
||||
|
||||
static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
|
||||
|
||||
enum class ComponentType {
|
||||
Invalid = 0,
|
||||
SNorm = 1,
|
||||
UNorm = 2,
|
||||
SInt = 3,
|
||||
UInt = 4,
|
||||
Float = 5,
|
||||
};
|
||||
|
||||
enum class SurfaceType {
|
||||
ColorTexture = 0,
|
||||
Depth = 1,
|
||||
DepthStencil = 2,
|
||||
Fill = 3,
|
||||
Invalid = 4,
|
||||
};
|
||||
|
||||
enum class SurfaceTarget {
|
||||
Texture1D,
|
||||
Texture2D,
|
||||
Texture3D,
|
||||
Texture1DArray,
|
||||
Texture2DArray,
|
||||
TextureCubemap,
|
||||
};
|
||||
|
||||
static SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
|
||||
switch (texture_type) {
|
||||
case Tegra::Texture::TextureType::Texture1D:
|
||||
return SurfaceTarget::Texture1D;
|
||||
case Tegra::Texture::TextureType::Texture2D:
|
||||
case Tegra::Texture::TextureType::Texture2DNoMipmap:
|
||||
return SurfaceTarget::Texture2D;
|
||||
case Tegra::Texture::TextureType::Texture3D:
|
||||
return SurfaceTarget::Texture3D;
|
||||
case Tegra::Texture::TextureType::TextureCubemap:
|
||||
return SurfaceTarget::TextureCubemap;
|
||||
case Tegra::Texture::TextureType::Texture1DArray:
|
||||
return SurfaceTarget::Texture1DArray;
|
||||
case Tegra::Texture::TextureType::Texture2DArray:
|
||||
return SurfaceTarget::Texture2DArray;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
|
||||
UNREACHABLE();
|
||||
return SurfaceTarget::Texture2D;
|
||||
}
|
||||
}
|
||||
|
||||
static std::string SurfaceTargetName(SurfaceTarget target) {
|
||||
switch (target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
@@ -49,8 +170,6 @@ struct SurfaceParams {
|
||||
return "Texture2DArray";
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
return "TextureCubemap";
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
return "TextureCubeArray";
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
@@ -58,8 +177,660 @@ struct SurfaceParams {
|
||||
}
|
||||
}
|
||||
|
||||
static bool SurfaceTargetIsLayered(SurfaceTarget target) {
|
||||
switch (target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceTarget::Texture3D:
|
||||
return false;
|
||||
case SurfaceTarget::Texture1DArray:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
return true;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
||||
* "compressed width" and "compressed height", not the overall compression factor of a
|
||||
* compressed image. This is used for maintaining proper surface sizes for compressed
|
||||
* texture formats.
|
||||
*/
|
||||
static constexpr u32 GetCompressionFactor(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
|
||||
constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
|
||||
1, // ABGR8U
|
||||
1, // ABGR8S
|
||||
1, // ABGR8UI
|
||||
1, // B5G6R5U
|
||||
1, // A2B10G10R10U
|
||||
1, // A1B5G5R5U
|
||||
1, // R8U
|
||||
1, // R8UI
|
||||
1, // RGBA16F
|
||||
1, // RGBA16U
|
||||
1, // RGBA16UI
|
||||
1, // R11FG11FB10F
|
||||
1, // RGBA32UI
|
||||
4, // DXT1
|
||||
4, // DXT23
|
||||
4, // DXT45
|
||||
4, // DXN1
|
||||
4, // DXN2UNORM
|
||||
4, // DXN2SNORM
|
||||
4, // BC7U
|
||||
4, // BC6H_UF16
|
||||
4, // BC6H_SF16
|
||||
4, // ASTC_2D_4X4
|
||||
1, // G8R8U
|
||||
1, // G8R8S
|
||||
1, // BGRA8
|
||||
1, // RGBA32F
|
||||
1, // RG32F
|
||||
1, // R32F
|
||||
1, // R16F
|
||||
1, // R16U
|
||||
1, // R16S
|
||||
1, // R16UI
|
||||
1, // R16I
|
||||
1, // RG16
|
||||
1, // RG16F
|
||||
1, // RG16UI
|
||||
1, // RG16I
|
||||
1, // RG16S
|
||||
1, // RGB32F
|
||||
1, // RGBA8_SRGB
|
||||
1, // RG8U
|
||||
1, // RG8S
|
||||
1, // RG32UI
|
||||
1, // R32UI
|
||||
4, // ASTC_2D_8X8
|
||||
4, // ASTC_2D_8X5
|
||||
4, // ASTC_2D_5X4
|
||||
1, // BGRA8_SRGB
|
||||
4, // DXT1_SRGB
|
||||
4, // DXT23_SRGB
|
||||
4, // DXT45_SRGB
|
||||
4, // BC7U_SRGB
|
||||
4, // ASTC_2D_4X4_SRGB
|
||||
4, // ASTC_2D_8X8_SRGB
|
||||
4, // ASTC_2D_8X5_SRGB
|
||||
4, // ASTC_2D_5X4_SRGB
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
1, // S8Z24
|
||||
1, // Z32FS8
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
|
||||
return compression_factor_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
|
||||
1, // ABGR8U
|
||||
1, // ABGR8S
|
||||
1, // ABGR8UI
|
||||
1, // B5G6R5U
|
||||
1, // A2B10G10R10U
|
||||
1, // A1B5G5R5U
|
||||
1, // R8U
|
||||
1, // R8UI
|
||||
1, // RGBA16F
|
||||
1, // RGBA16U
|
||||
1, // RGBA16UI
|
||||
1, // R11FG11FB10F
|
||||
1, // RGBA32UI
|
||||
4, // DXT1
|
||||
4, // DXT23
|
||||
4, // DXT45
|
||||
4, // DXN1
|
||||
4, // DXN2UNORM
|
||||
4, // DXN2SNORM
|
||||
4, // BC7U
|
||||
4, // BC6H_UF16
|
||||
4, // BC6H_SF16
|
||||
4, // ASTC_2D_4X4
|
||||
1, // G8R8U
|
||||
1, // G8R8S
|
||||
1, // BGRA8
|
||||
1, // RGBA32F
|
||||
1, // RG32F
|
||||
1, // R32F
|
||||
1, // R16F
|
||||
1, // R16U
|
||||
1, // R16S
|
||||
1, // R16UI
|
||||
1, // R16I
|
||||
1, // RG16
|
||||
1, // RG16F
|
||||
1, // RG16UI
|
||||
1, // RG16I
|
||||
1, // RG16S
|
||||
1, // RGB32F
|
||||
1, // RGBA8_SRGB
|
||||
1, // RG8U
|
||||
1, // RG8S
|
||||
1, // RG32UI
|
||||
1, // R32UI
|
||||
8, // ASTC_2D_8X8
|
||||
5, // ASTC_2D_8X5
|
||||
4, // ASTC_2D_5X4
|
||||
1, // BGRA8_SRGB
|
||||
4, // DXT1_SRGB
|
||||
4, // DXT23_SRGB
|
||||
4, // DXT45_SRGB
|
||||
4, // BC7U_SRGB
|
||||
4, // ASTC_2D_4X4_SRGB
|
||||
8, // ASTC_2D_8X8_SRGB
|
||||
5, // ASTC_2D_8X5_SRGB
|
||||
4, // ASTC_2D_5X4_SRGB
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
1, // S8Z24
|
||||
1, // Z32FS8
|
||||
}};
|
||||
ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
|
||||
return block_height_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
static constexpr u32 GetFormatBpp(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
|
||||
constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
|
||||
32, // ABGR8U
|
||||
32, // ABGR8S
|
||||
32, // ABGR8UI
|
||||
16, // B5G6R5U
|
||||
32, // A2B10G10R10U
|
||||
16, // A1B5G5R5U
|
||||
8, // R8U
|
||||
8, // R8UI
|
||||
64, // RGBA16F
|
||||
64, // RGBA16U
|
||||
64, // RGBA16UI
|
||||
32, // R11FG11FB10F
|
||||
128, // RGBA32UI
|
||||
64, // DXT1
|
||||
128, // DXT23
|
||||
128, // DXT45
|
||||
64, // DXN1
|
||||
128, // DXN2UNORM
|
||||
128, // DXN2SNORM
|
||||
128, // BC7U
|
||||
128, // BC6H_UF16
|
||||
128, // BC6H_SF16
|
||||
32, // ASTC_2D_4X4
|
||||
16, // G8R8U
|
||||
16, // G8R8S
|
||||
32, // BGRA8
|
||||
128, // RGBA32F
|
||||
64, // RG32F
|
||||
32, // R32F
|
||||
16, // R16F
|
||||
16, // R16U
|
||||
16, // R16S
|
||||
16, // R16UI
|
||||
16, // R16I
|
||||
32, // RG16
|
||||
32, // RG16F
|
||||
32, // RG16UI
|
||||
32, // RG16I
|
||||
32, // RG16S
|
||||
96, // RGB32F
|
||||
32, // RGBA8_SRGB
|
||||
16, // RG8U
|
||||
16, // RG8S
|
||||
64, // RG32UI
|
||||
32, // R32UI
|
||||
16, // ASTC_2D_8X8
|
||||
16, // ASTC_2D_8X5
|
||||
32, // ASTC_2D_5X4
|
||||
32, // BGRA8_SRGB
|
||||
64, // DXT1_SRGB
|
||||
128, // DXT23_SRGB
|
||||
128, // DXT45_SRGB
|
||||
128, // BC7U
|
||||
32, // ASTC_2D_4X4_SRGB
|
||||
16, // ASTC_2D_8X8_SRGB
|
||||
16, // ASTC_2D_8X5_SRGB
|
||||
32, // ASTC_2D_5X4_SRGB
|
||||
32, // Z32F
|
||||
16, // Z16
|
||||
32, // Z24S8
|
||||
32, // S8Z24
|
||||
64, // Z32FS8
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
|
||||
return bpp_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
u32 GetFormatBpp() const {
|
||||
return VideoCore::Surface::GetFormatBpp(pixel_format);
|
||||
return GetFormatBpp(pixel_format);
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::DepthFormat::S8_Z24_UNORM:
|
||||
return PixelFormat::S8Z24;
|
||||
case Tegra::DepthFormat::Z24_S8_UNORM:
|
||||
return PixelFormat::Z24S8;
|
||||
case Tegra::DepthFormat::Z32_FLOAT:
|
||||
return PixelFormat::Z32F;
|
||||
case Tegra::DepthFormat::Z16_UNORM:
|
||||
return PixelFormat::Z16;
|
||||
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
||||
return PixelFormat::Z32FS8;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
|
||||
switch (format) {
|
||||
// TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
|
||||
// gamma.
|
||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||
return PixelFormat::RGBA8_SRGB;
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
return PixelFormat::ABGR8U;
|
||||
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
||||
return PixelFormat::ABGR8S;
|
||||
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
||||
return PixelFormat::ABGR8UI;
|
||||
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
||||
return PixelFormat::BGRA8_SRGB;
|
||||
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
||||
return PixelFormat::BGRA8;
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
return PixelFormat::A2B10G10R10U;
|
||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||
return PixelFormat::RGBA16F;
|
||||
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
||||
return PixelFormat::RGBA16U;
|
||||
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
||||
return PixelFormat::RGBA16UI;
|
||||
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
||||
return PixelFormat::RGBA32F;
|
||||
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
||||
return PixelFormat::RG32F;
|
||||
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
||||
return PixelFormat::R11FG11FB10F;
|
||||
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
||||
return PixelFormat::B5G6R5U;
|
||||
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
||||
return PixelFormat::A1B5G5R5U;
|
||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||
return PixelFormat::RGBA32UI;
|
||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||
return PixelFormat::R8U;
|
||||
case Tegra::RenderTargetFormat::R8_UINT:
|
||||
return PixelFormat::R8UI;
|
||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||
return PixelFormat::RG16F;
|
||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||
return PixelFormat::RG16UI;
|
||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||
return PixelFormat::RG16I;
|
||||
case Tegra::RenderTargetFormat::RG16_UNORM:
|
||||
return PixelFormat::RG16;
|
||||
case Tegra::RenderTargetFormat::RG16_SNORM:
|
||||
return PixelFormat::RG16S;
|
||||
case Tegra::RenderTargetFormat::RG8_UNORM:
|
||||
return PixelFormat::RG8U;
|
||||
case Tegra::RenderTargetFormat::RG8_SNORM:
|
||||
return PixelFormat::RG8S;
|
||||
case Tegra::RenderTargetFormat::R16_FLOAT:
|
||||
return PixelFormat::R16F;
|
||||
case Tegra::RenderTargetFormat::R16_UNORM:
|
||||
return PixelFormat::R16U;
|
||||
case Tegra::RenderTargetFormat::R16_SNORM:
|
||||
return PixelFormat::R16S;
|
||||
case Tegra::RenderTargetFormat::R16_UINT:
|
||||
return PixelFormat::R16UI;
|
||||
case Tegra::RenderTargetFormat::R16_SINT:
|
||||
return PixelFormat::R16I;
|
||||
case Tegra::RenderTargetFormat::R32_FLOAT:
|
||||
return PixelFormat::R32F;
|
||||
case Tegra::RenderTargetFormat::R32_UINT:
|
||||
return PixelFormat::R32UI;
|
||||
case Tegra::RenderTargetFormat::RG32_UINT:
|
||||
return PixelFormat::RG32UI;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
||||
Tegra::Texture::ComponentType component_type,
|
||||
bool is_srgb) {
|
||||
// TODO(Subv): Properly implement this
|
||||
switch (format) {
|
||||
case Tegra::Texture::TextureFormat::A8R8G8B8:
|
||||
if (is_srgb) {
|
||||
return PixelFormat::RGBA8_SRGB;
|
||||
}
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::ABGR8U;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::ABGR8S;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::ABGR8UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::B5G6R5:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::B5G6R5U;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::A2B10G10R10:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::A2B10G10R10U;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::A1B5G5R5:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::A1B5G5R5U;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R8:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::R8U;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R8UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::G8R8:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::G8R8U;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::G8R8S;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::RGBA16U;
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RGBA16F;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::BF10GF11RF11:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::R11FG11FB10F;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RGBA32F;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::RGBA32UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32_G32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RG32F;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::RG32UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32_G32_B32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RGB32F;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R16:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::R16F;
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::R16U;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::R16S;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R16UI;
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
return PixelFormat::R16I;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::R32F;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R32UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::ZF32:
|
||||
return PixelFormat::Z32F;
|
||||
case Tegra::Texture::TextureFormat::Z16:
|
||||
return PixelFormat::Z16;
|
||||
case Tegra::Texture::TextureFormat::Z24S8:
|
||||
return PixelFormat::Z24S8;
|
||||
case Tegra::Texture::TextureFormat::DXT1:
|
||||
return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
|
||||
case Tegra::Texture::TextureFormat::DXT23:
|
||||
return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
|
||||
case Tegra::Texture::TextureFormat::DXT45:
|
||||
return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
|
||||
case Tegra::Texture::TextureFormat::DXN1:
|
||||
return PixelFormat::DXN1;
|
||||
case Tegra::Texture::TextureFormat::DXN2:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::DXN2UNORM;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::DXN2SNORM;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::BC7U:
|
||||
return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
|
||||
case Tegra::Texture::TextureFormat::BC6H_UF16:
|
||||
return PixelFormat::BC6H_UF16;
|
||||
case Tegra::Texture::TextureFormat::BC6H_SF16:
|
||||
return PixelFormat::BC6H_SF16;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
|
||||
case Tegra::Texture::TextureFormat::R16_G16:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RG16F;
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::RG16;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::RG16S;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::RG16UI;
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
return PixelFormat::RG16I;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}",
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}",
|
||||
static_cast<u32>(format), static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
|
||||
// TODO(Subv): Implement more component types
|
||||
switch (type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return ComponentType::Float;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return ComponentType::SNorm;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return ComponentType::UInt;
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
return ComponentType::SInt;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
|
||||
// TODO(Subv): Implement more render targets
|
||||
switch (format) {
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
||||
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RG16_UNORM:
|
||||
case Tegra::RenderTargetFormat::R16_UNORM:
|
||||
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
||||
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
||||
case Tegra::RenderTargetFormat::RG8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
||||
case Tegra::RenderTargetFormat::RG16_SNORM:
|
||||
case Tegra::RenderTargetFormat::R16_SNORM:
|
||||
case Tegra::RenderTargetFormat::RG8_SNORM:
|
||||
return ComponentType::SNorm;
|
||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
||||
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
||||
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||
case Tegra::RenderTargetFormat::R16_FLOAT:
|
||||
case Tegra::RenderTargetFormat::R32_FLOAT:
|
||||
return ComponentType::Float;
|
||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||
case Tegra::RenderTargetFormat::R8_UINT:
|
||||
case Tegra::RenderTargetFormat::R16_UINT:
|
||||
case Tegra::RenderTargetFormat::RG32_UINT:
|
||||
case Tegra::RenderTargetFormat::R32_UINT:
|
||||
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
||||
return ComponentType::UInt;
|
||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||
case Tegra::RenderTargetFormat::R16_SINT:
|
||||
return ComponentType::SInt;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||
return PixelFormat::ABGR8U;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::DepthFormat::Z16_UNORM:
|
||||
case Tegra::DepthFormat::S8_Z24_UNORM:
|
||||
case Tegra::DepthFormat::Z24_S8_UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::DepthFormat::Z32_FLOAT:
|
||||
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
||||
return ComponentType::Float;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
static SurfaceType GetFormatType(PixelFormat pixel_format) {
|
||||
if (static_cast<std::size_t>(pixel_format) <
|
||||
static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
|
||||
return SurfaceType::ColorTexture;
|
||||
}
|
||||
|
||||
if (static_cast<std::size_t>(pixel_format) <
|
||||
static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
|
||||
return SurfaceType::Depth;
|
||||
}
|
||||
|
||||
if (static_cast<std::size_t>(pixel_format) <
|
||||
static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
|
||||
return SurfaceType::DepthStencil;
|
||||
}
|
||||
|
||||
// TODO(Subv): Implement the other formats
|
||||
ASSERT(false);
|
||||
|
||||
return SurfaceType::Invalid;
|
||||
}
|
||||
|
||||
/// Returns the sizer in bytes of the specified pixel format
|
||||
static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
|
||||
if (pixel_format == SurfaceParams::PixelFormat::Invalid) {
|
||||
return 0;
|
||||
}
|
||||
return GetFormatBpp(pixel_format) / CHAR_BIT;
|
||||
}
|
||||
|
||||
/// Returns the rectangle corresponding to this surface
|
||||
@@ -141,7 +912,7 @@ struct SurfaceParams {
|
||||
}
|
||||
|
||||
u32 MipDepth(u32 mip_level) const {
|
||||
return is_layered ? depth : std::max(1U, depth >> mip_level);
|
||||
return std::max(1U, depth >> mip_level);
|
||||
}
|
||||
|
||||
// Auto block resizing algorithm from:
|
||||
@@ -264,8 +1035,6 @@ struct hash<SurfaceReserveKey> {
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class RasterizerOpenGL;
|
||||
|
||||
class CachedSurface final : public RasterizerCacheObject {
|
||||
public:
|
||||
CachedSurface(const SurfaceParams& params);
|
||||
@@ -313,7 +1082,7 @@ private:
|
||||
|
||||
class RasterizerCacheOpenGL final : public RasterizerCache<Surface> {
|
||||
public:
|
||||
explicit RasterizerCacheOpenGL(RasterizerOpenGL& rasterizer);
|
||||
RasterizerCacheOpenGL();
|
||||
|
||||
/// Get a surface based on the texture configuration
|
||||
Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config,
|
||||
|
||||
@@ -1,186 +0,0 @@
|
||||
// Copyright 2015 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <utility>
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_ResourceCreation, "OpenGL", "Resource Creation", MP_RGB(128, 128, 192));
|
||||
MICROPROFILE_DEFINE(OpenGL_ResourceDeletion, "OpenGL", "Resource Deletion", MP_RGB(128, 128, 192));
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
void OGLTexture::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenTextures(1, &handle);
|
||||
}
|
||||
|
||||
void OGLTexture::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteTextures(1, &handle);
|
||||
OpenGLState::GetCurState().UnbindTexture(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLSampler::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenSamplers(1, &handle);
|
||||
}
|
||||
|
||||
void OGLSampler::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteSamplers(1, &handle);
|
||||
OpenGLState::GetCurState().ResetSampler(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLShader::Create(const char* source, GLenum type) {
|
||||
if (handle != 0)
|
||||
return;
|
||||
if (source == nullptr)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
handle = GLShader::LoadShader(source, type);
|
||||
}
|
||||
|
||||
void OGLShader::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteShader(handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLProgram::CreateFromSource(const char* vert_shader, const char* geo_shader,
|
||||
const char* frag_shader, bool separable_program) {
|
||||
OGLShader vert, geo, frag;
|
||||
if (vert_shader)
|
||||
vert.Create(vert_shader, GL_VERTEX_SHADER);
|
||||
if (geo_shader)
|
||||
geo.Create(geo_shader, GL_GEOMETRY_SHADER);
|
||||
if (frag_shader)
|
||||
frag.Create(frag_shader, GL_FRAGMENT_SHADER);
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
Create(separable_program, vert.handle, geo.handle, frag.handle);
|
||||
}
|
||||
|
||||
void OGLProgram::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteProgram(handle);
|
||||
OpenGLState::GetCurState().ResetProgram(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLPipeline::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenProgramPipelines(1, &handle);
|
||||
}
|
||||
|
||||
void OGLPipeline::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteProgramPipelines(1, &handle);
|
||||
OpenGLState::GetCurState().ResetPipeline(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLBuffer::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenBuffers(1, &handle);
|
||||
}
|
||||
|
||||
void OGLBuffer::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteBuffers(1, &handle);
|
||||
OpenGLState::GetCurState().ResetBuffer(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLSync::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
// Don't profile here, this one is expected to happen ingame.
|
||||
handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
|
||||
void OGLSync::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
// Don't profile here, this one is expected to happen ingame.
|
||||
glDeleteSync(handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLVertexArray::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenVertexArrays(1, &handle);
|
||||
}
|
||||
|
||||
void OGLVertexArray::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteVertexArrays(1, &handle);
|
||||
OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
void OGLFramebuffer::Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceCreation);
|
||||
glGenFramebuffers(1, &handle);
|
||||
}
|
||||
|
||||
void OGLFramebuffer::Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
|
||||
MICROPROFILE_SCOPE(OpenGL_ResourceDeletion);
|
||||
glDeleteFramebuffers(1, &handle);
|
||||
OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
} // namespace OpenGL
|
||||
@@ -8,6 +8,7 @@
|
||||
#include <glad/glad.h>
|
||||
#include "common/common_types.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_util.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
@@ -28,10 +29,20 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
glGenTextures(1, &handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteTextures(1, &handle);
|
||||
OpenGLState::GetCurState().UnbindTexture(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -53,10 +64,20 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
glGenSamplers(1, &handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteSamplers(1, &handle);
|
||||
OpenGLState::GetCurState().ResetSampler(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -77,9 +98,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Create(const char* source, GLenum type);
|
||||
void Create(const char* source, GLenum type) {
|
||||
if (handle != 0)
|
||||
return;
|
||||
if (source == nullptr)
|
||||
return;
|
||||
handle = GLShader::LoadShader(source, type);
|
||||
}
|
||||
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteShader(handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -109,10 +141,25 @@ public:
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void CreateFromSource(const char* vert_shader, const char* geo_shader, const char* frag_shader,
|
||||
bool separable_program = false);
|
||||
bool separable_program = false) {
|
||||
OGLShader vert, geo, frag;
|
||||
if (vert_shader)
|
||||
vert.Create(vert_shader, GL_VERTEX_SHADER);
|
||||
if (geo_shader)
|
||||
geo.Create(geo_shader, GL_GEOMETRY_SHADER);
|
||||
if (frag_shader)
|
||||
frag.Create(frag_shader, GL_FRAGMENT_SHADER);
|
||||
Create(separable_program, vert.handle, geo.handle, frag.handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteProgram(handle);
|
||||
OpenGLState::GetCurState().ResetProgram(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -131,10 +178,20 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
glGenProgramPipelines(1, &handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteProgramPipelines(1, &handle);
|
||||
OpenGLState::GetCurState().ResetPipeline(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -156,10 +213,20 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
glGenBuffers(1, &handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteBuffers(1, &handle);
|
||||
OpenGLState::GetCurState().ResetBuffer(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -180,10 +247,19 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
handle = glFenceSync(GL_SYNC_GPU_COMMANDS_COMPLETE, 0);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteSync(handle);
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLsync handle = 0;
|
||||
};
|
||||
@@ -205,10 +281,20 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
glGenVertexArrays(1, &handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteVertexArrays(1, &handle);
|
||||
OpenGLState::GetCurState().ResetVertexArray(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
@@ -230,10 +316,20 @@ public:
|
||||
}
|
||||
|
||||
/// Creates a new internal OpenGL resource and stores the handle
|
||||
void Create();
|
||||
void Create() {
|
||||
if (handle != 0)
|
||||
return;
|
||||
glGenFramebuffers(1, &handle);
|
||||
}
|
||||
|
||||
/// Deletes the internal OpenGL resource
|
||||
void Release();
|
||||
void Release() {
|
||||
if (handle == 0)
|
||||
return;
|
||||
glDeleteFramebuffers(1, &handle);
|
||||
OpenGLState::GetCurState().ResetFramebuffer(handle).Apply();
|
||||
handle = 0;
|
||||
}
|
||||
|
||||
GLuint handle = 0;
|
||||
};
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
#include "core/core.h"
|
||||
#include "core/memory.h"
|
||||
#include "video_core/engines/maxwell_3d.h"
|
||||
#include "video_core/renderer_opengl/gl_rasterizer.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_cache.h"
|
||||
#include "video_core/renderer_opengl/gl_shader_manager.h"
|
||||
#include "video_core/renderer_opengl/utils.h"
|
||||
#include "video_core/utils.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
@@ -121,16 +121,12 @@ GLint CachedShader::GetUniformLocation(const GLShader::SamplerEntry& sampler) {
|
||||
}
|
||||
|
||||
GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
|
||||
const std::string& glsl_topology, u32 max_vertices,
|
||||
const std::string& glsl_topology,
|
||||
const std::string& debug_name) {
|
||||
if (target_program.handle != 0) {
|
||||
return target_program.handle;
|
||||
}
|
||||
std::string source = "#version 430 core\n";
|
||||
source += "layout (" + glsl_topology + ") in;\n";
|
||||
source += "#define MAX_VERTEX_INPUT " + std::to_string(max_vertices) + '\n';
|
||||
source += geometry_programs.code;
|
||||
|
||||
const std::string source{geometry_programs.code + "layout (" + glsl_topology + ") in;\n"};
|
||||
OGLShader shader;
|
||||
shader.Create(source.c_str(), GL_GEOMETRY_SHADER);
|
||||
target_program.Create(true, shader.handle);
|
||||
@@ -139,8 +135,6 @@ GLuint CachedShader::LazyGeometryProgram(OGLProgram& target_program,
|
||||
return target_program.handle;
|
||||
};
|
||||
|
||||
ShaderCacheOpenGL::ShaderCacheOpenGL(RasterizerOpenGL& rasterizer) : RasterizerCache{rasterizer} {}
|
||||
|
||||
Shader ShaderCacheOpenGL::GetStageProgram(Maxwell::ShaderProgram program) {
|
||||
const VAddr program_addr{GetShaderAddress(program)};
|
||||
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
namespace OpenGL {
|
||||
|
||||
class CachedShader;
|
||||
class RasterizerOpenGL;
|
||||
|
||||
using Shader = std::shared_ptr<CachedShader>;
|
||||
using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||
|
||||
@@ -48,23 +46,22 @@ public:
|
||||
}
|
||||
switch (primitive_mode) {
|
||||
case GL_POINTS:
|
||||
return LazyGeometryProgram(geometry_programs.points, "points", 1, "ShaderPoints");
|
||||
return LazyGeometryProgram(geometry_programs.points, "points", "ShaderPoints");
|
||||
case GL_LINES:
|
||||
case GL_LINE_STRIP:
|
||||
return LazyGeometryProgram(geometry_programs.lines, "lines", 2, "ShaderLines");
|
||||
return LazyGeometryProgram(geometry_programs.lines, "lines", "ShaderLines");
|
||||
case GL_LINES_ADJACENCY:
|
||||
case GL_LINE_STRIP_ADJACENCY:
|
||||
return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency", 4,
|
||||
return LazyGeometryProgram(geometry_programs.lines_adjacency, "lines_adjacency",
|
||||
"ShaderLinesAdjacency");
|
||||
case GL_TRIANGLES:
|
||||
case GL_TRIANGLE_STRIP:
|
||||
case GL_TRIANGLE_FAN:
|
||||
return LazyGeometryProgram(geometry_programs.triangles, "triangles", 3,
|
||||
"ShaderTriangles");
|
||||
return LazyGeometryProgram(geometry_programs.triangles, "triangles", "ShaderTriangles");
|
||||
case GL_TRIANGLES_ADJACENCY:
|
||||
case GL_TRIANGLE_STRIP_ADJACENCY:
|
||||
return LazyGeometryProgram(geometry_programs.triangles_adjacency, "triangles_adjacency",
|
||||
6, "ShaderTrianglesAdjacency");
|
||||
"ShaderLines");
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown primitive mode.");
|
||||
}
|
||||
@@ -79,7 +76,7 @@ public:
|
||||
private:
|
||||
/// Generates a geometry shader or returns one that already exists.
|
||||
GLuint LazyGeometryProgram(OGLProgram& target_program, const std::string& glsl_topology,
|
||||
u32 max_vertices, const std::string& debug_name);
|
||||
const std::string& debug_name);
|
||||
|
||||
VAddr addr;
|
||||
Maxwell::ShaderProgram program_type;
|
||||
@@ -107,8 +104,6 @@ private:
|
||||
|
||||
class ShaderCacheOpenGL final : public RasterizerCache<Shader> {
|
||||
public:
|
||||
explicit ShaderCacheOpenGL(RasterizerOpenGL& rasterizer);
|
||||
|
||||
/// Gets the current specified shader stage program
|
||||
Shader GetStageProgram(Maxwell::ShaderProgram program);
|
||||
};
|
||||
|
||||
@@ -373,7 +373,6 @@ public:
|
||||
if (sets_cc) {
|
||||
const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )";
|
||||
SetInternalFlag(InternalFlag::ZeroFlag, zero_condition);
|
||||
LOG_WARNING(HW_GPU, "Control Codes Imcomplete.");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -494,10 +493,10 @@ public:
|
||||
// instruction for now.
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Geometry) {
|
||||
// TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry
|
||||
// shader. These instructions use a dirty register as buffer index, to avoid some
|
||||
// drivers from complaining about out of boundary writes, guard them.
|
||||
const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " +
|
||||
std::to_string(MAX_GEOMETRY_BUFFERS) + ')'};
|
||||
// shader. These instructions use a dirty register as buffer index. To avoid some
|
||||
// drivers from complaining for the out of boundary writes, guard them.
|
||||
const std::string buf_index{"min(" + GetRegisterAsInteger(buf_reg) + ", " +
|
||||
std::to_string(MAX_GEOMETRY_BUFFERS - 1) + ')'};
|
||||
shader.AddLine("amem[" + buf_index + "][" +
|
||||
std::to_string(static_cast<u32>(attribute)) + ']' +
|
||||
GetSwizzle(elem) + " = " + src + ';');
|
||||
@@ -811,11 +810,7 @@ private:
|
||||
std::optional<Register> vertex = {}) {
|
||||
auto GeometryPass = [&](const std::string& name) {
|
||||
if (stage == Maxwell3D::Regs::ShaderStage::Geometry && vertex) {
|
||||
// TODO(Rodrigo): Guard geometry inputs against out of bound reads. Some games set
|
||||
// an 0x80000000 index for those and the shader fails to build. Find out why this
|
||||
// happens and what's its intent.
|
||||
return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) +
|
||||
" % MAX_VERTEX_INPUT]";
|
||||
return "gs_" + name + '[' + GetRegisterAsInteger(*vertex, 0, false) + ']';
|
||||
}
|
||||
return name;
|
||||
};
|
||||
@@ -1530,10 +1525,6 @@ private:
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " * " + op_b, 1, 1,
|
||||
instr.alu.saturate_d, 0, true);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "FMUL Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FADD_C:
|
||||
@@ -1544,10 +1535,6 @@ private:
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1,
|
||||
instr.alu.saturate_d, 0, true);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "FADD Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::MUFU: {
|
||||
@@ -1601,10 +1588,6 @@ private:
|
||||
'(' + condition + ") ? min(" + parameters + ") : max(" +
|
||||
parameters + ')',
|
||||
1, 1, false, 0, true);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "FMNMX Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::RRO_C:
|
||||
@@ -1635,10 +1618,6 @@ private:
|
||||
regs.GetRegisterAsFloat(instr.gpr8) + " * " +
|
||||
GetImmediate32(instr),
|
||||
1, 1, instr.fmul32.saturate, 0, true);
|
||||
if (instr.op_32.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "FMUL32 Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::FADD32I: {
|
||||
@@ -1662,10 +1641,6 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a + " + " + op_b, 1, 1, false, 0, true);
|
||||
if (instr.op_32.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "FADD32 Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1686,10 +1661,6 @@ private:
|
||||
std::to_string(instr.bfe.GetLeftShiftValue() + instr.bfe.shift_position) + ')';
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, outer_shift, 1, 1);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "BFE Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1727,20 +1698,12 @@ private:
|
||||
// Cast to int is superfluous for arithmetic shift, it's only for a logical shift
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, "int(" + op_a + " >> " + op_b + ')',
|
||||
1, 1);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "SHR Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::SHL_C:
|
||||
case OpCode::Id::SHL_R:
|
||||
case OpCode::Id::SHL_IMM:
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "SHL Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
default: {
|
||||
LOG_CRITICAL(HW_GPU, "Unhandled shift instruction: {}", opcode->get().GetName());
|
||||
@@ -1760,10 +1723,6 @@ private:
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
|
||||
instr.iadd32i.saturate != 0);
|
||||
if (instr.op_32.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "IADD32 Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case OpCode::Id::LOP32I: {
|
||||
if (instr.alu.lop32i.invert_a)
|
||||
@@ -1775,10 +1734,6 @@ private:
|
||||
WriteLogicOperation(instr.gpr0, instr.alu.lop32i.operation, op_a, op_b,
|
||||
Tegra::Shader::PredicateResultMode::None,
|
||||
Tegra::Shader::Pred::UnusedIndex);
|
||||
if (instr.op_32.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "LOP32I Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -1815,10 +1770,6 @@ private:
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " + " + op_b, 1, 1,
|
||||
instr.alu.saturate_d);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "IADD Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::IADD3_C:
|
||||
@@ -1880,11 +1831,6 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0, result, 1, 1);
|
||||
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "IADD3 Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::ISCADD_C:
|
||||
@@ -1900,10 +1846,6 @@ private:
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, true, 0,
|
||||
"((" + op_a + " << " + shift + ") + " + op_b + ')', 1, 1);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "ISCADD Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::POPC_C:
|
||||
@@ -1935,10 +1877,6 @@ private:
|
||||
|
||||
WriteLogicOperation(instr.gpr0, instr.alu.lop.operation, op_a, op_b,
|
||||
instr.alu.lop.pred_result_mode, instr.alu.lop.pred48);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "LOP Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::LOP3_C:
|
||||
@@ -1954,10 +1892,6 @@ private:
|
||||
}
|
||||
|
||||
WriteLop3Instruction(instr.gpr0, op_a, op_b, op_c, lut);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "LOP3 Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::IMNMX_C:
|
||||
@@ -1972,10 +1906,6 @@ private:
|
||||
'(' + condition + ") ? min(" + parameters + ") : max(" +
|
||||
parameters + ')',
|
||||
1, 1);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "IMNMX Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::LEA_R2:
|
||||
@@ -2177,10 +2107,6 @@ private:
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, "fma(" + op_a + ", " + op_b + ", " + op_c + ')',
|
||||
1, 1, instr.alu.saturate_d, 0, true);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "FFMA Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -2286,11 +2212,6 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
|
||||
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "I2F Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::F2F_R: {
|
||||
@@ -2329,11 +2250,6 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1, instr.alu.saturate_d);
|
||||
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "F2F Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::F2I_R:
|
||||
@@ -2383,10 +2299,6 @@ private:
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_output_signed, 0, op_a, 1,
|
||||
1, false, 0, instr.conversion.dest_size);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "F2I Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -2746,12 +2658,12 @@ private:
|
||||
}
|
||||
case 3: {
|
||||
if (is_array) {
|
||||
const std::string index = regs.GetRegisterAsInteger(instr.gpr8);
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2);
|
||||
const std::string z = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
coord =
|
||||
"vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + ");";
|
||||
UNIMPLEMENTED_MSG("3-coordinate arrays not fully implemented");
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string y = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
coord = "vec2 coords = vec2(" + x + ", " + y + ");";
|
||||
texture_type = Tegra::Shader::TextureType::Texture2D;
|
||||
is_array = false;
|
||||
} else {
|
||||
const std::string x = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||
@@ -2781,11 +2693,7 @@ private:
|
||||
break;
|
||||
}
|
||||
case Tegra::Shader::TextureProcessMode::LZ: {
|
||||
if (depth_compare && is_array) {
|
||||
texture = "texture(" + sampler + ", coords)";
|
||||
} else {
|
||||
texture = "textureLod(" + sampler + ", coords, 0.0)";
|
||||
}
|
||||
texture = "textureLod(" + sampler + ", coords, 0.0)";
|
||||
break;
|
||||
}
|
||||
case Tegra::Shader::TextureProcessMode::LL: {
|
||||
@@ -3199,11 +3107,6 @@ private:
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, value, 1, 1);
|
||||
}
|
||||
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "PSET Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OpCode::Type::PredicateSetPredicate: {
|
||||
@@ -3469,10 +3372,6 @@ private:
|
||||
}
|
||||
|
||||
regs.SetRegisterToInteger(instr.gpr0, is_signed, 0, sum, 1, 1);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "XMAD Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -3482,12 +3381,6 @@ private:
|
||||
EmitFragmentOutputsWrite();
|
||||
}
|
||||
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
if (cc != Tegra::Shader::ControlCode::T) {
|
||||
LOG_CRITICAL(HW_GPU, "EXIT Control Code used: {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
switch (instr.flow.cond) {
|
||||
case Tegra::Shader::FlowCondition::Always:
|
||||
shader.AddLine("return true;");
|
||||
@@ -3517,11 +3410,6 @@ private:
|
||||
|
||||
// Enclose "discard" in a conditional, so that GLSL compilation does not complain
|
||||
// about unexecuted instructions that may follow this.
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
if (cc != Tegra::Shader::ControlCode::T) {
|
||||
LOG_CRITICAL(HW_GPU, "KIL Control Code used: {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
}
|
||||
shader.AddLine("if (true) {");
|
||||
++shader.scope;
|
||||
shader.AddLine("discard;");
|
||||
@@ -3579,11 +3467,6 @@ private:
|
||||
case OpCode::Id::BRA: {
|
||||
ASSERT_MSG(instr.bra.constant_buffer == 0,
|
||||
"BRA with constant buffers are not implemented");
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
if (cc != Tegra::Shader::ControlCode::T) {
|
||||
LOG_CRITICAL(HW_GPU, "BRA Control Code used: {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
}
|
||||
const u32 target = offset + instr.bra.GetBranchTarget();
|
||||
shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }");
|
||||
break;
|
||||
@@ -3624,21 +3507,13 @@ private:
|
||||
}
|
||||
case OpCode::Id::SYNC: {
|
||||
// The SYNC opcode jumps to the address previously set by the SSY opcode
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
if (cc != Tegra::Shader::ControlCode::T) {
|
||||
LOG_CRITICAL(HW_GPU, "SYNC Control Code used: {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
}
|
||||
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
|
||||
EmitPopFromFlowStack();
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::BRK: {
|
||||
// The BRK opcode jumps to the address previously set by the PBK opcode
|
||||
const Tegra::Shader::ControlCode cc = instr.flow_control_code;
|
||||
if (cc != Tegra::Shader::ControlCode::T) {
|
||||
LOG_CRITICAL(HW_GPU, "BRK Control Code used: {}", static_cast<u32>(cc));
|
||||
UNREACHABLE();
|
||||
}
|
||||
ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
|
||||
EmitPopFromFlowStack();
|
||||
break;
|
||||
}
|
||||
@@ -3668,11 +3543,6 @@ private:
|
||||
regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
|
||||
instr.vmad.saturate == 1, 0, Register::Size::Word,
|
||||
instr.vmad.cc);
|
||||
if (instr.generates_cc) {
|
||||
LOG_CRITICAL(HW_GPU, "VMAD Generates an unhandled Control Code");
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::VSETP: {
|
||||
|
||||
@@ -82,8 +82,8 @@ void main() {
|
||||
}
|
||||
|
||||
ProgramResult GenerateGeometryShader(const ShaderSetup& setup) {
|
||||
// Version is intentionally skipped in shader generation, it's added by the lazy compilation.
|
||||
std::string out = "#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||
std::string out = "#version 430 core\n";
|
||||
out += "#extension GL_ARB_separate_shader_objects : enable\n\n";
|
||||
out += Decompiler::GetCommonDeclarations();
|
||||
out += "bool exec_geometry();\n";
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@
|
||||
#include <glad/glad.h>
|
||||
|
||||
#include "video_core/renderer_opengl/gl_resource_manager.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/maxwell_to_gl.h"
|
||||
|
||||
namespace OpenGL::GLShader {
|
||||
|
||||
@@ -22,15 +22,17 @@ OpenGLState::OpenGLState() {
|
||||
depth.test_enabled = false;
|
||||
depth.test_func = GL_LESS;
|
||||
depth.write_mask = GL_TRUE;
|
||||
depth.depth_range_near = 0.0f;
|
||||
depth.depth_range_far = 1.0f;
|
||||
|
||||
primitive_restart.enabled = false;
|
||||
primitive_restart.index = 0;
|
||||
for (auto& item : color_mask) {
|
||||
item.red_enabled = GL_TRUE;
|
||||
item.green_enabled = GL_TRUE;
|
||||
item.blue_enabled = GL_TRUE;
|
||||
item.alpha_enabled = GL_TRUE;
|
||||
}
|
||||
|
||||
color_mask.red_enabled = GL_TRUE;
|
||||
color_mask.green_enabled = GL_TRUE;
|
||||
color_mask.blue_enabled = GL_TRUE;
|
||||
color_mask.alpha_enabled = GL_TRUE;
|
||||
|
||||
stencil.test_enabled = false;
|
||||
auto reset_stencil = [](auto& config) {
|
||||
config.test_func = GL_ALWAYS;
|
||||
@@ -43,33 +45,19 @@ OpenGLState::OpenGLState() {
|
||||
};
|
||||
reset_stencil(stencil.front);
|
||||
reset_stencil(stencil.back);
|
||||
for (auto& item : viewports) {
|
||||
item.x = 0;
|
||||
item.y = 0;
|
||||
item.width = 0;
|
||||
item.height = 0;
|
||||
item.depth_range_near = 0.0f;
|
||||
item.depth_range_far = 1.0f;
|
||||
}
|
||||
scissor.enabled = false;
|
||||
scissor.x = 0;
|
||||
scissor.y = 0;
|
||||
scissor.width = 0;
|
||||
scissor.height = 0;
|
||||
for (auto& item : blend) {
|
||||
item.enabled = true;
|
||||
item.rgb_equation = GL_FUNC_ADD;
|
||||
item.a_equation = GL_FUNC_ADD;
|
||||
item.src_rgb_func = GL_ONE;
|
||||
item.dst_rgb_func = GL_ZERO;
|
||||
item.src_a_func = GL_ONE;
|
||||
item.dst_a_func = GL_ZERO;
|
||||
}
|
||||
independant_blend.enabled = false;
|
||||
blend_color.red = 0.0f;
|
||||
blend_color.green = 0.0f;
|
||||
blend_color.blue = 0.0f;
|
||||
blend_color.alpha = 0.0f;
|
||||
|
||||
blend.enabled = true;
|
||||
blend.rgb_equation = GL_FUNC_ADD;
|
||||
blend.a_equation = GL_FUNC_ADD;
|
||||
blend.src_rgb_func = GL_ONE;
|
||||
blend.dst_rgb_func = GL_ZERO;
|
||||
blend.src_a_func = GL_ONE;
|
||||
blend.dst_a_func = GL_ZERO;
|
||||
blend.color.red = 0.0f;
|
||||
blend.color.green = 0.0f;
|
||||
blend.color.blue = 0.0f;
|
||||
blend.color.alpha = 0.0f;
|
||||
|
||||
logic_op.enabled = false;
|
||||
logic_op.operation = GL_COPY;
|
||||
|
||||
@@ -85,23 +73,23 @@ OpenGLState::OpenGLState() {
|
||||
draw.shader_program = 0;
|
||||
draw.program_pipeline = 0;
|
||||
|
||||
scissor.enabled = false;
|
||||
scissor.x = 0;
|
||||
scissor.y = 0;
|
||||
scissor.width = 0;
|
||||
scissor.height = 0;
|
||||
|
||||
viewport.x = 0;
|
||||
viewport.y = 0;
|
||||
viewport.width = 0;
|
||||
viewport.height = 0;
|
||||
|
||||
clip_distance = {};
|
||||
|
||||
point.size = 1;
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyDefaultState() {
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
glDisable(GL_CULL_FACE);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
glEnable(GL_BLEND);
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
|
||||
void OpenGLState::ApplySRgb() const {
|
||||
void OpenGLState::Apply() const {
|
||||
// sRGB
|
||||
if (framebuffer_srgb.enabled != cur_state.framebuffer_srgb.enabled) {
|
||||
if (framebuffer_srgb.enabled) {
|
||||
@@ -112,281 +100,139 @@ void OpenGLState::ApplySRgb() const {
|
||||
glDisable(GL_FRAMEBUFFER_SRGB);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyCulling() const {
|
||||
// Culling
|
||||
const bool cull_changed = cull.enabled != cur_state.cull.enabled;
|
||||
if (cull_changed) {
|
||||
if (cull.enabled != cur_state.cull.enabled) {
|
||||
if (cull.enabled) {
|
||||
glEnable(GL_CULL_FACE);
|
||||
} else {
|
||||
glDisable(GL_CULL_FACE);
|
||||
}
|
||||
}
|
||||
if (cull.enabled) {
|
||||
if (cull_changed || cull.mode != cur_state.cull.mode) {
|
||||
glCullFace(cull.mode);
|
||||
}
|
||||
|
||||
if (cull_changed || cull.front_face != cur_state.cull.front_face) {
|
||||
glFrontFace(cull.front_face);
|
||||
}
|
||||
if (cull.mode != cur_state.cull.mode) {
|
||||
glCullFace(cull.mode);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyColorMask() const {
|
||||
if (GLAD_GL_ARB_viewport_array) {
|
||||
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||
const auto& updated = color_mask[i];
|
||||
const auto& current = cur_state.color_mask[i];
|
||||
if (updated.red_enabled != current.red_enabled ||
|
||||
updated.green_enabled != current.green_enabled ||
|
||||
updated.blue_enabled != current.blue_enabled ||
|
||||
updated.alpha_enabled != current.alpha_enabled) {
|
||||
glColorMaski(static_cast<GLuint>(i), updated.red_enabled, updated.green_enabled,
|
||||
updated.blue_enabled, updated.alpha_enabled);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto& updated = color_mask[0];
|
||||
const auto& current = cur_state.color_mask[0];
|
||||
if (updated.red_enabled != current.red_enabled ||
|
||||
updated.green_enabled != current.green_enabled ||
|
||||
updated.blue_enabled != current.blue_enabled ||
|
||||
updated.alpha_enabled != current.alpha_enabled) {
|
||||
glColorMask(updated.red_enabled, updated.green_enabled, updated.blue_enabled,
|
||||
updated.alpha_enabled);
|
||||
}
|
||||
if (cull.front_face != cur_state.cull.front_face) {
|
||||
glFrontFace(cull.front_face);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyDepth() const {
|
||||
// Depth test
|
||||
const bool depth_test_changed = depth.test_enabled != cur_state.depth.test_enabled;
|
||||
if (depth_test_changed) {
|
||||
if (depth.test_enabled != cur_state.depth.test_enabled) {
|
||||
if (depth.test_enabled) {
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
} else {
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
if (depth.test_enabled &&
|
||||
(depth_test_changed || depth.test_func != cur_state.depth.test_func)) {
|
||||
|
||||
if (depth.test_func != cur_state.depth.test_func) {
|
||||
glDepthFunc(depth.test_func);
|
||||
}
|
||||
|
||||
// Depth mask
|
||||
if (depth.write_mask != cur_state.depth.write_mask) {
|
||||
glDepthMask(depth.write_mask);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyPrimitiveRestart() const {
|
||||
const bool primitive_restart_changed =
|
||||
primitive_restart.enabled != cur_state.primitive_restart.enabled;
|
||||
if (primitive_restart_changed) {
|
||||
// Depth range
|
||||
if (depth.depth_range_near != cur_state.depth.depth_range_near ||
|
||||
depth.depth_range_far != cur_state.depth.depth_range_far) {
|
||||
glDepthRange(depth.depth_range_near, depth.depth_range_far);
|
||||
}
|
||||
|
||||
// Primitive restart
|
||||
if (primitive_restart.enabled != cur_state.primitive_restart.enabled) {
|
||||
if (primitive_restart.enabled) {
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
} else {
|
||||
glDisable(GL_PRIMITIVE_RESTART);
|
||||
}
|
||||
}
|
||||
if (primitive_restart_changed ||
|
||||
(primitive_restart.enabled &&
|
||||
primitive_restart.index != cur_state.primitive_restart.index)) {
|
||||
if (primitive_restart.index != cur_state.primitive_restart.index) {
|
||||
glPrimitiveRestartIndex(primitive_restart.index);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyStencilTest() const {
|
||||
const bool stencil_test_changed = stencil.test_enabled != cur_state.stencil.test_enabled;
|
||||
if (stencil_test_changed) {
|
||||
// Color mask
|
||||
if (color_mask.red_enabled != cur_state.color_mask.red_enabled ||
|
||||
color_mask.green_enabled != cur_state.color_mask.green_enabled ||
|
||||
color_mask.blue_enabled != cur_state.color_mask.blue_enabled ||
|
||||
color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) {
|
||||
glColorMask(color_mask.red_enabled, color_mask.green_enabled, color_mask.blue_enabled,
|
||||
color_mask.alpha_enabled);
|
||||
}
|
||||
|
||||
// Stencil test
|
||||
if (stencil.test_enabled != cur_state.stencil.test_enabled) {
|
||||
if (stencil.test_enabled) {
|
||||
glEnable(GL_STENCIL_TEST);
|
||||
} else {
|
||||
glDisable(GL_STENCIL_TEST);
|
||||
}
|
||||
}
|
||||
if (stencil.test_enabled) {
|
||||
auto config_stencil = [stencil_test_changed](GLenum face, const auto& config,
|
||||
const auto& prev_config) {
|
||||
if (stencil_test_changed || config.test_func != prev_config.test_func ||
|
||||
config.test_ref != prev_config.test_ref ||
|
||||
config.test_mask != prev_config.test_mask) {
|
||||
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
|
||||
}
|
||||
if (stencil_test_changed || config.action_depth_fail != prev_config.action_depth_fail ||
|
||||
config.action_depth_pass != prev_config.action_depth_pass ||
|
||||
config.action_stencil_fail != prev_config.action_stencil_fail) {
|
||||
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
|
||||
config.action_depth_pass);
|
||||
}
|
||||
if (config.write_mask != prev_config.write_mask) {
|
||||
glStencilMaskSeparate(face, config.write_mask);
|
||||
}
|
||||
};
|
||||
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
|
||||
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
||||
}
|
||||
}
|
||||
auto config_stencil = [](GLenum face, const auto& config, const auto& prev_config) {
|
||||
if (config.test_func != prev_config.test_func || config.test_ref != prev_config.test_ref ||
|
||||
config.test_mask != prev_config.test_mask) {
|
||||
glStencilFuncSeparate(face, config.test_func, config.test_ref, config.test_mask);
|
||||
}
|
||||
if (config.action_depth_fail != prev_config.action_depth_fail ||
|
||||
config.action_depth_pass != prev_config.action_depth_pass ||
|
||||
config.action_stencil_fail != prev_config.action_stencil_fail) {
|
||||
glStencilOpSeparate(face, config.action_stencil_fail, config.action_depth_fail,
|
||||
config.action_depth_pass);
|
||||
}
|
||||
if (config.write_mask != prev_config.write_mask) {
|
||||
glStencilMaskSeparate(face, config.write_mask);
|
||||
}
|
||||
};
|
||||
config_stencil(GL_FRONT, stencil.front, cur_state.stencil.front);
|
||||
config_stencil(GL_BACK, stencil.back, cur_state.stencil.back);
|
||||
|
||||
void OpenGLState::ApplyScissor() const {
|
||||
const bool scissor_changed = scissor.enabled != cur_state.scissor.enabled;
|
||||
if (scissor_changed) {
|
||||
if (scissor.enabled) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
if (scissor.enabled &&
|
||||
(scissor_changed || scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
|
||||
scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height)) {
|
||||
glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyViewport() const {
|
||||
if (GLAD_GL_ARB_viewport_array) {
|
||||
for (GLuint i = 0;
|
||||
i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumRenderTargets); i++) {
|
||||
const auto& current = cur_state.viewports[i];
|
||||
const auto& updated = viewports[i];
|
||||
if (updated.x != current.x || updated.y != current.y ||
|
||||
updated.width != current.width || updated.height != current.height) {
|
||||
glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height);
|
||||
}
|
||||
if (updated.depth_range_near != current.depth_range_near ||
|
||||
updated.depth_range_far != current.depth_range_far) {
|
||||
glDepthRangeIndexed(i, updated.depth_range_near, updated.depth_range_far);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
const auto& current = cur_state.viewports[0];
|
||||
const auto& updated = viewports[0];
|
||||
if (updated.x != current.x || updated.y != current.y || updated.width != current.width ||
|
||||
updated.height != current.height) {
|
||||
glViewport(updated.x, updated.y, updated.width, updated.height);
|
||||
}
|
||||
if (updated.depth_range_near != current.depth_range_near ||
|
||||
updated.depth_range_far != current.depth_range_far) {
|
||||
glDepthRange(updated.depth_range_near, updated.depth_range_far);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyGlobalBlending() const {
|
||||
const Blend& current = cur_state.blend[0];
|
||||
const Blend& updated = blend[0];
|
||||
const bool blend_changed = updated.enabled != current.enabled;
|
||||
if (blend_changed) {
|
||||
if (updated.enabled) {
|
||||
// Blending
|
||||
if (blend.enabled != cur_state.blend.enabled) {
|
||||
if (blend.enabled) {
|
||||
ASSERT(!logic_op.enabled);
|
||||
glEnable(GL_BLEND);
|
||||
} else {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
if (!updated.enabled) {
|
||||
return;
|
||||
}
|
||||
if (updated.separate_alpha) {
|
||||
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
|
||||
updated.dst_rgb_func != current.dst_rgb_func ||
|
||||
updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
|
||||
glBlendFuncSeparate(updated.src_rgb_func, updated.dst_rgb_func, updated.src_a_func,
|
||||
updated.dst_a_func);
|
||||
}
|
||||
|
||||
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
||||
updated.a_equation != current.a_equation) {
|
||||
glBlendEquationSeparate(updated.rgb_equation, updated.a_equation);
|
||||
}
|
||||
} else {
|
||||
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
|
||||
updated.dst_rgb_func != current.dst_rgb_func) {
|
||||
glBlendFunc(updated.src_rgb_func, updated.dst_rgb_func);
|
||||
}
|
||||
|
||||
if (blend_changed || updated.rgb_equation != current.rgb_equation) {
|
||||
glBlendEquation(updated.rgb_equation);
|
||||
}
|
||||
if (blend.color.red != cur_state.blend.color.red ||
|
||||
blend.color.green != cur_state.blend.color.green ||
|
||||
blend.color.blue != cur_state.blend.color.blue ||
|
||||
blend.color.alpha != cur_state.blend.color.alpha) {
|
||||
glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyTargetBlending(int target, bool force) const {
|
||||
const Blend& updated = blend[target];
|
||||
const Blend& current = cur_state.blend[target];
|
||||
const bool blend_changed = updated.enabled != current.enabled || force;
|
||||
if (blend_changed) {
|
||||
if (updated.enabled) {
|
||||
glEnablei(GL_BLEND, static_cast<GLuint>(target));
|
||||
} else {
|
||||
glDisablei(GL_BLEND, static_cast<GLuint>(target));
|
||||
}
|
||||
if (blend.src_rgb_func != cur_state.blend.src_rgb_func ||
|
||||
blend.dst_rgb_func != cur_state.blend.dst_rgb_func ||
|
||||
blend.src_a_func != cur_state.blend.src_a_func ||
|
||||
blend.dst_a_func != cur_state.blend.dst_a_func) {
|
||||
glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func,
|
||||
blend.dst_a_func);
|
||||
}
|
||||
if (!updated.enabled) {
|
||||
return;
|
||||
}
|
||||
if (updated.separate_alpha) {
|
||||
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
|
||||
updated.dst_rgb_func != current.dst_rgb_func ||
|
||||
updated.src_a_func != current.src_a_func || updated.dst_a_func != current.dst_a_func) {
|
||||
glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func,
|
||||
updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func);
|
||||
}
|
||||
|
||||
if (blend_changed || updated.rgb_equation != current.rgb_equation ||
|
||||
updated.a_equation != current.a_equation) {
|
||||
glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation,
|
||||
updated.a_equation);
|
||||
}
|
||||
} else {
|
||||
if (blend_changed || updated.src_rgb_func != current.src_rgb_func ||
|
||||
updated.dst_rgb_func != current.dst_rgb_func) {
|
||||
glBlendFunciARB(static_cast<GLuint>(target), updated.src_rgb_func,
|
||||
updated.dst_rgb_func);
|
||||
}
|
||||
|
||||
if (blend_changed || updated.rgb_equation != current.rgb_equation) {
|
||||
glBlendEquationiARB(static_cast<GLuint>(target), updated.rgb_equation);
|
||||
}
|
||||
if (blend.rgb_equation != cur_state.blend.rgb_equation ||
|
||||
blend.a_equation != cur_state.blend.a_equation) {
|
||||
glBlendEquationSeparate(blend.rgb_equation, blend.a_equation);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyBlending() const {
|
||||
if (independant_blend.enabled) {
|
||||
for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) {
|
||||
ApplyTargetBlending(i,
|
||||
independant_blend.enabled != cur_state.independant_blend.enabled);
|
||||
}
|
||||
} else {
|
||||
ApplyGlobalBlending();
|
||||
}
|
||||
if (blend_color.red != cur_state.blend_color.red ||
|
||||
blend_color.green != cur_state.blend_color.green ||
|
||||
blend_color.blue != cur_state.blend_color.blue ||
|
||||
blend_color.alpha != cur_state.blend_color.alpha) {
|
||||
glBlendColor(blend_color.red, blend_color.green, blend_color.blue, blend_color.alpha);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyLogicOp() const {
|
||||
const bool logic_op_changed = logic_op.enabled != cur_state.logic_op.enabled;
|
||||
if (logic_op_changed) {
|
||||
// Logic Operation
|
||||
if (logic_op.enabled != cur_state.logic_op.enabled) {
|
||||
if (logic_op.enabled) {
|
||||
ASSERT(!blend.enabled);
|
||||
glEnable(GL_COLOR_LOGIC_OP);
|
||||
} else {
|
||||
glDisable(GL_COLOR_LOGIC_OP);
|
||||
}
|
||||
}
|
||||
|
||||
if (logic_op.enabled &&
|
||||
(logic_op_changed || logic_op.operation != cur_state.logic_op.operation)) {
|
||||
if (logic_op.operation != cur_state.logic_op.operation) {
|
||||
glLogicOp(logic_op.operation);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyTextures() const {
|
||||
// Textures
|
||||
for (std::size_t i = 0; i < std::size(texture_units); ++i) {
|
||||
const auto& texture_unit = texture_units[i];
|
||||
const auto& cur_state_texture_unit = cur_state.texture_units[i];
|
||||
@@ -405,29 +251,28 @@ void OpenGLState::ApplyTextures() const {
|
||||
glTexParameteriv(texture_unit.target, GL_TEXTURE_SWIZZLE_RGBA, mask.data());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplySamplers() const {
|
||||
bool has_delta{};
|
||||
std::size_t first{}, last{};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
|
||||
for (std::size_t i = 0; i < std::size(samplers); ++i) {
|
||||
samplers[i] = texture_units[i].sampler;
|
||||
if (samplers[i] != cur_state.texture_units[i].sampler) {
|
||||
if (!has_delta) {
|
||||
first = i;
|
||||
has_delta = true;
|
||||
// Samplers
|
||||
{
|
||||
bool has_delta{};
|
||||
std::size_t first{}, last{};
|
||||
std::array<GLuint, Tegra::Engines::Maxwell3D::Regs::NumTextureSamplers> samplers;
|
||||
for (std::size_t i = 0; i < std::size(samplers); ++i) {
|
||||
samplers[i] = texture_units[i].sampler;
|
||||
if (samplers[i] != cur_state.texture_units[i].sampler) {
|
||||
if (!has_delta) {
|
||||
first = i;
|
||||
has_delta = true;
|
||||
}
|
||||
last = i;
|
||||
}
|
||||
last = i;
|
||||
}
|
||||
if (has_delta) {
|
||||
glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
|
||||
samplers.data());
|
||||
}
|
||||
}
|
||||
if (has_delta) {
|
||||
glBindSamplers(static_cast<GLuint>(first), static_cast<GLsizei>(last - first + 1),
|
||||
samplers.data());
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyFramebufferState() const {
|
||||
// Framebuffer
|
||||
if (draw.read_framebuffer != cur_state.draw.read_framebuffer) {
|
||||
glBindFramebuffer(GL_READ_FRAMEBUFFER, draw.read_framebuffer);
|
||||
@@ -435,9 +280,7 @@ void OpenGLState::ApplyFramebufferState() const {
|
||||
if (draw.draw_framebuffer != cur_state.draw.draw_framebuffer) {
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, draw.draw_framebuffer);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::ApplyVertexBufferState() const {
|
||||
// Vertex array
|
||||
if (draw.vertex_array != cur_state.draw.vertex_array) {
|
||||
glBindVertexArray(draw.vertex_array);
|
||||
@@ -447,11 +290,7 @@ void OpenGLState::ApplyVertexBufferState() const {
|
||||
if (draw.vertex_buffer != cur_state.draw.vertex_buffer) {
|
||||
glBindBuffer(GL_ARRAY_BUFFER, draw.vertex_buffer);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLState::Apply() const {
|
||||
ApplyFramebufferState();
|
||||
ApplyVertexBufferState();
|
||||
// Uniform buffer
|
||||
if (draw.uniform_buffer != cur_state.draw.uniform_buffer) {
|
||||
glBindBuffer(GL_UNIFORM_BUFFER, draw.uniform_buffer);
|
||||
@@ -466,6 +305,27 @@ void OpenGLState::Apply() const {
|
||||
if (draw.program_pipeline != cur_state.draw.program_pipeline) {
|
||||
glBindProgramPipeline(draw.program_pipeline);
|
||||
}
|
||||
|
||||
// Scissor test
|
||||
if (scissor.enabled != cur_state.scissor.enabled) {
|
||||
if (scissor.enabled) {
|
||||
glEnable(GL_SCISSOR_TEST);
|
||||
} else {
|
||||
glDisable(GL_SCISSOR_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (scissor.x != cur_state.scissor.x || scissor.y != cur_state.scissor.y ||
|
||||
scissor.width != cur_state.scissor.width || scissor.height != cur_state.scissor.height) {
|
||||
glScissor(scissor.x, scissor.y, scissor.width, scissor.height);
|
||||
}
|
||||
|
||||
if (viewport.x != cur_state.viewport.x || viewport.y != cur_state.viewport.y ||
|
||||
viewport.width != cur_state.viewport.width ||
|
||||
viewport.height != cur_state.viewport.height) {
|
||||
glViewport(viewport.x, viewport.y, viewport.width, viewport.height);
|
||||
}
|
||||
|
||||
// Clip distance
|
||||
for (std::size_t i = 0; i < clip_distance.size(); ++i) {
|
||||
if (clip_distance[i] != cur_state.clip_distance[i]) {
|
||||
@@ -476,22 +336,12 @@ void OpenGLState::Apply() const {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Point
|
||||
if (point.size != cur_state.point.size) {
|
||||
glPointSize(point.size);
|
||||
}
|
||||
ApplyColorMask();
|
||||
ApplyViewport();
|
||||
ApplyScissor();
|
||||
ApplyStencilTest();
|
||||
ApplySRgb();
|
||||
ApplyCulling();
|
||||
ApplyDepth();
|
||||
ApplyPrimitiveRestart();
|
||||
ApplyBlending();
|
||||
ApplyLogicOp();
|
||||
ApplyTextures();
|
||||
ApplySamplers();
|
||||
|
||||
cur_state = *this;
|
||||
}
|
||||
|
||||
|
||||
@@ -46,9 +46,11 @@ public:
|
||||
} cull;
|
||||
|
||||
struct {
|
||||
bool test_enabled; // GL_DEPTH_TEST
|
||||
GLenum test_func; // GL_DEPTH_FUNC
|
||||
GLboolean write_mask; // GL_DEPTH_WRITEMASK
|
||||
bool test_enabled; // GL_DEPTH_TEST
|
||||
GLenum test_func; // GL_DEPTH_FUNC
|
||||
GLboolean write_mask; // GL_DEPTH_WRITEMASK
|
||||
GLfloat depth_range_near; // GL_DEPTH_RANGE
|
||||
GLfloat depth_range_far; // GL_DEPTH_RANGE
|
||||
} depth;
|
||||
|
||||
struct {
|
||||
@@ -56,14 +58,13 @@ public:
|
||||
GLuint index;
|
||||
} primitive_restart; // GL_PRIMITIVE_RESTART
|
||||
|
||||
struct ColorMask {
|
||||
struct {
|
||||
GLboolean red_enabled;
|
||||
GLboolean green_enabled;
|
||||
GLboolean blue_enabled;
|
||||
GLboolean alpha_enabled;
|
||||
};
|
||||
std::array<ColorMask, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets>
|
||||
color_mask; // GL_COLOR_WRITEMASK
|
||||
} color_mask; // GL_COLOR_WRITEMASK
|
||||
|
||||
struct {
|
||||
bool test_enabled; // GL_STENCIL_TEST
|
||||
struct {
|
||||
@@ -77,28 +78,22 @@ public:
|
||||
} front, back;
|
||||
} stencil;
|
||||
|
||||
struct Blend {
|
||||
struct {
|
||||
bool enabled; // GL_BLEND
|
||||
bool separate_alpha; // Independent blend enabled
|
||||
GLenum rgb_equation; // GL_BLEND_EQUATION_RGB
|
||||
GLenum a_equation; // GL_BLEND_EQUATION_ALPHA
|
||||
GLenum src_rgb_func; // GL_BLEND_SRC_RGB
|
||||
GLenum dst_rgb_func; // GL_BLEND_DST_RGB
|
||||
GLenum src_a_func; // GL_BLEND_SRC_ALPHA
|
||||
GLenum dst_a_func; // GL_BLEND_DST_ALPHA
|
||||
};
|
||||
std::array<Blend, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> blend;
|
||||
|
||||
struct {
|
||||
bool enabled;
|
||||
} independant_blend;
|
||||
|
||||
struct {
|
||||
GLclampf red;
|
||||
GLclampf green;
|
||||
GLclampf blue;
|
||||
GLclampf alpha;
|
||||
} blend_color; // GL_BLEND_COLOR
|
||||
struct {
|
||||
GLclampf red;
|
||||
GLclampf green;
|
||||
GLclampf blue;
|
||||
GLclampf alpha;
|
||||
} color; // GL_BLEND_COLOR
|
||||
} blend;
|
||||
|
||||
struct {
|
||||
bool enabled; // GL_LOGIC_OP_MODE
|
||||
@@ -143,16 +138,6 @@ public:
|
||||
GLuint program_pipeline; // GL_PROGRAM_PIPELINE_BINDING
|
||||
} draw;
|
||||
|
||||
struct viewport {
|
||||
GLfloat x;
|
||||
GLfloat y;
|
||||
GLfloat width;
|
||||
GLfloat height;
|
||||
GLfloat depth_range_near; // GL_DEPTH_RANGE
|
||||
GLfloat depth_range_far; // GL_DEPTH_RANGE
|
||||
};
|
||||
std::array<viewport, Tegra::Engines::Maxwell3D::Regs::NumRenderTargets> viewports;
|
||||
|
||||
struct {
|
||||
bool enabled; // GL_SCISSOR_TEST
|
||||
GLint x;
|
||||
@@ -161,6 +146,13 @@ public:
|
||||
GLsizei height;
|
||||
} scissor;
|
||||
|
||||
struct {
|
||||
GLint x;
|
||||
GLint y;
|
||||
GLsizei width;
|
||||
GLsizei height;
|
||||
} viewport;
|
||||
|
||||
struct {
|
||||
float size; // GL_POINT_SIZE
|
||||
} point;
|
||||
@@ -181,12 +173,7 @@ public:
|
||||
}
|
||||
/// Apply this state as the current OpenGL state
|
||||
void Apply() const;
|
||||
/// Apply only the state afecting the framebuffer
|
||||
void ApplyFramebufferState() const;
|
||||
/// Apply only the state afecting the vertex buffer
|
||||
void ApplyVertexBufferState() const;
|
||||
/// Set the initial OpenGL state
|
||||
static void ApplyDefaultState();
|
||||
|
||||
/// Resets any references to the given resource
|
||||
OpenGLState& UnbindTexture(GLuint handle);
|
||||
OpenGLState& ResetSampler(GLuint handle);
|
||||
@@ -201,20 +188,6 @@ private:
|
||||
// Workaround for sRGB problems caused by
|
||||
// QT not supporting srgb output
|
||||
static bool s_rgb_used;
|
||||
void ApplySRgb() const;
|
||||
void ApplyCulling() const;
|
||||
void ApplyColorMask() const;
|
||||
void ApplyDepth() const;
|
||||
void ApplyPrimitiveRestart() const;
|
||||
void ApplyStencilTest() const;
|
||||
void ApplyViewport() const;
|
||||
void ApplyTargetBlending(int target, bool force) const;
|
||||
void ApplyGlobalBlending() const;
|
||||
void ApplyBlending() const;
|
||||
void ApplyLogicOp() const;
|
||||
void ApplyTextures() const;
|
||||
void ApplySamplers() const;
|
||||
void ApplyScissor() const;
|
||||
};
|
||||
|
||||
} // namespace OpenGL
|
||||
|
||||
@@ -6,13 +6,9 @@
|
||||
#include <vector>
|
||||
#include "common/alignment.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/microprofile.h"
|
||||
#include "video_core/renderer_opengl/gl_state.h"
|
||||
#include "video_core/renderer_opengl/gl_stream_buffer.h"
|
||||
|
||||
MICROPROFILE_DEFINE(OpenGL_StreamBuffer, "OpenGL", "Stream Buffer Orphaning",
|
||||
MP_RGB(128, 128, 192));
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
OGLStreamBuffer::OGLStreamBuffer(GLenum target, GLsizeiptr size, bool prefer_coherent)
|
||||
@@ -79,7 +75,6 @@ std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr a
|
||||
}
|
||||
|
||||
if (invalidate || !persistent) {
|
||||
MICROPROFILE_SCOPE(OpenGL_StreamBuffer);
|
||||
GLbitfield flags = GL_MAP_WRITE_BIT | (persistent ? GL_MAP_PERSISTENT_BIT : 0) |
|
||||
(coherent ? GL_MAP_COHERENT_BIT : GL_MAP_FLUSH_EXPLICIT_BIT) |
|
||||
(invalidate ? GL_MAP_INVALIDATE_BUFFER_BIT : GL_MAP_UNSYNCHRONIZED_BIT);
|
||||
|
||||
@@ -159,8 +159,10 @@ inline GLenum TextureFilterMode(Tegra::Texture::TextureFilter filter_mode,
|
||||
}
|
||||
}
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented texture filter mode={}", static_cast<u32>(filter_mode));
|
||||
return GL_LINEAR;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture filter mode={}",
|
||||
static_cast<u32>(filter_mode));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
|
||||
@@ -181,8 +183,9 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) {
|
||||
case Tegra::Texture::WrapMode::MirrorOnceClampToEdge:
|
||||
return GL_MIRROR_CLAMP_TO_EDGE;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode));
|
||||
return GL_REPEAT;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
|
||||
@@ -204,9 +207,10 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) {
|
||||
case Tegra::Texture::DepthCompareFunc::Always:
|
||||
return GL_ALWAYS;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented texture depth compare function ={}",
|
||||
static_cast<u32>(func));
|
||||
return GL_GREATER;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented texture depth compare function ={}",
|
||||
static_cast<u32>(func));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
|
||||
@@ -222,8 +226,9 @@ inline GLenum BlendEquation(Maxwell::Blend::Equation equation) {
|
||||
case Maxwell::Blend::Equation::Max:
|
||||
return GL_MAX;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
|
||||
return GL_FUNC_ADD;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
|
||||
@@ -286,8 +291,9 @@ inline GLenum BlendFunc(Maxwell::Blend::Factor factor) {
|
||||
case Maxwell::Blend::Factor::OneMinusConstantAlphaGL:
|
||||
return GL_ONE_MINUS_CONSTANT_ALPHA;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
|
||||
return GL_ZERO;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented blend factor={}", static_cast<u32>(factor));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
|
||||
@@ -306,8 +312,9 @@ inline GLenum SwizzleSource(Tegra::Texture::SwizzleSource source) {
|
||||
case Tegra::Texture::SwizzleSource::OneFloat:
|
||||
return GL_ONE;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source));
|
||||
return GL_ZERO;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented swizzle source={}", static_cast<u32>(source));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
|
||||
@@ -337,39 +344,33 @@ inline GLenum ComparisonOp(Maxwell::ComparisonOp comparison) {
|
||||
case Maxwell::ComparisonOp::AlwaysOld:
|
||||
return GL_ALWAYS;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison));
|
||||
return GL_ALWAYS;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented comparison op={}", static_cast<u32>(comparison));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum StencilOp(Maxwell::StencilOp stencil) {
|
||||
switch (stencil) {
|
||||
case Maxwell::StencilOp::Keep:
|
||||
case Maxwell::StencilOp::KeepOGL:
|
||||
return GL_KEEP;
|
||||
case Maxwell::StencilOp::Zero:
|
||||
case Maxwell::StencilOp::ZeroOGL:
|
||||
return GL_ZERO;
|
||||
case Maxwell::StencilOp::Replace:
|
||||
case Maxwell::StencilOp::ReplaceOGL:
|
||||
return GL_REPLACE;
|
||||
case Maxwell::StencilOp::Incr:
|
||||
case Maxwell::StencilOp::IncrOGL:
|
||||
return GL_INCR;
|
||||
case Maxwell::StencilOp::Decr:
|
||||
case Maxwell::StencilOp::DecrOGL:
|
||||
return GL_DECR;
|
||||
case Maxwell::StencilOp::Invert:
|
||||
case Maxwell::StencilOp::InvertOGL:
|
||||
return GL_INVERT;
|
||||
case Maxwell::StencilOp::IncrWrap:
|
||||
case Maxwell::StencilOp::IncrWrapOGL:
|
||||
return GL_INCR_WRAP;
|
||||
case Maxwell::StencilOp::DecrWrap:
|
||||
case Maxwell::StencilOp::DecrWrapOGL:
|
||||
return GL_DECR_WRAP;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil));
|
||||
return GL_KEEP;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented stencil op={}", static_cast<u32>(stencil));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
|
||||
@@ -379,8 +380,9 @@ inline GLenum FrontFace(Maxwell::Cull::FrontFace front_face) {
|
||||
case Maxwell::Cull::FrontFace::CounterClockWise:
|
||||
return GL_CCW;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face));
|
||||
return GL_CCW;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented front face cull={}", static_cast<u32>(front_face));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
|
||||
@@ -392,8 +394,9 @@ inline GLenum CullFace(Maxwell::Cull::CullFace cull_face) {
|
||||
case Maxwell::Cull::CullFace::FrontAndBack:
|
||||
return GL_FRONT_AND_BACK;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face));
|
||||
return GL_BACK;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented cull face={}", static_cast<u32>(cull_face));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
inline GLenum LogicOp(Maxwell::LogicOperation operation) {
|
||||
@@ -431,8 +434,9 @@ inline GLenum LogicOp(Maxwell::LogicOperation operation) {
|
||||
case Maxwell::LogicOperation::Set:
|
||||
return GL_SET;
|
||||
}
|
||||
LOG_ERROR(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation));
|
||||
return GL_COPY;
|
||||
LOG_CRITICAL(Render_OpenGL, "Unimplemented logic operation={}", static_cast<u32>(operation));
|
||||
UNREACHABLE();
|
||||
return {};
|
||||
}
|
||||
|
||||
} // namespace MaxwellToGL
|
||||
|
||||
@@ -1,490 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/math_util.h"
|
||||
#include "video_core/surface.h"
|
||||
|
||||
namespace VideoCore::Surface {
|
||||
|
||||
SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type) {
|
||||
switch (texture_type) {
|
||||
case Tegra::Texture::TextureType::Texture1D:
|
||||
return SurfaceTarget::Texture1D;
|
||||
case Tegra::Texture::TextureType::Texture2D:
|
||||
case Tegra::Texture::TextureType::Texture2DNoMipmap:
|
||||
return SurfaceTarget::Texture2D;
|
||||
case Tegra::Texture::TextureType::Texture3D:
|
||||
return SurfaceTarget::Texture3D;
|
||||
case Tegra::Texture::TextureType::TextureCubemap:
|
||||
return SurfaceTarget::TextureCubemap;
|
||||
case Tegra::Texture::TextureType::TextureCubeArray:
|
||||
return SurfaceTarget::TextureCubeArray;
|
||||
case Tegra::Texture::TextureType::Texture1DArray:
|
||||
return SurfaceTarget::Texture1DArray;
|
||||
case Tegra::Texture::TextureType::Texture2DArray:
|
||||
return SurfaceTarget::Texture2DArray;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented texture_type={}", static_cast<u32>(texture_type));
|
||||
UNREACHABLE();
|
||||
return SurfaceTarget::Texture2D;
|
||||
}
|
||||
}
|
||||
|
||||
bool SurfaceTargetIsLayered(SurfaceTarget target) {
|
||||
switch (target) {
|
||||
case SurfaceTarget::Texture1D:
|
||||
case SurfaceTarget::Texture2D:
|
||||
case SurfaceTarget::Texture3D:
|
||||
return false;
|
||||
case SurfaceTarget::Texture1DArray:
|
||||
case SurfaceTarget::Texture2DArray:
|
||||
case SurfaceTarget::TextureCubemap:
|
||||
case SurfaceTarget::TextureCubeArray:
|
||||
return true;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented surface_target={}", static_cast<u32>(target));
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::DepthFormat::S8_Z24_UNORM:
|
||||
return PixelFormat::S8Z24;
|
||||
case Tegra::DepthFormat::Z24_S8_UNORM:
|
||||
return PixelFormat::Z24S8;
|
||||
case Tegra::DepthFormat::Z32_FLOAT:
|
||||
return PixelFormat::Z32F;
|
||||
case Tegra::DepthFormat::Z16_UNORM:
|
||||
return PixelFormat::Z16;
|
||||
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
||||
return PixelFormat::Z32FS8;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format) {
|
||||
switch (format) {
|
||||
// TODO (Hexagon12): Converting SRGBA to RGBA is a hack and doesn't completely correct the
|
||||
// gamma.
|
||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||
return PixelFormat::RGBA8_SRGB;
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
return PixelFormat::ABGR8U;
|
||||
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
||||
return PixelFormat::ABGR8S;
|
||||
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
||||
return PixelFormat::ABGR8UI;
|
||||
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
||||
return PixelFormat::BGRA8_SRGB;
|
||||
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
||||
return PixelFormat::BGRA8;
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
return PixelFormat::A2B10G10R10U;
|
||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||
return PixelFormat::RGBA16F;
|
||||
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
||||
return PixelFormat::RGBA16U;
|
||||
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
||||
return PixelFormat::RGBA16UI;
|
||||
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
||||
return PixelFormat::RGBA32F;
|
||||
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
||||
return PixelFormat::RG32F;
|
||||
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
||||
return PixelFormat::R11FG11FB10F;
|
||||
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
||||
return PixelFormat::B5G6R5U;
|
||||
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
||||
return PixelFormat::A1B5G5R5U;
|
||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||
return PixelFormat::RGBA32UI;
|
||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||
return PixelFormat::R8U;
|
||||
case Tegra::RenderTargetFormat::R8_UINT:
|
||||
return PixelFormat::R8UI;
|
||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||
return PixelFormat::RG16F;
|
||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||
return PixelFormat::RG16UI;
|
||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||
return PixelFormat::RG16I;
|
||||
case Tegra::RenderTargetFormat::RG16_UNORM:
|
||||
return PixelFormat::RG16;
|
||||
case Tegra::RenderTargetFormat::RG16_SNORM:
|
||||
return PixelFormat::RG16S;
|
||||
case Tegra::RenderTargetFormat::RG8_UNORM:
|
||||
return PixelFormat::RG8U;
|
||||
case Tegra::RenderTargetFormat::RG8_SNORM:
|
||||
return PixelFormat::RG8S;
|
||||
case Tegra::RenderTargetFormat::R16_FLOAT:
|
||||
return PixelFormat::R16F;
|
||||
case Tegra::RenderTargetFormat::R16_UNORM:
|
||||
return PixelFormat::R16U;
|
||||
case Tegra::RenderTargetFormat::R16_SNORM:
|
||||
return PixelFormat::R16S;
|
||||
case Tegra::RenderTargetFormat::R16_UINT:
|
||||
return PixelFormat::R16UI;
|
||||
case Tegra::RenderTargetFormat::R16_SINT:
|
||||
return PixelFormat::R16I;
|
||||
case Tegra::RenderTargetFormat::R32_FLOAT:
|
||||
return PixelFormat::R32F;
|
||||
case Tegra::RenderTargetFormat::R32_UINT:
|
||||
return PixelFormat::R32UI;
|
||||
case Tegra::RenderTargetFormat::RG32_UINT:
|
||||
return PixelFormat::RG32UI;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
||||
Tegra::Texture::ComponentType component_type,
|
||||
bool is_srgb) {
|
||||
// TODO(Subv): Properly implement this
|
||||
switch (format) {
|
||||
case Tegra::Texture::TextureFormat::A8R8G8B8:
|
||||
if (is_srgb) {
|
||||
return PixelFormat::RGBA8_SRGB;
|
||||
}
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::ABGR8U;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::ABGR8S;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::ABGR8UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::B5G6R5:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::B5G6R5U;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::A2B10G10R10:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::A2B10G10R10U;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::A1B5G5R5:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::A1B5G5R5U;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R8:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::R8U;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R8UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::G8R8:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::G8R8U;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::G8R8S;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::RGBA16U;
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RGBA16F;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::BF10GF11RF11:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::R11FG11FB10F;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32_G32_B32_A32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RGBA32F;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::RGBA32UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32_G32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RG32F;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::RG32UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32_G32_B32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RGB32F;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R16:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::R16F;
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::R16U;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::R16S;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R16UI;
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
return PixelFormat::R16I;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::R32:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::R32F;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::R32UI;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::ZF32:
|
||||
return PixelFormat::Z32F;
|
||||
case Tegra::Texture::TextureFormat::Z16:
|
||||
return PixelFormat::Z16;
|
||||
case Tegra::Texture::TextureFormat::Z24S8:
|
||||
return PixelFormat::Z24S8;
|
||||
case Tegra::Texture::TextureFormat::DXT1:
|
||||
return is_srgb ? PixelFormat::DXT1_SRGB : PixelFormat::DXT1;
|
||||
case Tegra::Texture::TextureFormat::DXT23:
|
||||
return is_srgb ? PixelFormat::DXT23_SRGB : PixelFormat::DXT23;
|
||||
case Tegra::Texture::TextureFormat::DXT45:
|
||||
return is_srgb ? PixelFormat::DXT45_SRGB : PixelFormat::DXT45;
|
||||
case Tegra::Texture::TextureFormat::DXN1:
|
||||
return PixelFormat::DXN1;
|
||||
case Tegra::Texture::TextureFormat::DXN2:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::DXN2UNORM;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::DXN2SNORM;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
case Tegra::Texture::TextureFormat::BC7U:
|
||||
return is_srgb ? PixelFormat::BC7U_SRGB : PixelFormat::BC7U;
|
||||
case Tegra::Texture::TextureFormat::BC6H_UF16:
|
||||
return PixelFormat::BC6H_UF16;
|
||||
case Tegra::Texture::TextureFormat::BC6H_SF16:
|
||||
return PixelFormat::BC6H_SF16;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_4X4:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_4X4_SRGB : PixelFormat::ASTC_2D_4X4;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_5X4:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_5X4_SRGB : PixelFormat::ASTC_2D_5X4;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_5X5:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_5X5_SRGB : PixelFormat::ASTC_2D_5X5;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_8X8:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_8X8_SRGB : PixelFormat::ASTC_2D_8X8;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_8X5:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_8X5_SRGB : PixelFormat::ASTC_2D_8X5;
|
||||
case Tegra::Texture::TextureFormat::ASTC_2D_10X8:
|
||||
return is_srgb ? PixelFormat::ASTC_2D_10X8_SRGB : PixelFormat::ASTC_2D_10X8;
|
||||
case Tegra::Texture::TextureFormat::R16_G16:
|
||||
switch (component_type) {
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return PixelFormat::RG16F;
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return PixelFormat::RG16;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return PixelFormat::RG16S;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return PixelFormat::RG16UI;
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
return PixelFormat::RG16I;
|
||||
}
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}, component_type={}", static_cast<u32>(format),
|
||||
static_cast<u32>(component_type));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) {
|
||||
// TODO(Subv): Implement more component types
|
||||
switch (type) {
|
||||
case Tegra::Texture::ComponentType::UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::Texture::ComponentType::FLOAT:
|
||||
return ComponentType::Float;
|
||||
case Tegra::Texture::ComponentType::SNORM:
|
||||
return ComponentType::SNorm;
|
||||
case Tegra::Texture::ComponentType::UINT:
|
||||
return ComponentType::UInt;
|
||||
case Tegra::Texture::ComponentType::SINT:
|
||||
return ComponentType::SInt;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented component type={}", static_cast<u32>(type));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format) {
|
||||
// TODO(Subv): Implement more render targets
|
||||
switch (format) {
|
||||
case Tegra::RenderTargetFormat::RGBA8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||
case Tegra::RenderTargetFormat::BGRA8_UNORM:
|
||||
case Tegra::RenderTargetFormat::BGRA8_SRGB:
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
case Tegra::RenderTargetFormat::R8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RG16_UNORM:
|
||||
case Tegra::RenderTargetFormat::R16_UNORM:
|
||||
case Tegra::RenderTargetFormat::B5G6R5_UNORM:
|
||||
case Tegra::RenderTargetFormat::BGR5A1_UNORM:
|
||||
case Tegra::RenderTargetFormat::RG8_UNORM:
|
||||
case Tegra::RenderTargetFormat::RGBA16_UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::RenderTargetFormat::RGBA8_SNORM:
|
||||
case Tegra::RenderTargetFormat::RG16_SNORM:
|
||||
case Tegra::RenderTargetFormat::R16_SNORM:
|
||||
case Tegra::RenderTargetFormat::RG8_SNORM:
|
||||
return ComponentType::SNorm;
|
||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||
case Tegra::RenderTargetFormat::R11G11B10_FLOAT:
|
||||
case Tegra::RenderTargetFormat::RGBA32_FLOAT:
|
||||
case Tegra::RenderTargetFormat::RG32_FLOAT:
|
||||
case Tegra::RenderTargetFormat::RG16_FLOAT:
|
||||
case Tegra::RenderTargetFormat::R16_FLOAT:
|
||||
case Tegra::RenderTargetFormat::R32_FLOAT:
|
||||
return ComponentType::Float;
|
||||
case Tegra::RenderTargetFormat::RGBA32_UINT:
|
||||
case Tegra::RenderTargetFormat::RGBA16_UINT:
|
||||
case Tegra::RenderTargetFormat::RG16_UINT:
|
||||
case Tegra::RenderTargetFormat::R8_UINT:
|
||||
case Tegra::RenderTargetFormat::R16_UINT:
|
||||
case Tegra::RenderTargetFormat::RG32_UINT:
|
||||
case Tegra::RenderTargetFormat::R32_UINT:
|
||||
case Tegra::RenderTargetFormat::RGBA8_UINT:
|
||||
return ComponentType::UInt;
|
||||
case Tegra::RenderTargetFormat::RG16_SINT:
|
||||
case Tegra::RenderTargetFormat::R16_SINT:
|
||||
return ComponentType::SInt;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::FramebufferConfig::PixelFormat::ABGR8:
|
||||
return PixelFormat::ABGR8U;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format) {
|
||||
switch (format) {
|
||||
case Tegra::DepthFormat::Z16_UNORM:
|
||||
case Tegra::DepthFormat::S8_Z24_UNORM:
|
||||
case Tegra::DepthFormat::Z24_S8_UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::DepthFormat::Z32_FLOAT:
|
||||
case Tegra::DepthFormat::Z32_S8_X24_FLOAT:
|
||||
return ComponentType::Float;
|
||||
default:
|
||||
LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
SurfaceType GetFormatType(PixelFormat pixel_format) {
|
||||
if (static_cast<std::size_t>(pixel_format) <
|
||||
static_cast<std::size_t>(PixelFormat::MaxColorFormat)) {
|
||||
return SurfaceType::ColorTexture;
|
||||
}
|
||||
|
||||
if (static_cast<std::size_t>(pixel_format) <
|
||||
static_cast<std::size_t>(PixelFormat::MaxDepthFormat)) {
|
||||
return SurfaceType::Depth;
|
||||
}
|
||||
|
||||
if (static_cast<std::size_t>(pixel_format) <
|
||||
static_cast<std::size_t>(PixelFormat::MaxDepthStencilFormat)) {
|
||||
return SurfaceType::DepthStencil;
|
||||
}
|
||||
|
||||
// TODO(Subv): Implement the other formats
|
||||
ASSERT(false);
|
||||
|
||||
return SurfaceType::Invalid;
|
||||
}
|
||||
|
||||
bool IsPixelFormatASTC(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::ASTC_2D_4X4:
|
||||
case PixelFormat::ASTC_2D_5X4:
|
||||
case PixelFormat::ASTC_2D_5X5:
|
||||
case PixelFormat::ASTC_2D_8X8:
|
||||
case PixelFormat::ASTC_2D_8X5:
|
||||
case PixelFormat::ASTC_2D_4X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_5X4_SRGB:
|
||||
case PixelFormat::ASTC_2D_5X5_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X8_SRGB:
|
||||
case PixelFormat::ASTC_2D_8X5_SRGB:
|
||||
case PixelFormat::ASTC_2D_10X8:
|
||||
case PixelFormat::ASTC_2D_10X8_SRGB:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
|
||||
return {GetDefaultBlockWidth(format), GetDefaultBlockHeight(format)};
|
||||
}
|
||||
|
||||
bool IsFormatBCn(PixelFormat format) {
|
||||
switch (format) {
|
||||
case PixelFormat::DXT1:
|
||||
case PixelFormat::DXT23:
|
||||
case PixelFormat::DXT45:
|
||||
case PixelFormat::DXN1:
|
||||
case PixelFormat::DXN2SNORM:
|
||||
case PixelFormat::DXN2UNORM:
|
||||
case PixelFormat::BC7U:
|
||||
case PixelFormat::BC6H_UF16:
|
||||
case PixelFormat::BC6H_SF16:
|
||||
case PixelFormat::DXT1_SRGB:
|
||||
case PixelFormat::DXT23_SRGB:
|
||||
case PixelFormat::DXT45_SRGB:
|
||||
case PixelFormat::BC7U_SRGB:
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace VideoCore::Surface
|
||||
@@ -1,477 +0,0 @@
|
||||
// Copyright 2014 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <climits>
|
||||
#include <utility>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "video_core/gpu.h"
|
||||
#include "video_core/textures/texture.h"
|
||||
|
||||
namespace VideoCore::Surface {
|
||||
|
||||
enum class PixelFormat {
|
||||
ABGR8U = 0,
|
||||
ABGR8S = 1,
|
||||
ABGR8UI = 2,
|
||||
B5G6R5U = 3,
|
||||
A2B10G10R10U = 4,
|
||||
A1B5G5R5U = 5,
|
||||
R8U = 6,
|
||||
R8UI = 7,
|
||||
RGBA16F = 8,
|
||||
RGBA16U = 9,
|
||||
RGBA16UI = 10,
|
||||
R11FG11FB10F = 11,
|
||||
RGBA32UI = 12,
|
||||
DXT1 = 13,
|
||||
DXT23 = 14,
|
||||
DXT45 = 15,
|
||||
DXN1 = 16, // This is also known as BC4
|
||||
DXN2UNORM = 17,
|
||||
DXN2SNORM = 18,
|
||||
BC7U = 19,
|
||||
BC6H_UF16 = 20,
|
||||
BC6H_SF16 = 21,
|
||||
ASTC_2D_4X4 = 22,
|
||||
G8R8U = 23,
|
||||
G8R8S = 24,
|
||||
BGRA8 = 25,
|
||||
RGBA32F = 26,
|
||||
RG32F = 27,
|
||||
R32F = 28,
|
||||
R16F = 29,
|
||||
R16U = 30,
|
||||
R16S = 31,
|
||||
R16UI = 32,
|
||||
R16I = 33,
|
||||
RG16 = 34,
|
||||
RG16F = 35,
|
||||
RG16UI = 36,
|
||||
RG16I = 37,
|
||||
RG16S = 38,
|
||||
RGB32F = 39,
|
||||
RGBA8_SRGB = 40,
|
||||
RG8U = 41,
|
||||
RG8S = 42,
|
||||
RG32UI = 43,
|
||||
R32UI = 44,
|
||||
ASTC_2D_8X8 = 45,
|
||||
ASTC_2D_8X5 = 46,
|
||||
ASTC_2D_5X4 = 47,
|
||||
BGRA8_SRGB = 48,
|
||||
DXT1_SRGB = 49,
|
||||
DXT23_SRGB = 50,
|
||||
DXT45_SRGB = 51,
|
||||
BC7U_SRGB = 52,
|
||||
ASTC_2D_4X4_SRGB = 53,
|
||||
ASTC_2D_8X8_SRGB = 54,
|
||||
ASTC_2D_8X5_SRGB = 55,
|
||||
ASTC_2D_5X4_SRGB = 56,
|
||||
ASTC_2D_5X5 = 57,
|
||||
ASTC_2D_5X5_SRGB = 58,
|
||||
ASTC_2D_10X8 = 59,
|
||||
ASTC_2D_10X8_SRGB = 60,
|
||||
|
||||
MaxColorFormat,
|
||||
|
||||
// Depth formats
|
||||
Z32F = 61,
|
||||
Z16 = 62,
|
||||
|
||||
MaxDepthFormat,
|
||||
|
||||
// DepthStencil formats
|
||||
Z24S8 = 63,
|
||||
S8Z24 = 64,
|
||||
Z32FS8 = 65,
|
||||
|
||||
MaxDepthStencilFormat,
|
||||
|
||||
Max = MaxDepthStencilFormat,
|
||||
Invalid = 255,
|
||||
};
|
||||
|
||||
static constexpr std::size_t MaxPixelFormat = static_cast<std::size_t>(PixelFormat::Max);
|
||||
|
||||
enum class ComponentType {
|
||||
Invalid = 0,
|
||||
SNorm = 1,
|
||||
UNorm = 2,
|
||||
SInt = 3,
|
||||
UInt = 4,
|
||||
Float = 5,
|
||||
};
|
||||
|
||||
enum class SurfaceType {
|
||||
ColorTexture = 0,
|
||||
Depth = 1,
|
||||
DepthStencil = 2,
|
||||
Fill = 3,
|
||||
Invalid = 4,
|
||||
};
|
||||
|
||||
enum class SurfaceTarget {
|
||||
Texture1D,
|
||||
Texture2D,
|
||||
Texture3D,
|
||||
Texture1DArray,
|
||||
Texture2DArray,
|
||||
TextureCubemap,
|
||||
TextureCubeArray,
|
||||
};
|
||||
|
||||
/**
|
||||
* Gets the compression factor for the specified PixelFormat. This applies to just the
|
||||
* "compressed width" and "compressed height", not the overall compression factor of a
|
||||
* compressed image. This is used for maintaining proper surface sizes for compressed
|
||||
* texture formats.
|
||||
*/
|
||||
static constexpr u32 GetCompressionFactor(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
|
||||
constexpr std::array<u32, MaxPixelFormat> compression_factor_table = {{
|
||||
1, // ABGR8U
|
||||
1, // ABGR8S
|
||||
1, // ABGR8UI
|
||||
1, // B5G6R5U
|
||||
1, // A2B10G10R10U
|
||||
1, // A1B5G5R5U
|
||||
1, // R8U
|
||||
1, // R8UI
|
||||
1, // RGBA16F
|
||||
1, // RGBA16U
|
||||
1, // RGBA16UI
|
||||
1, // R11FG11FB10F
|
||||
1, // RGBA32UI
|
||||
4, // DXT1
|
||||
4, // DXT23
|
||||
4, // DXT45
|
||||
4, // DXN1
|
||||
4, // DXN2UNORM
|
||||
4, // DXN2SNORM
|
||||
4, // BC7U
|
||||
4, // BC6H_UF16
|
||||
4, // BC6H_SF16
|
||||
4, // ASTC_2D_4X4
|
||||
1, // G8R8U
|
||||
1, // G8R8S
|
||||
1, // BGRA8
|
||||
1, // RGBA32F
|
||||
1, // RG32F
|
||||
1, // R32F
|
||||
1, // R16F
|
||||
1, // R16U
|
||||
1, // R16S
|
||||
1, // R16UI
|
||||
1, // R16I
|
||||
1, // RG16
|
||||
1, // RG16F
|
||||
1, // RG16UI
|
||||
1, // RG16I
|
||||
1, // RG16S
|
||||
1, // RGB32F
|
||||
1, // RGBA8_SRGB
|
||||
1, // RG8U
|
||||
1, // RG8S
|
||||
1, // RG32UI
|
||||
1, // R32UI
|
||||
4, // ASTC_2D_8X8
|
||||
4, // ASTC_2D_8X5
|
||||
4, // ASTC_2D_5X4
|
||||
1, // BGRA8_SRGB
|
||||
4, // DXT1_SRGB
|
||||
4, // DXT23_SRGB
|
||||
4, // DXT45_SRGB
|
||||
4, // BC7U_SRGB
|
||||
4, // ASTC_2D_4X4_SRGB
|
||||
4, // ASTC_2D_8X8_SRGB
|
||||
4, // ASTC_2D_8X5_SRGB
|
||||
4, // ASTC_2D_5X4_SRGB
|
||||
4, // ASTC_2D_5X5
|
||||
4, // ASTC_2D_5X5_SRGB
|
||||
4, // ASTC_2D_10X8
|
||||
4, // ASTC_2D_10X8_SRGB
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
1, // S8Z24
|
||||
1, // Z32FS8
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<std::size_t>(format) < compression_factor_table.size());
|
||||
return compression_factor_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
static constexpr u32 GetDefaultBlockWidth(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
constexpr std::array<u32, MaxPixelFormat> block_width_table = {{
|
||||
1, // ABGR8U
|
||||
1, // ABGR8S
|
||||
1, // ABGR8UI
|
||||
1, // B5G6R5U
|
||||
1, // A2B10G10R10U
|
||||
1, // A1B5G5R5U
|
||||
1, // R8U
|
||||
1, // R8UI
|
||||
1, // RGBA16F
|
||||
1, // RGBA16U
|
||||
1, // RGBA16UI
|
||||
1, // R11FG11FB10F
|
||||
1, // RGBA32UI
|
||||
4, // DXT1
|
||||
4, // DXT23
|
||||
4, // DXT45
|
||||
4, // DXN1
|
||||
4, // DXN2UNORM
|
||||
4, // DXN2SNORM
|
||||
4, // BC7U
|
||||
4, // BC6H_UF16
|
||||
4, // BC6H_SF16
|
||||
4, // ASTC_2D_4X4
|
||||
1, // G8R8U
|
||||
1, // G8R8S
|
||||
1, // BGRA8
|
||||
1, // RGBA32F
|
||||
1, // RG32F
|
||||
1, // R32F
|
||||
1, // R16F
|
||||
1, // R16U
|
||||
1, // R16S
|
||||
1, // R16UI
|
||||
1, // R16I
|
||||
1, // RG16
|
||||
1, // RG16F
|
||||
1, // RG16UI
|
||||
1, // RG16I
|
||||
1, // RG16S
|
||||
1, // RGB32F
|
||||
1, // RGBA8_SRGB
|
||||
1, // RG8U
|
||||
1, // RG8S
|
||||
1, // RG32UI
|
||||
1, // R32UI
|
||||
8, // ASTC_2D_8X8
|
||||
8, // ASTC_2D_8X5
|
||||
5, // ASTC_2D_5X4
|
||||
1, // BGRA8_SRGB
|
||||
4, // DXT1_SRGB
|
||||
4, // DXT23_SRGB
|
||||
4, // DXT45_SRGB
|
||||
4, // BC7U_SRGB
|
||||
4, // ASTC_2D_4X4_SRGB
|
||||
8, // ASTC_2D_8X8_SRGB
|
||||
8, // ASTC_2D_8X5_SRGB
|
||||
5, // ASTC_2D_5X4_SRGB
|
||||
5, // ASTC_2D_5X5
|
||||
5, // ASTC_2D_5X5_SRGB
|
||||
10, // ASTC_2D_10X8
|
||||
10, // ASTC_2D_10X8_SRGB
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
1, // S8Z24
|
||||
1, // Z32FS8
|
||||
}};
|
||||
ASSERT(static_cast<std::size_t>(format) < block_width_table.size());
|
||||
return block_width_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
static constexpr u32 GetDefaultBlockHeight(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
|
||||
constexpr std::array<u32, MaxPixelFormat> block_height_table = {{
|
||||
1, // ABGR8U
|
||||
1, // ABGR8S
|
||||
1, // ABGR8UI
|
||||
1, // B5G6R5U
|
||||
1, // A2B10G10R10U
|
||||
1, // A1B5G5R5U
|
||||
1, // R8U
|
||||
1, // R8UI
|
||||
1, // RGBA16F
|
||||
1, // RGBA16U
|
||||
1, // RGBA16UI
|
||||
1, // R11FG11FB10F
|
||||
1, // RGBA32UI
|
||||
4, // DXT1
|
||||
4, // DXT23
|
||||
4, // DXT45
|
||||
4, // DXN1
|
||||
4, // DXN2UNORM
|
||||
4, // DXN2SNORM
|
||||
4, // BC7U
|
||||
4, // BC6H_UF16
|
||||
4, // BC6H_SF16
|
||||
4, // ASTC_2D_4X4
|
||||
1, // G8R8U
|
||||
1, // G8R8S
|
||||
1, // BGRA8
|
||||
1, // RGBA32F
|
||||
1, // RG32F
|
||||
1, // R32F
|
||||
1, // R16F
|
||||
1, // R16U
|
||||
1, // R16S
|
||||
1, // R16UI
|
||||
1, // R16I
|
||||
1, // RG16
|
||||
1, // RG16F
|
||||
1, // RG16UI
|
||||
1, // RG16I
|
||||
1, // RG16S
|
||||
1, // RGB32F
|
||||
1, // RGBA8_SRGB
|
||||
1, // RG8U
|
||||
1, // RG8S
|
||||
1, // RG32UI
|
||||
1, // R32UI
|
||||
8, // ASTC_2D_8X8
|
||||
5, // ASTC_2D_8X5
|
||||
4, // ASTC_2D_5X4
|
||||
1, // BGRA8_SRGB
|
||||
4, // DXT1_SRGB
|
||||
4, // DXT23_SRGB
|
||||
4, // DXT45_SRGB
|
||||
4, // BC7U_SRGB
|
||||
4, // ASTC_2D_4X4_SRGB
|
||||
8, // ASTC_2D_8X8_SRGB
|
||||
5, // ASTC_2D_8X5_SRGB
|
||||
4, // ASTC_2D_5X4_SRGB
|
||||
5, // ASTC_2D_5X5
|
||||
5, // ASTC_2D_5X5_SRGB
|
||||
8, // ASTC_2D_10X8
|
||||
8, // ASTC_2D_10X8_SRGB
|
||||
1, // Z32F
|
||||
1, // Z16
|
||||
1, // Z24S8
|
||||
1, // S8Z24
|
||||
1, // Z32FS8
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<std::size_t>(format) < block_height_table.size());
|
||||
return block_height_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
static constexpr u32 GetFormatBpp(PixelFormat format) {
|
||||
if (format == PixelFormat::Invalid)
|
||||
return 0;
|
||||
|
||||
constexpr std::array<u32, MaxPixelFormat> bpp_table = {{
|
||||
32, // ABGR8U
|
||||
32, // ABGR8S
|
||||
32, // ABGR8UI
|
||||
16, // B5G6R5U
|
||||
32, // A2B10G10R10U
|
||||
16, // A1B5G5R5U
|
||||
8, // R8U
|
||||
8, // R8UI
|
||||
64, // RGBA16F
|
||||
64, // RGBA16U
|
||||
64, // RGBA16UI
|
||||
32, // R11FG11FB10F
|
||||
128, // RGBA32UI
|
||||
64, // DXT1
|
||||
128, // DXT23
|
||||
128, // DXT45
|
||||
64, // DXN1
|
||||
128, // DXN2UNORM
|
||||
128, // DXN2SNORM
|
||||
128, // BC7U
|
||||
128, // BC6H_UF16
|
||||
128, // BC6H_SF16
|
||||
128, // ASTC_2D_4X4
|
||||
16, // G8R8U
|
||||
16, // G8R8S
|
||||
32, // BGRA8
|
||||
128, // RGBA32F
|
||||
64, // RG32F
|
||||
32, // R32F
|
||||
16, // R16F
|
||||
16, // R16U
|
||||
16, // R16S
|
||||
16, // R16UI
|
||||
16, // R16I
|
||||
32, // RG16
|
||||
32, // RG16F
|
||||
32, // RG16UI
|
||||
32, // RG16I
|
||||
32, // RG16S
|
||||
96, // RGB32F
|
||||
32, // RGBA8_SRGB
|
||||
16, // RG8U
|
||||
16, // RG8S
|
||||
64, // RG32UI
|
||||
32, // R32UI
|
||||
128, // ASTC_2D_8X8
|
||||
128, // ASTC_2D_8X5
|
||||
128, // ASTC_2D_5X4
|
||||
32, // BGRA8_SRGB
|
||||
64, // DXT1_SRGB
|
||||
128, // DXT23_SRGB
|
||||
128, // DXT45_SRGB
|
||||
128, // BC7U
|
||||
128, // ASTC_2D_4X4_SRGB
|
||||
128, // ASTC_2D_8X8_SRGB
|
||||
128, // ASTC_2D_8X5_SRGB
|
||||
128, // ASTC_2D_5X4_SRGB
|
||||
128, // ASTC_2D_5X5
|
||||
128, // ASTC_2D_5X5_SRGB
|
||||
128, // ASTC_2D_10X8
|
||||
128, // ASTC_2D_10X8_SRGB
|
||||
32, // Z32F
|
||||
16, // Z16
|
||||
32, // Z24S8
|
||||
32, // S8Z24
|
||||
64, // Z32FS8
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<std::size_t>(format) < bpp_table.size());
|
||||
return bpp_table[static_cast<std::size_t>(format)];
|
||||
}
|
||||
|
||||
/// Returns the sizer in bytes of the specified pixel format
|
||||
static constexpr u32 GetBytesPerPixel(PixelFormat pixel_format) {
|
||||
if (pixel_format == PixelFormat::Invalid) {
|
||||
return 0;
|
||||
}
|
||||
return GetFormatBpp(pixel_format) / CHAR_BIT;
|
||||
}
|
||||
|
||||
SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
|
||||
|
||||
bool SurfaceTargetIsLayered(SurfaceTarget target);
|
||||
|
||||
PixelFormat PixelFormatFromDepthFormat(Tegra::DepthFormat format);
|
||||
|
||||
PixelFormat PixelFormatFromRenderTargetFormat(Tegra::RenderTargetFormat format);
|
||||
|
||||
PixelFormat PixelFormatFromTextureFormat(Tegra::Texture::TextureFormat format,
|
||||
Tegra::Texture::ComponentType component_type,
|
||||
bool is_srgb);
|
||||
|
||||
ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type);
|
||||
|
||||
ComponentType ComponentTypeFromRenderTarget(Tegra::RenderTargetFormat format);
|
||||
|
||||
PixelFormat PixelFormatFromGPUPixelFormat(Tegra::FramebufferConfig::PixelFormat format);
|
||||
|
||||
ComponentType ComponentTypeFromDepthFormat(Tegra::DepthFormat format);
|
||||
|
||||
SurfaceType GetFormatType(PixelFormat pixel_format);
|
||||
|
||||
bool IsPixelFormatASTC(PixelFormat format);
|
||||
|
||||
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
|
||||
|
||||
/// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN
|
||||
bool IsFormatBCn(PixelFormat format);
|
||||
|
||||
} // namespace VideoCore::Surface
|
||||
@@ -1598,29 +1598,27 @@ static void DecompressBlock(uint8_t inBuf[16], const uint32_t blockWidth,
|
||||
namespace Tegra::Texture::ASTC {
|
||||
|
||||
std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint32_t block_width, uint32_t block_height) {
|
||||
uint32_t block_width, uint32_t block_height) {
|
||||
uint32_t blockIdx = 0;
|
||||
std::vector<uint8_t> outData(height * width * depth * 4);
|
||||
for (uint32_t k = 0; k < depth; k++) {
|
||||
for (uint32_t j = 0; j < height; j += block_height) {
|
||||
for (uint32_t i = 0; i < width; i += block_width) {
|
||||
std::vector<uint8_t> outData(height * width * 4);
|
||||
for (uint32_t j = 0; j < height; j += block_height) {
|
||||
for (uint32_t i = 0; i < width; i += block_width) {
|
||||
|
||||
uint8_t* blockPtr = data.data() + blockIdx * 16;
|
||||
uint8_t* blockPtr = data.data() + blockIdx * 16;
|
||||
|
||||
// Blocks can be at most 12x12
|
||||
uint32_t uncompData[144];
|
||||
ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
|
||||
// Blocks can be at most 12x12
|
||||
uint32_t uncompData[144];
|
||||
ASTCC::DecompressBlock(blockPtr, block_width, block_height, uncompData);
|
||||
|
||||
uint32_t decompWidth = std::min(block_width, width - i);
|
||||
uint32_t decompHeight = std::min(block_height, height - j);
|
||||
uint32_t decompWidth = std::min(block_width, width - i);
|
||||
uint32_t decompHeight = std::min(block_height, height - j);
|
||||
|
||||
uint8_t* outRow = outData.data() + (j * width + i) * 4;
|
||||
for (uint32_t jj = 0; jj < decompHeight; jj++) {
|
||||
memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4);
|
||||
}
|
||||
|
||||
blockIdx++;
|
||||
uint8_t* outRow = outData.data() + (j * width + i) * 4;
|
||||
for (uint32_t jj = 0; jj < decompHeight; jj++) {
|
||||
memcpy(outRow + jj * width * 4, uncompData + jj * block_width, decompWidth * 4);
|
||||
}
|
||||
|
||||
blockIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,6 @@
|
||||
namespace Tegra::Texture::ASTC {
|
||||
|
||||
std::vector<uint8_t> Decompress(std::vector<uint8_t>& data, uint32_t width, uint32_t height,
|
||||
uint32_t depth, uint32_t block_width, uint32_t block_height);
|
||||
uint32_t block_width, uint32_t block_height);
|
||||
|
||||
} // namespace Tegra::Texture::ASTC
|
||||
|
||||
@@ -202,8 +202,6 @@ u32 BytesPerPixel(TextureFormat format) {
|
||||
case TextureFormat::ASTC_2D_5X4:
|
||||
case TextureFormat::ASTC_2D_8X8:
|
||||
case TextureFormat::ASTC_2D_8X5:
|
||||
case TextureFormat::ASTC_2D_10X8:
|
||||
case TextureFormat::ASTC_2D_5X5:
|
||||
case TextureFormat::A8R8G8B8:
|
||||
case TextureFormat::A2B10G10R10:
|
||||
case TextureFormat::BF10GF11RF11:
|
||||
@@ -229,14 +227,12 @@ u32 BytesPerPixel(TextureFormat format) {
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
|
||||
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||
u32 block_height, u32 block_depth) {
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
|
||||
u32 height, u32 depth, u32 block_height, u32 block_depth) {
|
||||
std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel);
|
||||
CopySwizzledData((width + tile_size_x - 1) / tile_size_x,
|
||||
(height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel,
|
||||
bytes_per_pixel, Memory::GetPointer(address), unswizzled_data.data(), true,
|
||||
block_height, block_depth);
|
||||
CopySwizzledData(width / tile_size, height / tile_size, depth, bytes_per_pixel, bytes_per_pixel,
|
||||
Memory::GetPointer(address), unswizzled_data.data(), true, block_height,
|
||||
block_depth);
|
||||
return unswizzled_data;
|
||||
}
|
||||
|
||||
@@ -296,8 +292,6 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
|
||||
case TextureFormat::BC6H_SF16:
|
||||
case TextureFormat::ASTC_2D_4X4:
|
||||
case TextureFormat::ASTC_2D_8X8:
|
||||
case TextureFormat::ASTC_2D_5X5:
|
||||
case TextureFormat::ASTC_2D_10X8:
|
||||
case TextureFormat::A8R8G8B8:
|
||||
case TextureFormat::A2B10G10R10:
|
||||
case TextureFormat::A1B5G5R5:
|
||||
|
||||
@@ -19,8 +19,8 @@ inline std::size_t GetGOBSize() {
|
||||
/**
|
||||
* Unswizzles a swizzled texture without changing its format.
|
||||
*/
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y,
|
||||
u32 bytes_per_pixel, u32 width, u32 height, u32 depth,
|
||||
std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width,
|
||||
u32 height, u32 depth,
|
||||
u32 block_height = TICEntry::DefaultBlockHeight,
|
||||
u32 block_depth = TICEntry::DefaultBlockHeight);
|
||||
|
||||
|
||||
@@ -168,29 +168,20 @@ struct TICEntry {
|
||||
|
||||
// High 16 bits of the pitch value
|
||||
BitField<0, 16, u32> pitch_high;
|
||||
BitField<26, 1, u32> use_header_opt_control;
|
||||
BitField<27, 1, u32> depth_texture;
|
||||
|
||||
BitField<28, 4, u32> max_mip_level;
|
||||
};
|
||||
union {
|
||||
BitField<0, 16, u32> width_minus_1;
|
||||
BitField<22, 1, u32> srgb_conversion;
|
||||
BitField<23, 4, TextureType> texture_type;
|
||||
BitField<29, 3, u32> border_size;
|
||||
};
|
||||
union {
|
||||
BitField<0, 16, u32> height_minus_1;
|
||||
BitField<16, 15, u32> depth_minus_1;
|
||||
};
|
||||
union {
|
||||
BitField<6, 13, u32> mip_lod_bias;
|
||||
BitField<27, 3, u32> max_anisotropy;
|
||||
};
|
||||
|
||||
union {
|
||||
BitField<0, 4, u32> res_min_mip_level;
|
||||
BitField<4, 4, u32> res_max_mip_level;
|
||||
};
|
||||
INSERT_PADDING_BYTES(8);
|
||||
|
||||
GPUVAddr Address() const {
|
||||
return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | address_low);
|
||||
|
||||
@@ -102,27 +102,16 @@ void TelemetryJson::Complete() {
|
||||
impl->SerializeSection(Telemetry::FieldType::App, "App");
|
||||
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
|
||||
impl->SerializeSection(Telemetry::FieldType::Performance, "Performance");
|
||||
impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
|
||||
impl->SerializeSection(Telemetry::FieldType::UserConfig, "UserConfig");
|
||||
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
|
||||
|
||||
auto content = impl->TopSection().dump();
|
||||
// Send the telemetry async but don't handle the errors since they were written to the log
|
||||
Common::DetachedTasks::AddTask([host{impl->host}, content]() {
|
||||
Client{host, "", ""}.PostJson("/telemetry", content, true);
|
||||
});
|
||||
}
|
||||
|
||||
bool TelemetryJson::SubmitTestcase() {
|
||||
impl->SerializeSection(Telemetry::FieldType::App, "App");
|
||||
impl->SerializeSection(Telemetry::FieldType::Session, "Session");
|
||||
impl->SerializeSection(Telemetry::FieldType::UserFeedback, "UserFeedback");
|
||||
impl->SerializeSection(Telemetry::FieldType::UserSystem, "UserSystem");
|
||||
|
||||
auto content = impl->TopSection().dump();
|
||||
Client client(impl->host, impl->username, impl->token);
|
||||
auto value = client.PostJson("/gamedb/testcase", content, false);
|
||||
|
||||
return value.result_code == Common::WebResult::Code::Success;
|
||||
Common::DetachedTasks::AddTask(
|
||||
[host{impl->host}, username{impl->username}, token{impl->token}, content]() {
|
||||
Client{host, username, token}.PostJson("/telemetry", content, true);
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace WebService
|
||||
|
||||
@@ -35,7 +35,6 @@ public:
|
||||
void Visit(const Telemetry::Field<std::chrono::microseconds>& field) override;
|
||||
|
||||
void Complete() override;
|
||||
bool SubmitTestcase() override;
|
||||
|
||||
private:
|
||||
struct Impl;
|
||||
|
||||
@@ -56,8 +56,6 @@ add_executable(yuzu
|
||||
main.h
|
||||
ui_settings.cpp
|
||||
ui_settings.h
|
||||
util/limitable_input_dialog.cpp
|
||||
util/limitable_input_dialog.h
|
||||
util/spinbox.cpp
|
||||
util/spinbox.h
|
||||
util/util.cpp
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#include <QButtonGroup>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include <QtConcurrent/qtconcurrentrun.h>
|
||||
#include "common/logging/log.h"
|
||||
#include "common/telemetry.h"
|
||||
#include "core/core.h"
|
||||
@@ -24,8 +23,6 @@ CompatDB::CompatDB(QWidget* parent)
|
||||
connect(ui->radioButton_IntroMenu, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(ui->radioButton_WontBoot, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||
connect(button(NextButton), &QPushButton::clicked, this, &CompatDB::Submit);
|
||||
connect(&testcase_watcher, &QFutureWatcher<bool>::finished, this,
|
||||
&CompatDB::OnTestcaseSubmitted);
|
||||
}
|
||||
|
||||
CompatDB::~CompatDB() = default;
|
||||
@@ -51,38 +48,18 @@ void CompatDB::Submit() {
|
||||
}
|
||||
break;
|
||||
case CompatDBPage::Final:
|
||||
back();
|
||||
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
|
||||
Core::Telemetry().AddField(Telemetry::FieldType::UserFeedback, "Compatibility",
|
||||
compatibility->checkedId());
|
||||
|
||||
button(NextButton)->setEnabled(false);
|
||||
button(NextButton)->setText(tr("Submitting"));
|
||||
// older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
|
||||
// workaround
|
||||
button(QWizard::CancelButton)->setVisible(false);
|
||||
|
||||
testcase_watcher.setFuture(QtConcurrent::run(
|
||||
[this]() { return Core::System::GetInstance().TelemetrySession().SubmitTestcase(); }));
|
||||
break;
|
||||
default:
|
||||
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
|
||||
}
|
||||
}
|
||||
|
||||
void CompatDB::OnTestcaseSubmitted() {
|
||||
if (!testcase_watcher.result()) {
|
||||
QMessageBox::critical(this, tr("Communication error"),
|
||||
tr("An error occured while sending the Testcase"));
|
||||
button(NextButton)->setEnabled(true);
|
||||
button(NextButton)->setText(tr("Next"));
|
||||
button(QWizard::CancelButton)->setVisible(true);
|
||||
} else {
|
||||
next();
|
||||
// older versions of QT don't support the "NoCancelButtonOnLastPage" option, this is a
|
||||
// workaround
|
||||
button(QWizard::CancelButton)->setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
void CompatDB::EnableNext() {
|
||||
button(NextButton)->setEnabled(true);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <QFutureWatcher>
|
||||
#include <QWizard>
|
||||
|
||||
namespace Ui {
|
||||
@@ -20,11 +19,8 @@ public:
|
||||
~CompatDB();
|
||||
|
||||
private:
|
||||
QFutureWatcher<bool> testcase_watcher;
|
||||
|
||||
std::unique_ptr<Ui::CompatDB> ui;
|
||||
|
||||
void Submit();
|
||||
void OnTestcaseSubmitted();
|
||||
void EnableNext();
|
||||
};
|
||||
|
||||
@@ -134,14 +134,6 @@ void Config::ReadValues() {
|
||||
Service::Account::MAX_USERS - 1);
|
||||
|
||||
Settings::values.language_index = qt_config->value("language_index", 1).toInt();
|
||||
|
||||
const auto enabled = qt_config->value("rng_seed_enabled", false).toBool();
|
||||
if (enabled) {
|
||||
Settings::values.rng_seed = qt_config->value("rng_seed", 0).toULongLong();
|
||||
} else {
|
||||
Settings::values.rng_seed = std::nullopt;
|
||||
}
|
||||
|
||||
qt_config->endGroup();
|
||||
|
||||
qt_config->beginGroup("Miscellaneous");
|
||||
@@ -170,6 +162,7 @@ void Config::ReadValues() {
|
||||
|
||||
qt_config->beginGroup("UIGameList");
|
||||
UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool();
|
||||
UISettings::values.show_add_ons = qt_config->value("show_add_ons", true).toBool();
|
||||
UISettings::values.icon_size = qt_config->value("icon_size", 64).toUInt();
|
||||
UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 3).toUInt();
|
||||
UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 2).toUInt();
|
||||
@@ -280,10 +273,6 @@ void Config::SaveValues() {
|
||||
qt_config->setValue("current_user", Settings::values.current_user);
|
||||
|
||||
qt_config->setValue("language_index", Settings::values.language_index);
|
||||
|
||||
qt_config->setValue("rng_seed_enabled", Settings::values.rng_seed.has_value());
|
||||
qt_config->setValue("rng_seed", Settings::values.rng_seed.value_or(0));
|
||||
|
||||
qt_config->endGroup();
|
||||
|
||||
qt_config->beginGroup("Miscellaneous");
|
||||
@@ -310,6 +299,7 @@ void Config::SaveValues() {
|
||||
|
||||
qt_config->beginGroup("UIGameList");
|
||||
qt_config->setValue("show_unknown", UISettings::values.show_unknown);
|
||||
qt_config->setValue("show_add_ons", UISettings::values.show_add_ons);
|
||||
qt_config->setValue("icon_size", UISettings::values.icon_size);
|
||||
qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id);
|
||||
qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id);
|
||||
|
||||
@@ -42,6 +42,7 @@ ConfigureGameList::~ConfigureGameList() = default;
|
||||
|
||||
void ConfigureGameList::applyConfiguration() {
|
||||
UISettings::values.show_unknown = ui->show_unknown->isChecked();
|
||||
UISettings::values.show_add_ons = ui->show_add_ons->isChecked();
|
||||
UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt();
|
||||
UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt();
|
||||
UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt();
|
||||
@@ -50,6 +51,7 @@ void ConfigureGameList::applyConfiguration() {
|
||||
|
||||
void ConfigureGameList::setConfiguration() {
|
||||
ui->show_unknown->setChecked(UISettings::values.show_unknown);
|
||||
ui->show_add_ons->setChecked(UISettings::values.show_add_ons);
|
||||
ui->icon_size_combobox->setCurrentIndex(
|
||||
ui->icon_size_combobox->findData(UISettings::values.icon_size));
|
||||
ui->row_1_text_combobox->setCurrentIndex(
|
||||
|
||||
@@ -1,126 +1,133 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigureGameList</class>
|
||||
<widget class="QWidget" name="ConfigureGeneral">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>377</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="HorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="VerticalLayout">
|
||||
<widget class="QWidget" name="ConfigureGameList">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>300</width>
|
||||
<height>377</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="HorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="VerticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="GeneralGroupBox">
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="GeneralHorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="GeneralGroupBox">
|
||||
<property name="title">
|
||||
<string>General</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="GeneralHorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="GeneralVerticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="show_unknown">
|
||||
<property name="text">
|
||||
<string>Show files with type 'Unknown'</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QCheckBox" name="show_unknown">
|
||||
<property name="text">
|
||||
<string>Show files with type 'Unknown'</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="IconSizeGroupBox">
|
||||
<property name="title">
|
||||
<string>Icon Size</string>
|
||||
<widget class="QCheckBox" name="show_add_ons">
|
||||
<property name="text">
|
||||
<string>Show Add-Ons Column</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="IconSizeGroupBox">
|
||||
<property name="title">
|
||||
<string>Icon Size</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="icon_size_qhbox_layout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="icon_size_qvbox_layout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="icon_size_label">
|
||||
<property name="text">
|
||||
<string>Icon Size:</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="icon_size_qhbox_layout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="icon_size_qvbox_layout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="icon_size_qhbox_layout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="icon_size_label">
|
||||
<property name="text">
|
||||
<string>Icon Size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="icon_size_combobox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="icon_size_combobox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="RowGroupBox">
|
||||
<property name="title">
|
||||
<string>Row Text</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="RowHorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="RowVerticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="row_1_qhbox_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="row_1_label">
|
||||
<property name="text">
|
||||
<string>Row 1 Text:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="row_1_text_combobox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="RowGroupBox">
|
||||
<property name="title">
|
||||
<string>Row Text</string>
|
||||
<layout class="QHBoxLayout" name="row_2_qhbox_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="row_2_label">
|
||||
<property name="text">
|
||||
<string>Row 2 Text:</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="RowHorizontalLayout">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="RowVerticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="row_1_qhbox_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="row_1_label">
|
||||
<property name="text">
|
||||
<string>Row 1 Text:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="row_1_text_combobox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="row_2_qhbox_layout">
|
||||
<item>
|
||||
<widget class="QLabel" name="row_2_label">
|
||||
<property name="text">
|
||||
<string>Row 2 Text:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="row_2_text_combobox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="row_2_text_combobox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -3,10 +3,6 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/am/am.h"
|
||||
#include "core/hle/service/am/applet_ae.h"
|
||||
#include "core/hle/service/am/applet_oe.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/settings.h"
|
||||
#include "ui_configure_general.h"
|
||||
#include "yuzu/configuration/configure_general.h"
|
||||
@@ -24,6 +20,7 @@ ConfigureGeneral::ConfigureGeneral(QWidget* parent)
|
||||
this->setConfiguration();
|
||||
|
||||
ui->use_cpu_jit->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
ui->use_docked_mode->setEnabled(!Core::System::GetInstance().IsPoweredOn());
|
||||
}
|
||||
|
||||
ConfigureGeneral::~ConfigureGeneral() = default;
|
||||
@@ -41,30 +38,6 @@ void ConfigureGeneral::PopulateHotkeyList(const HotkeyRegistry& registry) {
|
||||
ui->widget->Populate(registry);
|
||||
}
|
||||
|
||||
void ConfigureGeneral::OnDockedModeChanged(bool last_state, bool new_state) {
|
||||
if (last_state == new_state) {
|
||||
return;
|
||||
}
|
||||
|
||||
Core::System& system{Core::System::GetInstance()};
|
||||
Service::SM::ServiceManager& sm = system.ServiceManager();
|
||||
|
||||
// Message queue is shared between these services, we just need to signal an operation
|
||||
// change to one and it will handle both automatically
|
||||
auto applet_oe = sm.GetService<Service::AM::AppletOE>("appletOE");
|
||||
auto applet_ae = sm.GetService<Service::AM::AppletAE>("appletAE");
|
||||
bool has_signalled = false;
|
||||
|
||||
if (applet_oe != nullptr) {
|
||||
applet_oe->GetMessageQueue()->OperationModeChanged();
|
||||
has_signalled = true;
|
||||
}
|
||||
|
||||
if (applet_ae != nullptr && !has_signalled) {
|
||||
applet_ae->GetMessageQueue()->OperationModeChanged();
|
||||
}
|
||||
}
|
||||
|
||||
void ConfigureGeneral::applyConfiguration() {
|
||||
UISettings::values.gamedir_deepscan = ui->toggle_deepscan->isChecked();
|
||||
UISettings::values.confirm_before_closing = ui->toggle_check_exit->isChecked();
|
||||
@@ -72,9 +45,6 @@ void ConfigureGeneral::applyConfiguration() {
|
||||
ui->theme_combobox->itemData(ui->theme_combobox->currentIndex()).toString();
|
||||
|
||||
Settings::values.use_cpu_jit = ui->use_cpu_jit->isChecked();
|
||||
const bool pre_docked_mode = Settings::values.use_docked_mode;
|
||||
Settings::values.use_docked_mode = ui->use_docked_mode->isChecked();
|
||||
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
|
||||
|
||||
Settings::values.enable_nfc = ui->enable_nfc->isChecked();
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user