diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra/emu_window/emu_window_glfw.cpp | 30 | ||||
| -rw-r--r-- | src/citra/emu_window/emu_window_glfw.h | 4 | ||||
| -rw-r--r-- | src/citra_qt/bootmanager.cpp | 27 | ||||
| -rw-r--r-- | src/citra_qt/bootmanager.h | 4 | ||||
| -rw-r--r-- | src/common/common_paths.h | 11 | ||||
| -rw-r--r-- | src/common/emu_window.cpp | 55 | ||||
| -rw-r--r-- | src/common/emu_window.h | 65 | ||||
| -rw-r--r-- | src/common/platform.h | 6 | ||||
| -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 | ||||
| -rw-r--r-- | src/video_core/color.h | 2 | ||||
| -rw-r--r-- | src/video_core/debug_utils/debug_utils.cpp | 6 | ||||
| -rw-r--r-- | src/video_core/vertex_shader.cpp | 44 |
22 files changed, 451 insertions, 243 deletions
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp index 81231e1e5..997e3bc7d 100644 --- a/src/citra/emu_window/emu_window_glfw.cpp +++ b/src/citra/emu_window/emu_window_glfw.cpp | |||
| @@ -16,18 +16,34 @@ EmuWindow_GLFW* EmuWindow_GLFW::GetEmuWindow(GLFWwindow* win) { | |||
| 16 | return static_cast<EmuWindow_GLFW*>(glfwGetWindowUserPointer(win)); | 16 | return static_cast<EmuWindow_GLFW*>(glfwGetWindowUserPointer(win)); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | void EmuWindow_GLFW::OnMouseButtonEvent(GLFWwindow* win, int button, int action, int mods) { | ||
| 20 | if (button == GLFW_MOUSE_BUTTON_LEFT) { | ||
| 21 | auto emu_window = GetEmuWindow(win); | ||
| 22 | auto layout = emu_window->GetFramebufferLayout(); | ||
| 23 | double x, y; | ||
| 24 | glfwGetCursorPos(win, &x, &y); | ||
| 25 | |||
| 26 | if (action == GLFW_PRESS) | ||
| 27 | emu_window->TouchPressed(static_cast<unsigned>(x), static_cast<unsigned>(y)); | ||
| 28 | else if (action == GLFW_RELEASE) | ||
| 29 | emu_window->TouchReleased(); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | void EmuWindow_GLFW::OnCursorPosEvent(GLFWwindow* win, double x, double y) { | ||
| 34 | GetEmuWindow(win)->TouchMoved(static_cast<unsigned>(x), static_cast<unsigned>(y)); | ||
| 35 | } | ||
| 36 | |||
| 19 | /// Called by GLFW when a key event occurs | 37 | /// Called by GLFW when a key event occurs |
| 20 | void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) { | 38 | void EmuWindow_GLFW::OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods) { |
| 21 | 39 | auto emu_window = GetEmuWindow(win); | |
| 22 | int keyboard_id = GetEmuWindow(win)->keyboard_id; | 40 | int keyboard_id = emu_window->keyboard_id; |
| 23 | 41 | ||
| 24 | if (action == GLFW_PRESS) { | 42 | if (action == GLFW_PRESS) { |
| 25 | EmuWindow::KeyPressed({key, keyboard_id}); | 43 | emu_window->KeyPressed({key, keyboard_id}); |
| 26 | } else if (action == GLFW_RELEASE) { | 44 | } else if (action == GLFW_RELEASE) { |
| 27 | EmuWindow::KeyReleased({key, keyboard_id}); | 45 | emu_window->KeyReleased({key, keyboard_id}); |
| 28 | } | 46 | } |
| 29 | |||
| 30 | Service::HID::PadUpdateComplete(); | ||
| 31 | } | 47 | } |
| 32 | 48 | ||
| 33 | /// Whether the window is still open, and a close request hasn't yet been sent | 49 | /// Whether the window is still open, and a close request hasn't yet been sent |
| @@ -88,6 +104,8 @@ EmuWindow_GLFW::EmuWindow_GLFW() { | |||
| 88 | 104 | ||
| 89 | // Setup callbacks | 105 | // Setup callbacks |
| 90 | glfwSetKeyCallback(m_render_window, OnKeyEvent); | 106 | glfwSetKeyCallback(m_render_window, OnKeyEvent); |
| 107 | glfwSetMouseButtonCallback(m_render_window, OnMouseButtonEvent); | ||
| 108 | glfwSetCursorPosCallback(m_render_window, OnCursorPosEvent); | ||
| 91 | glfwSetFramebufferSizeCallback(m_render_window, OnFramebufferResizeEvent); | 109 | glfwSetFramebufferSizeCallback(m_render_window, OnFramebufferResizeEvent); |
| 92 | glfwSetWindowSizeCallback(m_render_window, OnClientAreaResizeEvent); | 110 | glfwSetWindowSizeCallback(m_render_window, OnClientAreaResizeEvent); |
| 93 | 111 | ||
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h index 5252fccc8..16c109b79 100644 --- a/src/citra/emu_window/emu_window_glfw.h +++ b/src/citra/emu_window/emu_window_glfw.h | |||
| @@ -27,6 +27,10 @@ public: | |||
| 27 | 27 | ||
| 28 | static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods); | 28 | static void OnKeyEvent(GLFWwindow* win, int key, int scancode, int action, int mods); |
| 29 | 29 | ||
| 30 | static void OnMouseButtonEvent(GLFWwindow* window, int button, int action, int mods); | ||
| 31 | |||
| 32 | static void OnCursorPosEvent(GLFWwindow* window, double x, double y); | ||
| 33 | |||
| 30 | /// Whether the window is still open, and a close request hasn't yet been sent | 34 | /// Whether the window is still open, and a close request hasn't yet been sent |
| 31 | const bool IsOpen(); | 35 | const bool IsOpen(); |
| 32 | 36 | ||
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp index a040e75c1..b81bd6167 100644 --- a/src/citra_qt/bootmanager.cpp +++ b/src/citra_qt/bootmanager.cpp | |||
| @@ -268,14 +268,33 @@ QByteArray GRenderWindow::saveGeometry() | |||
| 268 | 268 | ||
| 269 | void GRenderWindow::keyPressEvent(QKeyEvent* event) | 269 | void GRenderWindow::keyPressEvent(QKeyEvent* event) |
| 270 | { | 270 | { |
| 271 | EmuWindow::KeyPressed({event->key(), keyboard_id}); | 271 | this->KeyPressed({event->key(), keyboard_id}); |
| 272 | Service::HID::PadUpdateComplete(); | ||
| 273 | } | 272 | } |
| 274 | 273 | ||
| 275 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) | 274 | void GRenderWindow::keyReleaseEvent(QKeyEvent* event) |
| 276 | { | 275 | { |
| 277 | EmuWindow::KeyReleased({event->key(), keyboard_id}); | 276 | this->KeyReleased({event->key(), keyboard_id}); |
| 278 | Service::HID::PadUpdateComplete(); | 277 | } |
| 278 | |||
| 279 | void GRenderWindow::mousePressEvent(QMouseEvent *event) | ||
| 280 | { | ||
| 281 | if (event->button() == Qt::LeftButton) | ||
| 282 | { | ||
| 283 | auto pos = event->pos(); | ||
| 284 | this->TouchPressed(static_cast<unsigned>(pos.x()), static_cast<unsigned>(pos.y())); | ||
| 285 | } | ||
| 286 | } | ||
| 287 | |||
| 288 | void GRenderWindow::mouseMoveEvent(QMouseEvent *event) | ||
| 289 | { | ||
| 290 | auto pos = event->pos(); | ||
| 291 | this->TouchMoved(static_cast<unsigned>(pos.x()), static_cast<unsigned>(pos.y())); | ||
| 292 | } | ||
| 293 | |||
| 294 | void GRenderWindow::mouseReleaseEvent(QMouseEvent *event) | ||
| 295 | { | ||
| 296 | if (event->button() == Qt::LeftButton) | ||
| 297 | this->TouchReleased(); | ||
| 279 | } | 298 | } |
| 280 | 299 | ||
| 281 | void GRenderWindow::ReloadSetKeymaps() | 300 | void GRenderWindow::ReloadSetKeymaps() |
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h index a55db682a..288da45a1 100644 --- a/src/citra_qt/bootmanager.h +++ b/src/citra_qt/bootmanager.h | |||
| @@ -121,6 +121,10 @@ public: | |||
| 121 | void keyPressEvent(QKeyEvent* event) override; | 121 | void keyPressEvent(QKeyEvent* event) override; |
| 122 | void keyReleaseEvent(QKeyEvent* event) override; | 122 | void keyReleaseEvent(QKeyEvent* event) override; |
| 123 | 123 | ||
| 124 | void mousePressEvent(QMouseEvent *event) override; | ||
| 125 | void mouseMoveEvent(QMouseEvent *event) override; | ||
| 126 | void mouseReleaseEvent(QMouseEvent *event) override; | ||
| 127 | |||
| 124 | void ReloadSetKeymaps() override; | 128 | void ReloadSetKeymaps() override; |
| 125 | 129 | ||
| 126 | void OnClientAreaResized(unsigned width, unsigned height); | 130 | void OnClientAreaResized(unsigned width, unsigned height); |
diff --git a/src/common/common_paths.h b/src/common/common_paths.h index eb43d589f..440b06060 100644 --- a/src/common/common_paths.h +++ b/src/common/common_paths.h | |||
| @@ -17,13 +17,12 @@ | |||
| 17 | 17 | ||
| 18 | // The user data dir | 18 | // The user data dir |
| 19 | #define ROOT_DIR "." | 19 | #define ROOT_DIR "." |
| 20 | #ifdef _WIN32 | 20 | #define USERDATA_DIR "user" |
| 21 | #define USERDATA_DIR "user" | 21 | #ifdef USER_DIR |
| 22 | #define EMU_DATA_DIR "Citra Emulator" | 22 | #define EMU_DATA_DIR USER_DIR |
| 23 | #else | 23 | #else |
| 24 | #define USERDATA_DIR "user" | 24 | #ifdef _WIN32 |
| 25 | #ifdef USER_DIR | 25 | #define EMU_DATA_DIR "Citra Emulator" |
| 26 | #define EMU_DATA_DIR USER_DIR | ||
| 27 | #else | 26 | #else |
| 28 | #define EMU_DATA_DIR "citra-emu" | 27 | #define EMU_DATA_DIR "citra-emu" |
| 29 | #endif | 28 | #endif |
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp index 6459d2f32..6516fc633 100644 --- a/src/common/emu_window.cpp +++ b/src/common/emu_window.cpp | |||
| @@ -6,18 +6,61 @@ | |||
| 6 | #include "video_core/video_core.h" | 6 | #include "video_core/video_core.h" |
| 7 | 7 | ||
| 8 | void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { | 8 | void EmuWindow::KeyPressed(KeyMap::HostDeviceKey key) { |
| 9 | Service::HID::PadState mapped_key = KeyMap::GetPadKey(key); | 9 | pad_state.hex |= KeyMap::GetPadKey(key).hex; |
| 10 | |||
| 11 | Service::HID::PadButtonPress(mapped_key); | ||
| 12 | } | 10 | } |
| 13 | 11 | ||
| 14 | void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { | 12 | void EmuWindow::KeyReleased(KeyMap::HostDeviceKey key) { |
| 15 | Service::HID::PadState mapped_key = KeyMap::GetPadKey(key); | 13 | pad_state.hex &= ~KeyMap::GetPadKey(key).hex; |
| 14 | } | ||
| 15 | |||
| 16 | /** | ||
| 17 | * Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout | ||
| 18 | * @param layout FramebufferLayout object describing the framebuffer size and screen positions | ||
| 19 | * @param framebuffer_x Framebuffer x-coordinate to check | ||
| 20 | * @param framebuffer_y Framebuffer y-coordinate to check | ||
| 21 | * @return True if the coordinates are within the touchpad, otherwise false | ||
| 22 | */ | ||
| 23 | static bool IsWithinTouchscreen(const EmuWindow::FramebufferLayout& layout, unsigned framebuffer_x, | ||
| 24 | unsigned framebuffer_y) { | ||
| 25 | return (framebuffer_y >= layout.bottom_screen.top && | ||
| 26 | framebuffer_y < layout.bottom_screen.bottom && | ||
| 27 | framebuffer_x >= layout.bottom_screen.left && | ||
| 28 | framebuffer_x < layout.bottom_screen.right); | ||
| 29 | } | ||
| 30 | |||
| 31 | void EmuWindow::TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y) { | ||
| 32 | if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | ||
| 33 | return; | ||
| 34 | |||
| 35 | touch_x = VideoCore::kScreenBottomWidth * (framebuffer_x - framebuffer_layout.bottom_screen.left) / | ||
| 36 | (framebuffer_layout.bottom_screen.right - framebuffer_layout.bottom_screen.left); | ||
| 37 | touch_y = VideoCore::kScreenBottomHeight * (framebuffer_y - framebuffer_layout.bottom_screen.top) / | ||
| 38 | (framebuffer_layout.bottom_screen.bottom - framebuffer_layout.bottom_screen.top); | ||
| 16 | 39 | ||
| 17 | Service::HID::PadButtonRelease(mapped_key); | 40 | touch_pressed = true; |
| 41 | pad_state.touch = 1; | ||
| 18 | } | 42 | } |
| 19 | 43 | ||
| 20 | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, unsigned height) { | 44 | void EmuWindow::TouchReleased() { |
| 45 | touch_pressed = false; | ||
| 46 | touch_x = 0; | ||
| 47 | touch_y = 0; | ||
| 48 | pad_state.touch = 0; | ||
| 49 | } | ||
| 50 | |||
| 51 | void EmuWindow::TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y) { | ||
| 52 | if (!touch_pressed) | ||
| 53 | return; | ||
| 54 | |||
| 55 | if (IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) | ||
| 56 | TouchPressed(framebuffer_x, framebuffer_y); | ||
| 57 | else | ||
| 58 | TouchReleased(); | ||
| 59 | } | ||
| 60 | |||
| 61 | EmuWindow::FramebufferLayout EmuWindow::FramebufferLayout::DefaultScreenLayout(unsigned width, | ||
| 62 | unsigned height) { | ||
| 63 | |||
| 21 | ASSERT(width > 0); | 64 | ASSERT(width > 0); |
| 22 | ASSERT(height > 0); | 65 | ASSERT(height > 0); |
| 23 | 66 | ||
diff --git a/src/common/emu_window.h b/src/common/emu_window.h index f6099fdb6..c8e2de04a 100644 --- a/src/common/emu_window.h +++ b/src/common/emu_window.h | |||
| @@ -71,10 +71,48 @@ public: | |||
| 71 | virtual void ReloadSetKeymaps() = 0; | 71 | virtual void ReloadSetKeymaps() = 0; |
| 72 | 72 | ||
| 73 | /// Signals a key press action to the HID module | 73 | /// Signals a key press action to the HID module |
| 74 | static void KeyPressed(KeyMap::HostDeviceKey key); | 74 | void KeyPressed(KeyMap::HostDeviceKey key); |
| 75 | 75 | ||
| 76 | /// Signals a key release action to the HID module | 76 | /// Signals a key release action to the HID module |
| 77 | static void KeyReleased(KeyMap::HostDeviceKey key); | 77 | void KeyReleased(KeyMap::HostDeviceKey key); |
| 78 | |||
| 79 | /** | ||
| 80 | * Signal that a touch pressed event has occurred (e.g. mouse click pressed) | ||
| 81 | * @param framebuffer_x Framebuffer x-coordinate that was pressed | ||
| 82 | * @param framebuffer_y Framebuffer y-coordinate that was pressed | ||
| 83 | */ | ||
| 84 | void TouchPressed(unsigned framebuffer_x, unsigned framebuffer_y); | ||
| 85 | |||
| 86 | /// Signal that a touch released event has occurred (e.g. mouse click released) | ||
| 87 | void TouchReleased(); | ||
| 88 | |||
| 89 | /** | ||
| 90 | * Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window) | ||
| 91 | * @param framebuffer_x Framebuffer x-coordinate | ||
| 92 | * @param framebuffer_y Framebuffer y-coordinate | ||
| 93 | */ | ||
| 94 | void TouchMoved(unsigned framebuffer_x, unsigned framebuffer_y); | ||
| 95 | |||
| 96 | /** | ||
| 97 | * Gets the current pad state (which buttons are pressed and the circle pad direction). | ||
| 98 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 99 | * @todo Fix this function to be thread-safe. | ||
| 100 | * @return PadState object indicating the current pad state | ||
| 101 | */ | ||
| 102 | const Service::HID::PadState GetPadState() const { | ||
| 103 | return pad_state; | ||
| 104 | } | ||
| 105 | |||
| 106 | /** | ||
| 107 | * Gets the current touch screen state (touch X/Y coordinates and whether or not it is pressed). | ||
| 108 | * @note This should be called by the core emu thread to get a state set by the window thread. | ||
| 109 | * @todo Fix this function to be thread-safe. | ||
| 110 | * @return std::tuple of (x, y, pressed) where `x` and `y` are the touch coordinates and | ||
| 111 | * `pressed` is true if the touch screen is currently being pressed | ||
| 112 | */ | ||
| 113 | const std::tuple<u16, u16, bool> GetTouchState() const { | ||
| 114 | return std::make_tuple(touch_x, touch_y, touch_pressed); | ||
| 115 | } | ||
| 78 | 116 | ||
| 79 | /** | 117 | /** |
| 80 | * Returns currently active configuration. | 118 | * Returns currently active configuration. |
| @@ -100,21 +138,15 @@ public: | |||
| 100 | return framebuffer_layout; | 138 | return framebuffer_layout; |
| 101 | } | 139 | } |
| 102 | 140 | ||
| 103 | /** | ||
| 104 | * Gets window client area width in logical coordinates. | ||
| 105 | * @note For high-DPI systems, this is smaller than the framebuffer size. | ||
| 106 | * @note This method is thread-safe | ||
| 107 | */ | ||
| 108 | std::pair<unsigned,unsigned> GetClientAreaSize() const { | ||
| 109 | return std::make_pair(client_area_width, client_area_height); | ||
| 110 | } | ||
| 111 | |||
| 112 | protected: | 141 | protected: |
| 113 | EmuWindow() | 142 | EmuWindow() { |
| 114 | { | ||
| 115 | // TODO: Find a better place to set this. | 143 | // TODO: Find a better place to set this. |
| 116 | config.min_client_area_size = std::make_pair(400u, 480u); | 144 | config.min_client_area_size = std::make_pair(400u, 480u); |
| 117 | active_config = config; | 145 | active_config = config; |
| 146 | pad_state.hex = 0; | ||
| 147 | touch_x = 0; | ||
| 148 | touch_y = 0; | ||
| 149 | touch_pressed = false; | ||
| 118 | } | 150 | } |
| 119 | virtual ~EmuWindow() {} | 151 | virtual ~EmuWindow() {} |
| 120 | 152 | ||
| @@ -168,4 +200,11 @@ private: | |||
| 168 | 200 | ||
| 169 | WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges) | 201 | WindowConfig config; ///< Internal configuration (changes pending for being applied in ProcessConfigurationChanges) |
| 170 | WindowConfig active_config; ///< Internal active configuration | 202 | WindowConfig active_config; ///< Internal active configuration |
| 203 | |||
| 204 | bool touch_pressed; ///< True if touchpad area is currently pressed, otherwise false | ||
| 205 | |||
| 206 | u16 touch_x; ///< Touchpad X-position in native 3DS pixel coordinates (0-320) | ||
| 207 | u16 touch_y; ///< Touchpad Y-position in native 3DS pixel coordinates (0-240) | ||
| 208 | |||
| 209 | Service::HID::PadState pad_state; | ||
| 171 | }; | 210 | }; |
diff --git a/src/common/platform.h b/src/common/platform.h index ba1109c9f..e27d6e31f 100644 --- a/src/common/platform.h +++ b/src/common/platform.h | |||
| @@ -83,7 +83,7 @@ inline struct tm* localtime_r(const time_t *clock, struct tm *result) { | |||
| 83 | } | 83 | } |
| 84 | #endif | 84 | #endif |
| 85 | 85 | ||
| 86 | #else | 86 | #else // EMU_PLATFORM != PLATFORM_WINDOWS |
| 87 | 87 | ||
| 88 | #define EMU_FASTCALL __attribute__((fastcall)) | 88 | #define EMU_FASTCALL __attribute__((fastcall)) |
| 89 | #define __stdcall | 89 | #define __stdcall |
| @@ -92,10 +92,6 @@ inline struct tm* localtime_r(const time_t *clock, struct tm *result) { | |||
| 92 | #define BOOL bool | 92 | #define BOOL bool |
| 93 | #define DWORD u32 | 93 | #define DWORD u32 |
| 94 | 94 | ||
| 95 | #endif | ||
| 96 | |||
| 97 | #if EMU_PLATFORM != PLATFORM_WINDOWS | ||
| 98 | |||
| 99 | // TODO: Hacks.. | 95 | // TODO: Hacks.. |
| 100 | #include <limits.h> | 96 | #include <limits.h> |
| 101 | 97 | ||
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: | |||
| 74 | virtual void SetCPSR(u32 cpsr) = 0; | 74 | virtual void SetCPSR(u32 cpsr) = 0; |
| 75 | 75 | ||
| 76 | /** | 76 | /** |
| 77 | * Returns the number of clock ticks since the last rese | ||
| 78 | * @return Returns number of clock ticks | ||
| 79 | */ | ||
| 80 | virtual u64 GetTicks() const = 0; | ||
| 81 | |||
| 82 | /** | ||
| 83 | * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time) | 77 | * Advance the CPU core by the specified number of ticks (e.g. to simulate CPU execution time) |
| 84 | * @param ticks Number of ticks to advance the CPU core | 78 | * @param ticks Number of ticks to advance the CPU core |
| 85 | */ | 79 | */ |
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) { | |||
| 68 | state->Cpsr = cpsr; | 68 | state->Cpsr = cpsr; |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | u64 ARM_DynCom::GetTicks() const { | ||
| 72 | // TODO(Subv): Remove ARM_DynCom::GetTicks() and use CoreTiming::GetTicks() directly once ARMemu is gone | ||
| 73 | return CoreTiming::GetTicks(); | ||
| 74 | } | ||
| 75 | |||
| 76 | void ARM_DynCom::AddTicks(u64 ticks) { | 71 | void ARM_DynCom::AddTicks(u64 ticks) { |
| 77 | down_count -= ticks; | 72 | down_count -= ticks; |
| 78 | if (down_count < 0) | 73 | 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: | |||
| 23 | u32 GetCPSR() const override; | 23 | u32 GetCPSR() const override; |
| 24 | void SetCPSR(u32 cpsr) override; | 24 | void SetCPSR(u32 cpsr) override; |
| 25 | 25 | ||
| 26 | u64 GetTicks() const override; | ||
| 27 | void AddTicks(u64 ticks) override; | 26 | void AddTicks(u64 ticks) override; |
| 28 | 27 | ||
| 29 | void ResetContext(Core::ThreadContext& context, u32 stack_top, u32 entry_point, u32 arg); | 28 | 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 @@ | |||
| 7 | #include "core/hle/service/hid/hid_spvr.h" | 7 | #include "core/hle/service/hid/hid_spvr.h" |
| 8 | #include "core/hle/service/hid/hid_user.h" | 8 | #include "core/hle/service/hid/hid_user.h" |
| 9 | 9 | ||
| 10 | #include "core/arm/arm_interface.h" | 10 | #include "core/core_timing.h" |
| 11 | #include "core/hle/kernel/event.h" | 11 | #include "core/hle/kernel/event.h" |
| 12 | #include "core/hle/kernel/shared_memory.h" | 12 | #include "core/hle/kernel/shared_memory.h" |
| 13 | #include "core/hle/hle.h" | 13 | #include "core/hle/hle.h" |
| 14 | 14 | ||
| 15 | #include "video_core/video_core.h" | ||
| 16 | |||
| 15 | namespace Service { | 17 | namespace Service { |
| 16 | namespace HID { | 18 | namespace HID { |
| 17 | 19 | ||
| 18 | Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem = nullptr; | 20 | static const int MAX_CIRCLEPAD_POS = 0x9C; ///< Max value for a circle pad position |
| 19 | 21 | ||
| 20 | Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; | 22 | // Handle to shared memory region designated to HID_User service |
| 21 | Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; | 23 | static Kernel::SharedPtr<Kernel::SharedMemory> shared_mem = nullptr; |
| 22 | Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; | 24 | |
| 23 | Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; | 25 | // Event handles |
| 24 | Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; | 26 | static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_1 = nullptr; |
| 25 | 27 | static Kernel::SharedPtr<Kernel::Event> event_pad_or_touch_2 = nullptr; | |
| 26 | // Next Pad state update information | 28 | static Kernel::SharedPtr<Kernel::Event> event_accelerometer = nullptr; |
| 27 | static PadState next_state = {{0}}; | 29 | static Kernel::SharedPtr<Kernel::Event> event_gyroscope = nullptr; |
| 28 | static u32 next_index = 0; | 30 | static Kernel::SharedPtr<Kernel::Event> event_debug_pad = nullptr; |
| 29 | static s16 next_circle_x = 0; | 31 | |
| 30 | static s16 next_circle_y = 0; | 32 | static u32 next_pad_index = 0; |
| 31 | 33 | static u32 next_touch_index = 0; | |
| 32 | /** | ||
| 33 | * Gets a pointer to the PadData structure inside HID shared memory | ||
| 34 | */ | ||
| 35 | static inline PadData* GetPadData() { | ||
| 36 | if (g_shared_mem == nullptr) | ||
| 37 | return nullptr; | ||
| 38 | return reinterpret_cast<PadData*>(g_shared_mem->GetPointer().ValueOr(nullptr)); | ||
| 39 | } | ||
| 40 | 34 | ||
| 41 | // TODO(peachum): | 35 | // TODO(peachum): |
| 42 | // Add a method for setting analog input from joystick device for the circle Pad. | 36 | // Add a method for setting analog input from joystick device for the circle Pad. |
| @@ -51,103 +45,114 @@ static inline PadData* GetPadData() { | |||
| 51 | // * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 | 45 | // * Set PadData.current_state.circle_left = 1 if current PadEntry.circle_pad_x <= -41 |
| 52 | // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 | 46 | // * Set PadData.current_state.circle_right = 1 if current PadEntry.circle_pad_y <= -41 |
| 53 | 47 | ||
| 54 | /** | 48 | void HIDUpdate() { |
| 55 | * Circle Pad from keys. | 49 | SharedMem* mem = reinterpret_cast<SharedMem*>(shared_mem->GetPointer().ValueOr(nullptr)); |
| 56 | * | 50 | const PadState state = VideoCore::g_emu_window->GetPadState(); |
| 57 | * This is implemented as "pushed all the way to an edge (max) or centered (0)". | ||
| 58 | * | ||
| 59 | * Indicate the circle pad is pushed completely to the edge in 1 of 8 directions. | ||
| 60 | */ | ||
| 61 | static void UpdateNextCirclePadState() { | ||
| 62 | static const s16 max_value = 0x9C; | ||
| 63 | next_circle_x = next_state.circle_left ? -max_value : 0x0; | ||
| 64 | next_circle_x += next_state.circle_right ? max_value : 0x0; | ||
| 65 | next_circle_y = next_state.circle_down ? -max_value : 0x0; | ||
| 66 | next_circle_y += next_state.circle_up ? max_value : 0x0; | ||
| 67 | } | ||
| 68 | |||
| 69 | /** | ||
| 70 | * Sets a Pad state (button or button combo) as pressed | ||
| 71 | */ | ||
| 72 | void PadButtonPress(const PadState& pad_state) { | ||
| 73 | next_state.hex |= pad_state.hex; | ||
| 74 | UpdateNextCirclePadState(); | ||
| 75 | } | ||
| 76 | |||
| 77 | /** | ||
| 78 | * Sets a Pad state (button or button combo) as released | ||
| 79 | */ | ||
| 80 | void PadButtonRelease(const PadState& pad_state) { | ||
| 81 | next_state.hex &= ~pad_state.hex; | ||
| 82 | UpdateNextCirclePadState(); | ||
| 83 | } | ||
| 84 | |||
| 85 | /** | ||
| 86 | * Called after all Pad changes to be included in this update have been made, | ||
| 87 | * including both Pad key changes and analog circle Pad changes. | ||
| 88 | */ | ||
| 89 | void PadUpdateComplete() { | ||
| 90 | PadData* pad_data = GetPadData(); | ||
| 91 | 51 | ||
| 92 | if (pad_data == nullptr) { | 52 | if (mem == nullptr) { |
| 53 | LOG_DEBUG(Service_HID, "Cannot update HID prior to mapping shared memory!"); | ||
| 93 | return; | 54 | return; |
| 94 | } | 55 | } |
| 95 | 56 | ||
| 96 | // Update PadData struct | 57 | mem->pad.current_state.hex = state.hex; |
| 97 | pad_data->current_state.hex = next_state.hex; | 58 | mem->pad.index = next_pad_index; |
| 98 | pad_data->index = next_index; | 59 | ++next_touch_index %= mem->pad.entries.size(); |
| 99 | next_index = (next_index + 1) % pad_data->entries.size(); | ||
| 100 | 60 | ||
| 101 | // Get the previous Pad state | 61 | // Get the previous Pad state |
| 102 | u32 last_entry_index = (pad_data->index - 1) % pad_data->entries.size(); | 62 | u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size(); |
| 103 | PadState old_state = pad_data->entries[last_entry_index].current_state; | 63 | PadState old_state = mem->pad.entries[last_entry_index].current_state; |
| 104 | 64 | ||
| 105 | // Compute bitmask with 1s for bits different from the old state | 65 | // Compute bitmask with 1s for bits different from the old state |
| 106 | PadState changed; | 66 | PadState changed = { { (state.hex ^ old_state.hex) } }; |
| 107 | changed.hex = (next_state.hex ^ old_state.hex); | ||
| 108 | |||
| 109 | // Compute what was added | ||
| 110 | PadState additions; | ||
| 111 | additions.hex = changed.hex & next_state.hex; | ||
| 112 | |||
| 113 | // Compute what was removed | ||
| 114 | PadState removals; | ||
| 115 | removals.hex = changed.hex & old_state.hex; | ||
| 116 | 67 | ||
| 117 | // Get the current Pad entry | 68 | // Get the current Pad entry |
| 118 | PadDataEntry* current_pad_entry = &pad_data->entries[pad_data->index]; | 69 | PadDataEntry* pad_entry = &mem->pad.entries[mem->pad.index]; |
| 119 | 70 | ||
| 120 | // Update entry properties | 71 | // Update entry properties |
| 121 | current_pad_entry->current_state.hex = next_state.hex; | 72 | pad_entry->current_state.hex = state.hex; |
| 122 | current_pad_entry->delta_additions.hex = additions.hex; | 73 | pad_entry->delta_additions.hex = changed.hex & state.hex; |
| 123 | current_pad_entry->delta_removals.hex = removals.hex; | 74 | pad_entry->delta_removals.hex = changed.hex & old_state.hex;; |
| 124 | 75 | ||
| 125 | // Set circle Pad | 76 | // Set circle Pad |
| 126 | current_pad_entry->circle_pad_x = next_circle_x; | 77 | pad_entry->circle_pad_x = state.circle_left ? -MAX_CIRCLEPAD_POS : |
| 127 | current_pad_entry->circle_pad_y = next_circle_y; | 78 | state.circle_right ? MAX_CIRCLEPAD_POS : 0x0; |
| 79 | pad_entry->circle_pad_y = state.circle_down ? -MAX_CIRCLEPAD_POS : | ||
| 80 | state.circle_up ? MAX_CIRCLEPAD_POS : 0x0; | ||
| 128 | 81 | ||
| 129 | // If we just updated index 0, provide a new timestamp | 82 | // If we just updated index 0, provide a new timestamp |
| 130 | if (pad_data->index == 0) { | 83 | if (mem->pad.index == 0) { |
| 131 | pad_data->index_reset_ticks_previous = pad_data->index_reset_ticks; | 84 | mem->pad.index_reset_ticks_previous = mem->pad.index_reset_ticks; |
| 132 | pad_data->index_reset_ticks = (s64)Core::g_app_core->GetTicks(); | 85 | mem->pad.index_reset_ticks = (s64)CoreTiming::GetTicks(); |
| 86 | } | ||
| 87 | |||
| 88 | mem->touch.index = next_touch_index; | ||
| 89 | ++next_touch_index %= mem->touch.entries.size(); | ||
| 90 | |||
| 91 | // Get the current touch entry | ||
| 92 | TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; | ||
| 93 | bool pressed = false; | ||
| 94 | |||
| 95 | std::tie(touch_entry->x, touch_entry->y, pressed) = VideoCore::g_emu_window->GetTouchState(); | ||
| 96 | touch_entry->valid = pressed ? 1 : 0; | ||
| 97 | |||
| 98 | // TODO(bunnei): We're not doing anything with offset 0xA8 + 0x18 of HID SharedMemory, which | ||
| 99 | // supposedly is "Touch-screen entry, which contains the raw coordinate data prior to being | ||
| 100 | // converted to pixel coordinates." (http://3dbrew.org/wiki/HID_Shared_Memory#Offset_0xA8). | ||
| 101 | |||
| 102 | // If we just updated index 0, provide a new timestamp | ||
| 103 | if (mem->touch.index == 0) { | ||
| 104 | mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; | ||
| 105 | mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); | ||
| 133 | } | 106 | } |
| 134 | 107 | ||
| 135 | // Signal both handles when there's an update to Pad or touch | 108 | // Signal both handles when there's an update to Pad or touch |
| 136 | g_event_pad_or_touch_1->Signal(); | 109 | event_pad_or_touch_1->Signal(); |
| 137 | g_event_pad_or_touch_2->Signal(); | 110 | event_pad_or_touch_2->Signal(); |
| 138 | } | 111 | } |
| 139 | 112 | ||
| 140 | void GetIPCHandles(Service::Interface* self) { | 113 | void GetIPCHandles(Service::Interface* self) { |
| 141 | u32* cmd_buff = Kernel::GetCommandBuffer(); | 114 | u32* cmd_buff = Kernel::GetCommandBuffer(); |
| 142 | 115 | ||
| 143 | cmd_buff[1] = 0; // No error | 116 | cmd_buff[1] = 0; // No error |
| 117 | cmd_buff[2] = 0x14000000; // IPC Command Structure translate-header | ||
| 144 | // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) | 118 | // TODO(yuriks): Return error from SendSyncRequest is this fails (part of IPC marshalling) |
| 145 | cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::g_shared_mem).MoveFrom(); | 119 | cmd_buff[3] = Kernel::g_handle_table.Create(Service::HID::shared_mem).MoveFrom(); |
| 146 | cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_1).MoveFrom(); | 120 | cmd_buff[4] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_1).MoveFrom(); |
| 147 | cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::g_event_pad_or_touch_2).MoveFrom(); | 121 | cmd_buff[5] = Kernel::g_handle_table.Create(Service::HID::event_pad_or_touch_2).MoveFrom(); |
| 148 | cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::g_event_accelerometer).MoveFrom(); | 122 | cmd_buff[6] = Kernel::g_handle_table.Create(Service::HID::event_accelerometer).MoveFrom(); |
| 149 | cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::g_event_gyroscope).MoveFrom(); | 123 | cmd_buff[7] = Kernel::g_handle_table.Create(Service::HID::event_gyroscope).MoveFrom(); |
| 150 | cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::g_event_debug_pad).MoveFrom(); | 124 | cmd_buff[8] = Kernel::g_handle_table.Create(Service::HID::event_debug_pad).MoveFrom(); |
| 125 | } | ||
| 126 | |||
| 127 | void EnableAccelerometer(Service::Interface* self) { | ||
| 128 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 129 | |||
| 130 | event_accelerometer->Signal(); | ||
| 131 | |||
| 132 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 133 | |||
| 134 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 135 | } | ||
| 136 | |||
| 137 | void EnableGyroscopeLow(Service::Interface* self) { | ||
| 138 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 139 | |||
| 140 | event_gyroscope->Signal(); | ||
| 141 | |||
| 142 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 143 | |||
| 144 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 145 | } | ||
| 146 | |||
| 147 | void GetSoundVolume(Service::Interface* self) { | ||
| 148 | u32* cmd_buff = Kernel::GetCommandBuffer(); | ||
| 149 | |||
| 150 | const u8 volume = 0x3F; // TODO(purpasmart): Find out if this is the max value for the volume | ||
| 151 | |||
| 152 | cmd_buff[1] = RESULT_SUCCESS.raw; | ||
| 153 | cmd_buff[2] = volume; | ||
| 154 | |||
| 155 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 151 | } | 156 | } |
| 152 | 157 | ||
| 153 | void HIDInit() { | 158 | void HIDInit() { |
| @@ -156,19 +161,22 @@ void HIDInit() { | |||
| 156 | AddService(new HID_U_Interface); | 161 | AddService(new HID_U_Interface); |
| 157 | AddService(new HID_SPVR_Interface); | 162 | AddService(new HID_SPVR_Interface); |
| 158 | 163 | ||
| 159 | g_shared_mem = SharedMemory::Create("HID:SharedMem"); | 164 | shared_mem = SharedMemory::Create("HID:SharedMem"); |
| 165 | |||
| 166 | next_pad_index = 0; | ||
| 167 | next_touch_index = 0; | ||
| 160 | 168 | ||
| 161 | // Create event handles | 169 | // Create event handles |
| 162 | g_event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); | 170 | event_pad_or_touch_1 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch1"); |
| 163 | g_event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); | 171 | event_pad_or_touch_2 = Event::Create(RESETTYPE_ONESHOT, "HID:EventPadOrTouch2"); |
| 164 | g_event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); | 172 | event_accelerometer = Event::Create(RESETTYPE_ONESHOT, "HID:EventAccelerometer"); |
| 165 | g_event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); | 173 | event_gyroscope = Event::Create(RESETTYPE_ONESHOT, "HID:EventGyroscope"); |
| 166 | g_event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); | 174 | event_debug_pad = Event::Create(RESETTYPE_ONESHOT, "HID:EventDebugPad"); |
| 167 | } | 175 | } |
| 168 | 176 | ||
| 169 | void HIDShutdown() { | 177 | void HIDShutdown() { |
| 170 | |||
| 171 | } | 178 | } |
| 172 | 179 | ||
| 173 | } | 180 | } // namespace HID |
| 174 | } | 181 | |
| 182 | } // 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 { | |||
| 18 | namespace Service { | 18 | namespace Service { |
| 19 | namespace HID { | 19 | namespace HID { |
| 20 | 20 | ||
| 21 | // Handle to shared memory region designated to HID_User service | ||
| 22 | extern Kernel::SharedPtr<Kernel::SharedMemory> g_shared_mem; | ||
| 23 | |||
| 24 | // Event handles | ||
| 25 | extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_1; | ||
| 26 | extern Kernel::SharedPtr<Kernel::Event> g_event_pad_or_touch_2; | ||
| 27 | extern Kernel::SharedPtr<Kernel::Event> g_event_accelerometer; | ||
| 28 | extern Kernel::SharedPtr<Kernel::Event> g_event_gyroscope; | ||
| 29 | extern Kernel::SharedPtr<Kernel::Event> g_event_debug_pad; | ||
| 30 | |||
| 31 | /** | 21 | /** |
| 32 | * Structure of a Pad controller state. | 22 | * Structure of a Pad controller state. |
| 33 | */ | 23 | */ |
| @@ -65,7 +55,7 @@ struct PadState { | |||
| 65 | }; | 55 | }; |
| 66 | 56 | ||
| 67 | /** | 57 | /** |
| 68 | * Structure of a single entry in the PadData's Pad state history array. | 58 | * Structure of a single entry of Pad state history within HID shared memory |
| 69 | */ | 59 | */ |
| 70 | struct PadDataEntry { | 60 | struct PadDataEntry { |
| 71 | PadState current_state; | 61 | PadState current_state; |
| @@ -77,24 +67,65 @@ struct PadDataEntry { | |||
| 77 | }; | 67 | }; |
| 78 | 68 | ||
| 79 | /** | 69 | /** |
| 80 | * Structure of all data related to the 3DS Pad. | 70 | * Structure of a single entry of touch state history within HID shared memory |
| 81 | */ | 71 | */ |
| 82 | struct PadData { | 72 | struct TouchDataEntry { |
| 83 | s64 index_reset_ticks; | 73 | u16 x; ///< Y-coordinate of a touchpad press on the lower screen |
| 84 | s64 index_reset_ticks_previous; | 74 | u16 y; ///< X-coordinate of a touchpad press on the lower screen |
| 85 | u32 index; // the index of the last updated Pad state history element | 75 | BitField<0, 7, u32> valid; ///< Set to 1 when this entry contains actual X/Y data, otherwise 0 |
| 76 | }; | ||
| 77 | |||
| 78 | /** | ||
| 79 | * Structure of data stored in HID shared memory | ||
| 80 | */ | ||
| 81 | struct SharedMem { | ||
| 82 | /// Pad data, this is used for buttons and the circle pad | ||
| 83 | struct { | ||
| 84 | s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 | ||
| 85 | s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` | ||
| 86 | u32 index; ///< Index of the last updated pad state entry | ||
| 87 | |||
| 88 | INSERT_PADDING_WORDS(0x2); | ||
| 89 | |||
| 90 | PadState current_state; ///< Current state of the pad buttons | ||
| 91 | |||
| 92 | // TODO(bunnei): Implement `raw_circle_pad_data` field | ||
| 93 | u32 raw_circle_pad_data; ///< Raw (analog) circle pad data, before being converted | ||
| 86 | 94 | ||
| 87 | u32 pad1; | 95 | INSERT_PADDING_WORDS(0x1); |
| 88 | u32 pad2; | ||
| 89 | 96 | ||
| 90 | PadState current_state; // same as entries[index].current_state | 97 | std::array<PadDataEntry, 8> entries; ///< Last 8 pad entries |
| 91 | u32 raw_circle_pad_data; | 98 | } pad; |
| 92 | 99 | ||
| 93 | u32 pad3; | 100 | /// Touchpad data, this is used for touchpad input |
| 101 | struct { | ||
| 102 | s64 index_reset_ticks; ///< CPU tick count for when HID module updated entry index 0 | ||
| 103 | s64 index_reset_ticks_previous; ///< Previous `index_reset_ticks` | ||
| 104 | u32 index; ///< Index of the last updated touch entry | ||
| 94 | 105 | ||
| 95 | std::array<PadDataEntry, 8> entries; // Pad state history | 106 | INSERT_PADDING_WORDS(0x1); |
| 107 | |||
| 108 | // TODO(bunnei): Implement `raw_entry` field | ||
| 109 | TouchDataEntry raw_entry; ///< Raw (analog) touch data, before being converted | ||
| 110 | |||
| 111 | std::array<TouchDataEntry, 8> entries; ///< Last 8 touch entries, in pixel coordinates | ||
| 112 | } touch; | ||
| 96 | }; | 113 | }; |
| 97 | 114 | ||
| 115 | // TODO: MSVC does not support using offsetof() on non-static data members even though this | ||
| 116 | // is technically allowed since C++11. This macro should be enabled once MSVC adds | ||
| 117 | // support for that. | ||
| 118 | #ifndef _MSC_VER | ||
| 119 | #define ASSERT_REG_POSITION(field_name, position) \ | ||
| 120 | static_assert(offsetof(SharedMem, field_name) == position * 4, \ | ||
| 121 | "Field "#field_name" has invalid position") | ||
| 122 | |||
| 123 | ASSERT_REG_POSITION(pad.index_reset_ticks, 0x0); | ||
| 124 | ASSERT_REG_POSITION(touch.index_reset_ticks, 0x2A); | ||
| 125 | |||
| 126 | #undef ASSERT_REG_POSITION | ||
| 127 | #endif // !defined(_MSC_VER) | ||
| 128 | |||
| 98 | // Pre-defined PadStates for single button presses | 129 | // Pre-defined PadStates for single button presses |
| 99 | const PadState PAD_NONE = {{0}}; | 130 | const PadState PAD_NONE = {{0}}; |
| 100 | const PadState PAD_A = {{1u << 0}}; | 131 | const PadState PAD_A = {{1u << 0}}; |
| @@ -130,7 +161,7 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | |||
| 130 | * None | 161 | * None |
| 131 | * Outputs: | 162 | * Outputs: |
| 132 | * 1 : Result of function, 0 on success, otherwise error code | 163 | * 1 : Result of function, 0 on success, otherwise error code |
| 133 | * 2 : Unused | 164 | * 2 : IPC Command Structure translate-header |
| 134 | * 3 : Handle to HID_User shared memory | 165 | * 3 : Handle to HID_User shared memory |
| 135 | * 4 : Event signaled by HID_User | 166 | * 4 : Event signaled by HID_User |
| 136 | * 5 : Event signaled by HID_User | 167 | * 5 : Event signaled by HID_User |
| @@ -140,12 +171,41 @@ const PadState PAD_CIRCLE_DOWN = {{1u << 31}}; | |||
| 140 | */ | 171 | */ |
| 141 | void GetIPCHandles(Interface* self); | 172 | void GetIPCHandles(Interface* self); |
| 142 | 173 | ||
| 143 | // Methods for updating the HID module's state | 174 | /** |
| 144 | void PadButtonPress(const PadState& pad_state); | 175 | * HID::EnableAccelerometer service function |
| 145 | void PadButtonRelease(const PadState& pad_state); | 176 | * Inputs: |
| 146 | void PadUpdateComplete(); | 177 | * None |
| 178 | * Outputs: | ||
| 179 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 180 | */ | ||
| 181 | void EnableAccelerometer(Interface* self); | ||
| 182 | |||
| 183 | /** | ||
| 184 | * HID::EnableGyroscopeLow service function | ||
| 185 | * Inputs: | ||
| 186 | * None | ||
| 187 | * Outputs: | ||
| 188 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 189 | */ | ||
| 190 | void EnableGyroscopeLow(Interface* self); | ||
| 191 | |||
| 192 | /** | ||
| 193 | * HID::GetSoundVolume service function | ||
| 194 | * Inputs: | ||
| 195 | * None | ||
| 196 | * Outputs: | ||
| 197 | * 1 : Result of function, 0 on success, otherwise error code | ||
| 198 | * 2 : u8 output value | ||
| 199 | */ | ||
| 200 | void GetSoundVolume(Interface* self); | ||
| 147 | 201 | ||
| 202 | /// Checks for user input updates | ||
| 203 | void HIDUpdate(); | ||
| 204 | |||
| 205 | /// Initialize HID service | ||
| 148 | void HIDInit(); | 206 | void HIDInit(); |
| 207 | |||
| 208 | /// Shutdown HID service | ||
| 149 | void HIDShutdown(); | 209 | void HIDShutdown(); |
| 150 | 210 | ||
| 151 | } | 211 | } |
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[] = { | |||
| 13 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | 13 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, |
| 14 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, | 14 | {0x000B0000, nullptr, "StartAnalogStickCalibration"}, |
| 15 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, | 15 | {0x000E0000, nullptr, "GetAnalogStickCalibrateParam"}, |
| 16 | {0x00110000, nullptr, "EnableAccelerometer"}, | 16 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, |
| 17 | {0x00120000, nullptr, "DisableAccelerometer"}, | 17 | {0x00120000, nullptr, "DisableAccelerometer"}, |
| 18 | {0x00130000, nullptr, "EnableGyroscopeLow"}, | 18 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, |
| 19 | {0x00140000, nullptr, "DisableGyroscopeLow"}, | 19 | {0x00140000, nullptr, "DisableGyroscopeLow"}, |
| 20 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | 20 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, |
| 21 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | 21 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, |
| 22 | {0x00170000, nullptr, "GetSoundVolume"}, | 22 | {0x00170000, GetSoundVolume, "GetSoundVolume"}, |
| 23 | }; | 23 | }; |
| 24 | 24 | ||
| 25 | HID_SPVR_Interface::HID_SPVR_Interface() { | 25 | 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 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/hle/hle.h" | 5 | #include "core/hle/hle.h" |
| 6 | #include "core/hle/kernel/event.h" | ||
| 7 | #include "core/hle/kernel/shared_memory.h" | ||
| 8 | #include "core/hle/service/hid/hid.h" | 6 | #include "core/hle/service/hid/hid.h" |
| 9 | #include "core/hle/service/hid/hid_user.h" | 7 | #include "core/hle/service/hid/hid_user.h" |
| 10 | 8 | ||
| @@ -12,14 +10,14 @@ namespace Service { | |||
| 12 | namespace HID { | 10 | namespace HID { |
| 13 | 11 | ||
| 14 | const Interface::FunctionInfo FunctionTable[] = { | 12 | const Interface::FunctionInfo FunctionTable[] = { |
| 15 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, | 13 | {0x000A0000, GetIPCHandles, "GetIPCHandles"}, |
| 16 | {0x00110000, nullptr, "EnableAccelerometer"}, | 14 | {0x00110000, EnableAccelerometer, "EnableAccelerometer"}, |
| 17 | {0x00120000, nullptr, "DisableAccelerometer"}, | 15 | {0x00120000, nullptr, "DisableAccelerometer"}, |
| 18 | {0x00130000, nullptr, "EnableGyroscopeLow"}, | 16 | {0x00130000, EnableGyroscopeLow, "EnableGyroscopeLow"}, |
| 19 | {0x00140000, nullptr, "DisableGyroscopeLow"}, | 17 | {0x00140000, nullptr, "DisableGyroscopeLow"}, |
| 20 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, | 18 | {0x00150000, nullptr, "GetGyroscopeLowRawToDpsCoefficient"}, |
| 21 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, | 19 | {0x00160000, nullptr, "GetGyroscopeLowCalibrateParam"}, |
| 22 | {0x00170000, nullptr, "GetSoundVolume"}, | 20 | {0x00170000, GetSoundVolume, "GetSoundVolume"}, |
| 23 | }; | 21 | }; |
| 24 | 22 | ||
| 25 | HID_U_Interface::HID_U_Interface() { | 23 | 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 @@ | |||
| 7 | #include "common/string_util.h" | 7 | #include "common/string_util.h" |
| 8 | #include "common/symbols.h" | 8 | #include "common/symbols.h" |
| 9 | 9 | ||
| 10 | #include "core/arm/arm_interface.h" | 10 | #include "core/core_timing.h" |
| 11 | #include "core/mem_map.h" | 11 | #include "core/mem_map.h" |
| 12 | #include "core/arm/arm_interface.h" | ||
| 12 | 13 | ||
| 13 | #include "core/hle/kernel/address_arbiter.h" | 14 | #include "core/hle/kernel/address_arbiter.h" |
| 14 | #include "core/hle/kernel/event.h" | 15 | #include "core/hle/kernel/event.h" |
| @@ -551,7 +552,7 @@ static void SleepThread(s64 nanoseconds) { | |||
| 551 | 552 | ||
| 552 | /// This returns the total CPU ticks elapsed since the CPU was powered-on | 553 | /// This returns the total CPU ticks elapsed since the CPU was powered-on |
| 553 | static s64 GetSystemTick() { | 554 | static s64 GetSystemTick() { |
| 554 | return (s64)Core::g_app_core->GetTicks(); | 555 | return (s64)CoreTiming::GetTicks(); |
| 555 | } | 556 | } |
| 556 | 557 | ||
| 557 | /// Creates a memory block at the specified address with the specified permissions and size | 558 | /// 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 @@ | |||
| 14 | #include "core/hle/hle.h" | 14 | #include "core/hle/hle.h" |
| 15 | #include "core/hle/service/gsp_gpu.h" | 15 | #include "core/hle/service/gsp_gpu.h" |
| 16 | #include "core/hle/service/dsp_dsp.h" | 16 | #include "core/hle/service/dsp_dsp.h" |
| 17 | #include "core/hle/service/hid/hid.h" | ||
| 17 | 18 | ||
| 18 | #include "core/hw/hw.h" | 19 | #include "core/hw/hw.h" |
| 19 | #include "core/hw/gpu.h" | 20 | #include "core/hw/gpu.h" |
| @@ -117,8 +118,14 @@ inline void Write(u32 addr, const T data) { | |||
| 117 | u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); | 118 | u8* src_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalInputAddress())); |
| 118 | u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); | 119 | u8* dst_pointer = Memory::GetPointer(Memory::PhysicalToVirtualAddress(config.GetPhysicalOutputAddress())); |
| 119 | 120 | ||
| 120 | unsigned horizontal_scale = (config.scale_horizontally != 0) ? 2 : 1; | 121 | if (config.scaling > config.ScaleXY) { |
| 121 | unsigned vertical_scale = (config.scale_vertically != 0) ? 2 : 1; | 122 | LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode %u", config.scaling.Value()); |
| 123 | UNIMPLEMENTED(); | ||
| 124 | break; | ||
| 125 | } | ||
| 126 | |||
| 127 | unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; | ||
| 128 | unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; | ||
| 122 | 129 | ||
| 123 | u32 output_width = config.output_width / horizontal_scale; | 130 | u32 output_width = config.output_width / horizontal_scale; |
| 124 | u32 output_height = config.output_height / vertical_scale; | 131 | u32 output_height = config.output_height / vertical_scale; |
| @@ -139,14 +146,23 @@ inline void Write(u32 addr, const T data) { | |||
| 139 | break; | 146 | break; |
| 140 | } | 147 | } |
| 141 | 148 | ||
| 142 | // TODO(Subv): Blend the pixels when horizontal / vertical scaling is enabled, | 149 | // TODO(Subv): Implement the box filter when scaling is enabled |
| 143 | // right now we're just skipping the extra pixels. | 150 | // right now we're just skipping the extra pixels. |
| 144 | for (u32 y = 0; y < output_height; ++y) { | 151 | for (u32 y = 0; y < output_height; ++y) { |
| 145 | for (u32 x = 0; x < output_width; ++x) { | 152 | for (u32 x = 0; x < output_width; ++x) { |
| 146 | Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; | 153 | Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; |
| 147 | 154 | ||
| 148 | u32 scaled_x = x * horizontal_scale; | 155 | // Calculate the [x,y] position of the input image |
| 149 | u32 scaled_y = y * vertical_scale; | 156 | // based on the current output position and the scale |
| 157 | u32 input_x = x * horizontal_scale; | ||
| 158 | u32 input_y = y * vertical_scale; | ||
| 159 | |||
| 160 | if (config.flip_vertically) { | ||
| 161 | // Flip the y value of the output data, | ||
| 162 | // we do this after calculating the [x,y] position of the input image | ||
| 163 | // to account for the scaling options. | ||
| 164 | y = output_height - y - 1; | ||
| 165 | } | ||
| 150 | 166 | ||
| 151 | u32 dst_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.output_format); | 167 | u32 dst_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.output_format); |
| 152 | u32 src_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.input_format); | 168 | u32 src_bytes_per_pixel = GPU::Regs::BytesPerPixel(config.input_format); |
| @@ -158,14 +174,14 @@ inline void Write(u32 addr, const T data) { | |||
| 158 | u32 coarse_y = y & ~7; | 174 | u32 coarse_y = y & ~7; |
| 159 | u32 stride = output_width * dst_bytes_per_pixel; | 175 | u32 stride = output_width * dst_bytes_per_pixel; |
| 160 | 176 | ||
| 161 | src_offset = (scaled_x + scaled_y * config.input_width) * src_bytes_per_pixel; | 177 | src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; |
| 162 | dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; | 178 | dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; |
| 163 | } else { | 179 | } else { |
| 164 | // Interpret the input as tiled and the output as linear | 180 | // Interpret the input as tiled and the output as linear |
| 165 | u32 coarse_y = scaled_y & ~7; | 181 | u32 coarse_y = input_y & ~7; |
| 166 | u32 stride = config.input_width * src_bytes_per_pixel; | 182 | u32 stride = config.input_width * src_bytes_per_pixel; |
| 167 | 183 | ||
| 168 | src_offset = VideoCore::GetMortonOffset(scaled_x, scaled_y, src_bytes_per_pixel) + coarse_y * stride; | 184 | src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; |
| 169 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; | 185 | dst_offset = (x + y * output_width) * dst_bytes_per_pixel; |
| 170 | } | 186 | } |
| 171 | 187 | ||
| @@ -295,6 +311,9 @@ static void VBlankCallback(u64 userdata, int cycles_late) { | |||
| 295 | // this. Certain games expect this to be periodically signaled. | 311 | // this. Certain games expect this to be periodically signaled. |
| 296 | DSP_DSP::SignalInterrupt(); | 312 | DSP_DSP::SignalInterrupt(); |
| 297 | 313 | ||
| 314 | // Check for user input updates | ||
| 315 | Service::HID::HIDUpdate(); | ||
| 316 | |||
| 298 | // Reschedule recurrent event | 317 | // Reschedule recurrent event |
| 299 | CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event); | 318 | CoreTiming::ScheduleEvent(frame_ticks - cycles_late, vblank_event); |
| 300 | } | 319 | } |
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 { | |||
| 188 | BitField<16, 16, u32> input_height; | 188 | BitField<16, 16, u32> input_height; |
| 189 | }; | 189 | }; |
| 190 | 190 | ||
| 191 | enum ScalingMode : u32 { | ||
| 192 | NoScale = 0, // Doesn't scale the image | ||
| 193 | ScaleX = 1, // Downscales the image in half in the X axis and applies a box filter | ||
| 194 | ScaleXY = 2, // Downscales the image in half in both the X and Y axes and applies a box filter | ||
| 195 | }; | ||
| 196 | |||
| 191 | union { | 197 | union { |
| 192 | u32 flags; | 198 | u32 flags; |
| 193 | 199 | ||
| 194 | BitField< 0, 1, u32> flip_data; // flips input data horizontally (TODO) if true | 200 | BitField< 0, 1, u32> flip_vertically; // flips input data vertically |
| 195 | BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format | 201 | BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format |
| 196 | BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing | 202 | BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing |
| 197 | BitField< 8, 3, PixelFormat> input_format; | 203 | BitField< 8, 3, PixelFormat> input_format; |
| 198 | BitField<12, 3, PixelFormat> output_format; | 204 | BitField<12, 3, PixelFormat> output_format; |
| 199 | 205 | ||
| 200 | BitField<24, 1, u32> scale_horizontally; | 206 | BitField<24, 2, ScalingMode> scaling; // Determines the scaling mode of the transfer |
| 201 | BitField<25, 1, u32> scale_vertically; | ||
| 202 | }; | 207 | }; |
| 203 | 208 | ||
| 204 | INSERT_PADDING_WORDS(0x1); | 209 | 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 { | |||
| 20 | u16 version; | 20 | u16 version; |
| 21 | u8 reserved_0[4]; | 21 | u8 reserved_0[4]; |
| 22 | u8 program_id[8]; | 22 | u8 program_id[8]; |
| 23 | u8 temp_flag; | 23 | u8 reserved_1[0x10]; |
| 24 | u8 reserved_1[0x2f]; | 24 | u8 logo_region_hash[0x20]; |
| 25 | u8 product_code[0x10]; | 25 | u8 product_code[0x10]; |
| 26 | u8 extended_header_hash[0x20]; | 26 | u8 extended_header_hash[0x20]; |
| 27 | u32 extended_header_size; | 27 | u32 extended_header_size; |
| @@ -29,15 +29,16 @@ struct NCCH_Header { | |||
| 29 | u8 flags[8]; | 29 | u8 flags[8]; |
| 30 | u32 plain_region_offset; | 30 | u32 plain_region_offset; |
| 31 | u32 plain_region_size; | 31 | u32 plain_region_size; |
| 32 | u8 reserved_3[8]; | 32 | u32 logo_region_offset; |
| 33 | u32 logo_region_size; | ||
| 33 | u32 exefs_offset; | 34 | u32 exefs_offset; |
| 34 | u32 exefs_size; | 35 | u32 exefs_size; |
| 35 | u32 exefs_hash_region_size; | 36 | u32 exefs_hash_region_size; |
| 36 | u8 reserved_4[4]; | 37 | u8 reserved_3[4]; |
| 37 | u32 romfs_offset; | 38 | u32 romfs_offset; |
| 38 | u32 romfs_size; | 39 | u32 romfs_size; |
| 39 | u32 romfs_hash_region_size; | 40 | u32 romfs_hash_region_size; |
| 40 | u8 reserved_5[4]; | 41 | u8 reserved_4[4]; |
| 41 | u8 exefs_super_block_hash[0x20]; | 42 | u8 exefs_super_block_hash[0x20]; |
| 42 | u8 romfs_super_block_hash[0x20]; | 43 | u8 romfs_super_block_hash[0x20]; |
| 43 | }; | 44 | }; |
| @@ -88,8 +89,7 @@ struct ExHeader_DependencyList{ | |||
| 88 | }; | 89 | }; |
| 89 | 90 | ||
| 90 | struct ExHeader_SystemInfo{ | 91 | struct ExHeader_SystemInfo{ |
| 91 | u32 save_data_size; | 92 | u64 save_data_size; |
| 92 | u8 reserved[4]; | ||
| 93 | u8 jump_id[8]; | 93 | u8 jump_id[8]; |
| 94 | u8 reserved_2[0x30]; | 94 | u8 reserved_2[0x30]; |
| 95 | }; | 95 | }; |
| @@ -104,11 +104,14 @@ struct ExHeader_StorageInfo{ | |||
| 104 | 104 | ||
| 105 | struct ExHeader_ARM11_SystemLocalCaps{ | 105 | struct ExHeader_ARM11_SystemLocalCaps{ |
| 106 | u8 program_id[8]; | 106 | u8 program_id[8]; |
| 107 | u8 flags[8]; | 107 | u32 core_version; |
| 108 | u8 resource_limit_descriptor[0x10][2]; | 108 | u8 flags[3]; |
| 109 | u8 priority; | ||
| 110 | u8 resource_limit_descriptor[0x16][2]; | ||
| 109 | ExHeader_StorageInfo storage_info; | 111 | ExHeader_StorageInfo storage_info; |
| 110 | u8 service_access_control[0x20][8]; | 112 | u8 service_access_control[0x32][8]; |
| 111 | u8 reserved[0x1f]; | 113 | u8 ex_service_access_control[0x2][8]; |
| 114 | u8 reserved[0xf]; | ||
| 112 | u8 resource_limit_category; | 115 | u8 resource_limit_category; |
| 113 | }; | 116 | }; |
| 114 | 117 | ||
diff --git a/src/video_core/color.h b/src/video_core/color.h index 14ade74f2..43d635e2c 100644 --- a/src/video_core/color.h +++ b/src/video_core/color.h | |||
| @@ -124,7 +124,7 @@ inline u32 DecodeD24(const u8* bytes) { | |||
| 124 | * @return Resulting values stored as a Math::Vec2 | 124 | * @return Resulting values stored as a Math::Vec2 |
| 125 | */ | 125 | */ |
| 126 | inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) { | 126 | inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) { |
| 127 | return { (bytes[2] << 16) | (bytes[1] << 8) | bytes[0], bytes[3] }; | 127 | return { static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3] }; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | /** | 130 | /** |
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 745c4f4ed..83982b4f2 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp | |||
| @@ -322,7 +322,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture | |||
| 322 | case Regs::TextureFormat::RGBA8: | 322 | case Regs::TextureFormat::RGBA8: |
| 323 | { | 323 | { |
| 324 | auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); | 324 | auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); |
| 325 | return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; | 325 | return { res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a()) }; |
| 326 | } | 326 | } |
| 327 | 327 | ||
| 328 | case Regs::TextureFormat::RGB8: | 328 | case Regs::TextureFormat::RGB8: |
| @@ -334,7 +334,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture | |||
| 334 | case Regs::TextureFormat::RGB5A1: | 334 | case Regs::TextureFormat::RGB5A1: |
| 335 | { | 335 | { |
| 336 | auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); | 336 | auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); |
| 337 | return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; | 337 | return { res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a()) }; |
| 338 | } | 338 | } |
| 339 | 339 | ||
| 340 | case Regs::TextureFormat::RGB565: | 340 | case Regs::TextureFormat::RGB565: |
| @@ -346,7 +346,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture | |||
| 346 | case Regs::TextureFormat::RGBA4: | 346 | case Regs::TextureFormat::RGBA4: |
| 347 | { | 347 | { |
| 348 | auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); | 348 | auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); |
| 349 | return { res.r(), res.g(), res.b(), disable_alpha ? 255 : res.a() }; | 349 | return { res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a()) }; |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | case Regs::TextureFormat::IA8: | 352 | case Regs::TextureFormat::IA8: |
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp index 4eb3e743e..e8d865172 100644 --- a/src/video_core/vertex_shader.cpp +++ b/src/video_core/vertex_shader.cpp | |||
| @@ -72,7 +72,7 @@ struct VertexShaderState { | |||
| 72 | u32* program_counter; | 72 | u32* program_counter; |
| 73 | 73 | ||
| 74 | const float24* input_register_table[16]; | 74 | const float24* input_register_table[16]; |
| 75 | float24* output_register_table[7*4]; | 75 | Math::Vec4<float24> output_registers[16]; |
| 76 | 76 | ||
| 77 | Math::Vec4<float24> temporary_registers[16]; | 77 | Math::Vec4<float24> temporary_registers[16]; |
| 78 | bool conditional_code[2]; | 78 | bool conditional_code[2]; |
| @@ -198,8 +198,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 198 | src2[3] = src2[3] * float24::FromFloat32(-1); | 198 | src2[3] = src2[3] * float24::FromFloat32(-1); |
| 199 | } | 199 | } |
| 200 | 200 | ||
| 201 | float24* dest = (instr.common.dest.Value() < 0x08) ? state.output_register_table[4*instr.common.dest.Value().GetIndex()] | 201 | float24* dest = (instr.common.dest.Value() < 0x10) ? &state.output_registers[instr.common.dest.Value().GetIndex()][0] |
| 202 | : (instr.common.dest.Value() < 0x10) ? dummy_vec4_float24 | ||
| 203 | : (instr.common.dest.Value() < 0x20) ? &state.temporary_registers[instr.common.dest.Value().GetIndex()][0] | 202 | : (instr.common.dest.Value() < 0x20) ? &state.temporary_registers[instr.common.dest.Value().GetIndex()][0] |
| 204 | : dummy_vec4_float24; | 203 | : dummy_vec4_float24; |
| 205 | 204 | ||
| @@ -409,8 +408,7 @@ static void ProcessShaderCode(VertexShaderState& state) { | |||
| 409 | src3[3] = src3[3] * float24::FromFloat32(-1); | 408 | src3[3] = src3[3] * float24::FromFloat32(-1); |
| 410 | } | 409 | } |
| 411 | 410 | ||
| 412 | float24* dest = (instr.mad.dest.Value() < 0x08) ? state.output_register_table[4*instr.mad.dest.Value().GetIndex()] | 411 | float24* dest = (instr.mad.dest.Value() < 0x10) ? &state.output_registers[instr.mad.dest.Value().GetIndex()][0] |
| 413 | : (instr.mad.dest.Value() < 0x10) ? dummy_vec4_float24 | ||
| 414 | : (instr.mad.dest.Value() < 0x20) ? &state.temporary_registers[instr.mad.dest.Value().GetIndex()][0] | 412 | : (instr.mad.dest.Value() < 0x20) ? &state.temporary_registers[instr.mad.dest.Value().GetIndex()][0] |
| 415 | : dummy_vec4_float24; | 413 | : dummy_vec4_float24; |
| 416 | 414 | ||
| @@ -587,12 +585,18 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) { | |||
| 587 | if(num_attributes > 14) state.input_register_table[attribute_register_map.attribute14_register] = &input.attr[14].x; | 585 | if(num_attributes > 14) state.input_register_table[attribute_register_map.attribute14_register] = &input.attr[14].x; |
| 588 | if(num_attributes > 15) state.input_register_table[attribute_register_map.attribute15_register] = &input.attr[15].x; | 586 | if(num_attributes > 15) state.input_register_table[attribute_register_map.attribute15_register] = &input.attr[15].x; |
| 589 | 587 | ||
| 590 | // Setup output register table | 588 | state.conditional_code[0] = false; |
| 591 | OutputVertex ret; | 589 | state.conditional_code[1] = false; |
| 592 | // Zero output so that attributes which aren't output won't have denormals in them, which will | 590 | |
| 593 | // slow us down later. | 591 | ProcessShaderCode(state); |
| 594 | memset(&ret, 0, sizeof(ret)); | 592 | DebugUtils::DumpShader(shader_memory.data(), state.debug.max_offset, swizzle_data.data(), |
| 593 | state.debug.max_opdesc_id, registers.vs_main_offset, | ||
| 594 | registers.vs_output_attributes); | ||
| 595 | 595 | ||
| 596 | // Setup output data | ||
| 597 | OutputVertex ret; | ||
| 598 | // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to | ||
| 599 | // figure out what those circumstances are and enable the remaining outputs then. | ||
| 596 | for (int i = 0; i < 7; ++i) { | 600 | for (int i = 0; i < 7; ++i) { |
| 597 | const auto& output_register_map = registers.vs_output_attributes[i]; | 601 | const auto& output_register_map = registers.vs_output_attributes[i]; |
| 598 | 602 | ||
| @@ -601,18 +605,18 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) { | |||
| 601 | output_register_map.map_z, output_register_map.map_w | 605 | output_register_map.map_z, output_register_map.map_w |
| 602 | }; | 606 | }; |
| 603 | 607 | ||
| 604 | for (int comp = 0; comp < 4; ++comp) | 608 | for (int comp = 0; comp < 4; ++comp) { |
| 605 | state.output_register_table[4*i+comp] = ((float24*)&ret) + semantics[comp]; | 609 | float24* out = ((float24*)&ret) + semantics[comp]; |
| 610 | if (semantics[comp] != Regs::VSOutputAttributes::INVALID) { | ||
| 611 | *out = state.output_registers[i][comp]; | ||
| 612 | } else { | ||
| 613 | // Zero output so that attributes which aren't output won't have denormals in them, | ||
| 614 | // which would slow us down later. | ||
| 615 | memset(out, 0, sizeof(*out)); | ||
| 616 | } | ||
| 617 | } | ||
| 606 | } | 618 | } |
| 607 | 619 | ||
| 608 | state.conditional_code[0] = false; | ||
| 609 | state.conditional_code[1] = false; | ||
| 610 | |||
| 611 | ProcessShaderCode(state); | ||
| 612 | DebugUtils::DumpShader(shader_memory.data(), state.debug.max_offset, swizzle_data.data(), | ||
| 613 | state.debug.max_opdesc_id, registers.vs_main_offset, | ||
| 614 | registers.vs_output_attributes); | ||
| 615 | |||
| 616 | LOG_TRACE(Render_Software, "Output vertex: pos (%.2f, %.2f, %.2f, %.2f), col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f)", | 620 | LOG_TRACE(Render_Software, "Output vertex: pos (%.2f, %.2f, %.2f, %.2f), col(%.2f, %.2f, %.2f, %.2f), tc0(%.2f, %.2f)", |
| 617 | ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(), | 621 | ret.pos.x.ToFloat32(), ret.pos.y.ToFloat32(), ret.pos.z.ToFloat32(), ret.pos.w.ToFloat32(), |
| 618 | ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(), | 622 | ret.color.x.ToFloat32(), ret.color.y.ToFloat32(), ret.color.z.ToFloat32(), ret.color.w.ToFloat32(), |