diff options
Diffstat (limited to 'src/core')
-rw-r--r-- | src/core/arm/arm_interface.h | 6 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom.cpp | 5 | ||||
-rw-r--r-- | src/core/arm/dyncom/arm_dyncom.h | 1 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid.cpp | 214 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid.h | 114 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid_spvr.cpp | 6 | ||||
-rw-r--r-- | src/core/hle/service/hid/hid_user.cpp | 18 | ||||
-rw-r--r-- | src/core/hle/svc.cpp | 5 | ||||
-rw-r--r-- | src/core/hw/gpu.cpp | 35 | ||||
-rw-r--r-- | src/core/hw/gpu.h | 11 | ||||
-rw-r--r-- | src/core/loader/ncch.h | 25 |
11 files changed, 261 insertions, 179 deletions
diff --git a/src/core/arm/arm_interface.h b/src/core/arm/arm_interface.h index ef37ee055..fe1e584ad 100644 --- a/src/core/arm/arm_interface.h +++ b/src/core/arm/arm_interface.h @@ -74,12 +74,6 @@ public: virtual void SetCPSR(u32 cpsr) = 0; /** - * Returns the number of clock ticks since the last rese - * @return Returns number of clock ticks - */ - virtual u64 GetTicks() const = 0; - - /** * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time) * @param ticks Number of ticks to advance the CPU core */ diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index bbcbbdd2b..cb1a410a0 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -68,11 +68,6 @@ void ARM_DynCom::SetCPSR(u32 cpsr) { state->Cpsr = cpsr; } -u64 ARM_DynCom::GetTicks() const { - // TODO(Subv): Remove ARM_DynCom::GetTicks() and use CoreTiming::GetTicks() directly once ARMemu is gone - return CoreTiming::GetTicks(); -} - void ARM_DynCom::AddTicks(u64 ticks) { down_count -= ticks; if (down_count < 0) diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h index 213cac1ad..a7f95d307 100644 --- a/src/core/arm/dyncom/arm_dyncom.h +++ b/src/core/arm/dyncom/arm_dyncom.h @@ -23,7 +23,6 @@ public: u32 GetCPSR() const override; void SetCPSR(u32 cpsr) override; - u64 GetTicks() const override; void AddTicks(u64 ticks) override; void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index e0689be2e..138603d9b 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -7,36 +7,30 @@ #include "core/hle/service/hid/hid_spvr.h" #include "core/hle/service/hid/hid_user.h" -#include "core/arm/arm_interface.h" +#include "core/core_timing.h" #include "core/hle/kernel/event.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/hle.h" +#include "video_core/video_core.h" + namespace Service { namespace HID { -Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem = nullptr; - -Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; -Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; -Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; -Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; -Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; - -// Next Pad state update information -static PadState next_state = {{0}}; -static u32 next_index = 0; -static s16 next_circle_x = 0; -static s16 next_circle_y = 0; - -/** - * Gets a pointer to the PadData structure inside HID shared memory - */ -static inline PadData* GetPadData() { - if (g_shared_mem == nullptr) - return nullptr; - return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); -} +static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position + +// Handle to shared memory region designated to HID_User service +static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr; + +// Event handles +static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr; +static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr; +static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr; +static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr; +static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr; + +static u32 next_pad_index = 0; +static u32 next_touch_index = 0; // TODO(peachum): // Add a method for setting analog input from joystick device for the circle Pad. @@ -51,103 +45,114 @@ static inline PadData* GetPadData() { // * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 -/** - * Circle Pad from keys. - * - * This is implemented as "pushed all the way to an edge (max) or centered (0)". - * - * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. - */ -static void UpdateNextCirclePadState() { - static const s16 max_value = 0x9C; - next_circle_x = next_state.circle_left ? -max_value : 0x0; - next_circle_x += next_state.circle_right ? max_value : 0x0; - next_circle_y = next_state.circle_down ? -max_value : 0x0; - next_circle_y += next_state.circle_up ? max_value : 0x0; -} - -/** - * Sets a Pad state (button or button combo) as pressed - */ -void PadButtonPress(const PadState& pad_state) { - next_state.hex |= pad_state.hex; - UpdateNextCirclePadState(); -} - -/** - * Sets a Pad state (button or button combo) as released - */ -void PadButtonRelease(const PadState& pad_state) { - next_state.hex &= ~pad_state.hex; - UpdateNextCirclePadState(); -} - -/** - * Called after all Pad changes to be included in this update have been made, - * including both Pad key changes and analog circle Pad changes. - */ -void PadUpdateComplete() { - PadData* pad_data = GetPadData(); +void HIDUpdate() { + SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr)); + const PadState state = VideoCore::g_emu_window->GetPadState(); - if (pad_data == nullptr) { + if (mem == nullptr) { + LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); return; } - // Update PadData struct - pad_data->current_state.hex = next_state.hex; - pad_data->index = next_index; - next_index = (next_index + 1) % pad_data->entries.size(); + mem->pad.current_state.hex = state.hex; + mem->pad.index = next_pad_index; + ++next_touch_index %= mem->pad.entries.size(); // Get the previous Pad state - u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); - PadState old_state = pad_data->entries[last_entry_index].current_state; + u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size(); + PadState old_state = mem->pad.entries[last_entry_index].current_state; // Compute bitmask with 1s for bits different from the old state - PadState changed; - changed.hex = (next_state.hex ^ old_state.hex); - - // Compute what was added - PadState additions; - additions.hex = changed.hex & next_state.hex; - - // Compute what was removed - PadState removals; - removals.hex = changed.hex & old_state.hex; + PadState changed = { { (state.hex ^ old_state.hex) } }; // Get the current Pad entry - PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; + PadDataEntry* pad_entry = &mem->pad.entries[mem->pad.index]; // Update entry properties - current_pad_entry->current_state.hex = next_state.hex; - current_pad_entry->delta_additions.hex = additions.hex; - current_pad_entry->delta_removals.hex = removals.hex; + pad_entry->current_state.hex = state.hex; + pad_entry->delta_additions.hex = changed.hex & state.hex; + pad_entry->delta_removals.hex = changed.hex & old_state.hex;; // Set circle Pad - current_pad_entry->circle_pad_x = next_circle_x; - current_pad_entry->circle_pad_y = next_circle_y; + pad_entry->circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS : + state.circle_right ? MAX_CIRCLEPAD_POS : 0x0; + pad_entry->circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS : + state.circle_up ? MAX_CIRCLEPAD_POS : 0x0; // If we just updated index 0, provide a new timestamp - if (pad_data->index == 0) { - pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; - pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); + if (mem->pad.index == 0) { + mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks; + mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks(); + } + + mem->touch.index = next_touch_index; + ++next_touch_index %= mem->touch.entries.size(); + + // Get the current touch entry + TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; + bool pressed = false; + + std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState(); + touch_entry->valid = pressed ? 1 : 0; + + // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which + // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being + // converted to pixel coordinates." (http://3dbrew.org/wiki/HID_Shared_Memory#Offset_0xA8). + + // If we just updated index 0, provide a new timestamp + if (mem->touch.index == 0) { + mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; + mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); } // Signal both handles when there's an update to Pad or touch - g_event_pad_or_touch_1->Signal(); - g_event_pad_or_touch_2->Signal(); + event_pad_or_touch_1->Signal(); + event_pad_or_touch_2->Signal(); } void GetIPCHandles(Service::Interface* self) { u32* cmd_buff = Kernel::GetCommandBuffer(); cmd_buff[1] = 0; // No error + cmd_buff[2] = 0x14000000; // IPC Command Structure translate-header // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) - cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); - cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); - cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); - cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); - cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); - cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); + cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom(); + cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).MoveFrom(); + cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_2).MoveFrom(); + cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::event_accelerometer).MoveFrom(); + cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::event_gyroscope).MoveFrom(); + cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).MoveFrom(); +} + +void EnableAccelerometer(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + event_accelerometer->Signal(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_HID, "(STUBBED) called"); +} + +void EnableGyroscopeLow(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + event_gyroscope->Signal(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_HID, "(STUBBED) called"); +} + +void GetSoundVolume(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + const u8 volume = 0x3F; // TODO(purpasmart): Find out if this is the max value for the volume + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = volume; + + LOG_WARNING(Service_HID, "(STUBBED) called"); } void HIDInit() { @@ -156,19 +161,22 @@ void HIDInit() { AddService(new HID_U_Interface); AddService(new HID_SPVR_Interface); - g_shared_mem = SharedMemory::Create("HID:SharedMem"); + shared_mem = SharedMemory::Create("HID:SharedMem"); + + next_pad_index = 0; + next_touch_index = 0; // Create event handles - g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); - g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); - g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); - g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); - g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); + event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); + event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); + event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); + event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); + event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); } void HIDShutdown() { - } -} -} +} // namespace HID + +} // namespace Service diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 9c6e86f77..97462c7f8 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -18,16 +18,6 @@ namespace Kernel { namespace Service { namespace HID { -// Handle to shared memory region designated to HID_User service -extern Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem; - -// Event handles -extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; -extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; -extern Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; -extern Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; -extern Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; - /** * Structure of a Pad controller state. */ @@ -65,7 +55,7 @@ struct PadState { }; /** - * Structure of a single entry in the PadData's Pad state history array. + * Structure of a single entry of Pad state history within HID shared memory */ struct PadDataEntry { PadState current_state; @@ -77,24 +67,65 @@ struct PadDataEntry { }; /** - * Structure of all data related to the 3DS Pad. + * Structure of a single entry of touch state history within HID shared memory */ -struct PadData { - s64 index_reset_ticks; - s64 index_reset_ticks_previous; - u32 index; // the index of the last updated Pad state history element +struct TouchDataEntry { + u16 x; ///< Y-coordinate of a touchpad press on the lower screen + u16 y; ///< X-coordinate of a touchpad press on the lower screen + BitField<0, 7, u32> valid; ///< Set to 1 when this entry contains actual X/Y data, otherwise 0 +}; + +/** + * Structure of data stored in HID shared memory + */ +struct SharedMem { + /// Pad data, this is used for buttons and the circle pad + struct { + s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 + s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` + u32 index; ///< Index of the last updated pad state entry + + INSERT_PADDING_WORDS(0x2); + + PadState current_state; ///< Current state of the pad buttons + + // TODO(bunnei): Implement `raw_circle_pad_data` field + u32 raw_circle_pad_data; ///< Raw (analog) circle pad data, before being converted - u32 pad1; - u32 pad2; + INSERT_PADDING_WORDS(0x1); - PadState current_state; // same as entries[index].current_state - u32 raw_circle_pad_data; + std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries + } pad; - u32 pad3; + /// Touchpad data, this is used for touchpad input + struct { + s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 + s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` + u32 index; ///< Index of the last updated touch entry - std::array<PadDataEntry, 8> entries; // Pad state history + INSERT_PADDING_WORDS(0x1); + + // TODO(bunnei): Implement `raw_entry` field + TouchDataEntry raw_entry; ///< Raw (analog) touch data, before being converted + + std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates + } touch; }; +// TODO: MSVC does not support using offsetof() on non-static data members even though this +// is technically allowed since C++11. This macro should be enabled once MSVC adds +// support for that. +#ifndef _MSC_VER +#define ASSERT_REG_POSITION(field_name, position) \ + static_assert(offsetof(SharedMem, field_name) == position * 4, \ + "Field "#field_name" has invalid position") + +ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0); +ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A); + +#undef ASSERT_REG_POSITION +#endif // !defined(_MSC_VER) + // Pre-defined PadStates for single button presses const PadState PAD_NONE = {{0}}; const PadState PAD_A = {{1u << 0}}; @@ -130,7 +161,7 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; * None * Outputs: * 1 : Result of function, 0 on success, otherwise error code - * 2 : Unused + * 2 : IPC Command Structure translate-header * 3 : Handle to HID_User shared memory * 4 : Event signaled by HID_User * 5 : Event signaled by HID_User @@ -140,12 +171,41 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; */ void GetIPCHandles(Interface* self); -// Methods for updating the HID module's state -void PadButtonPress(const PadState& pad_state); -void PadButtonRelease(const PadState& pad_state); -void PadUpdateComplete(); +/** + * HID::EnableAccelerometer service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void EnableAccelerometer(Interface* self); + +/** + * HID::EnableGyroscopeLow service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + */ +void EnableGyroscopeLow(Interface* self); + +/** + * HID::GetSoundVolume service function + * Inputs: + * None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : u8 output value + */ +void GetSoundVolume(Interface* self); +/// Checks for user input updates +void HIDUpdate(); + +/// Initialize HID service void HIDInit(); + +/// Shutdown HID service void HIDShutdown(); } diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp index 790dcabbf..f296b076f 100644 --- a/src/core/hle/service/hid/hid_spvr.cpp +++ b/src/core/hle/service/hid/hid_spvr.cpp @@ -13,13 +13,13 @@ const Interface::FunctionInfo FunctionTable[] = { {0x000A0000, GetIPCHandles, "GetIPCHandles"}, {0x000B0000, nullptr, "StartAnalogStickCalibration"}, {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, - {0x00110000, nullptr, "EnableAccelerometer"}, + {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, {0x00120000, nullptr, "DisableAccelerometer"}, - {0x00130000, nullptr, "EnableGyroscopeLow"}, + {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, {0x00140000, nullptr, "DisableGyroscopeLow"}, {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, - {0x00170000, nullptr, "GetSoundVolume"}, + {0x00170000, GetSoundVolume, "GetSoundVolume"}, }; HID_SPVR_Interface::HID_SPVR_Interface() { diff --git a/src/core/hle/service/hid/hid_user.cpp b/src/core/hle/service/hid/hid_user.cpp index 1d0accefe..3682c9416 100644 --- a/src/core/hle/service/hid/hid_user.cpp +++ b/src/core/hle/service/hid/hid_user.cpp @@ -3,8 +3,6 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/kernel/event.h" -#include "core/hle/kernel/shared_memory.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid_user.h" @@ -12,14 +10,14 @@ namespace Service { namespace HID { const Interface::FunctionInfo FunctionTable[] = { - {0x000A0000, GetIPCHandles, "GetIPCHandles"}, - {0x00110000, nullptr, "EnableAccelerometer"}, - {0x00120000, nullptr, "DisableAccelerometer"}, - {0x00130000, nullptr, "EnableGyroscopeLow"}, - {0x00140000, nullptr, "DisableGyroscopeLow"}, - {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, - {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, - {0x00170000, nullptr, "GetSoundVolume"}, + {0x000A0000, GetIPCHandles, "GetIPCHandles"}, + {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, + {0x00120000, nullptr, "DisableAccelerometer"}, + {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, + {0x00140000, nullptr, "DisableGyroscopeLow"}, + {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, + {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, + {0x00170000, GetSoundVolume, "GetSoundVolume"}, }; HID_U_Interface::HID_U_Interface() { diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 17385f9b2..bbb4eb9cd 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -7,8 +7,9 @@ #include "common/string_util.h" #include "common/symbols.h" -#include "core/arm/arm_interface.h" +#include "core/core_timing.h" #include "core/mem_map.h" +#include "core/arm/arm_interface.h" #include "core/hle/kernel/address_arbiter.h" #include "core/hle/kernel/event.h" @@ -551,7 +552,7 @@ static void SleepThread(s64 nanoseconds) { /// This returns the total CPU ticks elapsed since the CPU was powered-on static s64 GetSystemTick() { - return (s64)Core::g_app_core->GetTicks(); + return (s64)CoreTiming::GetTicks(); } /// Creates a memory block at the specified address with the specified permissions and size diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index 30318fc06..e6983a225 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -14,6 +14,7 @@ #include "core/hle/hle.h" #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/dsp_dsp.h" +#include "core/hle/service/hid/hid.h" #include "core/hw/hw.h" #include "core/hw/gpu.h" @@ -117,8 +118,14 @@ inline void Write(u32 addr, const T data) { u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); - unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1; - unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1; + if (config.scaling > config.ScaleXY) { + LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode %u", config.scaling.Value()); + UNIMPLEMENTED(); + break; + } + + unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; + unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; u32 output_width = config.output_width / horizontal_scale; u32 output_height = config.output_height / vertical_scale; @@ -139,14 +146,23 @@ inline void Write(u32 addr, const T data) { break; } - // TODO(Subv): Blend the pixels when horizontal / vertical scaling is enabled, + // TODO(Subv): Implement the box filter when scaling is enabled // right now we're just skipping the extra pixels. for (u32 y = 0; y < output_height; ++y) { for (u32 x = 0; x < output_width; ++x) { Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; - u32 scaled_x = x * horizontal_scale; - u32 scaled_y = y * vertical_scale; + // Calculate the [x,y] position of the input image + // based on the current output position and the scale + u32 input_x = x * horizontal_scale; + u32 input_y = y * vertical_scale; + + if (config.flip_vertically) { + // Flip the y value of the output data, + // we do this after calculating the [x,y] position of the input image + // to account for the scaling options. + y = output_height - y - 1; + } u32 dst_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.output_format); u32 src_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.input_format); @@ -158,14 +174,14 @@ inline void Write(u32 addr, const T data) { u32 coarse_y = y & ~7; u32 stride = output_width * dst_bytes_per_pixel; - src_offset = (scaled_x + scaled_y * config.input_width) * src_bytes_per_pixel; + src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; } else { // Interpret the input as tiled and the output as linear - u32 coarse_y = scaled_y & ~7; + u32 coarse_y = input_y & ~7; u32 stride = config.input_width * src_bytes_per_pixel; - src_offset = VideoCore::GetMortonOffset(scaled_x, scaled_y, src_bytes_per_pixel) + coarse_y * stride; + src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; dst_offset = (x + y * output_width) * dst_bytes_per_pixel; } @@ -295,6 +311,9 @@ static void VBlankCallback(u64 userdata, int cycles_late) { // this. Certain games expect this to be periodically signaled. DSP_DSP::SignalInterrupt(); + // Check for user input updates + Service::HID::HIDUpdate(); + // Reschedule recurrent event CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event); } diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h index 5b7f0a4e9..c8f884494 100644 --- a/src/core/hw/gpu.h +++ b/src/core/hw/gpu.h @@ -188,17 +188,22 @@ struct Regs { BitField<16, 16, u32> input_height; }; + enum ScalingMode : u32 { + NoScale = 0, // Doesn't scale the image + ScaleX = 1, // Downscales the image in half in the X axis and applies a box filter + ScaleXY = 2, // Downscales the image in half in both the X and Y axes and applies a box filter + }; + union { u32 flags; - BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true + BitField< 0, 1, u32> flip_vertically; // flips input data vertically BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing BitField< 8, 3, PixelFormat> input_format; BitField<12, 3, PixelFormat> output_format; - BitField<24, 1, u32> scale_horizontally; - BitField<25, 1, u32> scale_vertically; + BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer }; INSERT_PADDING_WORDS(0x1); diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h index 9ae2de99f..f6f670060 100644 --- a/src/core/loader/ncch.h +++ b/src/core/loader/ncch.h @@ -20,8 +20,8 @@ struct NCCH_Header { u16 version; u8 reserved_0[4]; u8 program_id[8]; - u8 temp_flag; - u8 reserved_1[0x2f]; + u8 reserved_1[0x10]; + u8 logo_region_hash[0x20]; u8 product_code[0x10]; u8 extended_header_hash[0x20]; u32 extended_header_size; @@ -29,15 +29,16 @@ struct NCCH_Header { u8 flags[8]; u32 plain_region_offset; u32 plain_region_size; - u8 reserved_3[8]; + u32 logo_region_offset; + u32 logo_region_size; u32 exefs_offset; u32 exefs_size; u32 exefs_hash_region_size; - u8 reserved_4[4]; + u8 reserved_3[4]; u32 romfs_offset; u32 romfs_size; u32 romfs_hash_region_size; - u8 reserved_5[4]; + u8 reserved_4[4]; u8 exefs_super_block_hash[0x20]; u8 romfs_super_block_hash[0x20]; }; @@ -88,8 +89,7 @@ struct ExHeader_DependencyList{ }; struct ExHeader_SystemInfo{ - u32 save_data_size; - u8 reserved[4]; + u64 save_data_size; u8 jump_id[8]; u8 reserved_2[0x30]; }; @@ -104,11 +104,14 @@ struct ExHeader_StorageInfo{ struct ExHeader_ARM11_SystemLocalCaps{ u8 program_id[8]; - u8 flags[8]; - u8 resource_limit_descriptor[0x10][2]; + u32 core_version; + u8 flags[3]; + u8 priority; + u8 resource_limit_descriptor[0x16][2]; ExHeader_StorageInfo storage_info; - u8 service_access_control[0x20][8]; - u8 reserved[0x1f]; + u8 service_access_control[0x32][8]; + u8 ex_service_access_control[0x2][8]; + u8 reserved[0xf]; u8 resource_limit_category; }; |