Compare commits
40 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a3f22ebc18 | ||
|
|
8995ad6f29 | ||
|
|
241d3c1473 | ||
|
|
b4043ea231 | ||
|
|
0f7b1a2818 | ||
|
|
50115fefa6 | ||
|
|
bb9d39b8fe | ||
|
|
27c0f9e02d | ||
|
|
41faeeeb03 | ||
|
|
63270e588b | ||
|
|
e54ea773fc | ||
|
|
0d64ddc6dd | ||
|
|
9cd87a6352 | ||
|
|
99f9d47d16 | ||
|
|
bbbe34429e | ||
|
|
11568c2ea3 | ||
|
|
888eb345c0 | ||
|
|
4c727d0ba8 | ||
|
|
bdd68fc210 | ||
|
|
f1bded1270 | ||
|
|
49309b5848 | ||
|
|
c02d7c8ce7 | ||
|
|
3957b0c34e | ||
|
|
ca5a4a704b | ||
|
|
15086a22be | ||
|
|
94fecef137 | ||
|
|
d1f9c750a6 | ||
|
|
99f12b05fa | ||
|
|
8df011a57f | ||
|
|
9a273bb23b | ||
|
|
6fcc7e9c36 | ||
|
|
c8e1383fa9 | ||
|
|
68937a662d | ||
|
|
734106dcb9 | ||
|
|
6306655665 | ||
|
|
0658973a4e | ||
|
|
0d843eaba6 | ||
|
|
5a763e8a5a | ||
|
|
220d4672df | ||
|
|
7757cc1a7f |
@@ -1,7 +1,7 @@
|
||||
#!/bin/bash -ex
|
||||
|
||||
apt-get update
|
||||
apt-get install -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget ninja-build
|
||||
apt-get install -y build-essential git libqt5opengl5-dev libsdl2-dev libssl-dev python qtbase5-dev wget
|
||||
|
||||
# Get a recent version of CMake
|
||||
wget https://cmake.org/files/v3.10/cmake-3.10.1-Linux-x86_64.sh
|
||||
@@ -10,7 +10,7 @@ sh cmake-3.10.1-Linux-x86_64.sh --exclude-subdir --prefix=/ --skip-license
|
||||
cd /yuzu
|
||||
|
||||
mkdir build && cd build
|
||||
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release -G Ninja
|
||||
ninja
|
||||
cmake .. -DYUZU_BUILD_UNICORN=ON -DCMAKE_BUILD_TYPE=Release
|
||||
make -j4
|
||||
|
||||
ctest -VV -C Release
|
||||
|
||||
@@ -35,6 +35,7 @@ namespace Log {
|
||||
SUB(Service, AM) \
|
||||
SUB(Service, AOC) \
|
||||
SUB(Service, APM) \
|
||||
SUB(Service, BCAT) \
|
||||
SUB(Service, Fatal) \
|
||||
SUB(Service, Friend) \
|
||||
SUB(Service, FS) \
|
||||
|
||||
@@ -55,6 +55,7 @@ enum class Class : ClassType {
|
||||
Service_AOC, ///< The AOC (AddOn Content) service
|
||||
Service_APM, ///< The APM (Performance) service
|
||||
Service_Audio, ///< The Audio (Audio control) service
|
||||
Service_BCAT, ///< The BCAT service
|
||||
Service_Fatal, ///< The Fatal service
|
||||
Service_Friend, ///< The friend service
|
||||
Service_FS, ///< The FS (Filesystem) service
|
||||
|
||||
@@ -124,6 +124,10 @@ add_library(core STATIC
|
||||
hle/service/audio/audren_u.h
|
||||
hle/service/audio/codecctl.cpp
|
||||
hle/service/audio/codecctl.h
|
||||
hle/service/bcat/module.cpp
|
||||
hle/service/bcat/module.h
|
||||
hle/service/bcat/bcat.cpp
|
||||
hle/service/bcat/bcat.h
|
||||
hle/service/fatal/fatal.cpp
|
||||
hle/service/fatal/fatal.h
|
||||
hle/service/fatal/fatal_p.cpp
|
||||
@@ -171,6 +175,8 @@ add_library(core STATIC
|
||||
hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
|
||||
hle/service/nvdrv/devices/nvhost_gpu.cpp
|
||||
hle/service/nvdrv/devices/nvhost_gpu.h
|
||||
hle/service/nvdrv/devices/nvhost_nvdec.cpp
|
||||
hle/service/nvdrv/devices/nvhost_nvdec.h
|
||||
hle/service/nvdrv/devices/nvmap.cpp
|
||||
hle/service/nvdrv/devices/nvmap.h
|
||||
hle/service/nvdrv/interface.cpp
|
||||
|
||||
@@ -29,7 +29,10 @@ enum class ControlCommand : u32 {
|
||||
};
|
||||
|
||||
enum class CommandType : u32 {
|
||||
Invalid = 0,
|
||||
LegacyRequest = 1,
|
||||
Close = 2,
|
||||
LegacyControl = 3,
|
||||
Request = 4,
|
||||
Control = 5,
|
||||
RequestWithContext = 6,
|
||||
|
||||
@@ -21,7 +21,9 @@ enum {
|
||||
|
||||
// Confirmed Switch OS error codes
|
||||
MisalignedAddress = 102,
|
||||
InvalidProcessorId = 113,
|
||||
InvalidHandle = 114,
|
||||
InvalidCombination = 116,
|
||||
Timeout = 117,
|
||||
SynchronizationCanceled = 118,
|
||||
TooLarge = 119,
|
||||
|
||||
@@ -732,7 +732,7 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask)
|
||||
}
|
||||
|
||||
static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
NGLOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:08X}, core=0x{:X}", thread_handle,
|
||||
NGLOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
|
||||
mask, core);
|
||||
|
||||
const SharedPtr<Thread> thread = g_handle_table.Get<Thread>(thread_handle);
|
||||
@@ -740,6 +740,31 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
|
||||
return ERR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
if (core == THREADPROCESSORID_DEFAULT) {
|
||||
ASSERT(thread->owner_process->ideal_processor != THREADPROCESSORID_DEFAULT);
|
||||
// Set the target CPU to the one specified in the process' exheader.
|
||||
core = thread->owner_process->ideal_processor;
|
||||
mask = 1 << core;
|
||||
}
|
||||
|
||||
if (mask == 0) {
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
|
||||
}
|
||||
|
||||
/// This value is used to only change the affinity mask without changing the current ideal core.
|
||||
static constexpr u32 OnlyChangeMask = static_cast<u32>(-3);
|
||||
|
||||
if (core == OnlyChangeMask) {
|
||||
core = thread->ideal_core;
|
||||
} else if (core >= Core::NUM_CPU_CORES && core != -1) {
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidProcessorId);
|
||||
}
|
||||
|
||||
// Error out if the input core isn't enabled in the input mask.
|
||||
if (core < Core::NUM_CPU_CORES && (mask & (1 << core)) == 0) {
|
||||
return ResultCode(ErrorModule::Kernel, ErrCodes::InvalidCombination);
|
||||
}
|
||||
|
||||
thread->ChangeCore(core, mask);
|
||||
|
||||
return RESULT_SUCCESS;
|
||||
|
||||
@@ -133,8 +133,11 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) {
|
||||
|
||||
auto lock_owner = thread->lock_owner;
|
||||
// Threads waking up by timeout from WaitProcessWideKey do not perform priority inheritance
|
||||
// and don't have a lock owner.
|
||||
ASSERT(lock_owner == nullptr);
|
||||
// and don't have a lock owner unless SignalProcessWideKey was called first and the thread
|
||||
// wasn't awakened due to the mutex already being acquired.
|
||||
if (lock_owner) {
|
||||
lock_owner->RemoveMutexWaiter(thread);
|
||||
}
|
||||
}
|
||||
|
||||
if (resume)
|
||||
@@ -460,13 +463,13 @@ void Thread::UpdatePriority() {
|
||||
|
||||
void Thread::ChangeCore(u32 core, u64 mask) {
|
||||
ideal_core = core;
|
||||
mask = mask;
|
||||
affinity_mask = mask;
|
||||
|
||||
if (status != THREADSTATUS_READY) {
|
||||
return;
|
||||
}
|
||||
|
||||
boost::optional<s32> new_processor_id{GetNextProcessorId(mask)};
|
||||
boost::optional<s32> new_processor_id{GetNextProcessorId(affinity_mask)};
|
||||
|
||||
if (!new_processor_id) {
|
||||
new_processor_id = processor_id;
|
||||
@@ -476,7 +479,7 @@ void Thread::ChangeCore(u32 core, u64 mask) {
|
||||
new_processor_id = ideal_core;
|
||||
}
|
||||
|
||||
ASSERT(new_processor_id < 4);
|
||||
ASSERT(*new_processor_id < 4);
|
||||
|
||||
// Add thread to new core's scheduler
|
||||
auto& next_scheduler = Core::System().GetInstance().Scheduler(*new_processor_id);
|
||||
|
||||
16
src/core/hle/service/bcat/bcat.cpp
Normal file
16
src/core/hle/service/bcat/bcat.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "core/hle/service/bcat/bcat.h"
|
||||
|
||||
namespace Service::BCAT {
|
||||
|
||||
BCAT::BCAT(std::shared_ptr<Module> module, const char* name)
|
||||
: Module::Interface(std::move(module), name) {
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, &BCAT::CreateBcatService, "CreateBcatService"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
} // namespace Service::BCAT
|
||||
16
src/core/hle/service/bcat/bcat.h
Normal file
16
src/core/hle/service/bcat/bcat.h
Normal file
@@ -0,0 +1,16 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/bcat/module.h"
|
||||
|
||||
namespace Service::BCAT {
|
||||
|
||||
class BCAT final : public Module::Interface {
|
||||
public:
|
||||
explicit BCAT(std::shared_ptr<Module> module, const char* name);
|
||||
};
|
||||
|
||||
} // namespace Service::BCAT
|
||||
53
src/core/hle/service/bcat/module.cpp
Normal file
53
src/core/hle/service/bcat/module.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/bcat/bcat.h"
|
||||
#include "core/hle/service/bcat/module.h"
|
||||
|
||||
namespace Service::BCAT {
|
||||
|
||||
class IBcatService final : public ServiceFramework<IBcatService> {
|
||||
public:
|
||||
IBcatService() : ServiceFramework("IBcatService") {
|
||||
static const FunctionInfo functions[] = {
|
||||
{10100, nullptr, "RequestSyncDeliveryCache"},
|
||||
{10101, nullptr, "RequestSyncDeliveryCacheWithDirectoryName"},
|
||||
{10200, nullptr, "CancelSyncDeliveryCacheRequest"},
|
||||
{20100, nullptr, "RequestSyncDeliveryCacheWithApplicationId"},
|
||||
{20101, nullptr, "RequestSyncDeliveryCacheWithApplicationIdAndDirectoryName"},
|
||||
{30100, nullptr, "SetPassphrase"},
|
||||
{30200, nullptr, "RegisterBackgroundDeliveryTask"},
|
||||
{30201, nullptr, "UnregisterBackgroundDeliveryTask"},
|
||||
{30202, nullptr, "BlockDeliveryTask"},
|
||||
{30203, nullptr, "UnblockDeliveryTask"},
|
||||
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
|
||||
{90200, nullptr, "GetDeliveryList"},
|
||||
{90201, nullptr, "ClearDeliveryCacheStorage"},
|
||||
{90300, nullptr, "GetPushNotificationLog"},
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
};
|
||||
|
||||
void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) {
|
||||
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushIpcInterface<IBcatService>();
|
||||
NGLOG_DEBUG(Service_BCAT, "called");
|
||||
}
|
||||
|
||||
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
|
||||
: ServiceFramework(name), module(std::move(module)) {}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager) {
|
||||
auto module = std::make_shared<Module>();
|
||||
std::make_shared<BCAT>(module, "bcat:a")->InstallAsService(service_manager);
|
||||
std::make_shared<BCAT>(module, "bcat:m")->InstallAsService(service_manager);
|
||||
std::make_shared<BCAT>(module, "bcat:u")->InstallAsService(service_manager);
|
||||
std::make_shared<BCAT>(module, "bcat:s")->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
} // namespace Service::BCAT
|
||||
27
src/core/hle/service/bcat/module.h
Normal file
27
src/core/hle/service/bcat/module.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::BCAT {
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
public:
|
||||
Interface(std::shared_ptr<Module> module, const char* name);
|
||||
|
||||
void CreateBcatService(Kernel::HLERequestContext& ctx);
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Module> module;
|
||||
};
|
||||
};
|
||||
|
||||
/// Registers all BCAT services with the specified service manager.
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager);
|
||||
|
||||
} // namespace Service::BCAT
|
||||
@@ -329,6 +329,7 @@ public:
|
||||
{130, nullptr, "SwapNpadAssignment"},
|
||||
{131, nullptr, "IsUnintendedHomeButtonInputProtectionEnabled"},
|
||||
{132, nullptr, "EnableUnintendedHomeButtonInputProtection"},
|
||||
{133, nullptr, "SetNpadJoyAssignmentModeSingleWithDestination"},
|
||||
{200, &Hid::GetVibrationDeviceInfo, "GetVibrationDeviceInfo"},
|
||||
{201, &Hid::SendVibrationValue, "SendVibrationValue"},
|
||||
{202, &Hid::GetActualVibrationValue, "GetActualVibrationValue"},
|
||||
@@ -336,12 +337,41 @@ public:
|
||||
{204, nullptr, "PermitVibration"},
|
||||
{205, nullptr, "IsVibrationPermitted"},
|
||||
{206, &Hid::SendVibrationValues, "SendVibrationValues"},
|
||||
{207, nullptr, "SendVibrationGcErmCommand"},
|
||||
{208, nullptr, "GetActualVibrationGcErmCommand"},
|
||||
{209, nullptr, "BeginPermitVibrationSession"},
|
||||
{210, nullptr, "EndPermitVibrationSession"},
|
||||
{300, nullptr, "ActivateConsoleSixAxisSensor"},
|
||||
{301, nullptr, "StartConsoleSixAxisSensor"},
|
||||
{302, nullptr, "StopConsoleSixAxisSensor"},
|
||||
{303, nullptr, "ActivateSevenSixAxisSensor"},
|
||||
{304, nullptr, "StartSevenSixAxisSensor"},
|
||||
{305, nullptr, "StopSevenSixAxisSensor"},
|
||||
{306, nullptr, "InitializeSevenSixAxisSensor"},
|
||||
{307, nullptr, "FinalizeSevenSixAxisSensor"},
|
||||
{308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
|
||||
{309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
|
||||
{400, nullptr, "IsUsbFullKeyControllerEnabled"},
|
||||
{401, nullptr, "EnableUsbFullKeyController"},
|
||||
{402, nullptr, "IsUsbFullKeyControllerConnected"},
|
||||
{403, nullptr, "HasBattery"},
|
||||
{404, nullptr, "HasLeftRightBattery"},
|
||||
{405, nullptr, "GetNpadInterfaceType"},
|
||||
{406, nullptr, "GetNpadLeftRightInterfaceType"},
|
||||
{500, nullptr, "GetPalmaConnectionHandle"},
|
||||
{501, nullptr, "InitializePalma"},
|
||||
{502, nullptr, "AcquirePalmaOperationCompleteEvent"},
|
||||
{503, nullptr, "GetPalmaOperationInfo"},
|
||||
{504, nullptr, "PlayPalmaActivity"},
|
||||
{505, nullptr, "SetPalmaFrModeType"},
|
||||
{506, nullptr, "ReadPalmaStep"},
|
||||
{507, nullptr, "EnablePalmaStep"},
|
||||
{508, nullptr, "SuspendPalmaStep"},
|
||||
{509, nullptr, "ResetPalmaStep"},
|
||||
{510, nullptr, "ReadPalmaApplicationSection"},
|
||||
{511, nullptr, "WritePalmaApplicationSection"},
|
||||
{512, nullptr, "ReadPalmaUniqueCode"},
|
||||
{513, nullptr, "SetPalmaUniqueCodeInvalid"},
|
||||
{1000, nullptr, "SetNpadCommunicationMode"},
|
||||
{1001, nullptr, "GetNpadCommunicationMode"},
|
||||
};
|
||||
|
||||
@@ -16,7 +16,11 @@ u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<
|
||||
case IoctlCommand::IocGetConfigCommand:
|
||||
return NvOsGetConfigU32(input, output);
|
||||
case IoctlCommand::IocCtrlEventWaitCommand:
|
||||
return IocCtrlEventWait(input, output);
|
||||
return IocCtrlEventWait(input, output, false);
|
||||
case IoctlCommand::IocCtrlEventWaitAsyncCommand:
|
||||
return IocCtrlEventWait(input, output, true);
|
||||
case IoctlCommand::IocCtrlEventRegisterCommand:
|
||||
return IocCtrlEventRegister(input, output);
|
||||
}
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
@@ -45,11 +49,13 @@ u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>&
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool is_async) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called, syncpt_id={} threshold={} timeout={}",
|
||||
params.syncpt_id, params.threshold, params.timeout);
|
||||
NGLOG_WARNING(Service_NVDRV,
|
||||
"(STUBBED) called, syncpt_id={}, threshold={}, timeout={}, is_async={}",
|
||||
params.syncpt_id, params.threshold, params.timeout, is_async);
|
||||
|
||||
// TODO(Subv): Implement actual syncpt waiting.
|
||||
params.value = 0;
|
||||
@@ -57,4 +63,10 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NGLOG_WARNING(Service_NVDRV, "(STUBBED) called");
|
||||
// TODO(bunnei): Implement this.
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -134,7 +134,9 @@ private:
|
||||
|
||||
u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
|
||||
|
||||
u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
|
||||
@@ -26,11 +26,19 @@ public:
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
IocAllocGPFIFOCommand = 0x40084805,
|
||||
IocSetClientDataCommand = 0x40084714,
|
||||
IocGetClientDataCommand = 0x80084715,
|
||||
IocZCullBind = 0xc010480b,
|
||||
IocSetErrorNotifierCommand = 0xC018480C,
|
||||
IocChannelSetPriorityCommand = 0x4004480D,
|
||||
IocEnableCommand = 0x0000480E,
|
||||
IocDisableCommand = 0x0000480F,
|
||||
IocPreemptCommand = 0x00004810,
|
||||
IocForceResetCommand = 0x00004811,
|
||||
IocEventIdControlCommand = 0x40084812,
|
||||
IocGetErrorNotificationCommand = 0xC0104817,
|
||||
IocAllocGPFIFOExCommand = 0x40204818,
|
||||
IocAllocGPFIFOEx2Command = 0xC020481A,
|
||||
IocAllocObjCtxCommand = 0xC0104809,
|
||||
IocChannelGetWaitbaseCommand = 0xC0080003,
|
||||
@@ -56,6 +64,12 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
|
||||
|
||||
struct IoctlAllocGPFIFO {
|
||||
u32_le num_entries;
|
||||
u32_le flags;
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
|
||||
|
||||
struct IoctlClientData {
|
||||
u64_le data;
|
||||
};
|
||||
@@ -76,12 +90,45 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
|
||||
|
||||
struct IoctlChannelSetPriority {
|
||||
u32_le priority;
|
||||
};
|
||||
static_assert(sizeof(IoctlChannelSetPriority) == 4,
|
||||
"IoctlChannelSetPriority is incorrect size");
|
||||
|
||||
struct IoctlEventIdControl {
|
||||
u32_le cmd; // 0=disable, 1=enable, 2=clear
|
||||
u32_le id;
|
||||
};
|
||||
static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
|
||||
|
||||
struct IoctlGetErrorNotification {
|
||||
u64_le timestamp;
|
||||
u32_le info32;
|
||||
u16_le info16;
|
||||
u16_le status; // always 0xFFFF
|
||||
};
|
||||
static_assert(sizeof(IoctlGetErrorNotification) == 16,
|
||||
"IoctlGetErrorNotification is incorrect size");
|
||||
|
||||
struct IoctlFence {
|
||||
u32_le id;
|
||||
u32_le value;
|
||||
};
|
||||
static_assert(sizeof(IoctlFence) == 8, "IoctlFence is incorrect size");
|
||||
|
||||
struct IoctlAllocGpfifoEx {
|
||||
u32_le num_entries;
|
||||
u32_le flags;
|
||||
u32_le unk0;
|
||||
u32_le unk1;
|
||||
u32_le unk2;
|
||||
u32_le unk3;
|
||||
u32_le unk4;
|
||||
u32_le unk5;
|
||||
};
|
||||
static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
|
||||
|
||||
struct IoctlAllocGpfifoEx2 {
|
||||
u32_le num_entries; // in
|
||||
u32_le flags; // in
|
||||
|
||||
32
src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
Normal file
32
src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
Normal file
@@ -0,0 +1,32 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
NGLOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}",
|
||||
command.raw, input.size(), output.size());
|
||||
|
||||
switch (static_cast<IoctlCommand>(command.raw)) {
|
||||
case IoctlCommand::IocSetNVMAPfdCommand:
|
||||
return SetNVMAPfd(input, output);
|
||||
}
|
||||
|
||||
UNIMPLEMENTED_MSG("Unimplemented ioctl");
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IoctlSetNvmapFD params{};
|
||||
std::memcpy(¶ms, input.data(), input.size());
|
||||
NGLOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
|
||||
nvmap_fd = params.nvmap_fd;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
38
src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
Normal file
38
src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
Normal file
@@ -0,0 +1,38 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
|
||||
namespace Service::Nvidia::Devices {
|
||||
|
||||
class nvhost_nvdec final : public nvdevice {
|
||||
public:
|
||||
nvhost_nvdec() = default;
|
||||
~nvhost_nvdec() override = default;
|
||||
|
||||
u32 ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
|
||||
|
||||
private:
|
||||
enum class IoctlCommand : u32_le {
|
||||
IocSetNVMAPfdCommand = 0x40044801,
|
||||
};
|
||||
|
||||
struct IoctlSetNvmapFD {
|
||||
u32_le nvmap_fd;
|
||||
};
|
||||
static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
|
||||
|
||||
u32_le nvmap_fd{};
|
||||
|
||||
u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
};
|
||||
|
||||
} // namespace Service::Nvidia::Devices
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvmap.h"
|
||||
#include "core/hle/service/nvdrv/interface.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
@@ -36,6 +37,7 @@ Module::Module() {
|
||||
devices["/dev/nvmap"] = nvmap_dev;
|
||||
devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(nvmap_dev);
|
||||
devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>();
|
||||
devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>();
|
||||
}
|
||||
|
||||
u32 Module::Open(std::string device_name) {
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "core/hle/service/aoc/aoc_u.h"
|
||||
#include "core/hle/service/apm/apm.h"
|
||||
#include "core/hle/service/audio/audio.h"
|
||||
#include "core/hle/service/bcat/bcat.h"
|
||||
#include "core/hle/service/fatal/fatal.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/friend/friend.h"
|
||||
@@ -183,6 +184,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) {
|
||||
AM::InstallInterfaces(*sm, nv_flinger);
|
||||
AOC::InstallInterfaces(*sm);
|
||||
APM::InstallInterfaces(*sm);
|
||||
BCAT::InstallInterfaces(*sm);
|
||||
Audio::InstallInterfaces(*sm);
|
||||
Fatal::InstallInterfaces(*sm);
|
||||
FileSystem::InstallInterfaces(*sm);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
@@ -77,7 +78,7 @@ public:
|
||||
{3, nullptr, "LoadLocationNameList"},
|
||||
{4, &ITimeZoneService::LoadTimeZoneRule, "LoadTimeZoneRule"},
|
||||
{5, nullptr, "GetTimeZoneRuleVersion"},
|
||||
{100, nullptr, "ToCalendarTime"},
|
||||
{100, &ITimeZoneService::ToCalendarTime, "ToCalendarTime"},
|
||||
{101, &ITimeZoneService::ToCalendarTimeWithMyRule, "ToCalendarTimeWithMyRule"},
|
||||
{200, nullptr, "ToPosixTime"},
|
||||
{201, nullptr, "ToPosixTimeWithMyRule"},
|
||||
@@ -86,9 +87,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
LocationName location_name{"UTC"};
|
||||
TimeZoneRule my_time_zone_rule{};
|
||||
|
||||
void GetDeviceLocationName(Kernel::HLERequestContext& ctx) {
|
||||
NGLOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
LocationName location_name{};
|
||||
NGLOG_DEBUG(Service_Time, "called");
|
||||
IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(location_name);
|
||||
@@ -103,23 +106,70 @@ private:
|
||||
|
||||
void LoadTimeZoneRule(Kernel::HLERequestContext& ctx) {
|
||||
NGLOG_WARNING(Service_Time, "(STUBBED) called");
|
||||
|
||||
ctx.WriteBuffer(&my_time_zone_rule, sizeof(TimeZoneRule));
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
}
|
||||
|
||||
void ToCalendarTime(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const u64 posix_time = rp.Pop<u64>();
|
||||
|
||||
NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
|
||||
|
||||
TimeZoneRule time_zone_rule{};
|
||||
auto buffer = ctx.ReadBuffer();
|
||||
std::memcpy(&time_zone_rule, buffer.data(), buffer.size());
|
||||
|
||||
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
|
||||
CalendarAdditionalInfo additional_info{};
|
||||
|
||||
PosixToCalendar(posix_time, calendar_time, additional_info, time_zone_rule);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(calendar_time);
|
||||
rb.PushRaw(additional_info);
|
||||
}
|
||||
|
||||
void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
u64 posix_time = rp.Pop<u64>();
|
||||
const u64 posix_time = rp.Pop<u64>();
|
||||
|
||||
NGLOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time);
|
||||
|
||||
CalendarTime calendar_time{2018, 1, 1, 0, 0, 0};
|
||||
CalendarAdditionalInfo additional_info{};
|
||||
|
||||
PosixToCalendar(posix_time, calendar_time, additional_info, my_time_zone_rule);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 10};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
rb.PushRaw(calendar_time);
|
||||
rb.PushRaw(additional_info);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) {
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::Time {
|
||||
|
||||
// TODO(Rozelette) RE this structure
|
||||
struct LocationName {
|
||||
INSERT_PADDING_BYTES(0x24);
|
||||
std::array<u8, 0x24> name;
|
||||
};
|
||||
static_assert(sizeof(LocationName) == 0x24, "LocationName is incorrect size");
|
||||
|
||||
@@ -25,26 +25,34 @@ struct CalendarTime {
|
||||
};
|
||||
static_assert(sizeof(CalendarTime) == 0x8, "CalendarTime structure has incorrect size");
|
||||
|
||||
// TODO(Rozelette) RE this structure
|
||||
struct CalendarAdditionalInfo {
|
||||
INSERT_PADDING_BYTES(0x18);
|
||||
u32_le day_of_week;
|
||||
u32_le day_of_year;
|
||||
std::array<u8, 8> name;
|
||||
INSERT_PADDING_BYTES(1);
|
||||
s32_le utc_offset;
|
||||
};
|
||||
static_assert(sizeof(CalendarAdditionalInfo) == 0x18,
|
||||
"CalendarAdditionalInfo structure has incorrect size");
|
||||
|
||||
// TODO(bunnei) RE this structure
|
||||
struct SystemClockContext {
|
||||
INSERT_PADDING_BYTES(0x20);
|
||||
// TODO(mailwl) RE this structure
|
||||
struct TimeZoneRule {
|
||||
INSERT_PADDING_BYTES(0x4000);
|
||||
};
|
||||
static_assert(sizeof(SystemClockContext) == 0x20,
|
||||
"SystemClockContext structure has incorrect size");
|
||||
|
||||
struct SteadyClockTimePoint {
|
||||
u64 value;
|
||||
u64_le value;
|
||||
INSERT_PADDING_WORDS(4);
|
||||
};
|
||||
static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size");
|
||||
|
||||
struct SystemClockContext {
|
||||
u64_le offset;
|
||||
SteadyClockTimePoint time_point;
|
||||
};
|
||||
static_assert(sizeof(SystemClockContext) == 0x20,
|
||||
"SystemClockContext structure has incorrect size");
|
||||
|
||||
class Module final {
|
||||
public:
|
||||
class Interface : public ServiceFramework<Interface> {
|
||||
|
||||
@@ -75,6 +75,10 @@ union Attribute {
|
||||
enum class Index : u64 {
|
||||
Position = 7,
|
||||
Attribute_0 = 8,
|
||||
// This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex
|
||||
// shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval
|
||||
// shader.
|
||||
TessCoordInstanceIDVertexID = 47,
|
||||
};
|
||||
|
||||
union {
|
||||
@@ -257,6 +261,19 @@ union Instruction {
|
||||
BitField<50, 1, u64> saturate_a;
|
||||
} conversion;
|
||||
|
||||
union {
|
||||
BitField<31, 4, u64> component_mask;
|
||||
|
||||
bool IsComponentEnabled(size_t component) const {
|
||||
return ((1 << component) & component_mask) != 0;
|
||||
}
|
||||
} tex;
|
||||
|
||||
union {
|
||||
// TODO(bunnei): This is just a guess, needs to be verified
|
||||
BitField<52, 1, u64> enable_g_component;
|
||||
} texs;
|
||||
|
||||
BitField<61, 1, u64> is_b_imm;
|
||||
BitField<60, 1, u64> is_b_gpr;
|
||||
BitField<59, 1, u64> is_c_gpr;
|
||||
@@ -277,6 +294,7 @@ public:
|
||||
KIL,
|
||||
LD_A,
|
||||
ST_A,
|
||||
TEX,
|
||||
TEXQ, // Texture Query
|
||||
TEXS, // Texture Fetch with scalar/non-vec4 source/destinations
|
||||
TLDS, // Texture Load with scalar/non-vec4 source/destinations
|
||||
@@ -293,8 +311,10 @@ public:
|
||||
FMUL_R,
|
||||
FMUL_IMM,
|
||||
FMUL32_IMM,
|
||||
MUFU, // Multi-Function Operator
|
||||
RRO, // Range Reduction Operator
|
||||
MUFU, // Multi-Function Operator
|
||||
RRO_C, // Range Reduction Operator
|
||||
RRO_R,
|
||||
RRO_IMM,
|
||||
F2F_C,
|
||||
F2F_R,
|
||||
F2F_IMM,
|
||||
@@ -438,6 +458,7 @@ private:
|
||||
INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
|
||||
INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
|
||||
INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
|
||||
INST("1100000000111---", Id::TEX, Type::Memory, "TEX"),
|
||||
INST("1101111101001---", Id::TEXQ, Type::Memory, "TEXQ"),
|
||||
INST("1101100---------", Id::TEXS, Type::Memory, "TEXS"),
|
||||
INST("1101101---------", Id::TLDS, Type::Memory, "TLDS"),
|
||||
@@ -455,10 +476,12 @@ private:
|
||||
INST("0011100-01101---", Id::FMUL_IMM, Type::Arithmetic, "FMUL_IMM"),
|
||||
INST("00011110--------", Id::FMUL32_IMM, Type::Arithmetic, "FMUL32_IMM"),
|
||||
INST("0101000010000---", Id::MUFU, Type::Arithmetic, "MUFU"),
|
||||
INST("0101110010010---", Id::RRO, Type::Arithmetic, "RRO"),
|
||||
INST("0100110010101---", Id::F2F_C, Type::Arithmetic, "F2F_C"),
|
||||
INST("0101110010101---", Id::F2F_R, Type::Arithmetic, "F2F_R"),
|
||||
INST("0011100-10101---", Id::F2F_IMM, Type::Arithmetic, "F2F_IMM"),
|
||||
INST("0100110010010---", Id::RRO_C, Type::Arithmetic, "RRO_C"),
|
||||
INST("0101110010010---", Id::RRO_R, Type::Arithmetic, "RRO_R"),
|
||||
INST("0011100-10010---", Id::RRO_IMM, Type::Arithmetic, "RRO_IMM"),
|
||||
INST("0100110010101---", Id::F2F_C, Type::Conversion, "F2F_C"),
|
||||
INST("0101110010101---", Id::F2F_R, Type::Conversion, "F2F_R"),
|
||||
INST("0011100-10101---", Id::F2F_IMM, Type::Conversion, "F2F_IMM"),
|
||||
INST("0100110010110---", Id::F2I_C, Type::Arithmetic, "F2I_C"),
|
||||
INST("0101110010110---", Id::F2I_R, Type::Arithmetic, "F2I_R"),
|
||||
INST("0011100-10110---", Id::F2I_IMM, Type::Arithmetic, "F2I_IMM"),
|
||||
|
||||
@@ -45,20 +45,23 @@ struct FormatTuple {
|
||||
|
||||
static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_format_tuples = {{
|
||||
{GL_RGBA8, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, false}, // ABGR8
|
||||
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5_REV, false}, // B5G6R5
|
||||
{GL_RGB, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, false}, // B5G6R5
|
||||
{GL_RGB10_A2, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, false}, // A2B10G10R10
|
||||
{GL_RGB5_A1, GL_RGBA, GL_UNSIGNED_SHORT_1_5_5_5_REV, false}, // A1B5G5R5
|
||||
{GL_R8, GL_RED, GL_UNSIGNED_BYTE, false}, // R8
|
||||
{GL_RGBA16F, GL_RGBA, GL_HALF_FLOAT, false}, // RGBA16F
|
||||
{GL_COMPRESSED_RGB_S3TC_DXT1_EXT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT1
|
||||
{GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT23
|
||||
{GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, true}, // DXT45
|
||||
{GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, true}, // DXN1
|
||||
}};
|
||||
|
||||
static const FormatTuple& GetFormatTuple(PixelFormat pixel_format, ComponentType component_type) {
|
||||
const SurfaceType type = SurfaceParams::GetFormatType(pixel_format);
|
||||
if (type == SurfaceType::ColorTexture) {
|
||||
ASSERT(static_cast<size_t>(pixel_format) < tex_format_tuples.size());
|
||||
// For now only UNORM components are supported
|
||||
ASSERT(component_type == ComponentType::UNorm);
|
||||
// For now only UNORM components are supported, or RGBA16F which is type FLOAT
|
||||
ASSERT(component_type == ComponentType::UNorm || pixel_format == PixelFormat::RGBA16F);
|
||||
return tex_format_tuples[static_cast<unsigned int>(pixel_format)];
|
||||
} else if (type == SurfaceType::Depth || type == SurfaceType::DepthStencil) {
|
||||
// TODO(Subv): Implement depth formats
|
||||
@@ -109,8 +112,9 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra:
|
||||
morton_to_gl_fns = {
|
||||
MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>,
|
||||
MortonCopy<true, PixelFormat::A2B10G10R10>, MortonCopy<true, PixelFormat::A1B5G5R5>,
|
||||
MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>,
|
||||
MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
|
||||
MortonCopy<true, PixelFormat::DXT45>,
|
||||
MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
|
||||
};
|
||||
|
||||
static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra::GPUVAddr,
|
||||
@@ -121,7 +125,10 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra:
|
||||
MortonCopy<false, PixelFormat::B5G6R5>,
|
||||
MortonCopy<false, PixelFormat::A2B10G10R10>,
|
||||
MortonCopy<false, PixelFormat::A1B5G5R5>,
|
||||
// TODO(Subv): Swizzling the DXT1/DXT23/DXT45 formats is not yet supported
|
||||
MortonCopy<false, PixelFormat::R8>,
|
||||
MortonCopy<false, PixelFormat::RGBA16F>,
|
||||
// TODO(Subv): Swizzling the DXT1/DXT23/DXT45/DXN1 formats is not yet supported
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
|
||||
@@ -58,9 +58,12 @@ struct SurfaceParams {
|
||||
B5G6R5 = 1,
|
||||
A2B10G10R10 = 2,
|
||||
A1B5G5R5 = 3,
|
||||
DXT1 = 4,
|
||||
DXT23 = 5,
|
||||
DXT45 = 6,
|
||||
R8 = 4,
|
||||
RGBA16F = 5,
|
||||
DXT1 = 6,
|
||||
DXT23 = 7,
|
||||
DXT45 = 8,
|
||||
DXN1 = 9, // This is also known as BC4
|
||||
|
||||
Max,
|
||||
Invalid = 255,
|
||||
@@ -100,9 +103,12 @@ struct SurfaceParams {
|
||||
1, // B5G6R5
|
||||
1, // A2B10G10R10
|
||||
1, // A1B5G5R5
|
||||
1, // R8
|
||||
2, // RGBA16F
|
||||
4, // DXT1
|
||||
4, // DXT23
|
||||
4, // DXT45
|
||||
4, // DXN1
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<size_t>(format) < compression_factor_table.size());
|
||||
@@ -121,9 +127,12 @@ struct SurfaceParams {
|
||||
16, // B5G6R5
|
||||
32, // A2B10G10R10
|
||||
16, // A1B5G5R5
|
||||
8, // R8
|
||||
64, // RGBA16F
|
||||
64, // DXT1
|
||||
128, // DXT23
|
||||
128, // DXT45
|
||||
64, // DXN1
|
||||
}};
|
||||
|
||||
ASSERT(static_cast<size_t>(format) < bpp_table.size());
|
||||
@@ -140,6 +149,8 @@ struct SurfaceParams {
|
||||
return PixelFormat::ABGR8;
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
return PixelFormat::A2B10G10R10;
|
||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||
return PixelFormat::RGBA16F;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
@@ -167,12 +178,18 @@ struct SurfaceParams {
|
||||
return PixelFormat::A2B10G10R10;
|
||||
case Tegra::Texture::TextureFormat::A1B5G5R5:
|
||||
return PixelFormat::A1B5G5R5;
|
||||
case Tegra::Texture::TextureFormat::R8:
|
||||
return PixelFormat::R8;
|
||||
case Tegra::Texture::TextureFormat::R16_G16_B16_A16:
|
||||
return PixelFormat::RGBA16F;
|
||||
case Tegra::Texture::TextureFormat::DXT1:
|
||||
return PixelFormat::DXT1;
|
||||
case Tegra::Texture::TextureFormat::DXT23:
|
||||
return PixelFormat::DXT23;
|
||||
case Tegra::Texture::TextureFormat::DXT45:
|
||||
return PixelFormat::DXT45;
|
||||
case Tegra::Texture::TextureFormat::DXN1:
|
||||
return PixelFormat::DXN1;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
@@ -190,12 +207,18 @@ struct SurfaceParams {
|
||||
return Tegra::Texture::TextureFormat::A2B10G10R10;
|
||||
case PixelFormat::A1B5G5R5:
|
||||
return Tegra::Texture::TextureFormat::A1B5G5R5;
|
||||
case PixelFormat::R8:
|
||||
return Tegra::Texture::TextureFormat::R8;
|
||||
case PixelFormat::RGBA16F:
|
||||
return Tegra::Texture::TextureFormat::R16_G16_B16_A16;
|
||||
case PixelFormat::DXT1:
|
||||
return Tegra::Texture::TextureFormat::DXT1;
|
||||
case PixelFormat::DXT23:
|
||||
return Tegra::Texture::TextureFormat::DXT23;
|
||||
case PixelFormat::DXT45:
|
||||
return Tegra::Texture::TextureFormat::DXT45;
|
||||
case PixelFormat::DXN1:
|
||||
return Tegra::Texture::TextureFormat::DXN1;
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
@@ -219,6 +242,8 @@ struct SurfaceParams {
|
||||
case Tegra::RenderTargetFormat::RGBA8_SRGB:
|
||||
case Tegra::RenderTargetFormat::RGB10_A2_UNORM:
|
||||
return ComponentType::UNorm;
|
||||
case Tegra::RenderTargetFormat::RGBA16_FLOAT:
|
||||
return ComponentType::Float;
|
||||
default:
|
||||
NGLOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format));
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -299,7 +299,7 @@ public:
|
||||
* are stored as floats, so this may require conversion.
|
||||
* @param reg The destination register to use.
|
||||
* @param elem The element to use for the operation.
|
||||
* @param attribute The input attibute to use as the source value.
|
||||
* @param attribute The input attribute to use as the source value.
|
||||
*/
|
||||
void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute) {
|
||||
std::string dest = GetRegisterAsFloat(reg);
|
||||
@@ -451,6 +451,12 @@ private:
|
||||
switch (attribute) {
|
||||
case Attribute::Index::Position:
|
||||
return "position";
|
||||
case Attribute::Index::TessCoordInstanceIDVertexID:
|
||||
// TODO(Subv): Find out what the values are for the first two elements when inside a
|
||||
// vertex shader, and what's the value of the fourth element when inside a Tess Eval
|
||||
// shader.
|
||||
ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex);
|
||||
return "vec4(0, 0, gl_InstanceID, gl_VertexID)";
|
||||
default:
|
||||
const u32 index{static_cast<u32>(attribute) -
|
||||
static_cast<u32>(Attribute::Index::Attribute_0)};
|
||||
@@ -786,8 +792,13 @@ private:
|
||||
1, 1);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::RRO: {
|
||||
NGLOG_DEBUG(HW_GPU, "Skipping RRO instruction");
|
||||
case OpCode::Id::RRO_C:
|
||||
case OpCode::Id::RRO_R:
|
||||
case OpCode::Id::RRO_IMM: {
|
||||
// Currently RRO is only implemented as a register move.
|
||||
// Usage of `abs_b` and `negate_b` here should also be correct.
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_b, 1, 1);
|
||||
NGLOG_WARNING(HW_GPU, "RRO instruction is incomplete");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
@@ -834,13 +845,14 @@ private:
|
||||
}
|
||||
case OpCode::Type::Conversion: {
|
||||
ASSERT_MSG(instr.conversion.size == Register::Size::Word, "Unimplemented");
|
||||
ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
|
||||
ASSERT_MSG(!instr.conversion.negate_a, "Unimplemented");
|
||||
ASSERT_MSG(!instr.conversion.saturate_a, "Unimplemented");
|
||||
|
||||
switch (opcode->GetId()) {
|
||||
case OpCode::Id::I2I_R:
|
||||
case OpCode::Id::I2F_R: {
|
||||
ASSERT_MSG(!instr.conversion.selector, "Unimplemented");
|
||||
|
||||
std::string op_a =
|
||||
regs.GetRegisterAsInteger(instr.gpr20, 0, instr.conversion.is_signed);
|
||||
|
||||
@@ -851,6 +863,16 @@ private:
|
||||
regs.SetRegisterToInteger(instr.gpr0, instr.conversion.is_signed, 0, op_a, 1, 1);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::F2F_R: {
|
||||
std::string op_a = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
|
||||
if (instr.conversion.abs_a) {
|
||||
op_a = "abs(" + op_a + ')';
|
||||
}
|
||||
|
||||
regs.SetRegisterToFloat(instr.gpr0, 0, op_a, 1, 1);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
NGLOG_CRITICAL(HW_GPU, "Unhandled conversion instruction: {}", opcode->GetName());
|
||||
UNREACHABLE();
|
||||
@@ -874,10 +896,10 @@ private:
|
||||
instr.gpr0);
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TEXS: {
|
||||
case OpCode::Id::TEX: {
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
|
||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1);
|
||||
const std::string sampler = GetSampler(instr.sampler);
|
||||
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
||||
// Add an extra scope and declare the texture coords inside to prevent overwriting
|
||||
@@ -886,8 +908,49 @@ private:
|
||||
++shader.scope;
|
||||
shader.AddLine(coord);
|
||||
const std::string texture = "texture(" + sampler + ", coords)";
|
||||
for (unsigned elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
|
||||
regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, elem);
|
||||
|
||||
size_t dest_elem{};
|
||||
for (size_t elem = 0; elem < instr.attribute.fmt20.size; ++elem) {
|
||||
if (!instr.tex.IsComponentEnabled(elem)) {
|
||||
// Skip disabled components
|
||||
continue;
|
||||
}
|
||||
regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem);
|
||||
++dest_elem;
|
||||
}
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
break;
|
||||
}
|
||||
case OpCode::Id::TEXS: {
|
||||
ASSERT_MSG(instr.attribute.fmt20.size == 4, "untested");
|
||||
const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8);
|
||||
const std::string op_b = regs.GetRegisterAsFloat(instr.gpr20);
|
||||
const std::string sampler = GetSampler(instr.sampler);
|
||||
const std::string coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");";
|
||||
// Add an extra scope and declare the texture coords inside to prevent
|
||||
// overwriting them in case they are used as outputs of the texs instruction.
|
||||
shader.AddLine("{");
|
||||
++shader.scope;
|
||||
shader.AddLine(coord);
|
||||
const std::string texture = "texture(" + sampler + ", coords)";
|
||||
|
||||
// TEXS has two destination registers. RG goes into gpr0+0 and gpr0+1, and BA goes
|
||||
// into gpr28+0 and gpr28+1
|
||||
size_t offset{};
|
||||
for (const auto& dest : {instr.gpr0.Value(), instr.gpr28.Value()}) {
|
||||
for (unsigned elem = 0; elem < 2; ++elem) {
|
||||
if (dest + elem >= Register::ZeroIndex) {
|
||||
// Skip invalid register values
|
||||
break;
|
||||
}
|
||||
regs.SetRegisterToFloat(dest, elem + offset, texture, 1, 4, false, elem);
|
||||
if (!instr.texs.enable_g_component) {
|
||||
// Skip the second component
|
||||
break;
|
||||
}
|
||||
}
|
||||
offset += 2;
|
||||
}
|
||||
--shader.scope;
|
||||
shader.AddLine("}");
|
||||
@@ -944,8 +1007,8 @@ private:
|
||||
'(' + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
|
||||
if (instr.fsetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
|
||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate, if
|
||||
// enabled
|
||||
// Set the secondary predicate to the result of !Predicate OP SecondPredicate,
|
||||
// if enabled
|
||||
SetPredicate(instr.fsetp.pred0,
|
||||
"!(" + predicate + ") " + combiner + " (" + second_pred + ')');
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ void CopySwizzledData(u32 width, u32 height, u32 bytes_per_pixel, u32 out_bytes_
|
||||
u32 BytesPerPixel(TextureFormat format) {
|
||||
switch (format) {
|
||||
case TextureFormat::DXT1:
|
||||
case TextureFormat::DXN1:
|
||||
// In this case a 'pixel' actually refers to a 4x4 tile.
|
||||
return 8;
|
||||
case TextureFormat::DXT23:
|
||||
@@ -58,6 +59,10 @@ u32 BytesPerPixel(TextureFormat format) {
|
||||
case TextureFormat::A1B5G5R5:
|
||||
case TextureFormat::B5G6R5:
|
||||
return 2;
|
||||
case TextureFormat::R8:
|
||||
return 1;
|
||||
case TextureFormat::R16_G16_B16_A16:
|
||||
return 8;
|
||||
default:
|
||||
UNIMPLEMENTED_MSG("Format not implemented");
|
||||
break;
|
||||
@@ -75,7 +80,9 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
|
||||
case TextureFormat::DXT1:
|
||||
case TextureFormat::DXT23:
|
||||
case TextureFormat::DXT45:
|
||||
// In the DXT formats, each 4x4 tile is swizzled instead of just individual pixel values.
|
||||
case TextureFormat::DXN1:
|
||||
// In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel
|
||||
// values.
|
||||
CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data,
|
||||
unswizzled_data.data(), true, block_height);
|
||||
break;
|
||||
@@ -83,6 +90,8 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
|
||||
case TextureFormat::A2B10G10R10:
|
||||
case TextureFormat::A1B5G5R5:
|
||||
case TextureFormat::B5G6R5:
|
||||
case TextureFormat::R8:
|
||||
case TextureFormat::R16_G16_B16_A16:
|
||||
CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data,
|
||||
unswizzled_data.data(), true, block_height);
|
||||
break;
|
||||
@@ -103,10 +112,12 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat
|
||||
case TextureFormat::DXT1:
|
||||
case TextureFormat::DXT23:
|
||||
case TextureFormat::DXT45:
|
||||
case TextureFormat::DXN1:
|
||||
case TextureFormat::A8R8G8B8:
|
||||
case TextureFormat::A2B10G10R10:
|
||||
case TextureFormat::A1B5G5R5:
|
||||
case TextureFormat::B5G6R5:
|
||||
case TextureFormat::R8:
|
||||
// TODO(Subv): For the time being just forward the same data without any decoding.
|
||||
rgba_data = texture_data;
|
||||
break;
|
||||
|
||||
@@ -14,13 +14,82 @@ namespace Tegra {
|
||||
namespace Texture {
|
||||
|
||||
enum class TextureFormat : u32 {
|
||||
A8R8G8B8 = 0x8,
|
||||
A2B10G10R10 = 0x9,
|
||||
R32_G32_B32_A32 = 0x01,
|
||||
R32_G32_B32 = 0x02,
|
||||
R16_G16_B16_A16 = 0x03,
|
||||
R32_G32 = 0x04,
|
||||
R32_B24G8 = 0x05,
|
||||
ETC2_RGB = 0x06,
|
||||
X8B8G8R8 = 0x07,
|
||||
A8R8G8B8 = 0x08,
|
||||
A2B10G10R10 = 0x09,
|
||||
ETC2_RGB_PTA = 0x0a,
|
||||
ETC2_RGBA = 0x0b,
|
||||
R16_G16 = 0x0c,
|
||||
G8R24 = 0x0d,
|
||||
G24R8 = 0x0e,
|
||||
R32 = 0x0f,
|
||||
BC6H_SF16 = 0x10,
|
||||
BC6H_UF16 = 0x11,
|
||||
A4B4G4R4 = 0x12,
|
||||
A5B5G5R1 = 0x13,
|
||||
A1B5G5R5 = 0x14,
|
||||
B5G6R5 = 0x15,
|
||||
B6G5R5 = 0x16,
|
||||
BC7U = 0x17,
|
||||
G8R8 = 0x18,
|
||||
EAC = 0x19,
|
||||
EACX2 = 0x1a,
|
||||
R16 = 0x1b,
|
||||
Y8_VIDEO = 0x1c,
|
||||
R8 = 0x1d,
|
||||
G4R4 = 0x1e,
|
||||
R1 = 0x1f,
|
||||
E5B9G9R9_SHAREDEXP = 0x20,
|
||||
BF10GF11RF11 = 0x21,
|
||||
G8B8G8R8 = 0x22,
|
||||
B8G8R8G8 = 0x23,
|
||||
DXT1 = 0x24,
|
||||
DXT23 = 0x25,
|
||||
DXT45 = 0x26,
|
||||
DXN1 = 0x27,
|
||||
DXN2 = 0x28,
|
||||
Z24S8 = 0x29,
|
||||
X8Z24 = 0x2a,
|
||||
S8Z24 = 0x2b,
|
||||
X4V4Z24__COV4R4V = 0x2c,
|
||||
X4V4Z24__COV8R8V = 0x2d,
|
||||
V8Z24__COV4R12V = 0x2e,
|
||||
ZF32 = 0x2f,
|
||||
ZF32_X24S8 = 0x30,
|
||||
X8Z24_X20V4S8__COV4R4V = 0x31,
|
||||
X8Z24_X20V4S8__COV8R8V = 0x32,
|
||||
ZF32_X20V4X8__COV4R4V = 0x33,
|
||||
ZF32_X20V4X8__COV8R8V = 0x34,
|
||||
ZF32_X20V4S8__COV4R4V = 0x35,
|
||||
ZF32_X20V4S8__COV8R8V = 0x36,
|
||||
X8Z24_X16V8S8__COV4R12V = 0x37,
|
||||
ZF32_X16V8X8__COV4R12V = 0x38,
|
||||
ZF32_X16V8S8__COV4R12V = 0x39,
|
||||
Z16 = 0x3a,
|
||||
V8Z24__COV8R24V = 0x3b,
|
||||
X8Z24_X16V8S8__COV8R24V = 0x3c,
|
||||
ZF32_X16V8X8__COV8R24V = 0x3d,
|
||||
ZF32_X16V8S8__COV8R24V = 0x3e,
|
||||
ASTC_2D_4X4 = 0x40,
|
||||
ASTC_2D_5X5 = 0x41,
|
||||
ASTC_2D_6X6 = 0x42,
|
||||
ASTC_2D_8X8 = 0x44,
|
||||
ASTC_2D_10X10 = 0x45,
|
||||
ASTC_2D_12X12 = 0x46,
|
||||
ASTC_2D_5X4 = 0x50,
|
||||
ASTC_2D_6X5 = 0x51,
|
||||
ASTC_2D_8X6 = 0x52,
|
||||
ASTC_2D_10X8 = 0x53,
|
||||
ASTC_2D_12X10 = 0x54,
|
||||
ASTC_2D_8X5 = 0x55,
|
||||
ASTC_2D_10X5 = 0x56,
|
||||
ASTC_2D_10X6 = 0x57,
|
||||
};
|
||||
|
||||
enum class TextureType : u32 {
|
||||
|
||||
Reference in New Issue
Block a user