summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/core/hle/ipc.h3
-rw-r--r--src/core/hle/kernel/errors.h2
-rw-r--r--src/core/hle/kernel/svc.cpp27
-rw-r--r--src/core/hle/kernel/thread.cpp13
-rw-r--r--src/core/hle/service/hid/hid.cpp30
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h4
-rw-r--r--src/core/hle/service/time/time.cpp58
-rw-r--r--src/core/hle/service/time/time.h28
-rw-r--r--src/video_core/engines/shader_bytecode.h10
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp17
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h24
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp21
-rw-r--r--src/video_core/textures/decoders.cpp9
14 files changed, 226 insertions, 40 deletions
diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h
index c9257de77..eaa5395ac 100644
--- a/src/core/hle/ipc.h
+++ b/src/core/hle/ipc.h
@@ -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,
diff --git a/src/core/hle/kernel/errors.h b/src/core/hle/kernel/errors.h
index 5be20c878..e1b5430bf 100644
--- a/src/core/hle/kernel/errors.h
+++ b/src/core/hle/kernel/errors.h
@@ -21,7 +21,9 @@ enum {
// Confirmed Switch OS error codes
MisalignedAddress = 102,
+ InvalidProcessorId = 113,
InvalidHandle = 114,
+ InvalidCombination = 116,
Timeout = 117,
SynchronizationCanceled = 118,
TooLarge = 119,
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 0811a16b8..ec3601e8b 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -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;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 46fcdefb8..cffa7ca83 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -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);
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1891255cb..00c5308ba 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -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"},
};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index e979b9707..7872d1e09 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -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(&params, 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
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index aa9b5a14b..090261a60 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -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
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp
index 2eb37fb42..654012189 100644
--- a/src/core/hle/service/time/time.cpp
+++ b/src/core/hle/service/time/time.cpp
@@ -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) {
diff --git a/src/core/hle/service/time/time.h b/src/core/hle/service/time/time.h
index 12fe1995a..49af38589 100644
--- a/src/core/hle/service/time/time.h
+++ b/src/core/hle/service/time/time.h
@@ -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> {
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index d75de85e2..f32a17057 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -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 {
@@ -456,9 +460,9 @@ private:
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("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"),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 5bb34037b..65d643447 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -45,21 +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
@@ -110,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::DXT1>,
- MortonCopy<true, PixelFormat::DXT23>, MortonCopy<true, PixelFormat::DXT45>,
+ MortonCopy<true, PixelFormat::R8>, MortonCopy<true, PixelFormat::RGBA16F>,
+ MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>,
+ MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>,
};
static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra::GPUVAddr,
@@ -123,7 +126,9 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr, Tegra:
MortonCopy<false, PixelFormat::A2B10G10R10>,
MortonCopy<false, PixelFormat::A1B5G5R5>,
MortonCopy<false, PixelFormat::R8>,
- // TODO(Subv): Swizzling the DXT1/DXT23/DXT45 formats is not yet supported
+ MortonCopy<false, PixelFormat::RGBA16F>,
+ // TODO(Subv): Swizzling the DXT1/DXT23/DXT45/DXN1 formats is not yet supported
+ nullptr,
nullptr,
nullptr,
nullptr,
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
index fc09f108c..6f08678ab 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h
@@ -59,9 +59,11 @@ struct SurfaceParams {
A2B10G10R10 = 2,
A1B5G5R5 = 3,
R8 = 4,
- DXT1 = 5,
- DXT23 = 6,
- DXT45 = 7,
+ RGBA16F = 5,
+ DXT1 = 6,
+ DXT23 = 7,
+ DXT45 = 8,
+ DXN1 = 9, // This is also known as BC4
Max,
Invalid = 255,
@@ -102,9 +104,11 @@ struct SurfaceParams {
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());
@@ -124,9 +128,11 @@ struct SurfaceParams {
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());
@@ -143,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();
@@ -172,12 +180,16 @@ struct SurfaceParams {
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();
@@ -197,12 +209,16 @@ struct SurfaceParams {
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();
}
@@ -226,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();
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index 75822e750..68efe74b8 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -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)};
@@ -834,13 +840,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 +858,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();
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp
index 9d7b73b73..2d2af5554 100644
--- a/src/video_core/textures/decoders.cpp
+++ b/src/video_core/textures/decoders.cpp
@@ -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:
@@ -60,6 +61,8 @@ u32 BytesPerPixel(TextureFormat format) {
return 2;
case TextureFormat::R8:
return 1;
+ case TextureFormat::R16_G16_B16_A16:
+ return 8;
default:
UNIMPLEMENTED_MSG("Format not implemented");
break;
@@ -77,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;
@@ -86,6 +91,7 @@ std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width,
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;
@@ -106,6 +112,7 @@ 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: