summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.travis-build.sh6
-rwxr-xr-x.travis-deps.sh22
-rwxr-xr-x[-rw-r--r--].travis-upload.sh1
-rw-r--r--.travis.yml22
-rw-r--r--CMakeLists.txt39
-rw-r--r--CONTRIBUTING.md38
-rw-r--r--README.md2
-rw-r--r--appveyor.yml2
-rw-r--r--externals/getopt/CMakeLists.txt11
-rw-r--r--externals/getopt/getopt.c962
-rw-r--r--externals/getopt/getopt.h136
-rwxr-xr-x[-rw-r--r--]hooks/pre-commit0
-rw-r--r--src/citra/CMakeLists.txt7
-rw-r--r--src/citra/citra.cpp42
-rw-r--r--src/citra/config.cpp3
-rw-r--r--src/citra/config.h6
-rw-r--r--src/citra/emu_window/emu_window_glfw.cpp12
-rw-r--r--src/citra/emu_window/emu_window_glfw.h2
-rw-r--r--src/citra_qt/CMakeLists.txt6
-rw-r--r--src/citra_qt/bootmanager.cpp6
-rw-r--r--src/citra_qt/bootmanager.h5
-rw-r--r--src/citra_qt/config.cpp2
-rw-r--r--src/citra_qt/config.h4
-rw-r--r--src/citra_qt/debugger/disassembler.cpp2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoint_observer.h2
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.cpp112
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints.h6
-rw-r--r--src/citra_qt/debugger/graphics_breakpoints_p.h2
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.cpp34
-rw-r--r--src/citra_qt/debugger/graphics_cmdlists.h2
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.cpp62
-rw-r--r--src/citra_qt/debugger/graphics_framebuffer.h4
-rw-r--r--src/citra_qt/debugger/graphics_tracing.cpp170
-rw-r--r--src/citra_qt/debugger/graphics_tracing.h32
-rw-r--r--src/citra_qt/debugger/graphics_vertex_shader.cpp4
-rw-r--r--src/citra_qt/debugger/profiler.cpp2
-rw-r--r--src/citra_qt/hotkeys.cpp5
-rw-r--r--src/citra_qt/hotkeys.h4
-rw-r--r--src/citra_qt/main.cpp15
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/assert.h1
-rw-r--r--src/common/bit_field.h5
-rw-r--r--src/common/chunk_file.h10
-rw-r--r--src/common/color.h27
-rw-r--r--src/common/common_funcs.h17
-rw-r--r--src/common/common_types.h28
-rw-r--r--src/common/emu_window.cpp6
-rw-r--r--src/common/emu_window.h12
-rw-r--r--src/common/fifo_queue.h111
-rw-r--r--src/common/file_util.cpp11
-rw-r--r--src/common/file_util.h16
-rw-r--r--src/common/logging/filter.h1
-rw-r--r--src/common/logging/log.h4
-rw-r--r--src/common/make_unique.h1
-rw-r--r--src/common/memory_util.cpp11
-rw-r--r--src/common/memory_util.h4
-rw-r--r--src/common/misc.cpp5
-rw-r--r--src/common/platform.h55
-rw-r--r--src/common/profiler.cpp11
-rw-r--r--src/common/profiler_reporting.h5
-rw-r--r--src/common/string_util.cpp11
-rw-r--r--src/common/string_util.h3
-rw-r--r--src/common/swap.h10
-rw-r--r--src/common/synchronized_wrapper.h1
-rw-r--r--src/common/thread.cpp17
-rw-r--r--src/common/thread.h16
-rw-r--r--src/common/thunk.h42
-rw-r--r--src/core/CMakeLists.txt7
-rw-r--r--src/core/arm/disassembler/load_symbol_map.cpp1
-rw-r--r--src/core/arm/dyncom/arm_dyncom.h5
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp13
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp14
-rw-r--r--src/core/arm/skyeye_common/arm_regformat.h2
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.cpp26
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp.h4
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpinstr.cpp75
-rw-r--r--src/core/arm/skyeye_common/vfp/vfpsingle.cpp4
-rw-r--r--src/core/core.cpp3
-rw-r--r--src/core/core_timing.cpp6
-rw-r--r--src/core/file_sys/archive_backend.cpp2
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp5
-rw-r--r--src/core/file_sys/archive_extsavedata.h7
-rw-r--r--src/core/file_sys/archive_romfs.cpp10
-rw-r--r--src/core/file_sys/archive_romfs.h10
-rw-r--r--src/core/file_sys/archive_savedata.cpp8
-rw-r--r--src/core/file_sys/archive_savedata.h7
-rw-r--r--src/core/file_sys/archive_savedatacheck.cpp17
-rw-r--r--src/core/file_sys/archive_savedatacheck.h9
-rw-r--r--src/core/file_sys/archive_sdmc.cpp3
-rw-r--r--src/core/file_sys/archive_sdmc.h7
-rw-r--r--src/core/file_sys/archive_systemsavedata.cpp6
-rw-r--r--src/core/file_sys/archive_systemsavedata.h7
-rw-r--r--src/core/file_sys/disk_archive.cpp12
-rw-r--r--src/core/file_sys/disk_archive.h15
-rw-r--r--src/core/file_sys/file_backend.h10
-rw-r--r--src/core/file_sys/ivfc_archive.cpp21
-rw-r--r--src/core/file_sys/ivfc_archive.h27
-rw-r--r--src/core/hle/applets/applet.cpp101
-rw-r--r--src/core/hle/applets/applet.h77
-rw-r--r--src/core/hle/applets/swkbd.cpp113
-rw-r--r--src/core/hle/applets/swkbd.h90
-rw-r--r--src/core/hle/function_wrappers.h24
-rw-r--r--src/core/hle/hle.cpp1
-rw-r--r--src/core/hle/kernel/event.cpp2
-rw-r--r--src/core/hle/kernel/event.h1
-rw-r--r--src/core/hle/kernel/kernel.cpp2
-rw-r--r--src/core/hle/kernel/kernel.h9
-rw-r--r--src/core/hle/kernel/process.cpp38
-rw-r--r--src/core/hle/kernel/process.h47
-rw-r--r--src/core/hle/kernel/session.h6
-rw-r--r--src/core/hle/kernel/shared_memory.h3
-rw-r--r--src/core/hle/kernel/thread.cpp29
-rw-r--r--src/core/hle/kernel/thread.h1
-rw-r--r--src/core/hle/kernel/vm_manager.cpp16
-rw-r--r--src/core/hle/kernel/vm_manager.h7
-rw-r--r--src/core/hle/result.h2
-rw-r--r--src/core/hle/service/am/am.cpp9
-rw-r--r--src/core/hle/service/am/am.h13
-rw-r--r--src/core/hle/service/am/am_app.cpp14
-rw-r--r--src/core/hle/service/apt/apt.cpp163
-rw-r--r--src/core/hle/service/apt/apt.h58
-rw-r--r--src/core/hle/service/apt/apt_a.cpp31
-rw-r--r--src/core/hle/service/apt/apt_u.cpp4
-rw-r--r--src/core/hle/service/cfg/cfg_s.cpp4
-rw-r--r--src/core/hle/service/dsp_dsp.cpp5
-rw-r--r--src/core/hle/service/dsp_dsp.h3
-rw-r--r--src/core/hle/service/frd/frd_u.cpp13
-rw-r--r--src/core/hle/service/fs/archive.cpp12
-rw-r--r--src/core/hle/service/fs/archive.h13
-rw-r--r--src/core/hle/service/fs/fs_user.cpp12
-rw-r--r--src/core/hle/service/gsp_gpu.cpp55
-rw-r--r--src/core/hle/service/gsp_gpu.h14
-rw-r--r--src/core/hle/service/hid/hid.cpp1
-rw-r--r--src/core/hle/service/hid/hid.h16
-rw-r--r--src/core/hle/service/nwm_uds.cpp4
-rw-r--r--src/core/hle/service/nwm_uds.h1
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/service.h3
-rw-r--r--src/core/hle/service/soc_u.cpp93
-rw-r--r--src/core/hle/service/soc_u.h2
-rw-r--r--src/core/hle/service/srv.cpp4
-rw-r--r--src/core/hle/service/srv.h1
-rw-r--r--src/core/hle/service/y2r_u.cpp5
-rw-r--r--src/core/hle/service/y2r_u.h3
-rw-r--r--src/core/hle/shared_page.cpp6
-rw-r--r--src/core/hle/shared_page.h3
-rw-r--r--src/core/hle/svc.cpp37
-rw-r--r--src/core/hle/svc.h2
-rw-r--r--src/core/hw/gpu.cpp214
-rw-r--r--src/core/hw/gpu.h2
-rw-r--r--src/core/hw/hw.cpp30
-rw-r--r--src/core/hw/lcd.cpp12
-rw-r--r--src/core/hw/lcd.h1
-rw-r--r--src/core/hw/y2r.cpp6
-rw-r--r--src/core/loader/3dsx.cpp73
-rw-r--r--src/core/loader/3dsx.h2
-rw-r--r--src/core/loader/elf.cpp93
-rw-r--r--src/core/loader/elf.h2
-rw-r--r--src/core/loader/loader.cpp10
-rw-r--r--src/core/loader/loader.h29
-rw-r--r--src/core/loader/ncch.cpp87
-rw-r--r--src/core/loader/ncch.h19
-rw-r--r--src/core/mem_map.cpp19
-rw-r--r--src/core/mem_map.h5
-rw-r--r--src/core/memory.cpp9
-rw-r--r--src/core/memory.h2
-rw-r--r--src/core/tracer/citrace.h101
-rw-r--r--src/core/tracer/recorder.cpp187
-rw-r--r--src/core/tracer/recorder.h90
-rw-r--r--src/video_core/clipper.cpp4
-rw-r--r--src/video_core/command_processor.cpp236
-rw-r--r--src/video_core/command_processor.h4
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp33
-rw-r--r--src/video_core/debug_utils/debug_utils.h11
-rw-r--r--src/video_core/hwrasterizer_base.h9
-rw-r--r--src/video_core/pica.h284
-rw-r--r--src/video_core/primitive_assembly.cpp3
-rw-r--r--src/video_core/rasterizer.cpp187
-rw-r--r--src/video_core/renderer_base.h4
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp19
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h5
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp16
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h29
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp19
-rw-r--r--src/video_core/vertex_shader.cpp18
-rw-r--r--src/video_core/vertex_shader.h7
-rw-r--r--src/video_core/video_core.h7
188 files changed, 4348 insertions, 1308 deletions
diff --git a/.travis-build.sh b/.travis-build.sh
index 8ec2ed70c..22a3a9fd6 100755
--- a/.travis-build.sh
+++ b/.travis-build.sh
@@ -11,8 +11,12 @@ fi
11 11
12#if OS is linux or is not set 12#if OS is linux or is not set
13if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then 13if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
14 export CC=gcc-4.9
15 export CXX=g++-4.9
16 export PKG_CONFIG_PATH=$HOME/.local/lib/pkgconfig:$PKG_CONFIG_PATH
17
14 mkdir build && cd build 18 mkdir build && cd build
15 cmake -DUSE_QT5=OFF .. 19 cmake -DCITRA_FORCE_QT4=ON ..
16 make -j4 20 make -j4
17elif [ "$TRAVIS_OS_NAME" = "osx" ]; then 21elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
18 export Qt5_DIR=$(brew --prefix)/opt/qt5 22 export Qt5_DIR=$(brew --prefix)/opt/qt5
diff --git a/.travis-deps.sh b/.travis-deps.sh
index b9561bb66..5c530dcb9 100755
--- a/.travis-deps.sh
+++ b/.travis-deps.sh
@@ -5,26 +5,26 @@ set -x
5 5
6#if OS is linux or is not set 6#if OS is linux or is not set
7if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then 7if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
8 sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y 8 export CC=gcc-4.9
9 sudo apt-get -qq update 9 export CXX=g++-4.9
10 sudo apt-get -qq install g++-4.9 xorg-dev libglu1-mesa-dev libxcursor-dev 10 mkdir -p $HOME/.local
11 sudo update-alternatives --install /usr/bin/g++ g++ /usr/bin/g++-4.9 90 11
12 curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \
13 | tar -xz -C $HOME/.local --strip-components=1
14
12 ( 15 (
13 git clone https://github.com/glfw/glfw.git --branch 3.0.4 --depth 1 16 git clone https://github.com/glfw/glfw.git --branch 3.1.1 --depth 1
14 mkdir glfw/build && cd glfw/build 17 mkdir glfw/build && cd glfw/build
15 cmake -DBUILD_SHARED_LIBS=ON \ 18 cmake -DBUILD_SHARED_LIBS=ON \
16 -DGLFW_BUILD_EXAMPLES=OFF \ 19 -DGLFW_BUILD_EXAMPLES=OFF \
17 -DGLFW_BUILD_TESTS=OFF \ 20 -DGLFW_BUILD_TESTS=OFF \
21 -DCMAKE_INSTALL_PREFIX=$HOME/.local \
18 .. 22 ..
19 make -j4 && sudo make install 23 make -j4 && make install
20 ) 24 )
21 25
22 sudo apt-get install lib32stdc++6
23 sudo mkdir -p /usr/local
24 curl http://www.cmake.org/files/v2.8/cmake-2.8.11-Linux-i386.tar.gz \
25 | sudo tar -xz -C /usr/local --strip-components=1
26elif [ "$TRAVIS_OS_NAME" = "osx" ]; then 26elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
27 brew tap homebrew/versions 27 brew update > /dev/null # silence the very verbose output
28 brew install qt5 glfw3 pkgconfig 28 brew install qt5 glfw3 pkgconfig
29 gem install xcpretty 29 gem install xcpretty
30fi 30fi
diff --git a/.travis-upload.sh b/.travis-upload.sh
index 0904b646a..3a15e8f6a 100644..100755
--- a/.travis-upload.sh
+++ b/.travis-upload.sh
@@ -7,7 +7,6 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
7 UPLOAD_DIR="/citra/nightly/linux-amd64" 7 UPLOAD_DIR="/citra/nightly/linux-amd64"
8 mkdir "$REV_NAME" 8 mkdir "$REV_NAME"
9 9
10 sudo apt-get -qq install lftp
11 cp build/src/citra/citra "$REV_NAME" 10 cp build/src/citra/citra "$REV_NAME"
12 cp build/src/citra_qt/citra-qt "$REV_NAME" 11 cp build/src/citra_qt/citra-qt "$REV_NAME"
13 elif [ "$TRAVIS_OS_NAME" = "osx" ]; then 12 elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
diff --git a/.travis.yml b/.travis.yml
index 5c882a574..4d21257bc 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -8,11 +8,21 @@ env:
8 global: 8 global:
9 - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" 9 - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg="
10 10
11before_install: 11sudo: false
12 - sh .travis-deps.sh
13 12
14script: 13addons:
15 - sh .travis-build.sh 14 apt:
15 sources:
16 - ubuntu-toolchain-r-test
17 packages:
18 - gcc-4.9
19 - g++-4.9
20 - xorg-dev
21 - libglu1-mesa-dev
22 - libxcursor-dev
23 - lib32stdc++6 # For CMake
24 - lftp # To upload builds
16 25
17after_success: 26install: ./.travis-deps.sh
18 - sh .travis-upload.sh 27script: ./.travis-build.sh
28after_success: ./.travis-upload.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6805ebed8..e945a6679 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -7,8 +7,7 @@ project(citra)
7if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit) 7if(NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks/pre-commit)
8 message(STATUS "Copying pre-commit hook") 8 message(STATUS "Copying pre-commit hook")
9 file(COPY hooks/pre-commit 9 file(COPY hooks/pre-commit
10 DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks 10 DESTINATION ${CMAKE_CURRENT_SOURCE_DIR}/.git/hooks)
11 FILE_PERMISSIONS WORLD_EXECUTE )
12endif() 11endif()
13 12
14if (NOT MSVC) 13if (NOT MSVC)
@@ -22,32 +21,34 @@ else()
22 21
23 # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms) 22 # set up output paths for executable binaries (.exe-files, and .dll-files on DLL-capable platforms)
24 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 23 set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
25 set(CMAKE_CONFIGURATION_TYPES Debug Release RelWithDebInfo CACHE STRING "" FORCE) 24 set(CMAKE_CONFIGURATION_TYPES Debug Release CACHE STRING "" FORCE)
26 25
27 # Tweak optimization settings 26 # Tweak optimization settings
28 # As far as I can tell, there's no way to override the CMake defaults while leaving user 27 # As far as I can tell, there's no way to override the CMake defaults while leaving user
29 # changes intact, so we'll just clobber everything and say sorry. 28 # changes intact, so we'll just clobber everything and say sorry.
30 message(STATUS "Cache compiler flags ignored, please edit CMakeLists.txt to change the flags.") 29 message(STATUS "Cache compiler flags ignored, please edit CMakeLists.txt to change the flags.")
31 # /O2 - Optimization level 2 30
32 # /Oy- - Don't omit frame pointer 31 # /W3 - Level 3 warnings
33 # /GR- - Disable RTTI
34 # /GS- - No stack buffer overflow checks
35 # /EHsc - C++-only exception handling semantics
36 set(optimization_flags "/O2 /Oy- /GR- /GS- /EHsc")
37 # /MP - Multi-threaded compilation 32 # /MP - Multi-threaded compilation
38 # /Zi - Output debugging information 33 # /Zi - Output debugging information
39 # /Zo - enahnced debug info for optimized builds 34 # /Zo - enahnced debug info for optimized builds
35 set(CMAKE_C_FLAGS "/W3 /MP /Zi /Zo" CACHE STRING "" FORCE)
36 # /GR- - Disable RTTI
37 # /EHsc - C++-only exception handling semantics
38 set(CMAKE_CXX_FLAGS "${CMAKE_C_FLAGS} /GR- /EHsc" CACHE STRING "" FORCE)
39
40 # /MDd - Multi-threaded Debug Runtime DLL 40 # /MDd - Multi-threaded Debug Runtime DLL
41 set(CMAKE_C_FLAGS_DEBUG "/MP /MDd /Zi" CACHE STRING "" FORCE) 41 set(CMAKE_C_FLAGS_DEBUG "/Od /MDd" CACHE STRING "" FORCE)
42 set(CMAKE_CXX_FLAGS_DEBUG "/MP /MDd /Zi" CACHE STRING "" FORCE) 42 set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG}" CACHE STRING "" FORCE)
43
44 # /O2 - Optimization level 2
45 # /GS- - No stack buffer overflow checks
43 # /MD - Multi-threaded runtime DLL 46 # /MD - Multi-threaded runtime DLL
44 set(CMAKE_C_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) 47 set(CMAKE_C_FLAGS_RELEASE "/O2 /GS- /MD" CACHE STRING "" FORCE)
45 set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) 48 set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE}" CACHE STRING "" FORCE)
46 set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE)
47 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE)
48 49
49 set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) 50 set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE)
50 set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG" CACHE STRING "" FORCE) 51 set(CMAKE_EXE_LINKER_FLAGS_RELEASE "/DEBUG" CACHE STRING "" FORCE)
51endif() 52endif()
52 53
53add_definitions(-DSINGLETHREADED) 54add_definitions(-DSINGLETHREADED)
@@ -201,6 +202,10 @@ add_subdirectory(${INI_PREFIX})
201 202
202include_directories(externals/nihstro/include) 203include_directories(externals/nihstro/include)
203 204
205if (MSVC)
206 add_subdirectory(externals/getopt)
207endif()
208
204# process subdirectories 209# process subdirectories
205if(ENABLE_QT) 210if(ENABLE_QT)
206 include_directories(externals/qhexedit) 211 include_directories(externals/qhexedit)
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 906a4bc7d..f2dbdf1a4 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -7,19 +7,14 @@ Citra is a brand new project, so we have a great opportunity to keep things clea
7* Don't ever introduce new external dependencies into Core 7* Don't ever introduce new external dependencies into Core
8* Don't use any platform specific code in Core 8* Don't use any platform specific code in Core
9* Use namespaces often 9* Use namespaces often
10* Avoid the use of C-style casts and instead prefer C++-style `static_cast` and `reinterpret_cast`. Never use `const_cast` or `dynamic_cast` (we build with RTTI disabled). The only exception to this rule is for casting between two numeric types, where C-style casts are encouraged for brevity and readability.
10 11
11### Naming Rules 12### Naming Rules
12* Functions 13* Functions: `PascalCase`
13 * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore) 14* Variables: `lower_case_underscored`. Prefix with `g_` if global.
14* Variables 15* Classes: `PascalCase`
15 * lower_case_underscored 16* Files and Directories: `lower_case_underscored`
16 * Prefix "g_" if global 17* Namespaces: `PascalCase`, `_` may also be used for clarity (e.g. `ARM_InitCore`)
17* Classes
18 * PascalCase, "_" may also be used for clarity (e.g. OGL_VideoInterface)
19* Files/Folders
20 * lower_case_underscored
21* Namespaces
22 * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore)
23 18
24### Indentation/Whitespace Style 19### Indentation/Whitespace Style
25Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. 20Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead.
@@ -36,25 +31,25 @@ namespace Example {
36 31
37// Declare globals at the top 32// Declare globals at the top
38int g_foo = 0; 33int g_foo = 0;
39char* g_some_pointer; // Notice the position of the * 34char* g_some_pointer; // Pointer * and reference & stick to the type name
40 35
41/// A colorful enum. 36/// A colorful enum.
42enum SomeEnum { 37enum SomeEnum {
43 COLOR_RED, ///< The color of fire. 38 COLOR_RED, ///< The color of fire.
44 COLOR_GREEN, ///< The color of grass. 39 COLOR_GREEN, ///< The color of grass.
45 COLOR_BLUE ///< Not actually the color of water. 40 COLOR_BLUE, ///< Not actually the color of water.
46}; 41};
47 42
48/** 43/**
49 * Very important struct that does a lot of stuff. 44 * Very important struct that does a lot of stuff.
50 * Note that the asterisks are indented by one space. 45 * Note that the asterisks are indented by one space to align to the first line.
51 */ 46 */
52struct Position { 47struct Position {
53 int x, y; 48 int x, y;
54}; 49};
55 50
56// Use "typename" rather than "class" here, just to be consistent 51// Use "typename" rather than "class" here
57template 52template <typename T>
58void FooBar() { 53void FooBar() {
59 int some_array[] = { 54 int some_array[] = {
60 5, 55 5,
@@ -72,7 +67,7 @@ void FooBar() {
72 // Comment directly above code when possible 67 // Comment directly above code when possible
73 if (some_condition) single_statement(); 68 if (some_condition) single_statement();
74 69
75 // Place a single space after the for loop semicolons 70 // Place a single space after the for loop semicolons, prefer pre-increment
76 for (int i = 0; i != 25; ++i) { 71 for (int i = 0; i != 25; ++i) {
77 // This is how we write loops 72 // This is how we write loops
78 } 73 }
@@ -83,6 +78,9 @@ void FooBar() {
83 if (this || condition_takes_up_multiple && 78 if (this || condition_takes_up_multiple &&
84 lines && like && this || everything || 79 lines && like && this || everything ||
85 alright || then) { 80 alright || then) {
81
82 // Leave a blank space before the if block body if the condition was continued across
83 // several lines.
86 } 84 }
87 85
88 switch (var) { 86 switch (var) {
@@ -101,11 +99,7 @@ void FooBar() {
101 break; 99 break;
102 } 100 }
103 101
104 std::vector 102 std::vector<T> you_can_declare, a_few, variables, like_this;
105 you_can_declare,
106 a_few,
107 variables,
108 like_this;
109} 103}
110 104
111} 105}
diff --git a/README.md b/README.md
index 71d19784e..0d9e52396 100644
--- a/README.md
+++ b/README.md
@@ -7,7 +7,7 @@ Citra is an experimental open-source Nintendo 3DS emulator/debugger written in C
7 7
8Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project. 8Citra is licensed under the GPLv2 (or any later version). Refer to the license.txt file included. Please read the [FAQ](https://github.com/citra-emu/citra/wiki/FAQ) before getting started with the project.
9 9
10For development discussion, please join us @ #citra on [freenode](http://webchat.freenode.net/?channels=citra). 10For development discussion, please join us @ #citra on freenode.
11 11
12### Development 12### Development
13 13
diff --git a/appveyor.yml b/appveyor.yml
index 7e9155e6d..5dc147639 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -13,7 +13,7 @@ configuration:
13 - Release 13 - Release
14 14
15install: 15install:
16 - git submodule update --init --recursive --depth 20 16 - git submodule update --init --recursive
17 17
18before_build: 18before_build:
19 - mkdir build 19 - mkdir build
diff --git a/externals/getopt/CMakeLists.txt b/externals/getopt/CMakeLists.txt
new file mode 100644
index 000000000..c8b745d55
--- /dev/null
+++ b/externals/getopt/CMakeLists.txt
@@ -0,0 +1,11 @@
1set(SRCS
2 getopt.c
3 )
4set(HEADERS
5 getopt.h
6 )
7
8create_directory_groups(${SRCS} ${HEADERS})
9add_library(getopt ${SRCS} ${HEADERS})
10target_compile_definitions(getopt PUBLIC STATIC_GETOPT)
11target_include_directories(getopt INTERFACE ${CMAKE_CURRENT_SOURCE_DIR})
diff --git a/externals/getopt/getopt.c b/externals/getopt/getopt.c
new file mode 100644
index 000000000..948d42683
--- /dev/null
+++ b/externals/getopt/getopt.c
@@ -0,0 +1,962 @@
1/* Getopt for Microsoft C
2This code is a modification of the Free Software Foundation, Inc.
3Getopt library for parsing command line argument the purpose was
4to provide a Microsoft Visual C friendly derivative. This code
5provides functionality for both Unicode and Multibyte builds.
6
7Date: 02/03/2011 - Ludvik Jerabek - Initial Release
8Version: 1.0
9Comment: Supports getopt, getopt_long, and getopt_long_only
10and POSIXLY_CORRECT environment flag
11License: LGPL
12
13Revisions:
14
1502/03/2011 - Ludvik Jerabek - Initial Release
1602/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
1707/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
1808/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
1908/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
2002/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
2108/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
2210/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
2306/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
24
25**DISCLAIMER**
26THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
27EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
28IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
29PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
30EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
31APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
32DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
33USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
34PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
35YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
36EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37*/
38#include <stdlib.h>
39#include <stdio.h>
40#ifdef _MSC_VER
41#include <malloc.h>
42#endif
43#include "getopt.h"
44
45#ifdef __cplusplus
46#define _GETOPT_THROW throw()
47#else
48#define _GETOPT_THROW
49#endif
50
51int optind = 1;
52int opterr = 1;
53int optopt = '?';
54enum ENUM_ORDERING { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER };
55
56
57static struct _getopt_data_a
58{
59 int optind;
60 int opterr;
61 int optopt;
62 char *optarg;
63 int __initialized;
64 char *__nextchar;
65 enum ENUM_ORDERING __ordering;
66 int __posixly_correct;
67 int __first_nonopt;
68 int __last_nonopt;
69} getopt_data_a;
70char *optarg_a;
71
72static void exchange_a(char **argv, struct _getopt_data_a *d)
73{
74 int bottom = d->__first_nonopt;
75 int middle = d->__last_nonopt;
76 int top = d->optind;
77 char *tem;
78 while (top > middle && middle > bottom)
79 {
80 if (top - middle > middle - bottom)
81 {
82 int len = middle - bottom;
83 register int i;
84 for (i = 0; i < len; i++)
85 {
86 tem = argv[bottom + i];
87 argv[bottom + i] = argv[top - (middle - bottom) + i];
88 argv[top - (middle - bottom) + i] = tem;
89 }
90 top -= len;
91 }
92 else
93 {
94 int len = top - middle;
95 register int i;
96 for (i = 0; i < len; i++)
97 {
98 tem = argv[bottom + i];
99 argv[bottom + i] = argv[middle + i];
100 argv[middle + i] = tem;
101 }
102 bottom += len;
103 }
104 }
105 d->__first_nonopt += (d->optind - d->__last_nonopt);
106 d->__last_nonopt = d->optind;
107}
108static const char *_getopt_initialize_a(const char *optstring, struct _getopt_data_a *d, int posixly_correct)
109{
110 d->__first_nonopt = d->__last_nonopt = d->optind;
111 d->__nextchar = NULL;
112 d->__posixly_correct = posixly_correct | !!getenv("POSIXLY_CORRECT");
113 if (optstring[0] == '-')
114 {
115 d->__ordering = RETURN_IN_ORDER;
116 ++optstring;
117 }
118 else if (optstring[0] == '+')
119 {
120 d->__ordering = REQUIRE_ORDER;
121 ++optstring;
122 }
123 else if (d->__posixly_correct)
124 d->__ordering = REQUIRE_ORDER;
125 else
126 d->__ordering = PERMUTE;
127 return optstring;
128}
129int _getopt_internal_r_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, struct _getopt_data_a *d, int posixly_correct)
130{
131 int print_errors = d->opterr;
132 if (argc < 1)
133 return -1;
134 d->optarg = NULL;
135 if (d->optind == 0 || !d->__initialized)
136 {
137 if (d->optind == 0)
138 d->optind = 1;
139 optstring = _getopt_initialize_a(optstring, d, posixly_correct);
140 d->__initialized = 1;
141 }
142 else if (optstring[0] == '-' || optstring[0] == '+')
143 optstring++;
144 if (optstring[0] == ':')
145 print_errors = 0;
146 if (d->__nextchar == NULL || *d->__nextchar == '\0')
147 {
148 if (d->__last_nonopt > d->optind)
149 d->__last_nonopt = d->optind;
150 if (d->__first_nonopt > d->optind)
151 d->__first_nonopt = d->optind;
152 if (d->__ordering == PERMUTE)
153 {
154 if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
155 exchange_a((char **)argv, d);
156 else if (d->__last_nonopt != d->optind)
157 d->__first_nonopt = d->optind;
158 while (d->optind < argc && (argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
159 d->optind++;
160 d->__last_nonopt = d->optind;
161 }
162 if (d->optind != argc && !strcmp(argv[d->optind], "--"))
163 {
164 d->optind++;
165 if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
166 exchange_a((char **)argv, d);
167 else if (d->__first_nonopt == d->__last_nonopt)
168 d->__first_nonopt = d->optind;
169 d->__last_nonopt = argc;
170 d->optind = argc;
171 }
172 if (d->optind == argc)
173 {
174 if (d->__first_nonopt != d->__last_nonopt)
175 d->optind = d->__first_nonopt;
176 return -1;
177 }
178 if ((argv[d->optind][0] != '-' || argv[d->optind][1] == '\0'))
179 {
180 if (d->__ordering == REQUIRE_ORDER)
181 return -1;
182 d->optarg = argv[d->optind++];
183 return 1;
184 }
185 d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == '-'));
186 }
187 if (longopts != NULL && (argv[d->optind][1] == '-' || (long_only && (argv[d->optind][2] || !strchr(optstring, argv[d->optind][1])))))
188 {
189 char *nameend;
190 unsigned int namelen;
191 const struct option_a *p;
192 const struct option_a *pfound = NULL;
193 struct option_list
194 {
195 const struct option_a *p;
196 struct option_list *next;
197 } *ambig_list = NULL;
198 int exact = 0;
199 int indfound = -1;
200 int option_index;
201 for (nameend = d->__nextchar; *nameend && *nameend != '='; nameend++);
202 namelen = (unsigned int)(nameend - d->__nextchar);
203 for (p = longopts, option_index = 0; p->name; p++, option_index++)
204 if (!strncmp(p->name, d->__nextchar, namelen))
205 {
206 if (namelen == (unsigned int)strlen(p->name))
207 {
208 pfound = p;
209 indfound = option_index;
210 exact = 1;
211 break;
212 }
213 else if (pfound == NULL)
214 {
215 pfound = p;
216 indfound = option_index;
217 }
218 else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
219 {
220 struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
221 newp->p = p;
222 newp->next = ambig_list;
223 ambig_list = newp;
224 }
225 }
226 if (ambig_list != NULL && !exact)
227 {
228 if (print_errors)
229 {
230 struct option_list first;
231 first.p = pfound;
232 first.next = ambig_list;
233 ambig_list = &first;
234 fprintf(stderr, "%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
235 do
236 {
237 fprintf(stderr, " '--%s'", ambig_list->p->name);
238 ambig_list = ambig_list->next;
239 } while (ambig_list != NULL);
240 fputc('\n', stderr);
241 }
242 d->__nextchar += strlen(d->__nextchar);
243 d->optind++;
244 d->optopt = 0;
245 return '?';
246 }
247 if (pfound != NULL)
248 {
249 option_index = indfound;
250 d->optind++;
251 if (*nameend)
252 {
253 if (pfound->has_arg)
254 d->optarg = nameend + 1;
255 else
256 {
257 if (print_errors)
258 {
259 if (argv[d->optind - 1][1] == '-')
260 {
261 fprintf(stderr, "%s: option '--%s' doesn't allow an argument\n", argv[0], pfound->name);
262 }
263 else
264 {
265 fprintf(stderr, "%s: option '%c%s' doesn't allow an argument\n", argv[0], argv[d->optind - 1][0], pfound->name);
266 }
267 }
268 d->__nextchar += strlen(d->__nextchar);
269 d->optopt = pfound->val;
270 return '?';
271 }
272 }
273 else if (pfound->has_arg == 1)
274 {
275 if (d->optind < argc)
276 d->optarg = argv[d->optind++];
277 else
278 {
279 if (print_errors)
280 {
281 fprintf(stderr, "%s: option '--%s' requires an argument\n", argv[0], pfound->name);
282 }
283 d->__nextchar += strlen(d->__nextchar);
284 d->optopt = pfound->val;
285 return optstring[0] == ':' ? ':' : '?';
286 }
287 }
288 d->__nextchar += strlen(d->__nextchar);
289 if (longind != NULL)
290 *longind = option_index;
291 if (pfound->flag)
292 {
293 *(pfound->flag) = pfound->val;
294 return 0;
295 }
296 return pfound->val;
297 }
298 if (!long_only || argv[d->optind][1] == '-' || strchr(optstring, *d->__nextchar) == NULL)
299 {
300 if (print_errors)
301 {
302 if (argv[d->optind][1] == '-')
303 {
304 fprintf(stderr, "%s: unrecognized option '--%s'\n", argv[0], d->__nextchar);
305 }
306 else
307 {
308 fprintf(stderr, "%s: unrecognized option '%c%s'\n", argv[0], argv[d->optind][0], d->__nextchar);
309 }
310 }
311 d->__nextchar = (char *)"";
312 d->optind++;
313 d->optopt = 0;
314 return '?';
315 }
316 }
317 {
318 char c = *d->__nextchar++;
319 char *temp = (char*)strchr(optstring, c);
320 if (*d->__nextchar == '\0')
321 ++d->optind;
322 if (temp == NULL || c == ':' || c == ';')
323 {
324 if (print_errors)
325 {
326 fprintf(stderr, "%s: invalid option -- '%c'\n", argv[0], c);
327 }
328 d->optopt = c;
329 return '?';
330 }
331 if (temp[0] == 'W' && temp[1] == ';')
332 {
333 char *nameend;
334 const struct option_a *p;
335 const struct option_a *pfound = NULL;
336 int exact = 0;
337 int ambig = 0;
338 int indfound = 0;
339 int option_index;
340 if (longopts == NULL)
341 goto no_longs;
342 if (*d->__nextchar != '\0')
343 {
344 d->optarg = d->__nextchar;
345 d->optind++;
346 }
347 else if (d->optind == argc)
348 {
349 if (print_errors)
350 {
351 fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c);
352 }
353 d->optopt = c;
354 if (optstring[0] == ':')
355 c = ':';
356 else
357 c = '?';
358 return c;
359 }
360 else
361 d->optarg = argv[d->optind++];
362 for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != '='; nameend++);
363 for (p = longopts, option_index = 0; p->name; p++, option_index++)
364 if (!strncmp(p->name, d->__nextchar, nameend - d->__nextchar))
365 {
366 if ((unsigned int)(nameend - d->__nextchar) == strlen(p->name))
367 {
368 pfound = p;
369 indfound = option_index;
370 exact = 1;
371 break;
372 }
373 else if (pfound == NULL)
374 {
375 pfound = p;
376 indfound = option_index;
377 }
378 else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
379 ambig = 1;
380 }
381 if (ambig && !exact)
382 {
383 if (print_errors)
384 {
385 fprintf(stderr, "%s: option '-W %s' is ambiguous\n", argv[0], d->optarg);
386 }
387 d->__nextchar += strlen(d->__nextchar);
388 d->optind++;
389 return '?';
390 }
391 if (pfound != NULL)
392 {
393 option_index = indfound;
394 if (*nameend)
395 {
396 if (pfound->has_arg)
397 d->optarg = nameend + 1;
398 else
399 {
400 if (print_errors)
401 {
402 fprintf(stderr, "%s: option '-W %s' doesn't allow an argument\n", argv[0], pfound->name);
403 }
404 d->__nextchar += strlen(d->__nextchar);
405 return '?';
406 }
407 }
408 else if (pfound->has_arg == 1)
409 {
410 if (d->optind < argc)
411 d->optarg = argv[d->optind++];
412 else
413 {
414 if (print_errors)
415 {
416 fprintf(stderr, "%s: option '-W %s' requires an argument\n", argv[0], pfound->name);
417 }
418 d->__nextchar += strlen(d->__nextchar);
419 return optstring[0] == ':' ? ':' : '?';
420 }
421 }
422 else
423 d->optarg = NULL;
424 d->__nextchar += strlen(d->__nextchar);
425 if (longind != NULL)
426 *longind = option_index;
427 if (pfound->flag)
428 {
429 *(pfound->flag) = pfound->val;
430 return 0;
431 }
432 return pfound->val;
433 }
434 no_longs:
435 d->__nextchar = NULL;
436 return 'W';
437 }
438 if (temp[1] == ':')
439 {
440 if (temp[2] == ':')
441 {
442 if (*d->__nextchar != '\0')
443 {
444 d->optarg = d->__nextchar;
445 d->optind++;
446 }
447 else
448 d->optarg = NULL;
449 d->__nextchar = NULL;
450 }
451 else
452 {
453 if (*d->__nextchar != '\0')
454 {
455 d->optarg = d->__nextchar;
456 d->optind++;
457 }
458 else if (d->optind == argc)
459 {
460 if (print_errors)
461 {
462 fprintf(stderr, "%s: option requires an argument -- '%c'\n", argv[0], c);
463 }
464 d->optopt = c;
465 if (optstring[0] == ':')
466 c = ':';
467 else
468 c = '?';
469 }
470 else
471 d->optarg = argv[d->optind++];
472 d->__nextchar = NULL;
473 }
474 }
475 return c;
476 }
477}
478int _getopt_internal_a(int argc, char *const *argv, const char *optstring, const struct option_a *longopts, int *longind, int long_only, int posixly_correct)
479{
480 int result;
481 getopt_data_a.optind = optind;
482 getopt_data_a.opterr = opterr;
483 result = _getopt_internal_r_a(argc, argv, optstring, longopts, longind, long_only, &getopt_data_a, posixly_correct);
484 optind = getopt_data_a.optind;
485 optarg_a = getopt_data_a.optarg;
486 optopt = getopt_data_a.optopt;
487 return result;
488}
489int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW
490{
491 return _getopt_internal_a(argc, argv, optstring, (const struct option_a *) 0, (int *)0, 0, 0);
492}
493int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
494{
495 return _getopt_internal_a(argc, argv, options, long_options, opt_index, 0, 0);
496}
497int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW
498{
499 return _getopt_internal_a(argc, argv, options, long_options, opt_index, 1, 0);
500}
501int _getopt_long_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
502{
503 return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 0, d, 0);
504}
505int _getopt_long_only_r_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index, struct _getopt_data_a *d)
506{
507 return _getopt_internal_r_a(argc, argv, options, long_options, opt_index, 1, d, 0);
508}
509
510
511static struct _getopt_data_w
512{
513 int optind;
514 int opterr;
515 int optopt;
516 wchar_t *optarg;
517 int __initialized;
518 wchar_t *__nextchar;
519 enum ENUM_ORDERING __ordering;
520 int __posixly_correct;
521 int __first_nonopt;
522 int __last_nonopt;
523} getopt_data_w;
524wchar_t *optarg_w;
525
526static void exchange_w(wchar_t **argv, struct _getopt_data_w *d)
527{
528 int bottom = d->__first_nonopt;
529 int middle = d->__last_nonopt;
530 int top = d->optind;
531 wchar_t *tem;
532 while (top > middle && middle > bottom)
533 {
534 if (top - middle > middle - bottom)
535 {
536 int len = middle - bottom;
537 register int i;
538 for (i = 0; i < len; i++)
539 {
540 tem = argv[bottom + i];
541 argv[bottom + i] = argv[top - (middle - bottom) + i];
542 argv[top - (middle - bottom) + i] = tem;
543 }
544 top -= len;
545 }
546 else
547 {
548 int len = top - middle;
549 register int i;
550 for (i = 0; i < len; i++)
551 {
552 tem = argv[bottom + i];
553 argv[bottom + i] = argv[middle + i];
554 argv[middle + i] = tem;
555 }
556 bottom += len;
557 }
558 }
559 d->__first_nonopt += (d->optind - d->__last_nonopt);
560 d->__last_nonopt = d->optind;
561}
562static const wchar_t *_getopt_initialize_w(const wchar_t *optstring, struct _getopt_data_w *d, int posixly_correct)
563{
564 d->__first_nonopt = d->__last_nonopt = d->optind;
565 d->__nextchar = NULL;
566 d->__posixly_correct = posixly_correct | !!_wgetenv(L"POSIXLY_CORRECT");
567 if (optstring[0] == L'-')
568 {
569 d->__ordering = RETURN_IN_ORDER;
570 ++optstring;
571 }
572 else if (optstring[0] == L'+')
573 {
574 d->__ordering = REQUIRE_ORDER;
575 ++optstring;
576 }
577 else if (d->__posixly_correct)
578 d->__ordering = REQUIRE_ORDER;
579 else
580 d->__ordering = PERMUTE;
581 return optstring;
582}
583int _getopt_internal_r_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, struct _getopt_data_w *d, int posixly_correct)
584{
585 int print_errors = d->opterr;
586 if (argc < 1)
587 return -1;
588 d->optarg = NULL;
589 if (d->optind == 0 || !d->__initialized)
590 {
591 if (d->optind == 0)
592 d->optind = 1;
593 optstring = _getopt_initialize_w(optstring, d, posixly_correct);
594 d->__initialized = 1;
595 }
596 else if (optstring[0] == L'-' || optstring[0] == L'+')
597 optstring++;
598 if (optstring[0] == L':')
599 print_errors = 0;
600 if (d->__nextchar == NULL || *d->__nextchar == L'\0')
601 {
602 if (d->__last_nonopt > d->optind)
603 d->__last_nonopt = d->optind;
604 if (d->__first_nonopt > d->optind)
605 d->__first_nonopt = d->optind;
606 if (d->__ordering == PERMUTE)
607 {
608 if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
609 exchange_w((wchar_t **)argv, d);
610 else if (d->__last_nonopt != d->optind)
611 d->__first_nonopt = d->optind;
612 while (d->optind < argc && (argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
613 d->optind++;
614 d->__last_nonopt = d->optind;
615 }
616 if (d->optind != argc && !wcscmp(argv[d->optind], L"--"))
617 {
618 d->optind++;
619 if (d->__first_nonopt != d->__last_nonopt && d->__last_nonopt != d->optind)
620 exchange_w((wchar_t **)argv, d);
621 else if (d->__first_nonopt == d->__last_nonopt)
622 d->__first_nonopt = d->optind;
623 d->__last_nonopt = argc;
624 d->optind = argc;
625 }
626 if (d->optind == argc)
627 {
628 if (d->__first_nonopt != d->__last_nonopt)
629 d->optind = d->__first_nonopt;
630 return -1;
631 }
632 if ((argv[d->optind][0] != L'-' || argv[d->optind][1] == L'\0'))
633 {
634 if (d->__ordering == REQUIRE_ORDER)
635 return -1;
636 d->optarg = argv[d->optind++];
637 return 1;
638 }
639 d->__nextchar = (argv[d->optind] + 1 + (longopts != NULL && argv[d->optind][1] == L'-'));
640 }
641 if (longopts != NULL && (argv[d->optind][1] == L'-' || (long_only && (argv[d->optind][2] || !wcschr(optstring, argv[d->optind][1])))))
642 {
643 wchar_t *nameend;
644 unsigned int namelen;
645 const struct option_w *p;
646 const struct option_w *pfound = NULL;
647 struct option_list
648 {
649 const struct option_w *p;
650 struct option_list *next;
651 } *ambig_list = NULL;
652 int exact = 0;
653 int indfound = -1;
654 int option_index;
655 for (nameend = d->__nextchar; *nameend && *nameend != L'='; nameend++);
656 namelen = (unsigned int)(nameend - d->__nextchar);
657 for (p = longopts, option_index = 0; p->name; p++, option_index++)
658 if (!wcsncmp(p->name, d->__nextchar, namelen))
659 {
660 if (namelen == (unsigned int)wcslen(p->name))
661 {
662 pfound = p;
663 indfound = option_index;
664 exact = 1;
665 break;
666 }
667 else if (pfound == NULL)
668 {
669 pfound = p;
670 indfound = option_index;
671 }
672 else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
673 {
674 struct option_list *newp = (struct option_list*)alloca(sizeof(*newp));
675 newp->p = p;
676 newp->next = ambig_list;
677 ambig_list = newp;
678 }
679 }
680 if (ambig_list != NULL && !exact)
681 {
682 if (print_errors)
683 {
684 struct option_list first;
685 first.p = pfound;
686 first.next = ambig_list;
687 ambig_list = &first;
688 fwprintf(stderr, L"%s: option '%s' is ambiguous; possibilities:", argv[0], argv[d->optind]);
689 do
690 {
691 fwprintf(stderr, L" '--%s'", ambig_list->p->name);
692 ambig_list = ambig_list->next;
693 } while (ambig_list != NULL);
694 fputwc(L'\n', stderr);
695 }
696 d->__nextchar += wcslen(d->__nextchar);
697 d->optind++;
698 d->optopt = 0;
699 return L'?';
700 }
701 if (pfound != NULL)
702 {
703 option_index = indfound;
704 d->optind++;
705 if (*nameend)
706 {
707 if (pfound->has_arg)
708 d->optarg = nameend + 1;
709 else
710 {
711 if (print_errors)
712 {
713 if (argv[d->optind - 1][1] == L'-')
714 {
715 fwprintf(stderr, L"%s: option '--%s' doesn't allow an argument\n", argv[0], pfound->name);
716 }
717 else
718 {
719 fwprintf(stderr, L"%s: option '%c%s' doesn't allow an argument\n", argv[0], argv[d->optind - 1][0], pfound->name);
720 }
721 }
722 d->__nextchar += wcslen(d->__nextchar);
723 d->optopt = pfound->val;
724 return L'?';
725 }
726 }
727 else if (pfound->has_arg == 1)
728 {
729 if (d->optind < argc)
730 d->optarg = argv[d->optind++];
731 else
732 {
733 if (print_errors)
734 {
735 fwprintf(stderr, L"%s: option '--%s' requires an argument\n", argv[0], pfound->name);
736 }
737 d->__nextchar += wcslen(d->__nextchar);
738 d->optopt = pfound->val;
739 return optstring[0] == L':' ? L':' : L'?';
740 }
741 }
742 d->__nextchar += wcslen(d->__nextchar);
743 if (longind != NULL)
744 *longind = option_index;
745 if (pfound->flag)
746 {
747 *(pfound->flag) = pfound->val;
748 return 0;
749 }
750 return pfound->val;
751 }
752 if (!long_only || argv[d->optind][1] == L'-' || wcschr(optstring, *d->__nextchar) == NULL)
753 {
754 if (print_errors)
755 {
756 if (argv[d->optind][1] == L'-')
757 {
758 fwprintf(stderr, L"%s: unrecognized option '--%s'\n", argv[0], d->__nextchar);
759 }
760 else
761 {
762 fwprintf(stderr, L"%s: unrecognized option '%c%s'\n", argv[0], argv[d->optind][0], d->__nextchar);
763 }
764 }
765 d->__nextchar = (wchar_t *)L"";
766 d->optind++;
767 d->optopt = 0;
768 return L'?';
769 }
770 }
771 {
772 wchar_t c = *d->__nextchar++;
773 wchar_t *temp = (wchar_t*)wcschr(optstring, c);
774 if (*d->__nextchar == L'\0')
775 ++d->optind;
776 if (temp == NULL || c == L':' || c == L';')
777 {
778 if (print_errors)
779 {
780 fwprintf(stderr, L"%s: invalid option -- '%c'\n", argv[0], c);
781 }
782 d->optopt = c;
783 return L'?';
784 }
785 if (temp[0] == L'W' && temp[1] == L';')
786 {
787 wchar_t *nameend;
788 const struct option_w *p;
789 const struct option_w *pfound = NULL;
790 int exact = 0;
791 int ambig = 0;
792 int indfound = 0;
793 int option_index;
794 if (longopts == NULL)
795 goto no_longs;
796 if (*d->__nextchar != L'\0')
797 {
798 d->optarg = d->__nextchar;
799 d->optind++;
800 }
801 else if (d->optind == argc)
802 {
803 if (print_errors)
804 {
805 fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c);
806 }
807 d->optopt = c;
808 if (optstring[0] == L':')
809 c = L':';
810 else
811 c = L'?';
812 return c;
813 }
814 else
815 d->optarg = argv[d->optind++];
816 for (d->__nextchar = nameend = d->optarg; *nameend && *nameend != L'='; nameend++);
817 for (p = longopts, option_index = 0; p->name; p++, option_index++)
818 if (!wcsncmp(p->name, d->__nextchar, nameend - d->__nextchar))
819 {
820 if ((unsigned int)(nameend - d->__nextchar) == wcslen(p->name))
821 {
822 pfound = p;
823 indfound = option_index;
824 exact = 1;
825 break;
826 }
827 else if (pfound == NULL)
828 {
829 pfound = p;
830 indfound = option_index;
831 }
832 else if (long_only || pfound->has_arg != p->has_arg || pfound->flag != p->flag || pfound->val != p->val)
833 ambig = 1;
834 }
835 if (ambig && !exact)
836 {
837 if (print_errors)
838 {
839 fwprintf(stderr, L"%s: option '-W %s' is ambiguous\n", argv[0], d->optarg);
840 }
841 d->__nextchar += wcslen(d->__nextchar);
842 d->optind++;
843 return L'?';
844 }
845 if (pfound != NULL)
846 {
847 option_index = indfound;
848 if (*nameend)
849 {
850 if (pfound->has_arg)
851 d->optarg = nameend + 1;
852 else
853 {
854 if (print_errors)
855 {
856 fwprintf(stderr, L"%s: option '-W %s' doesn't allow an argument\n", argv[0], pfound->name);
857 }
858 d->__nextchar += wcslen(d->__nextchar);
859 return L'?';
860 }
861 }
862 else if (pfound->has_arg == 1)
863 {
864 if (d->optind < argc)
865 d->optarg = argv[d->optind++];
866 else
867 {
868 if (print_errors)
869 {
870 fwprintf(stderr, L"%s: option '-W %s' requires an argument\n", argv[0], pfound->name);
871 }
872 d->__nextchar += wcslen(d->__nextchar);
873 return optstring[0] == L':' ? L':' : L'?';
874 }
875 }
876 else
877 d->optarg = NULL;
878 d->__nextchar += wcslen(d->__nextchar);
879 if (longind != NULL)
880 *longind = option_index;
881 if (pfound->flag)
882 {
883 *(pfound->flag) = pfound->val;
884 return 0;
885 }
886 return pfound->val;
887 }
888 no_longs:
889 d->__nextchar = NULL;
890 return L'W';
891 }
892 if (temp[1] == L':')
893 {
894 if (temp[2] == L':')
895 {
896 if (*d->__nextchar != L'\0')
897 {
898 d->optarg = d->__nextchar;
899 d->optind++;
900 }
901 else
902 d->optarg = NULL;
903 d->__nextchar = NULL;
904 }
905 else
906 {
907 if (*d->__nextchar != L'\0')
908 {
909 d->optarg = d->__nextchar;
910 d->optind++;
911 }
912 else if (d->optind == argc)
913 {
914 if (print_errors)
915 {
916 fwprintf(stderr, L"%s: option requires an argument -- '%c'\n", argv[0], c);
917 }
918 d->optopt = c;
919 if (optstring[0] == L':')
920 c = L':';
921 else
922 c = L'?';
923 }
924 else
925 d->optarg = argv[d->optind++];
926 d->__nextchar = NULL;
927 }
928 }
929 return c;
930 }
931}
932int _getopt_internal_w(int argc, wchar_t *const *argv, const wchar_t *optstring, const struct option_w *longopts, int *longind, int long_only, int posixly_correct)
933{
934 int result;
935 getopt_data_w.optind = optind;
936 getopt_data_w.opterr = opterr;
937 result = _getopt_internal_r_w(argc, argv, optstring, longopts, longind, long_only, &getopt_data_w, posixly_correct);
938 optind = getopt_data_w.optind;
939 optarg_w = getopt_data_w.optarg;
940 optopt = getopt_data_w.optopt;
941 return result;
942}
943int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW
944{
945 return _getopt_internal_w(argc, argv, optstring, (const struct option_w *) 0, (int *)0, 0, 0);
946}
947int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
948{
949 return _getopt_internal_w(argc, argv, options, long_options, opt_index, 0, 0);
950}
951int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW
952{
953 return _getopt_internal_w(argc, argv, options, long_options, opt_index, 1, 0);
954}
955int _getopt_long_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
956{
957 return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 0, d, 0);
958}
959int _getopt_long_only_r_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index, struct _getopt_data_w *d)
960{
961 return _getopt_internal_r_w(argc, argv, options, long_options, opt_index, 1, d, 0);
962} \ No newline at end of file
diff --git a/externals/getopt/getopt.h b/externals/getopt/getopt.h
new file mode 100644
index 000000000..87e2ca396
--- /dev/null
+++ b/externals/getopt/getopt.h
@@ -0,0 +1,136 @@
1/* Getopt for Microsoft C
2This code is a modification of the Free Software Foundation, Inc.
3Getopt library for parsing command line argument the purpose was
4to provide a Microsoft Visual C friendly derivative. This code
5provides functionality for both Unicode and Multibyte builds.
6
7Date: 02/03/2011 - Ludvik Jerabek - Initial Release
8Version: 1.0
9Comment: Supports getopt, getopt_long, and getopt_long_only
10and POSIXLY_CORRECT environment flag
11License: LGPL
12
13Revisions:
14
1502/03/2011 - Ludvik Jerabek - Initial Release
1602/20/2011 - Ludvik Jerabek - Fixed compiler warnings at Level 4
1707/05/2011 - Ludvik Jerabek - Added no_argument, required_argument, optional_argument defs
1808/03/2011 - Ludvik Jerabek - Fixed non-argument runtime bug which caused runtime exception
1908/09/2011 - Ludvik Jerabek - Added code to export functions for DLL and LIB
2002/15/2012 - Ludvik Jerabek - Fixed _GETOPT_THROW definition missing in implementation file
2108/01/2012 - Ludvik Jerabek - Created separate functions for char and wchar_t characters so single dll can do both unicode and ansi
2210/15/2012 - Ludvik Jerabek - Modified to match latest GNU features
2306/19/2015 - Ludvik Jerabek - Fixed maximum option limitation caused by option_a (255) and option_w (65535) structure val variable
24
25**DISCLAIMER**
26THIS MATERIAL IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND,
27EITHER EXPRESS OR IMPLIED, INCLUDING, BUT Not LIMITED TO, THE
28IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
29PURPOSE, OR NON-INFRINGEMENT. SOME JURISDICTIONS DO NOT ALLOW THE
30EXCLUSION OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY NOT
31APPLY TO YOU. IN NO EVENT WILL I BE LIABLE TO ANY PARTY FOR ANY
32DIRECT, INDIRECT, SPECIAL OR OTHER CONSEQUENTIAL DAMAGES FOR ANY
33USE OF THIS MATERIAL INCLUDING, WITHOUT LIMITATION, ANY LOST
34PROFITS, BUSINESS INTERRUPTION, LOSS OF PROGRAMS OR OTHER DATA ON
35YOUR INFORMATION HANDLING SYSTEM OR OTHERWISE, EVEN If WE ARE
36EXPRESSLY ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
37*/
38#ifndef __GETOPT_H_
39#define __GETOPT_H_
40
41#ifdef _GETOPT_API
42#undef _GETOPT_API
43#endif
44
45#if defined(EXPORTS_GETOPT) && defined(STATIC_GETOPT)
46#error "The preprocessor definitions of EXPORTS_GETOPT and STATIC_GETOPT can only be used individually"
47#elif defined(STATIC_GETOPT)
48#pragma message("Warning static builds of getopt violate the Lesser GNU Public License")
49#define _GETOPT_API
50#elif defined(EXPORTS_GETOPT)
51#pragma message("Exporting getopt library")
52#define _GETOPT_API __declspec(dllexport)
53#else
54#pragma message("Importing getopt library")
55#define _GETOPT_API __declspec(dllimport)
56#endif
57
58// Change behavior for C\C++
59#ifdef __cplusplus
60#define _BEGIN_EXTERN_C extern "C" {
61#define _END_EXTERN_C }
62#define _GETOPT_THROW throw()
63#else
64#define _BEGIN_EXTERN_C
65#define _END_EXTERN_C
66#define _GETOPT_THROW
67#endif
68
69// Standard GNU options
70#define null_argument 0
71#define no_argument 0
72#define required_argument 1
73#define optional_argument 2
74
75// Shorter Options
76#define ARG_NULL 0
77#define ARG_NONE 0
78#define ARG_REQ 1
79#define ARG_OPT 2
80
81#include <string.h>
82#include <wchar.h>
83
84_BEGIN_EXTERN_C
85
86extern _GETOPT_API int optind;
87extern _GETOPT_API int opterr;
88extern _GETOPT_API int optopt;
89
90// Ansi
91struct option_a
92{
93 const char* name;
94 int has_arg;
95 int *flag;
96 int val;
97};
98extern _GETOPT_API char *optarg_a;
99extern _GETOPT_API int getopt_a(int argc, char *const *argv, const char *optstring) _GETOPT_THROW;
100extern _GETOPT_API int getopt_long_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
101extern _GETOPT_API int getopt_long_only_a(int argc, char *const *argv, const char *options, const struct option_a *long_options, int *opt_index) _GETOPT_THROW;
102
103// Unicode
104struct option_w
105{
106 const wchar_t* name;
107 int has_arg;
108 int *flag;
109 int val;
110};
111extern _GETOPT_API wchar_t *optarg_w;
112extern _GETOPT_API int getopt_w(int argc, wchar_t *const *argv, const wchar_t *optstring) _GETOPT_THROW;
113extern _GETOPT_API int getopt_long_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
114extern _GETOPT_API int getopt_long_only_w(int argc, wchar_t *const *argv, const wchar_t *options, const struct option_w *long_options, int *opt_index) _GETOPT_THROW;
115
116_END_EXTERN_C
117
118#undef _BEGIN_EXTERN_C
119#undef _END_EXTERN_C
120#undef _GETOPT_THROW
121#undef _GETOPT_API
122
123#ifdef _UNICODE
124#define getopt getopt_w
125#define getopt_long getopt_long_w
126#define getopt_long_only getopt_long_only_w
127#define option option_w
128#define optarg optarg_w
129#else
130#define getopt getopt_a
131#define getopt_long getopt_long_a
132#define getopt_long_only getopt_long_only_a
133#define option option_a
134#define optarg optarg_a
135#endif
136#endif // __GETOPT_H_
diff --git a/hooks/pre-commit b/hooks/pre-commit
index bad84b14b..bad84b14b 100644..100755
--- a/hooks/pre-commit
+++ b/hooks/pre-commit
diff --git a/src/citra/CMakeLists.txt b/src/citra/CMakeLists.txt
index 713f49193..918687312 100644
--- a/src/citra/CMakeLists.txt
+++ b/src/citra/CMakeLists.txt
@@ -16,6 +16,11 @@ create_directory_groups(${SRCS} ${HEADERS})
16add_executable(citra ${SRCS} ${HEADERS}) 16add_executable(citra ${SRCS} ${HEADERS})
17target_link_libraries(citra core common video_core) 17target_link_libraries(citra core common video_core)
18target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih) 18target_link_libraries(citra ${GLFW_LIBRARIES} ${OPENGL_gl_LIBRARY} inih)
19if (MSVC)
20 target_link_libraries(citra getopt)
21endif()
19target_link_libraries(citra ${PLATFORM_LIBRARIES}) 22target_link_libraries(citra ${PLATFORM_LIBRARIES})
20 23
21#install(TARGETS citra RUNTIME DESTINATION ${bindir}) 24if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
25 install(TARGETS citra RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
26endif() \ No newline at end of file
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index ce8d7dd25..182646f4c 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -2,13 +2,20 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <string>
5#include <thread> 6#include <thread>
7#include <iostream>
8
9#ifdef _MSC_VER
10#include <getopt.h>
11#else
12#include <unistd.h>
13#include <getopt.h>
14#endif
6 15
7#include "common/logging/log.h" 16#include "common/logging/log.h"
8#include "common/logging/text_formatter.h"
9#include "common/logging/backend.h" 17#include "common/logging/backend.h"
10#include "common/logging/filter.h" 18#include "common/logging/filter.h"
11#include "common/scope_exit.h"
12 19
13#include "core/settings.h" 20#include "core/settings.h"
14#include "core/system.h" 21#include "core/system.h"
@@ -20,12 +27,39 @@
20 27
21#include "video_core/video_core.h" 28#include "video_core/video_core.h"
22 29
30
31static void PrintHelp()
32{
33 std::cout << "Usage: citra <filename>" << std::endl;
34}
35
23/// Application entry point 36/// Application entry point
24int main(int argc, char **argv) { 37int main(int argc, char **argv) {
38 int option_index = 0;
39 std::string boot_filename;
40 static struct option long_options[] = {
41 { "help", no_argument, 0, 'h' },
42 { 0, 0, 0, 0 }
43 };
44
45 while (optind < argc) {
46 char arg = getopt_long(argc, argv, ":h", long_options, &option_index);
47 if (arg != -1) {
48 switch (arg) {
49 case 'h':
50 PrintHelp();
51 return 0;
52 }
53 } else {
54 boot_filename = argv[optind];
55 optind++;
56 }
57 }
58
25 Log::Filter log_filter(Log::Level::Debug); 59 Log::Filter log_filter(Log::Level::Debug);
26 Log::SetFilter(&log_filter); 60 Log::SetFilter(&log_filter);
27 61
28 if (argc < 2) { 62 if (boot_filename.empty()) {
29 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified"); 63 LOG_CRITICAL(Frontend, "Failed to load ROM: No ROM specified");
30 return -1; 64 return -1;
31 } 65 }
@@ -33,7 +67,7 @@ int main(int argc, char **argv) {
33 Config config; 67 Config config;
34 log_filter.ParseFilterString(Settings::values.log_filter); 68 log_filter.ParseFilterString(Settings::values.log_filter);
35 69
36 std::string boot_filename = argv[1]; 70
37 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW; 71 EmuWindow_GLFW* emu_window = new EmuWindow_GLFW;
38 72
39 VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer; 73 VideoCore::g_hw_renderer_enabled = Settings::values.use_hw_renderer;
diff --git a/src/citra/config.cpp b/src/citra/config.cpp
index 1378567c1..506cb7939 100644
--- a/src/citra/config.cpp
+++ b/src/citra/config.cpp
@@ -2,7 +2,9 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#define GLFW_INCLUDE_NONE
5#include <GLFW/glfw3.h> 6#include <GLFW/glfw3.h>
7#include <inih/cpp/INIReader.h>
6 8
7#include "citra/default_ini.h" 9#include "citra/default_ini.h"
8 10
@@ -10,7 +12,6 @@
10#include "common/logging/log.h" 12#include "common/logging/log.h"
11 13
12#include "core/settings.h" 14#include "core/settings.h"
13#include "core/core.h"
14 15
15#include "config.h" 16#include "config.h"
16 17
diff --git a/src/citra/config.h b/src/citra/config.h
index 0eb176c7d..c326ec669 100644
--- a/src/citra/config.h
+++ b/src/citra/config.h
@@ -4,11 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <map> 7#include <string>
8 8
9#include <inih/cpp/INIReader.h> 9class INIReader;
10
11#include "common/common_types.h"
12 10
13class Config { 11class Config {
14 INIReader* glfw_config; 12 INIReader* glfw_config;
diff --git a/src/citra/emu_window/emu_window_glfw.cpp b/src/citra/emu_window/emu_window_glfw.cpp
index 341b48d2a..42fb683a9 100644
--- a/src/citra/emu_window/emu_window_glfw.cpp
+++ b/src/citra/emu_window/emu_window_glfw.cpp
@@ -2,13 +2,25 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstdlib>
7#include <string>
8
9// Let’s use our own GL header, instead of one from GLFW.
10#include "video_core/renderer_opengl/generated/gl_3_2_core.h"
11#define GLFW_INCLUDE_NONE
5#include <GLFW/glfw3.h> 12#include <GLFW/glfw3.h>
6 13
14#include "common/assert.h"
15#include "common/key_map.h"
7#include "common/logging/log.h" 16#include "common/logging/log.h"
17#include "common/scm_rev.h"
18#include "common/string_util.h"
8 19
9#include "video_core/video_core.h" 20#include "video_core/video_core.h"
10 21
11#include "core/settings.h" 22#include "core/settings.h"
23#include "core/hle/service/hid/hid.h"
12 24
13#include "citra/emu_window/emu_window_glfw.h" 25#include "citra/emu_window/emu_window_glfw.h"
14 26
diff --git a/src/citra/emu_window/emu_window_glfw.h b/src/citra/emu_window/emu_window_glfw.h
index 16c109b79..7ccd5e6aa 100644
--- a/src/citra/emu_window/emu_window_glfw.h
+++ b/src/citra/emu_window/emu_window_glfw.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <utility>
8
7#include "common/emu_window.h" 9#include "common/emu_window.h"
8 10
9struct GLFWwindow; 11struct GLFWwindow;
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index c2d1ad240..47aaeca24 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -12,6 +12,7 @@ set(SRCS
12 debugger/graphics_breakpoints.cpp 12 debugger/graphics_breakpoints.cpp
13 debugger/graphics_cmdlists.cpp 13 debugger/graphics_cmdlists.cpp
14 debugger/graphics_framebuffer.cpp 14 debugger/graphics_framebuffer.cpp
15 debugger/graphics_tracing.cpp
15 debugger/graphics_vertex_shader.cpp 16 debugger/graphics_vertex_shader.cpp
16 debugger/profiler.cpp 17 debugger/profiler.cpp
17 debugger/ramview.cpp 18 debugger/ramview.cpp
@@ -35,6 +36,7 @@ set(HEADERS
35 debugger/graphics_breakpoints_p.h 36 debugger/graphics_breakpoints_p.h
36 debugger/graphics_cmdlists.h 37 debugger/graphics_cmdlists.h
37 debugger/graphics_framebuffer.h 38 debugger/graphics_framebuffer.h
39 debugger/graphics_tracing.h
38 debugger/graphics_vertex_shader.h 40 debugger/graphics_vertex_shader.h
39 debugger/profiler.h 41 debugger/profiler.h
40 debugger/ramview.h 42 debugger/ramview.h
@@ -73,7 +75,9 @@ target_link_libraries(citra-qt core common video_core qhexedit)
73target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS}) 75target_link_libraries(citra-qt ${OPENGL_gl_LIBRARY} ${CITRA_QT_LIBS})
74target_link_libraries(citra-qt ${PLATFORM_LIBRARIES}) 76target_link_libraries(citra-qt ${PLATFORM_LIBRARIES})
75 77
76#install(TARGETS citra-qt RUNTIME DESTINATION ${bindir}) 78if(${CMAKE_SYSTEM_NAME} MATCHES "Linux|FreeBSD|OpenBSD|NetBSD")
79 install(TARGETS citra-qt RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin")
80endif()
77 81
78if (Qt5_FOUND AND MSVC) 82if (Qt5_FOUND AND MSVC)
79 set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin") 83 set(Qt5_DLL_DIR "${Qt5_DIR}/../../../bin")
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 3db09c65b..fa7bce466 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -11,6 +11,10 @@
11#include "bootmanager.h" 11#include "bootmanager.h"
12#include "main.h" 12#include "main.h"
13 13
14#include "common/string_util.h"
15#include "common/scm_rev.h"
16#include "common/key_map.h"
17
14#include "core/core.h" 18#include "core/core.h"
15#include "core/settings.h" 19#include "core/settings.h"
16#include "core/system.h" 20#include "core/system.h"
@@ -61,7 +65,7 @@ void EmuThread::run() {
61 was_active = false; 65 was_active = false;
62 } else { 66 } else {
63 std::unique_lock<std::mutex> lock(running_mutex); 67 std::unique_lock<std::mutex> lock(running_mutex);
64 running_cv.wait(lock, [this]{ return IsRunning() || stop_run; }); 68 running_cv.wait(lock, [this]{ return IsRunning() || exec_step || stop_run; });
65 } 69 }
66 } 70 }
67 71
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 475124319..1a1e0e6a5 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -35,7 +35,10 @@ public:
35 * Steps the emulation thread by a single CPU instruction (if the CPU is not already running) 35 * Steps the emulation thread by a single CPU instruction (if the CPU is not already running)
36 * @note This function is thread-safe 36 * @note This function is thread-safe
37 */ 37 */
38 void ExecStep() { exec_step = true; } 38 void ExecStep() {
39 exec_step = true;
40 running_cv.notify_all();
41 }
39 42
40 /** 43 /**
41 * Sets whether the emulation thread is running or not 44 * Sets whether the emulation thread is running or not
diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp
index 2a9af1f38..5c056446e 100644
--- a/src/citra_qt/config.cpp
+++ b/src/citra_qt/config.cpp
@@ -2,11 +2,11 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QSettings>
5#include <QString> 6#include <QString>
6#include <QStringList> 7#include <QStringList>
7 8
8#include "core/settings.h" 9#include "core/settings.h"
9#include "core/core.h"
10#include "common/file_util.h" 10#include "common/file_util.h"
11 11
12#include "config.h" 12#include "config.h"
diff --git a/src/citra_qt/config.h b/src/citra_qt/config.h
index 4485cae73..dd0b2ef0b 100644
--- a/src/citra_qt/config.h
+++ b/src/citra_qt/config.h
@@ -4,9 +4,9 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <QSettings> 7#include <string>
8 8
9#include "common/common_types.h" 9class QSettings;
10 10
11class Config { 11class Config {
12 QSettings* qt_config; 12 QSettings* qt_config;
diff --git a/src/citra_qt/debugger/disassembler.cpp b/src/citra_qt/debugger/disassembler.cpp
index e99ec1b30..b41c40a0e 100644
--- a/src/citra_qt/debugger/disassembler.cpp
+++ b/src/citra_qt/debugger/disassembler.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QShortcut>
6
5#include "disassembler.h" 7#include "disassembler.h"
6 8
7#include "../bootmanager.h" 9#include "../bootmanager.h"
diff --git a/src/citra_qt/debugger/graphics_breakpoint_observer.h b/src/citra_qt/debugger/graphics_breakpoint_observer.h
index f0d3361f8..02a0f4f4f 100644
--- a/src/citra_qt/debugger/graphics_breakpoint_observer.h
+++ b/src/citra_qt/debugger/graphics_breakpoint_observer.h
@@ -13,7 +13,7 @@
13 * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while 13 * This is because the Pica breakpoint callbacks are called from a non-GUI thread, while
14 * the widget usually wants to perform reactions in the GUI thread. 14 * the widget usually wants to perform reactions in the GUI thread.
15 */ 15 */
16class BreakPointObserverDock : public QDockWidget, private Pica::DebugContext::BreakPointObserver { 16class BreakPointObserverDock : public QDockWidget, protected Pica::DebugContext::BreakPointObserver {
17 Q_OBJECT 17 Q_OBJECT
18 18
19public: 19public:
diff --git a/src/citra_qt/debugger/graphics_breakpoints.cpp b/src/citra_qt/debugger/graphics_breakpoints.cpp
index 1da64f616..5202c168c 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.cpp
+++ b/src/citra_qt/debugger/graphics_breakpoints.cpp
@@ -4,7 +4,7 @@
4 4
5#include <QMetaType> 5#include <QMetaType>
6#include <QPushButton> 6#include <QPushButton>
7#include <QTreeWidget> 7#include <QTreeView>
8#include <QVBoxLayout> 8#include <QVBoxLayout>
9#include <QLabel> 9#include <QLabel>
10 10
@@ -23,7 +23,7 @@ BreakPointModel::BreakPointModel(std::shared_ptr<Pica::DebugContext> debug_conte
23 23
24int BreakPointModel::columnCount(const QModelIndex& parent) const 24int BreakPointModel::columnCount(const QModelIndex& parent) const
25{ 25{
26 return 2; 26 return 1;
27} 27}
28 28
29int BreakPointModel::rowCount(const QModelIndex& parent) const 29int BreakPointModel::rowCount(const QModelIndex& parent) const
@@ -38,29 +38,29 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
38 switch (role) { 38 switch (role) {
39 case Qt::DisplayRole: 39 case Qt::DisplayRole:
40 { 40 {
41 switch (index.column()) { 41 if (index.column() == 0) {
42 case 0:
43 {
44 static const std::map<Pica::DebugContext::Event, QString> map = { 42 static const std::map<Pica::DebugContext::Event, QString> map = {
45 { Pica::DebugContext::Event::CommandLoaded, tr("Pica command loaded") }, 43 { Pica::DebugContext::Event::PicaCommandLoaded, tr("Pica command loaded") },
46 { Pica::DebugContext::Event::CommandProcessed, tr("Pica command processed") }, 44 { Pica::DebugContext::Event::PicaCommandProcessed, tr("Pica command processed") },
47 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") }, 45 { Pica::DebugContext::Event::IncomingPrimitiveBatch, tr("Incoming primitive batch") },
48 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") }, 46 { Pica::DebugContext::Event::FinishedPrimitiveBatch, tr("Finished primitive batch") },
49 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") } 47 { Pica::DebugContext::Event::VertexLoaded, tr("Vertex loaded") },
48 { Pica::DebugContext::Event::IncomingDisplayTransfer, tr("Incoming display transfer") },
49 { Pica::DebugContext::Event::GSPCommandProcessed, tr("GSP command processed") },
50 { Pica::DebugContext::Event::BufferSwapped, tr("Buffers swapped") }
50 }; 51 };
51 52
52 DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents)); 53 DEBUG_ASSERT(map.size() == static_cast<size_t>(Pica::DebugContext::Event::NumEvents));
53
54 return (map.find(event) != map.end()) ? map.at(event) : QString(); 54 return (map.find(event) != map.end()) ? map.at(event) : QString();
55 } 55 }
56 56
57 case 1: 57 break;
58 return data(index, Role_IsEnabled).toBool() ? tr("Enabled") : tr("Disabled"); 58 }
59
60 default:
61 break;
62 }
63 59
60 case Qt::CheckStateRole:
61 {
62 if (index.column() == 0)
63 return data(index, Role_IsEnabled).toBool() ? Qt::Checked : Qt::Unchecked;
64 break; 64 break;
65 } 65 }
66 66
@@ -84,37 +84,34 @@ QVariant BreakPointModel::data(const QModelIndex& index, int role) const
84 return QVariant(); 84 return QVariant();
85} 85}
86 86
87QVariant BreakPointModel::headerData(int section, Qt::Orientation orientation, int role) const 87Qt::ItemFlags BreakPointModel::flags(const QModelIndex &index) const
88{ 88{
89 switch(role) { 89 if (!index.isValid())
90 case Qt::DisplayRole: 90 return 0;
91 {
92 if (section == 0) {
93 return tr("Event");
94 } else if (section == 1) {
95 return tr("Status");
96 }
97
98 break;
99 }
100 }
101 91
102 return QVariant(); 92 Qt::ItemFlags flags = Qt::ItemIsEnabled;
93 if (index.column() == 0)
94 flags |= Qt::ItemIsUserCheckable;
95 return flags;
103} 96}
104 97
98
105bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role) 99bool BreakPointModel::setData(const QModelIndex& index, const QVariant& value, int role)
106{ 100{
107 const auto event = static_cast<Pica::DebugContext::Event>(index.row()); 101 const auto event = static_cast<Pica::DebugContext::Event>(index.row());
108 102
109 switch (role) { 103 switch (role) {
110 case Role_IsEnabled: 104 case Qt::CheckStateRole:
111 { 105 {
106 if (index.column() != 0)
107 return false;
108
112 auto context = context_weak.lock(); 109 auto context = context_weak.lock();
113 if (!context) 110 if (!context)
114 return false; 111 return false;
115 112
116 context->breakpoints[event].enabled = value.toBool(); 113 context->breakpoints[event].enabled = value == Qt::Checked;
117 QModelIndex changed_index = createIndex(index.row(), 1); 114 QModelIndex changed_index = createIndex(index.row(), 0);
118 emit dataChanged(changed_index, changed_index); 115 emit dataChanged(changed_index, changed_index);
119 return true; 116 return true;
120 } 117 }
@@ -133,7 +130,7 @@ void BreakPointModel::OnBreakPointHit(Pica::DebugContext::Event event)
133 active_breakpoint = context->active_breakpoint; 130 active_breakpoint = context->active_breakpoint;
134 at_breakpoint = context->at_breakpoint; 131 at_breakpoint = context->at_breakpoint;
135 emit dataChanged(createIndex(static_cast<int>(event), 0), 132 emit dataChanged(createIndex(static_cast<int>(event), 0),
136 createIndex(static_cast<int>(event), 1)); 133 createIndex(static_cast<int>(event), 0));
137} 134}
138 135
139void BreakPointModel::OnResumed() 136void BreakPointModel::OnResumed()
@@ -144,7 +141,7 @@ void BreakPointModel::OnResumed()
144 141
145 at_breakpoint = context->at_breakpoint; 142 at_breakpoint = context->at_breakpoint;
146 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0), 143 emit dataChanged(createIndex(static_cast<int>(active_breakpoint), 0),
147 createIndex(static_cast<int>(active_breakpoint), 1)); 144 createIndex(static_cast<int>(active_breakpoint), 0));
148 active_breakpoint = context->active_breakpoint; 145 active_breakpoint = context->active_breakpoint;
149} 146}
150 147
@@ -162,13 +159,15 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
162 159
163 breakpoint_model = new BreakPointModel(debug_context, this); 160 breakpoint_model = new BreakPointModel(debug_context, this);
164 breakpoint_list = new QTreeView; 161 breakpoint_list = new QTreeView;
162 breakpoint_list->setRootIsDecorated(false);
163 breakpoint_list->setHeaderHidden(true);
165 breakpoint_list->setModel(breakpoint_model); 164 breakpoint_list->setModel(breakpoint_model);
166 165
167 toggle_breakpoint_button = new QPushButton(tr("Enable"));
168 toggle_breakpoint_button->setEnabled(false);
169
170 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event"); 166 qRegisterMetaType<Pica::DebugContext::Event>("Pica::DebugContext::Event");
171 167
168 connect(breakpoint_list, SIGNAL(doubleClicked(const QModelIndex&)),
169 this, SLOT(OnItemDoubleClicked(const QModelIndex&)));
170
172 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested())); 171 connect(resume_button, SIGNAL(clicked()), this, SLOT(OnResumeRequested()));
173 172
174 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)), 173 connect(this, SIGNAL(BreakPointHit(Pica::DebugContext::Event,void*)),
@@ -184,11 +183,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
184 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)), 183 connect(this, SIGNAL(BreakPointsChanged(const QModelIndex&,const QModelIndex&)),
185 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&))); 184 breakpoint_model, SIGNAL(dataChanged(const QModelIndex&,const QModelIndex&)));
186 185
187 connect(breakpoint_list->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)),
188 this, SLOT(OnBreakpointSelectionChanged(QModelIndex)));
189
190 connect(toggle_breakpoint_button, SIGNAL(clicked()), this, SLOT(OnToggleBreakpointEnabled()));
191
192 QWidget* main_widget = new QWidget; 186 QWidget* main_widget = new QWidget;
193 auto main_layout = new QVBoxLayout; 187 auto main_layout = new QVBoxLayout;
194 { 188 {
@@ -198,7 +192,6 @@ GraphicsBreakPointsWidget::GraphicsBreakPointsWidget(std::shared_ptr<Pica::Debug
198 main_layout->addLayout(sub_layout); 192 main_layout->addLayout(sub_layout);
199 } 193 }
200 main_layout->addWidget(breakpoint_list); 194 main_layout->addWidget(breakpoint_list);
201 main_layout->addWidget(toggle_breakpoint_button);
202 main_widget->setLayout(main_layout); 195 main_widget->setLayout(main_layout);
203 196
204 setWidget(main_widget); 197 setWidget(main_widget);
@@ -234,32 +227,15 @@ void GraphicsBreakPointsWidget::OnResumeRequested()
234 context->Resume(); 227 context->Resume();
235} 228}
236 229
237void GraphicsBreakPointsWidget::OnBreakpointSelectionChanged(const QModelIndex& index) 230void GraphicsBreakPointsWidget::OnItemDoubleClicked(const QModelIndex& index)
238{ 231{
239 if (!index.isValid()) { 232 if (!index.isValid())
240 toggle_breakpoint_button->setEnabled(false);
241 return; 233 return;
242 }
243 234
244 toggle_breakpoint_button->setEnabled(true); 235 QModelIndex check_index = breakpoint_list->model()->index(index.row(), 0);
245 UpdateToggleBreakpointButton(index); 236 QVariant enabled = breakpoint_list->model()->data(check_index, Qt::CheckStateRole);
246} 237 QVariant new_state = Qt::Unchecked;
247 238 if (enabled == Qt::Unchecked)
248void GraphicsBreakPointsWidget::OnToggleBreakpointEnabled() 239 new_state = Qt::Checked;
249{ 240 breakpoint_list->model()->setData(check_index, new_state, Qt::CheckStateRole);
250 QModelIndex index = breakpoint_list->selectionModel()->currentIndex();
251 bool new_state = !(breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool());
252
253 breakpoint_model->setData(index, new_state,
254 BreakPointModel::Role_IsEnabled);
255 UpdateToggleBreakpointButton(index);
256}
257
258void GraphicsBreakPointsWidget::UpdateToggleBreakpointButton(const QModelIndex& index)
259{
260 if (true == breakpoint_model->data(index, BreakPointModel::Role_IsEnabled).toBool()) {
261 toggle_breakpoint_button->setText(tr("Disable"));
262 } else {
263 toggle_breakpoint_button->setText(tr("Enable"));
264 }
265} 241}
diff --git a/src/citra_qt/debugger/graphics_breakpoints.h b/src/citra_qt/debugger/graphics_breakpoints.h
index 5b9ba324e..d900729da 100644
--- a/src/citra_qt/debugger/graphics_breakpoints.h
+++ b/src/citra_qt/debugger/graphics_breakpoints.h
@@ -31,10 +31,9 @@ public:
31 31
32public slots: 32public slots:
33 void OnBreakPointHit(Pica::DebugContext::Event event, void* data); 33 void OnBreakPointHit(Pica::DebugContext::Event event, void* data);
34 void OnItemDoubleClicked(const QModelIndex&);
34 void OnResumeRequested(); 35 void OnResumeRequested();
35 void OnResumed(); 36 void OnResumed();
36 void OnBreakpointSelectionChanged(const QModelIndex&);
37 void OnToggleBreakpointEnabled();
38 37
39signals: 38signals:
40 void Resumed(); 39 void Resumed();
@@ -42,11 +41,8 @@ signals:
42 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight); 41 void BreakPointsChanged(const QModelIndex& topLeft, const QModelIndex& bottomRight);
43 42
44private: 43private:
45 void UpdateToggleBreakpointButton(const QModelIndex& index);
46
47 QLabel* status_text; 44 QLabel* status_text;
48 QPushButton* resume_button; 45 QPushButton* resume_button;
49 QPushButton* toggle_breakpoint_button;
50 46
51 BreakPointModel* breakpoint_model; 47 BreakPointModel* breakpoint_model;
52 QTreeView* breakpoint_list; 48 QTreeView* breakpoint_list;
diff --git a/src/citra_qt/debugger/graphics_breakpoints_p.h b/src/citra_qt/debugger/graphics_breakpoints_p.h
index 34e72e859..00d8d5101 100644
--- a/src/citra_qt/debugger/graphics_breakpoints_p.h
+++ b/src/citra_qt/debugger/graphics_breakpoints_p.h
@@ -23,7 +23,7 @@ public:
23 int columnCount(const QModelIndex& parent = QModelIndex()) const override; 23 int columnCount(const QModelIndex& parent = QModelIndex()) const override;
24 int rowCount(const QModelIndex& parent = QModelIndex()) const override; 24 int rowCount(const QModelIndex& parent = QModelIndex()) const override;
25 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; 25 QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override;
26 QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; 26 Qt::ItemFlags flags(const QModelIndex &index) const;
27 27
28 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; 28 bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override;
29 29
diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp
index cabf5fe07..de10bce1f 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.cpp
+++ b/src/citra_qt/debugger/graphics_cmdlists.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QApplication>
6#include <QClipboard>
5#include <QLabel> 7#include <QLabel>
6#include <QListView> 8#include <QListView>
7#include <QMainWindow> 9#include <QMainWindow>
@@ -74,7 +76,7 @@ TextureInfoDockWidget::TextureInfoDockWidget(const Pica::DebugUtils::TextureInfo
74 format_choice->addItem(tr("I8")); 76 format_choice->addItem(tr("I8"));
75 format_choice->addItem(tr("A8")); 77 format_choice->addItem(tr("A8"));
76 format_choice->addItem(tr("IA4")); 78 format_choice->addItem(tr("IA4"));
77 format_choice->addItem(tr("UNK10")); 79 format_choice->addItem(tr("I4"));
78 format_choice->addItem(tr("A4")); 80 format_choice->addItem(tr("A4"));
79 format_choice->addItem(tr("ETC1")); 81 format_choice->addItem(tr("ETC1"));
80 format_choice->addItem(tr("ETC1A4")); 82 format_choice->addItem(tr("ETC1A4"));
@@ -168,7 +170,7 @@ GPUCommandListModel::GPUCommandListModel(QObject* parent) : QAbstractListModel(p
168} 170}
169 171
170int GPUCommandListModel::rowCount(const QModelIndex& parent) const { 172int GPUCommandListModel::rowCount(const QModelIndex& parent) const {
171 return pica_trace.writes.size(); 173 return static_cast<int>(pica_trace.writes.size());
172} 174}
173 175
174int GPUCommandListModel::columnCount(const QModelIndex& parent) const { 176int GPUCommandListModel::columnCount(const QModelIndex& parent) const {
@@ -304,16 +306,24 @@ GPUCommandListWidget::GPUCommandListWidget(QWidget* parent) : QDockWidget(tr("Pi
304 this, SLOT(OnCommandDoubleClicked(const QModelIndex&))); 306 this, SLOT(OnCommandDoubleClicked(const QModelIndex&)));
305 307
306 toggle_tracing = new QPushButton(tr("Start Tracing")); 308 toggle_tracing = new QPushButton(tr("Start Tracing"));
309 QPushButton* copy_all = new QPushButton(tr("Copy All"));
307 310
308 connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing())); 311 connect(toggle_tracing, SIGNAL(clicked()), this, SLOT(OnToggleTracing()));
309 connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)), 312 connect(this, SIGNAL(TracingFinished(const Pica::DebugUtils::PicaTrace&)),
310 model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&))); 313 model, SLOT(OnPicaTraceFinished(const Pica::DebugUtils::PicaTrace&)));
311 314
315 connect(copy_all, SIGNAL(clicked()), this, SLOT(CopyAllToClipboard()));
316
312 command_info_widget = new QWidget; 317 command_info_widget = new QWidget;
313 318
314 QVBoxLayout* main_layout = new QVBoxLayout; 319 QVBoxLayout* main_layout = new QVBoxLayout;
315 main_layout->addWidget(list_widget); 320 main_layout->addWidget(list_widget);
316 main_layout->addWidget(toggle_tracing); 321 {
322 QHBoxLayout* sub_layout = new QHBoxLayout;
323 sub_layout->addWidget(toggle_tracing);
324 sub_layout->addWidget(copy_all);
325 main_layout->addLayout(sub_layout);
326 }
317 main_layout->addWidget(command_info_widget); 327 main_layout->addWidget(command_info_widget);
318 main_widget->setLayout(main_layout); 328 main_widget->setLayout(main_layout);
319 329
@@ -330,3 +340,21 @@ void GPUCommandListWidget::OnToggleTracing() {
330 toggle_tracing->setText(tr("Start Tracing")); 340 toggle_tracing->setText(tr("Start Tracing"));
331 } 341 }
332} 342}
343
344void GPUCommandListWidget::CopyAllToClipboard() {
345 QClipboard* clipboard = QApplication::clipboard();
346 QString text;
347
348 QAbstractItemModel* model = static_cast<QAbstractListModel*>(list_widget->model());
349
350 for (int row = 0; row < model->rowCount({}); ++row) {
351 for (int col = 0; col < model->columnCount({}); ++col) {
352 QModelIndex index = model->index(row, col);
353 text += model->data(index).value<QString>();
354 text += '\t';
355 }
356 text += '\n';
357 }
358
359 clipboard->setText(text);
360}
diff --git a/src/citra_qt/debugger/graphics_cmdlists.h b/src/citra_qt/debugger/graphics_cmdlists.h
index a465d044c..4859b6ec8 100644
--- a/src/citra_qt/debugger/graphics_cmdlists.h
+++ b/src/citra_qt/debugger/graphics_cmdlists.h
@@ -49,6 +49,8 @@ public slots:
49 49
50 void SetCommandInfo(const QModelIndex&); 50 void SetCommandInfo(const QModelIndex&);
51 51
52 void CopyAllToClipboard();
53
52signals: 54signals:
53 void TracingFinished(const Pica::DebugUtils::PicaTrace&); 55 void TracingFinished(const Pica::DebugUtils::PicaTrace&);
54 56
diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp
index 6bbe7572c..39eefbf75 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.cpp
+++ b/src/citra_qt/debugger/graphics_framebuffer.cpp
@@ -55,7 +55,9 @@ GraphicsFramebufferWidget::GraphicsFramebufferWidget(std::shared_ptr<Pica::Debug
55 framebuffer_format_control->addItem(tr("RGBA4")); 55 framebuffer_format_control->addItem(tr("RGBA4"));
56 framebuffer_format_control->addItem(tr("D16")); 56 framebuffer_format_control->addItem(tr("D16"));
57 framebuffer_format_control->addItem(tr("D24")); 57 framebuffer_format_control->addItem(tr("D24"));
58 framebuffer_format_control->addItem(tr("D24S8")); 58 framebuffer_format_control->addItem(tr("D24X8"));
59 framebuffer_format_control->addItem(tr("X24S8"));
60 framebuffer_format_control->addItem(tr("(unknown)"));
59 61
60 // TODO: This QLabel should shrink the image to the available space rather than just expanding... 62 // TODO: This QLabel should shrink the image to the available space rather than just expanding...
61 framebuffer_picture_label = new QLabel; 63 framebuffer_picture_label = new QLabel;
@@ -184,8 +186,32 @@ void GraphicsFramebufferWidget::OnUpdate()
184 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress(); 186 framebuffer_address = framebuffer.GetColorBufferPhysicalAddress();
185 framebuffer_width = framebuffer.GetWidth(); 187 framebuffer_width = framebuffer.GetWidth();
186 framebuffer_height = framebuffer.GetHeight(); 188 framebuffer_height = framebuffer.GetHeight();
187 // TODO: It's unknown how this format is actually specified 189
188 framebuffer_format = Format::RGBA8; 190 switch (framebuffer.color_format) {
191 case Pica::Regs::ColorFormat::RGBA8:
192 framebuffer_format = Format::RGBA8;
193 break;
194
195 case Pica::Regs::ColorFormat::RGB8:
196 framebuffer_format = Format::RGB8;
197 break;
198
199 case Pica::Regs::ColorFormat::RGB5A1:
200 framebuffer_format = Format::RGB5A1;
201 break;
202
203 case Pica::Regs::ColorFormat::RGB565:
204 framebuffer_format = Format::RGB565;
205 break;
206
207 case Pica::Regs::ColorFormat::RGBA4:
208 framebuffer_format = Format::RGBA4;
209 break;
210
211 default:
212 framebuffer_format = Format::Unknown;
213 break;
214 }
189 215
190 break; 216 break;
191 } 217 }
@@ -197,7 +223,24 @@ void GraphicsFramebufferWidget::OnUpdate()
197 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress(); 223 framebuffer_address = framebuffer.GetDepthBufferPhysicalAddress();
198 framebuffer_width = framebuffer.GetWidth(); 224 framebuffer_width = framebuffer.GetWidth();
199 framebuffer_height = framebuffer.GetHeight(); 225 framebuffer_height = framebuffer.GetHeight();
200 framebuffer_format = Format::D16; 226
227 switch (framebuffer.depth_format) {
228 case Pica::Regs::DepthFormat::D16:
229 framebuffer_format = Format::D16;
230 break;
231
232 case Pica::Regs::DepthFormat::D24:
233 framebuffer_format = Format::D24;
234 break;
235
236 case Pica::Regs::DepthFormat::D24S8:
237 framebuffer_format = Format::D24X8;
238 break;
239
240 default:
241 framebuffer_format = Format::Unknown;
242 break;
243 }
201 244
202 break; 245 break;
203 } 246 }
@@ -258,7 +301,7 @@ void GraphicsFramebufferWidget::OnUpdate()
258 color.b() = (data >> 16) & 0xFF; 301 color.b() = (data >> 16) & 0xFF;
259 break; 302 break;
260 } 303 }
261 case Format::D24S8: 304 case Format::D24X8:
262 { 305 {
263 Math::Vec2<u32> data = Color::DecodeD24S8(pixel); 306 Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
264 color.r() = data.x & 0xFF; 307 color.r() = data.x & 0xFF;
@@ -266,6 +309,12 @@ void GraphicsFramebufferWidget::OnUpdate()
266 color.b() = (data.x >> 16) & 0xFF; 309 color.b() = (data.x >> 16) & 0xFF;
267 break; 310 break;
268 } 311 }
312 case Format::X24S8:
313 {
314 Math::Vec2<u32> data = Color::DecodeD24S8(pixel);
315 color.r() = color.g() = color.b() = data.y;
316 break;
317 }
269 default: 318 default:
270 qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format); 319 qDebug() << "Unknown fb color format " << static_cast<int>(framebuffer_format);
271 break; 320 break;
@@ -286,7 +335,8 @@ void GraphicsFramebufferWidget::OnUpdate()
286u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) { 335u32 GraphicsFramebufferWidget::BytesPerPixel(GraphicsFramebufferWidget::Format format) {
287 switch (format) { 336 switch (format) {
288 case Format::RGBA8: 337 case Format::RGBA8:
289 case Format::D24S8: 338 case Format::D24X8:
339 case Format::X24S8:
290 return 4; 340 return 4;
291 case Format::RGB8: 341 case Format::RGB8:
292 case Format::D24: 342 case Format::D24:
diff --git a/src/citra_qt/debugger/graphics_framebuffer.h b/src/citra_qt/debugger/graphics_framebuffer.h
index 4cb396ffe..e9eae679f 100644
--- a/src/citra_qt/debugger/graphics_framebuffer.h
+++ b/src/citra_qt/debugger/graphics_framebuffer.h
@@ -35,7 +35,9 @@ class GraphicsFramebufferWidget : public BreakPointObserverDock {
35 RGBA4 = 4, 35 RGBA4 = 4,
36 D16 = 5, 36 D16 = 5,
37 D24 = 6, 37 D24 = 6,
38 D24S8 = 7 38 D24X8 = 7,
39 X24S8 = 8,
40 Unknown = 9
39 }; 41 };
40 42
41 static u32 BytesPerPixel(Format format); 43 static u32 BytesPerPixel(Format format);
diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp
new file mode 100644
index 000000000..3f20f149d
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_tracing.cpp
@@ -0,0 +1,170 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <memory>
6
7#include <QBoxLayout>
8#include <QComboBox>
9#include <QFileDialog>
10#include <QLabel>
11#include <QMessageBox>
12#include <QPushButton>
13#include <QSpinBox>
14
15#include <boost/range/algorithm/copy.hpp>
16
17#include "core/hw/gpu.h"
18#include "core/hw/lcd.h"
19
20#include "video_core/pica.h"
21
22#include "nihstro/float24.h"
23
24#include "graphics_tracing.h"
25
26GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context,
27 QWidget* parent)
28 : BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) {
29
30 setObjectName("CiTracing");
31
32 QPushButton* start_recording = new QPushButton(tr("Start Recording"));
33 QPushButton* stop_recording = new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save"));
34 QPushButton* abort_recording = new QPushButton(tr("Abort Recording"));
35
36 connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, SLOT(setVisible(bool)));
37 connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, SLOT(setVisible(bool)));
38 connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, SLOT(setVisible(bool)));
39 connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording()));
40 connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording()));
41 connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording()));
42
43 stop_recording->setVisible(false);
44 abort_recording->setVisible(false);
45
46 auto main_widget = new QWidget;
47 auto main_layout = new QVBoxLayout;
48 {
49 auto sub_layout = new QHBoxLayout;
50 sub_layout->addWidget(start_recording);
51 sub_layout->addWidget(stop_recording);
52 sub_layout->addWidget(abort_recording);
53 main_layout->addLayout(sub_layout);
54 }
55 main_widget->setLayout(main_layout);
56 setWidget(main_widget);
57}
58
59void GraphicsTracingWidget::StartRecording() {
60 auto context = context_weak.lock();
61 if (!context)
62 return;
63
64 auto shader_binary = Pica::g_state.vs.program_code;
65 auto swizzle_data = Pica::g_state.vs.swizzle_data;
66
67 // Encode floating point numbers to 24-bit values
68 // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally.
69 std::array<uint32_t, 4 * 16> default_attributes;
70 for (unsigned i = 0; i < 16; ++i) {
71 for (unsigned comp = 0; comp < 3; ++comp) {
72 default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32());
73 }
74 }
75
76 std::array<uint32_t, 4 * 96> vs_float_uniforms;
77 for (unsigned i = 0; i < 96; ++i)
78 for (unsigned comp = 0; comp < 3; ++comp)
79 vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32());
80
81 CiTrace::Recorder::InitialState state;
82 std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), std::back_inserter(state.gpu_registers));
83 std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), std::back_inserter(state.lcd_registers));
84 std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), std::back_inserter(state.pica_registers));
85 boost::copy(default_attributes, std::back_inserter(state.default_attributes));
86 boost::copy(shader_binary, std::back_inserter(state.vs_program_binary));
87 boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data));
88 boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms));
89 //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary));
90 //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data));
91 //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms));
92
93 auto recorder = new CiTrace::Recorder(state);
94 context->recorder = std::shared_ptr<CiTrace::Recorder>(recorder);
95
96 emit SetStartTracingButtonEnabled(false);
97 emit SetStopTracingButtonEnabled(true);
98 emit SetAbortTracingButtonEnabled(true);
99}
100
101void GraphicsTracingWidget::StopRecording() {
102 auto context = context_weak.lock();
103 if (!context)
104 return;
105
106 QString filename = QFileDialog::getSaveFileName(this, tr("Save CiTrace"), "citrace.ctf",
107 tr("CiTrace File (*.ctf)"));
108
109 if (filename.isEmpty()) {
110 // If the user canceled the dialog, keep recording
111 return;
112 }
113
114 context->recorder->Finish(filename.toStdString());
115 context->recorder = nullptr;
116
117 emit SetStopTracingButtonEnabled(false);
118 emit SetAbortTracingButtonEnabled(false);
119 emit SetStartTracingButtonEnabled(true);
120}
121
122void GraphicsTracingWidget::AbortRecording() {
123 auto context = context_weak.lock();
124 if (!context)
125 return;
126
127 context->recorder = nullptr;
128
129 emit SetStopTracingButtonEnabled(false);
130 emit SetAbortTracingButtonEnabled(false);
131 emit SetStartTracingButtonEnabled(true);
132}
133
134void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) {
135 widget()->setEnabled(true);
136}
137
138void GraphicsTracingWidget::OnResumed() {
139 widget()->setEnabled(false);
140}
141
142void GraphicsTracingWidget::OnEmulationStarting(EmuThread* emu_thread) {
143 // Disable tracing starting/stopping until a GPU breakpoint is reached
144 widget()->setEnabled(false);
145}
146
147void GraphicsTracingWidget::OnEmulationStopping() {
148 // TODO: Is it safe to access the context here?
149
150 auto context = context_weak.lock();
151 if (!context)
152 return;
153
154
155 if (context->recorder) {
156 auto reply = QMessageBox::question(this, tr("CiTracing still active"),
157 tr("A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded."),
158 QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes);
159
160 if (reply == QMessageBox::Yes) {
161 StopRecording();
162 } else {
163 AbortRecording();
164 }
165 }
166
167 // If the widget was disabled before, enable it now to allow starting
168 // tracing before starting the next emulation session
169 widget()->setEnabled(true);
170}
diff --git a/src/citra_qt/debugger/graphics_tracing.h b/src/citra_qt/debugger/graphics_tracing.h
new file mode 100644
index 000000000..2a0e4819b
--- /dev/null
+++ b/src/citra_qt/debugger/graphics_tracing.h
@@ -0,0 +1,32 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "graphics_breakpoint_observer.h"
8
9class EmuThread;
10
11class GraphicsTracingWidget : public BreakPointObserverDock {
12 Q_OBJECT
13
14public:
15 GraphicsTracingWidget(std::shared_ptr<Pica::DebugContext> debug_context, QWidget* parent = nullptr);
16
17private slots:
18 void StartRecording();
19 void StopRecording();
20 void AbortRecording();
21
22 void OnBreakPointHit(Pica::DebugContext::Event event, void* data) override;
23 void OnResumed() override;
24
25 void OnEmulationStarting(EmuThread* emu_thread);
26 void OnEmulationStopping();
27
28signals:
29 void SetStartTracingButtonEnabled(bool enable);
30 void SetStopTracingButtonEnabled(bool enable);
31 void SetAbortTracingButtonEnabled(bool enable);
32};
diff --git a/src/citra_qt/debugger/graphics_vertex_shader.cpp b/src/citra_qt/debugger/graphics_vertex_shader.cpp
index 14d3f8f39..f42a2f4ce 100644
--- a/src/citra_qt/debugger/graphics_vertex_shader.cpp
+++ b/src/citra_qt/debugger/graphics_vertex_shader.cpp
@@ -34,7 +34,7 @@ int GraphicsVertexShaderModel::columnCount(const QModelIndex& parent) const {
34} 34}
35 35
36int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const { 36int GraphicsVertexShaderModel::rowCount(const QModelIndex& parent) const {
37 return info.code.size(); 37 return static_cast<int>(info.code.size());
38} 38}
39 39
40QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const { 40QVariant GraphicsVertexShaderModel::headerData(int section, Qt::Orientation orientation, int role) const {
@@ -259,7 +259,7 @@ void GraphicsVertexShaderModel::OnUpdate()
259 for (auto pattern : Pica::g_state.vs.swizzle_data) 259 for (auto pattern : Pica::g_state.vs.swizzle_data)
260 info.swizzle_info.push_back({pattern}); 260 info.swizzle_info.push_back({pattern});
261 261
262 info.labels.insert({ Pica::g_state.regs.vs_main_offset, "main" }); 262 info.labels.insert({ Pica::g_state.regs.vs.main_offset, "main" });
263 263
264 endResetModel(); 264 endResetModel();
265} 265}
diff --git a/src/citra_qt/debugger/profiler.cpp b/src/citra_qt/debugger/profiler.cpp
index 2ac1748b7..89b28c2f4 100644
--- a/src/citra_qt/debugger/profiler.cpp
+++ b/src/citra_qt/debugger/profiler.cpp
@@ -74,7 +74,7 @@ int ProfilerModel::rowCount(const QModelIndex& parent) const
74 if (parent.isValid()) { 74 if (parent.isValid()) {
75 return 0; 75 return 0;
76 } else { 76 } else {
77 return results.time_per_category.size() + 2; 77 return static_cast<int>(results.time_per_category.size() + 2);
78 } 78 }
79} 79}
80 80
diff --git a/src/citra_qt/hotkeys.cpp b/src/citra_qt/hotkeys.cpp
index 322c25c9e..5ed6cf0b1 100644
--- a/src/citra_qt/hotkeys.cpp
+++ b/src/citra_qt/hotkeys.cpp
@@ -2,10 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map>
6
5#include <QKeySequence> 7#include <QKeySequence>
6#include <QSettings> 8#include <QSettings>
9#include <QShortcut>
10
7#include "hotkeys.h" 11#include "hotkeys.h"
8#include <map>
9 12
10struct Hotkey 13struct Hotkey
11{ 14{
diff --git a/src/citra_qt/hotkeys.h b/src/citra_qt/hotkeys.h
index 75c7cc625..2317f8188 100644
--- a/src/citra_qt/hotkeys.h
+++ b/src/citra_qt/hotkeys.h
@@ -2,12 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <QShortcut>
6#include <QDialog>
7#include "ui_hotkeys.h" 5#include "ui_hotkeys.h"
8 6
7class QDialog;
9class QKeySequence; 8class QKeySequence;
10class QSettings; 9class QSettings;
10class QShortcut;
11 11
12/** 12/**
13 * Register a hotkey. 13 * Register a hotkey.
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index 8041816a0..2746de779 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -10,18 +10,16 @@
10#include "qhexedit.h" 10#include "qhexedit.h"
11#include "main.h" 11#include "main.h"
12 12
13#include "common/string_util.h"
13#include "common/logging/text_formatter.h" 14#include "common/logging/text_formatter.h"
14#include "common/logging/log.h" 15#include "common/logging/log.h"
15#include "common/logging/backend.h" 16#include "common/logging/backend.h"
16#include "common/logging/filter.h" 17#include "common/logging/filter.h"
17#include "common/make_unique.h" 18#include "common/make_unique.h"
18#include "common/platform.h" 19#include "common/platform.h"
20#include "common/scm_rev.h"
19#include "common/scope_exit.h" 21#include "common/scope_exit.h"
20 22
21#if EMU_PLATFORM == PLATFORM_LINUX
22#include <unistd.h>
23#endif
24
25#include "bootmanager.h" 23#include "bootmanager.h"
26#include "hotkeys.h" 24#include "hotkeys.h"
27 25
@@ -34,6 +32,7 @@
34#include "debugger/graphics_breakpoints.h" 32#include "debugger/graphics_breakpoints.h"
35#include "debugger/graphics_cmdlists.h" 33#include "debugger/graphics_cmdlists.h"
36#include "debugger/graphics_framebuffer.h" 34#include "debugger/graphics_framebuffer.h"
35#include "debugger/graphics_tracing.h"
37#include "debugger/graphics_vertex_shader.h" 36#include "debugger/graphics_vertex_shader.h"
38#include "debugger/profiler.h" 37#include "debugger/profiler.h"
39 38
@@ -96,6 +95,10 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
96 addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget); 95 addDockWidget(Qt::RightDockWidgetArea, graphicsVertexShaderWidget);
97 graphicsVertexShaderWidget->hide(); 96 graphicsVertexShaderWidget->hide();
98 97
98 auto graphicsTracingWidget = new GraphicsTracingWidget(Pica::g_debug_context, this);
99 addDockWidget(Qt::RightDockWidgetArea, graphicsTracingWidget);
100 graphicsTracingWidget->hide();
101
99 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging")); 102 QMenu* debug_menu = ui.menu_View->addMenu(tr("Debugging"));
100 debug_menu->addAction(profilerWidget->toggleViewAction()); 103 debug_menu->addAction(profilerWidget->toggleViewAction());
101 debug_menu->addAction(disasmWidget->toggleViewAction()); 104 debug_menu->addAction(disasmWidget->toggleViewAction());
@@ -106,6 +109,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
106 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction()); 109 debug_menu->addAction(graphicsBreakpointsWidget->toggleViewAction());
107 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction()); 110 debug_menu->addAction(graphicsFramebufferWidget->toggleViewAction());
108 debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction()); 111 debug_menu->addAction(graphicsVertexShaderWidget->toggleViewAction());
112 debug_menu->addAction(graphicsTracingWidget->toggleViewAction());
109 113
110 // Set default UI state 114 // Set default UI state
111 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half 115 // geometry: 55% of the window contents are in the upper screen half, 45% in the lower half
@@ -150,6 +154,9 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
150 connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping())); 154 connect(this, SIGNAL(EmulationStopping()), registersWidget, SLOT(OnEmulationStopping()));
151 connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*))); 155 connect(this, SIGNAL(EmulationStarting(EmuThread*)), render_window, SLOT(OnEmulationStarting(EmuThread*)));
152 connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping())); 156 connect(this, SIGNAL(EmulationStopping()), render_window, SLOT(OnEmulationStopping()));
157 connect(this, SIGNAL(EmulationStarting(EmuThread*)), graphicsTracingWidget, SLOT(OnEmulationStarting(EmuThread*)));
158 connect(this, SIGNAL(EmulationStopping()), graphicsTracingWidget, SLOT(OnEmulationStopping()));
159
153 160
154 // Setup hotkeys 161 // Setup hotkeys
155 RegisterHotkey("Main Window", "Load File", QKeySequence::Open); 162 RegisterHotkey("Main Window", "Load File", QKeySequence::Open);
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index e78f4f144..4c086cd2f 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -31,7 +31,6 @@ set(HEADERS
31 cpu_detect.h 31 cpu_detect.h
32 debug_interface.h 32 debug_interface.h
33 emu_window.h 33 emu_window.h
34 fifo_queue.h
35 file_util.h 34 file_util.h
36 key_map.h 35 key_map.h
37 linear_disk_cache.h 36 linear_disk_cache.h
@@ -53,7 +52,6 @@ set(HEADERS
53 synchronized_wrapper.h 52 synchronized_wrapper.h
54 thread.h 53 thread.h
55 thread_queue_list.h 54 thread_queue_list.h
56 thunk.h
57 timer.h 55 timer.h
58 vector_math.h 56 vector_math.h
59 ) 57 )
diff --git a/src/common/assert.h b/src/common/assert.h
index 7b7d8bf28..6849778b7 100644
--- a/src/common/assert.h
+++ b/src/common/assert.h
@@ -4,7 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstdio>
8#include <cstdlib> 7#include <cstdlib>
9 8
10#include "common/common_funcs.h" 9#include "common/common_funcs.h"
diff --git a/src/common/bit_field.h b/src/common/bit_field.h
index 1f3ecf844..f64ebdaf6 100644
--- a/src/common/bit_field.h
+++ b/src/common/bit_field.h
@@ -32,6 +32,7 @@
32 32
33#pragma once 33#pragma once
34 34
35#include <cstddef>
35#include <limits> 36#include <limits>
36#include <type_traits> 37#include <type_traits>
37 38
@@ -160,7 +161,7 @@ public:
160 if (std::numeric_limits<T>::is_signed) 161 if (std::numeric_limits<T>::is_signed)
161 { 162 {
162 std::size_t shift = 8 * sizeof(T)-bits; 163 std::size_t shift = 8 * sizeof(T)-bits;
163 return (T)(((storage & GetMask()) << (shift - position)) >> shift); 164 return (T)((storage << (shift - position)) >> shift);
164 } 165 }
165 else 166 else
166 { 167 {
@@ -188,7 +189,7 @@ private:
188 189
189 __forceinline StorageType GetMask() const 190 __forceinline StorageType GetMask() const
190 { 191 {
191 return ((~(StorageTypeU)0) >> (8 * sizeof(T)-bits)) << position; 192 return (((StorageTypeU)~0) >> (8 * sizeof(T)-bits)) << position;
192 } 193 }
193 194
194 StorageType storage; 195 StorageType storage;
diff --git a/src/common/chunk_file.h b/src/common/chunk_file.h
index dcd80525e..8be0b1109 100644
--- a/src/common/chunk_file.h
+++ b/src/common/chunk_file.h
@@ -26,16 +26,18 @@
26// - Zero backwards/forwards compatibility 26// - Zero backwards/forwards compatibility
27// - Serialization code for anything complex has to be manually written. 27// - Serialization code for anything complex has to be manually written.
28 28
29#include <map> 29#include <cstring>
30#include <vector>
31#include <deque> 30#include <deque>
32#include <string>
33#include <list> 31#include <list>
32#include <map>
34#include <set> 33#include <set>
34#include <string>
35#include <type_traits> 35#include <type_traits>
36#include <utility>
37#include <vector>
36 38
39#include "common/assert.h"
37#include "common/common_types.h" 40#include "common/common_types.h"
38#include "common/file_util.h"
39#include "common/logging/log.h" 41#include "common/logging/log.h"
40 42
41template <class T> 43template <class T>
diff --git a/src/common/color.h b/src/common/color.h
index 422fdc8af..9dafdca0c 100644
--- a/src/common/color.h
+++ b/src/common/color.h
@@ -208,7 +208,32 @@ inline void EncodeD24(u32 value, u8* bytes) {
208 * @param bytes Pointer where to store the encoded value 208 * @param bytes Pointer where to store the encoded value
209 */ 209 */
210inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) { 210inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) {
211 *reinterpret_cast<u32_le*>(bytes) = (stencil << 24) | depth; 211 bytes[0] = depth & 0xFF;
212 bytes[1] = (depth >> 8) & 0xFF;
213 bytes[2] = (depth >> 16) & 0xFF;
214 bytes[3] = stencil;
215}
216
217/**
218 * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused)
219 * @param depth 24 bit source depth value to encode
220 * @param bytes Pointer where to store the encoded value
221 * @note unused bits will not be modified
222 */
223inline void EncodeD24X8(u32 depth, u8* bytes) {
224 bytes[0] = depth & 0xFF;
225 bytes[1] = (depth >> 8) & 0xFF;
226 bytes[2] = (depth >> 16) & 0xFF;
227}
228
229/**
230 * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused)
231 * @param stencil 8 bit source stencil value to encode
232 * @param bytes Pointer where to store the encoded value
233 * @note unused bits will not be modified
234 */
235inline void EncodeX24S8(u8 stencil, u8* bytes) {
236 bytes[3] = stencil;
212} 237}
213 238
214} // namespace 239} // namespace
diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h
index 91b74c6bc..59bd16dbf 100644
--- a/src/common/common_funcs.h
+++ b/src/common/common_funcs.h
@@ -5,15 +5,6 @@
5#pragma once 5#pragma once
6 6
7#include "common_types.h" 7#include "common_types.h"
8#include <cstdlib>
9
10
11#define b2(x) ( (x) | ( (x) >> 1) )
12#define b4(x) ( b2(x) | ( b2(x) >> 2) )
13#define b8(x) ( b4(x) | ( b4(x) >> 4) )
14#define b16(x) ( b8(x) | ( b8(x) >> 8) )
15#define b32(x) (b16(x) | (b16(x) >>16) )
16#define ROUND_UP_POW2(x) (b32(x - 1) + 1)
17 8
18#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 9#define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0]))
19 10
@@ -43,8 +34,6 @@
43 34
44#ifndef _MSC_VER 35#ifndef _MSC_VER
45 36
46#include <errno.h>
47
48#if defined(__x86_64__) || defined(_M_X64) 37#if defined(__x86_64__) || defined(_M_X64)
49#define Crash() __asm__ __volatile__("int $3") 38#define Crash() __asm__ __volatile__("int $3")
50#elif defined(_M_ARM) 39#elif defined(_M_ARM)
@@ -80,8 +69,10 @@ inline u64 _rotr64(u64 x, unsigned int shift){
80} 69}
81 70
82#else // _MSC_VER 71#else // _MSC_VER
83 // Function Cross-Compatibility 72 #if (_MSC_VER < 1900)
84 #define snprintf _snprintf 73 // Function Cross-Compatibility
74 #define snprintf _snprintf
75 #endif
85 76
86 // Locale Cross-Compatibility 77 // Locale Cross-Compatibility
87 #define locale_t _locale_t 78 #define locale_t _locale_t
diff --git a/src/common/common_types.h b/src/common/common_types.h
index f6de0adfc..fa3e0b8d6 100644
--- a/src/common/common_types.h
+++ b/src/common/common_types.h
@@ -24,9 +24,7 @@
24 24
25#pragma once 25#pragma once
26 26
27#include <cmath>
28#include <cstdint> 27#include <cstdint>
29#include <cstdlib>
30 28
31#ifdef _MSC_VER 29#ifdef _MSC_VER
32#ifndef __func__ 30#ifndef __func__
@@ -52,32 +50,6 @@ typedef double f64; ///< 64-bit floating point
52typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space. 50typedef u32 VAddr; ///< Represents a pointer in the userspace virtual address space.
53typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space. 51typedef u32 PAddr; ///< Represents a pointer in the ARM11 physical address space.
54 52
55/// Union for fast 16-bit type casting
56union t16 {
57 u8 _u8[2]; ///< 8-bit unsigned char(s)
58 u16 _u16; ///< 16-bit unsigned shorts(s)
59};
60
61/// Union for fast 32-bit type casting
62union t32 {
63 f32 _f32; ///< 32-bit floating point(s)
64 u32 _u32; ///< 32-bit unsigned int(s)
65 s32 _s32; ///< 32-bit signed int(s)
66 u16 _u16[2]; ///< 16-bit unsigned shorts(s)
67 u8 _u8[4]; ///< 8-bit unsigned char(s)
68};
69
70/// Union for fast 64-bit type casting
71union t64 {
72 f64 _f64; ///< 64-bit floating point
73 u64 _u64; ///< 64-bit unsigned long
74 f32 _f32[2]; ///< 32-bit floating point(s)
75 u32 _u32[2]; ///< 32-bit unsigned int(s)
76 s32 _s32[2]; ///< 32-bit signed int(s)
77 u16 _u16[4]; ///< 16-bit unsigned shorts(s)
78 u8 _u8[8]; ///< 8-bit unsigned char(s)
79};
80
81// An inheritable class to disallow the copy constructor and operator= functions 53// An inheritable class to disallow the copy constructor and operator= functions
82class NonCopyable { 54class NonCopyable {
83protected: 55protected:
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index 43facb85c..b69b05cb9 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -2,6 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cmath>
7
8#include "common/assert.h"
9#include "common/key_map.h"
10
5#include "emu_window.h" 11#include "emu_window.h"
6#include "video_core/video_core.h" 12#include "video_core/video_core.h"
7 13
diff --git a/src/common/emu_window.h b/src/common/emu_window.h
index 8eca6b5d5..a0ae4c9fa 100644
--- a/src/common/emu_window.h
+++ b/src/common/emu_window.h
@@ -4,11 +4,17 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <tuple>
8#include <utility>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8#include "common/key_map.h"
9#include "common/math_util.h" 11#include "common/math_util.h"
10#include "common/scm_rev.h" 12
11#include "common/string_util.h" 13#include "core/hle/service/hid/hid.h"
14
15namespace KeyMap {
16struct HostDeviceKey;
17}
12 18
13/** 19/**
14 * Abstraction class used to provide an interface between emulation code and the frontend 20 * Abstraction class used to provide an interface between emulation code and the frontend
diff --git a/src/common/fifo_queue.h b/src/common/fifo_queue.h
deleted file mode 100644
index b426e6596..000000000
--- a/src/common/fifo_queue.h
+++ /dev/null
@@ -1,111 +0,0 @@
1#pragma once
2
3// a simple lockless thread-safe,
4// single reader, single writer queue
5
6#include "common/atomic.h"
7
8namespace Common
9{
10
11template <typename T>
12class FifoQueue
13{
14public:
15 FifoQueue() : m_size(0)
16 {
17 m_write_ptr = m_read_ptr = new ElementPtr();
18 }
19
20 ~FifoQueue()
21 {
22 // this will empty out the whole queue
23 delete m_read_ptr;
24 }
25
26 u32 Size() const
27 {
28 return m_size;
29 }
30
31 bool Empty() const
32 {
33 //return (m_read_ptr == m_write_ptr);
34 return (0 == m_size);
35 }
36
37 T& Front() const
38 {
39 return *m_read_ptr->current;
40 }
41
42 template <typename Arg>
43 void Push(Arg&& t)
44 {
45 // create the element, add it to the queue
46 m_write_ptr->current = new T(std::forward<Arg>(t));
47 // set the next pointer to a new element ptr
48 // then advance the write pointer
49 m_write_ptr = m_write_ptr->next = new ElementPtr();
50 Common::AtomicIncrement(m_size);
51 }
52
53 void Pop()
54 {
55 Common::AtomicDecrement(m_size);
56 ElementPtr *const tmpptr = m_read_ptr;
57 // advance the read pointer
58 m_read_ptr = m_read_ptr->next;
59 // set the next element to NULL to stop the recursive deletion
60 tmpptr->next = nullptr;
61 delete tmpptr; // this also deletes the element
62 }
63
64 bool Pop(T& t)
65 {
66 if (Empty())
67 return false;
68
69 t = std::move(Front());
70 Pop();
71
72 return true;
73 }
74
75 // not thread-safe
76 void Clear()
77 {
78 m_size = 0;
79 delete m_read_ptr;
80 m_write_ptr = m_read_ptr = new ElementPtr();
81 }
82
83private:
84 // stores a pointer to element
85 // and a pointer to the next ElementPtr
86 class ElementPtr
87 {
88 public:
89 ElementPtr() : current(nullptr), next(nullptr) {}
90
91 ~ElementPtr()
92 {
93 if (current)
94 {
95 delete current;
96 // recusion ftw
97 if (next)
98 delete next;
99 }
100 }
101
102 T *volatile current;
103 ElementPtr *volatile next;
104 };
105
106 ElementPtr *volatile m_write_ptr;
107 ElementPtr *volatile m_read_ptr;
108 volatile u32 m_size;
109};
110
111}
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 24648ea33..836b58d52 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -17,6 +17,8 @@
17 #include <direct.h> // getcwd 17 #include <direct.h> // getcwd
18 #include <tchar.h> 18 #include <tchar.h>
19 19
20 #include "common/string_util.h"
21
20 // 64 bit offsets for windows 22 // 64 bit offsets for windows
21 #define fseeko _fseeki64 23 #define fseeko _fseeki64
22 #define ftello _ftelli64 24 #define ftello _ftelli64
@@ -25,8 +27,13 @@
25 #define fstat64 _fstat64 27 #define fstat64 _fstat64
26 #define fileno _fileno 28 #define fileno _fileno
27#else 29#else
28 #include <sys/param.h> 30 #ifdef __APPLE__
29 #include <sys/types.h> 31 #include <sys/param.h>
32 #endif
33 #include <cctype>
34 #include <cerrno>
35 #include <cstdlib>
36 #include <cstring>
30 #include <dirent.h> 37 #include <dirent.h>
31 #include <pwd.h> 38 #include <pwd.h>
32 #include <unistd.h> 39 #include <unistd.h>
diff --git a/src/common/file_util.h b/src/common/file_util.h
index b65829291..d0dccdf69 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -6,13 +6,12 @@
6 6
7#include <array> 7#include <array>
8#include <fstream> 8#include <fstream>
9#include <cstddef>
9#include <cstdio> 10#include <cstdio>
10#include <cstring>
11#include <string> 11#include <string>
12#include <vector> 12#include <vector>
13 13
14#include "common/common_types.h" 14#include "common/common_types.h"
15#include "common/string_util.h"
16 15
17// User directory indices for GetUserPath 16// User directory indices for GetUserPath
18enum { 17enum {
@@ -117,9 +116,6 @@ bool SetCurrentDir(const std::string &directory);
117// directory. To be used in "multi-user" mode (that is, installed). 116// directory. To be used in "multi-user" mode (that is, installed).
118const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath=""); 117const std::string& GetUserPath(const unsigned int DirIDX, const std::string &newPath="");
119 118
120// probably doesn't belong here
121//std::string GetThemeDir(const std::string& theme_name);
122
123// Returns the path to where the sys file are 119// Returns the path to where the sys file are
124std::string GetSysDirectory(); 120std::string GetSysDirectory();
125 121
@@ -182,6 +178,10 @@ public:
182 template <typename T> 178 template <typename T>
183 size_t WriteArray(const T* data, size_t length) 179 size_t WriteArray(const T* data, size_t length)
184 { 180 {
181 static_assert(std::is_standard_layout<T>::value, "Given array does not consist of standard layout objects");
182 // TODO: gcc 4.8 does not support is_trivially_copyable, but we really should check for it here.
183 //static_assert(std::is_trivially_copyable<T>::value, "Given array does not consist of trivially copyable objects");
184
185 if (!IsOpen()) { 185 if (!IsOpen()) {
186 m_good = false; 186 m_good = false;
187 return -1; 187 return -1;
@@ -204,6 +204,12 @@ public:
204 return WriteArray(reinterpret_cast<const char*>(data), length); 204 return WriteArray(reinterpret_cast<const char*>(data), length);
205 } 205 }
206 206
207 template<typename T>
208 size_t WriteObject(const T& object) {
209 static_assert(!std::is_pointer<T>::value, "Given object is a pointer");
210 return WriteArray(&object, 1);
211 }
212
207 bool IsOpen() { return nullptr != m_file; } 213 bool IsOpen() { return nullptr != m_file; }
208 214
209 // m_good is set to false when a read, write or other function fails 215 // m_good is set to false when a read, write or other function fails
diff --git a/src/common/logging/filter.h b/src/common/logging/filter.h
index 0b71ea3b2..a2b4eca43 100644
--- a/src/common/logging/filter.h
+++ b/src/common/logging/filter.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cstddef>
8#include <string> 9#include <string>
9 10
10#include "common/logging/log.h" 11#include "common/logging/log.h"
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 5b3a731e9..e16dde7fc 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -4,10 +4,6 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cassert>
8#include <chrono>
9#include <string>
10
11#include "common/common_types.h" 7#include "common/common_types.h"
12 8
13namespace Log { 9namespace Log {
diff --git a/src/common/make_unique.h b/src/common/make_unique.h
index 2a7b76412..f6e7f017c 100644
--- a/src/common/make_unique.h
+++ b/src/common/make_unique.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <memory> 8#include <memory>
8 9
9namespace Common { 10namespace Common {
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
index 20b791a10..2b3ace528 100644
--- a/src/common/memory_util.cpp
+++ b/src/common/memory_util.cpp
@@ -3,14 +3,17 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5 5
6#include "common/common_funcs.h"
7#include "common/logging/log.h" 6#include "common/logging/log.h"
8#include "common/memory_util.h" 7#include "common/memory_util.h"
9#include "common/string_util.h"
10 8
11#ifdef _WIN32 9#ifdef _WIN32
12#include <windows.h> 10 #include <windows.h>
13#include <psapi.h> 11 #include <psapi.h>
12 #include "common/common_funcs.h"
13 #include "common/string_util.h"
14#else
15 #include <cstdlib>
16 #include <sys/mman.h>
14#endif 17#endif
15 18
16#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT) 19#if !defined(_WIN32) && defined(__x86_64__) && !defined(MAP_32BIT)
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
index 9fdbf1f12..9bf37c44f 100644
--- a/src/common/memory_util.h
+++ b/src/common/memory_util.h
@@ -4,9 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#ifndef _WIN32 7#include <cstddef>
8#include <sys/mman.h>
9#endif
10#include <string> 8#include <string>
11 9
12void* AllocateExecutableMemory(size_t size, bool low = true); 10void* AllocateExecutableMemory(size_t size, bool low = true);
diff --git a/src/common/misc.cpp b/src/common/misc.cpp
index 53cacf37c..d2a049b63 100644
--- a/src/common/misc.cpp
+++ b/src/common/misc.cpp
@@ -2,12 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_funcs.h" 5#include <cstddef>
6 6
7#ifdef _WIN32 7#ifdef _WIN32
8#include <windows.h> 8#include <windows.h>
9#else 9#else
10#include <string.h> 10#include <cerrno>
11#include <cstring>
11#endif 12#endif
12 13
13// Neither Android nor OS X support TLS 14// Neither Android nor OS X support TLS
diff --git a/src/common/platform.h b/src/common/platform.h
index df780ac6f..0a912dda3 100644
--- a/src/common/platform.h
+++ b/src/common/platform.h
@@ -24,66 +24,11 @@
24 24
25#pragma once 25#pragma once
26 26
27#include "common/common_types.h"
28
29////////////////////////////////////////////////////////////////////////////////////////////////////
30// Platform definitions
31
32/// Enumeration for defining the supported platforms
33#define PLATFORM_NULL 0
34#define PLATFORM_WINDOWS 1
35#define PLATFORM_MACOSX 2
36#define PLATFORM_LINUX 3
37#define PLATFORM_ANDROID 4
38
39//////////////////////////////////////////////////////////////////////////////////////////////////// 27////////////////////////////////////////////////////////////////////////////////////////////////////
40// Platform detection 28// Platform detection
41 29
42#ifndef EMU_PLATFORM
43
44#if defined( __WIN32__ ) || defined( _WIN32 )
45#define EMU_PLATFORM PLATFORM_WINDOWS
46
47#elif defined( __APPLE__ ) || defined( __APPLE_CC__ )
48#define EMU_PLATFORM PLATFORM_MACOSX
49
50#elif defined(__linux__)
51#define EMU_PLATFORM PLATFORM_LINUX
52
53#else // Assume linux otherwise
54#define EMU_PLATFORM PLATFORM_LINUX
55
56#endif
57
58#endif
59
60#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) 30#if defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__)
61 #define EMU_ARCH_BITS 64 31 #define EMU_ARCH_BITS 64
62#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM) 32#elif defined(__i386) || defined(_M_IX86) || defined(__arm__) || defined(_M_ARM)
63 #define EMU_ARCH_BITS 32 33 #define EMU_ARCH_BITS 32
64#endif 34#endif
65
66////////////////////////////////////////////////////////////////////////////////////////////////////
67// Feature detection
68
69#if defined _M_GENERIC
70# define _M_SSE 0x0
71#elif defined __GNUC__
72# if defined __SSE4_2__
73# define _M_SSE 0x402
74# elif defined __SSE4_1__
75# define _M_SSE 0x401
76# elif defined __SSSE3__
77# define _M_SSE 0x301
78# elif defined __SSE3__
79# define _M_SSE 0x300
80# endif
81#elif (_MSC_VER >= 1500) || __INTEL_COMPILER // Visual Studio 2008
82# define _M_SSE 0x402
83#endif
84
85////////////////////////////////////////////////////////////////////////////////////////////////////
86// Compiler-Specific Definitions
87
88#define GCC_VERSION_AVAILABLE(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || \
89 (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))
diff --git a/src/common/profiler.cpp b/src/common/profiler.cpp
index cf6b6b258..7792edd2f 100644
--- a/src/common/profiler.cpp
+++ b/src/common/profiler.cpp
@@ -2,13 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstddef>
7#include <vector>
8
9#include "common/assert.h"
5#include "common/profiler.h" 10#include "common/profiler.h"
6#include "common/profiler_reporting.h" 11#include "common/profiler_reporting.h"
7#include "common/assert.h" 12#include "common/synchronized_wrapper.h"
8 13
9#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013. 14#if defined(_MSC_VER) && _MSC_VER <= 1800 // MSVC 2013.
10#define WIN32_LEAN_AND_MEAN 15 #define WIN32_LEAN_AND_MEAN
11#include <Windows.h> // For QueryPerformanceCounter/Frequency 16 #include <Windows.h> // For QueryPerformanceCounter/Frequency
12#endif 17#endif
13 18
14namespace Common { 19namespace Common {
diff --git a/src/common/profiler_reporting.h b/src/common/profiler_reporting.h
index 3abb73315..df98e05b7 100644
--- a/src/common/profiler_reporting.h
+++ b/src/common/profiler_reporting.h
@@ -4,10 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <cstddef>
8#include <chrono>
9#include <mutex>
10#include <utility>
11#include <vector> 8#include <vector>
12 9
13#include "common/profiler.h" 10#include "common/profiler.h"
diff --git a/src/common/string_util.cpp b/src/common/string_util.cpp
index 7dc0ba7ba..b2f7f7b1d 100644
--- a/src/common/string_util.cpp
+++ b/src/common/string_util.cpp
@@ -2,9 +2,13 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <boost/range/algorithm.hpp> 5#include <cctype>
6#include <cerrno>
7#include <cstdio>
8#include <cstdlib>
9#include <cstring>
10#include <boost/range/algorithm/transform.hpp>
6 11
7#include "common/common_funcs.h"
8#include "common/common_paths.h" 12#include "common/common_paths.h"
9#include "common/logging/log.h" 13#include "common/logging/log.h"
10#include "common/string_util.h" 14#include "common/string_util.h"
@@ -12,6 +16,7 @@
12#ifdef _MSC_VER 16#ifdef _MSC_VER
13 #include <Windows.h> 17 #include <Windows.h>
14 #include <codecvt> 18 #include <codecvt>
19 #include "common/common_funcs.h"
15#else 20#else
16 #include <iconv.h> 21 #include <iconv.h>
17#endif 22#endif
@@ -308,7 +313,7 @@ static std::string UTF16ToUTF8(const std::wstring& input)
308 std::string output; 313 std::string output;
309 output.resize(size); 314 output.resize(size);
310 315
311 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), input.size(), &output[0], output.size(), nullptr, nullptr)) 316 if (size == 0 || size != WideCharToMultiByte(CP_UTF8, 0, input.data(), static_cast<int>(input.size()), &output[0], static_cast<int>(output.size()), nullptr, nullptr))
312 output.clear(); 317 output.clear();
313 318
314 return output; 319 return output;
diff --git a/src/common/string_util.h b/src/common/string_util.h
index fdc410499..c5c474c6f 100644
--- a/src/common/string_util.h
+++ b/src/common/string_util.h
@@ -5,9 +5,10 @@
5#pragma once 5#pragma once
6 6
7#include <cstdarg> 7#include <cstdarg>
8#include <cstddef>
8#include <iomanip> 9#include <iomanip>
9#include <string>
10#include <sstream> 10#include <sstream>
11#include <string>
11#include <vector> 12#include <vector>
12 13
13#include "common/common_types.h" 14#include "common/common_types.h"
diff --git a/src/common/swap.h b/src/common/swap.h
index 588cebc70..b92e5bfa4 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -17,12 +17,16 @@
17 17
18#pragma once 18#pragma once
19 19
20#if defined(__linux__) 20#if defined(_MSC_VER)
21#include <byteswap.h> 21 #include <cstdlib>
22#elif defined(__linux__)
23 #include <byteswap.h>
22#elif defined(__FreeBSD__) 24#elif defined(__FreeBSD__)
23#include <sys/endian.h> 25 #include <sys/endian.h>
24#endif 26#endif
25 27
28#include "common/common_types.h"
29
26// GCC 4.6+ 30// GCC 4.6+
27#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) 31#if __GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)
28 32
diff --git a/src/common/synchronized_wrapper.h b/src/common/synchronized_wrapper.h
index 946252b8c..ae5e8b1ed 100644
--- a/src/common/synchronized_wrapper.h
+++ b/src/common/synchronized_wrapper.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
7#include <mutex> 8#include <mutex>
8 9
9namespace Common { 10namespace Common {
diff --git a/src/common/thread.cpp b/src/common/thread.cpp
index 8bf005857..7bbf080bc 100644
--- a/src/common/thread.cpp
+++ b/src/common/thread.cpp
@@ -5,11 +5,20 @@
5#include "common/thread.h" 5#include "common/thread.h"
6 6
7#ifdef __APPLE__ 7#ifdef __APPLE__
8#include <mach/mach.h> 8 #include <mach/mach.h>
9#elif defined(BSD4_4) || defined(__OpenBSD__)
10#include <pthread_np.h>
11#elif defined(_WIN32) 9#elif defined(_WIN32)
12#include <Windows.h> 10 #include <Windows.h>
11#else
12 #if defined(BSD4_4) || defined(__OpenBSD__)
13 #include <pthread_np.h>
14 #else
15 #include <pthread.h>
16 #endif
17 #include <sched.h>
18#endif
19
20#ifndef _WIN32
21 #include <unistd.h>
13#endif 22#endif
14 23
15namespace Common 24namespace Common
diff --git a/src/common/thread.h b/src/common/thread.h
index 7bc419497..8255ee6d3 100644
--- a/src/common/thread.h
+++ b/src/common/thread.h
@@ -4,24 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include <cstddef>
8#include <cstdio>
9#include <cstring>
10#include <thread> 8#include <thread>
11#include <condition_variable> 9#include <condition_variable>
12#include <mutex> 10#include <mutex>
13 11
14// This may not be defined outside _WIN32 12#include "common/common_types.h"
15#ifndef _WIN32
16#ifndef INFINITE
17#define INFINITE 0xffffffff
18#endif
19
20//for gettimeofday and struct time(spec|val)
21#include <time.h>
22#include <sys/time.h>
23#include <unistd.h>
24#endif
25 13
26// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very 14// Support for C++11's thread_local keyword was surprisingly spotty in compilers until very
27// recently. Fortunately, thread local variables have been well supported for compilers for a while, 15// recently. Fortunately, thread local variables have been well supported for compilers for a while,
diff --git a/src/common/thunk.h b/src/common/thunk.h
deleted file mode 100644
index 533480056..000000000
--- a/src/common/thunk.h
+++ /dev/null
@@ -1,42 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <map>
8
9#include "common/common_types.h"
10
11// This simple class creates a wrapper around a C/C++ function that saves all fp state
12// before entering it, and restores it upon exit. This is required to be able to selectively
13// call functions from generated code, without inflicting the performance hit and increase
14// of complexity that it means to protect the generated code from this problem.
15
16// This process is called thunking.
17
18// There will only ever be one level of thunking on the stack, plus,
19// we don't want to pollute the stack, so we store away regs somewhere global.
20// NOT THREAD SAFE. This may only be used from the CPU thread.
21// Any other thread using this stuff will be FATAL.
22
23class ThunkManager : public Gen::XCodeBlock
24{
25 std::map<void *, const u8 *> thunks;
26
27 const u8 *save_regs;
28 const u8 *load_regs;
29
30public:
31 ThunkManager() {
32 Init();
33 }
34 ~ThunkManager() {
35 Shutdown();
36 }
37 void *ProtectFunction(void *function, int num_params);
38private:
39 void Init();
40 void Shutdown();
41 void Reset();
42};
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4fcda4874..8267ee586 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -25,6 +25,8 @@ set(SRCS
25 file_sys/ivfc_archive.cpp 25 file_sys/ivfc_archive.cpp
26 hle/config_mem.cpp 26 hle/config_mem.cpp
27 hle/hle.cpp 27 hle/hle.cpp
28 hle/applets/applet.cpp
29 hle/applets/swkbd.cpp
28 hle/kernel/address_arbiter.cpp 30 hle/kernel/address_arbiter.cpp
29 hle/kernel/event.cpp 31 hle/kernel/event.cpp
30 hle/kernel/kernel.cpp 32 hle/kernel/kernel.cpp
@@ -113,6 +115,7 @@ set(SRCS
113 loader/elf.cpp 115 loader/elf.cpp
114 loader/loader.cpp 116 loader/loader.cpp
115 loader/ncch.cpp 117 loader/ncch.cpp
118 tracer/recorder.cpp
116 mem_map.cpp 119 mem_map.cpp
117 memory.cpp 120 memory.cpp
118 settings.cpp 121 settings.cpp
@@ -150,6 +153,8 @@ set(HEADERS
150 hle/config_mem.h 153 hle/config_mem.h
151 hle/function_wrappers.h 154 hle/function_wrappers.h
152 hle/hle.h 155 hle/hle.h
156 hle/applets/applet.h
157 hle/applets/swkbd.h
153 hle/kernel/address_arbiter.h 158 hle/kernel/address_arbiter.h
154 hle/kernel/event.h 159 hle/kernel/event.h
155 hle/kernel/kernel.h 160 hle/kernel/kernel.h
@@ -239,6 +244,8 @@ set(HEADERS
239 loader/elf.h 244 loader/elf.h
240 loader/loader.h 245 loader/loader.h
241 loader/ncch.h 246 loader/ncch.h
247 tracer/recorder.h
248 tracer/citrace.h
242 mem_map.h 249 mem_map.h
243 memory.h 250 memory.h
244 memory_setup.h 251 memory_setup.h
diff --git a/src/core/arm/disassembler/load_symbol_map.cpp b/src/core/arm/disassembler/load_symbol_map.cpp
index 13d26d170..eb20bf6f7 100644
--- a/src/core/arm/disassembler/load_symbol_map.cpp
+++ b/src/core/arm/disassembler/load_symbol_map.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sstream>
5#include <string> 6#include <string>
6#include <vector> 7#include <vector>
7 8
diff --git a/src/core/arm/dyncom/arm_dyncom.h b/src/core/arm/dyncom/arm_dyncom.h
index 2488c879c..cc9355722 100644
--- a/src/core/arm/dyncom/arm_dyncom.h
+++ b/src/core/arm/dyncom/arm_dyncom.h
@@ -10,6 +10,11 @@
10 10
11#include "core/arm/arm_interface.h" 11#include "core/arm/arm_interface.h"
12#include "core/arm/skyeye_common/armdefs.h" 12#include "core/arm/skyeye_common/armdefs.h"
13#include "core/arm/skyeye_common/arm_regformat.h"
14
15namespace Core {
16struct ThreadContext;
17}
13 18
14class ARM_DynCom final : virtual public ARM_Interface { 19class ARM_DynCom final : virtual public ARM_Interface {
15public: 20public:
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index b00eb49a9..785f39566 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -4144,11 +4144,13 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4144 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 4144 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
4145 bx_inst* const inst_cream = (bx_inst*)inst_base->component; 4145 bx_inst* const inst_cream = (bx_inst*)inst_base->component;
4146 4146
4147 u32 address = RM;
4148
4147 if (inst_cream->Rm == 15) 4149 if (inst_cream->Rm == 15)
4148 LOG_WARNING(Core_ARM11, "BX at pc %x: use of Rm = R15 is discouraged", cpu->Reg[15]); 4150 address += 2 * GET_INST_SIZE(cpu);
4149 4151
4150 cpu->TFlag = cpu->Reg[inst_cream->Rm] & 0x1; 4152 cpu->TFlag = address & 1;
4151 cpu->Reg[15] = cpu->Reg[inst_cream->Rm] & 0xfffffffe; 4153 cpu->Reg[15] = address & 0xfffffffe;
4152 INC_PC(sizeof(bx_inst)); 4154 INC_PC(sizeof(bx_inst));
4153 goto DISPATCH; 4155 goto DISPATCH;
4154 } 4156 }
@@ -5695,7 +5697,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5695 const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF); 5697 const s16 operand2 = (high) ? ((rm_val >> 16) & 0xFFFF) : (rm_val & 0xFFFF);
5696 const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16); 5698 const s64 result = (s64)(s32)rn_val * (s64)(s32)operand2 + ((s64)(s32)ra_val << 16);
5697 5699
5698 RD = (result & (0xFFFFFFFFFFFFFFFFLL >> 15)) >> 16; 5700 RD = BITS(result, 16, 47);
5699 5701
5700 if ((result >> 16) != (s32)RD) 5702 if ((result >> 16) != (s32)RD)
5701 cpu->Cpsr |= (1 << 27); 5703 cpu->Cpsr |= (1 << 27);
@@ -6246,7 +6248,8 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6246 SWI_INST: 6248 SWI_INST:
6247 { 6249 {
6248 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 6250 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
6249 SVC::CallSVC(Memory::Read32(cpu->Reg[15])); 6251 swi_inst* const inst_cream = (swi_inst*)inst_base->component;
6252 SVC::CallSVC(inst_cream->num & 0xFFFF);
6250 } 6253 }
6251 6254
6252 cpu->Reg[15] += GET_INST_SIZE(cpu); 6255 cpu->Reg[15] += GET_INST_SIZE(cpu);
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index 3e79c44c0..f10a5b70f 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -130,14 +130,13 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
130 } 130 }
131 } else { 131 } else {
132 ARMword Rd = ((tinstr & 0x0007) >> 0); 132 ARMword Rd = ((tinstr & 0x0007) >> 0);
133 ARMword Rs = ((tinstr & 0x0038) >> 3); 133 ARMword Rs = ((tinstr & 0x0078) >> 3);
134 134
135 if (tinstr & (1 << 7)) 135 if (tinstr & (1 << 7))
136 Rd += 8; 136 Rd += 8;
137 if (tinstr & (1 << 6))
138 Rs += 8;
139 137
140 switch ((tinstr & 0x03C0) >> 6) { 138 switch ((tinstr & 0x03C0) >> 6) {
139 case 0x0: // ADD Rd,Rd,Rs
141 case 0x1: // ADD Rd,Rd,Hs 140 case 0x1: // ADD Rd,Rd,Hs
142 case 0x2: // ADD Hd,Hd,Rs 141 case 0x2: // ADD Hd,Hd,Rs
143 case 0x3: // ADD Hd,Hd,Hs 142 case 0x3: // ADD Hd,Hd,Hs
@@ -146,19 +145,19 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
146 |(Rd << 12) // Rd 145 |(Rd << 12) // Rd
147 |(Rs << 0); // Rm 146 |(Rs << 0); // Rm
148 break; 147 break;
148 case 0x4: // CMP Rd,Rs
149 case 0x5: // CMP Rd,Hs 149 case 0x5: // CMP Rd,Hs
150 case 0x6: // CMP Hd,Rs 150 case 0x6: // CMP Hd,Rs
151 case 0x7: // CMP Hd,Hs 151 case 0x7: // CMP Hd,Hs
152 *ainstr = 0xE1500000 // base 152 *ainstr = 0xE1500000 // base
153 | (Rd << 16) // Rn 153 | (Rd << 16) // Rn
154 |(Rd << 12) // Rd
155 |(Rs << 0); // Rm 154 |(Rs << 0); // Rm
156 break; 155 break;
156 case 0x8: // MOV Rd,Rs
157 case 0x9: // MOV Rd,Hs 157 case 0x9: // MOV Rd,Hs
158 case 0xA: // MOV Hd,Rs 158 case 0xA: // MOV Hd,Rs
159 case 0xB: // MOV Hd,Hs 159 case 0xB: // MOV Hd,Hs
160 *ainstr = 0xE1A00000 // base 160 *ainstr = 0xE1A00000 // base
161 | (Rd << 16) // Rn
162 |(Rd << 12) // Rd 161 |(Rd << 12) // Rd
163 |(Rs << 0); // Rm 162 |(Rs << 0); // Rm
164 break; 163 break;
@@ -167,11 +166,6 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
167 *ainstr = 0xE12FFF10 // base 166 *ainstr = 0xE12FFF10 // base
168 | ((tinstr & 0x0078) >> 3); // Rd 167 | ((tinstr & 0x0078) >> 3); // Rd
169 break; 168 break;
170 case 0x0: // UNDEFINED
171 case 0x4: // UNDEFINED
172 case 0x8: // UNDEFINED
173 valid = t_undefined;
174 break;
175 case 0xE: // BLX 169 case 0xE: // BLX
176 case 0xF: // BLX 170 case 0xF: // BLX
177 *ainstr = 0xE1200030 // base 171 *ainstr = 0xE1200030 // base
diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h
index a92effbb4..d1c721809 100644
--- a/src/core/arm/skyeye_common/arm_regformat.h
+++ b/src/core/arm/skyeye_common/arm_regformat.h
@@ -59,6 +59,8 @@ enum {
59 VFP_FPSID, 59 VFP_FPSID,
60 VFP_FPSCR, 60 VFP_FPSCR,
61 VFP_FPEXC, 61 VFP_FPEXC,
62 VFP_FPINST,
63 VFP_FPINST2,
62 VFP_MVFR0, 64 VFP_MVFR0,
63 VFP_MVFR1, 65 VFP_MVFR1,
64 66
diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp
index 571d6c2f2..1ffc1f9af 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfp.cpp
@@ -20,36 +20,27 @@
20 20
21/* Note: this file handles interface with arm core and vfp registers */ 21/* Note: this file handles interface with arm core and vfp registers */
22 22
23#include "common/common_funcs.h"
23#include "common/logging/log.h" 24#include "common/logging/log.h"
24 25
25#include "core/arm/skyeye_common/armdefs.h" 26#include "core/arm/skyeye_common/armdefs.h"
26#include "core/arm/skyeye_common/vfp/asm_vfp.h" 27#include "core/arm/skyeye_common/vfp/asm_vfp.h"
27#include "core/arm/skyeye_common/vfp/vfp.h" 28#include "core/arm/skyeye_common/vfp/vfp.h"
28 29
29unsigned VFPInit(ARMul_State* state) 30void VFPInit(ARMul_State* state)
30{ 31{
31 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 | 32 state->VFP[VFP_FPSID] = VFP_FPSID_IMPLMEN<<24 | VFP_FPSID_SW<<23 | VFP_FPSID_SUBARCH<<16 |
32 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION; 33 VFP_FPSID_PARTNUM<<8 | VFP_FPSID_VARIANT<<4 | VFP_FPSID_REVISION;
33 state->VFP[VFP_FPEXC] = 0; 34 state->VFP[VFP_FPEXC] = 0;
34 state->VFP[VFP_FPSCR] = 0; 35 state->VFP[VFP_FPSCR] = 0;
35 36
37 // ARM11 MPCore instruction register reset values.
38 state->VFP[VFP_FPINST] = 0xEE000A00;
39 state->VFP[VFP_FPINST2] = 0;
40
36 // ARM11 MPCore feature register values. 41 // ARM11 MPCore feature register values.
37 state->VFP[VFP_MVFR0] = 0x11111111; 42 state->VFP[VFP_MVFR0] = 0x11111111;
38 state->VFP[VFP_MVFR1] = 0; 43 state->VFP[VFP_MVFR1] = 0;
39
40 return 0;
41}
42
43void VMSR(ARMul_State* state, ARMword reg, ARMword Rt)
44{
45 if (reg == 1)
46 {
47 state->VFP[VFP_FPSCR] = state->Reg[Rt];
48 }
49 else if (reg == 8)
50 {
51 state->VFP[VFP_FPEXC] = state->Reg[Rt];
52 }
53} 44}
54 45
55void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value) 46void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value)
@@ -153,9 +144,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
153 LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions); 144 LOG_TRACE(Core_ARM11, "VFP: raising exceptions %08x\n", exceptions);
154 145
155 if (exceptions == VFP_EXCEPTION_ERROR) { 146 if (exceptions == VFP_EXCEPTION_ERROR) {
156 LOG_TRACE(Core_ARM11, "unhandled bounce %x\n", inst); 147 LOG_CRITICAL(Core_ARM11, "unhandled bounce %x\n", inst);
157 exit(-1); 148 Crash();
158 return;
159 } 149 }
160 150
161 /* 151 /*
diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h
index acefae9bb..80ca93ccd 100644
--- a/src/core/arm/skyeye_common/vfp/vfp.h
+++ b/src/core/arm/skyeye_common/vfp/vfp.h
@@ -26,7 +26,7 @@
26#define CHECK_VFP_ENABLED 26#define CHECK_VFP_ENABLED
27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); 27#define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]);
28 28
29unsigned VFPInit(ARMul_State* state); 29void VFPInit(ARMul_State* state);
30 30
31s32 vfp_get_float(ARMul_State* state, u32 reg); 31s32 vfp_get_float(ARMul_State* state, u32 reg);
32void vfp_put_float(ARMul_State* state, s32 val, u32 reg); 32void vfp_put_float(ARMul_State* state, s32 val, u32 reg);
@@ -36,10 +36,8 @@ void vfp_raise_exceptions(ARMul_State* state, u32 exceptions, u32 inst, u32 fpsc
36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 36u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr); 37u32 vfp_double_cpdo(ARMul_State* state, u32 inst, u32 fpscr);
38 38
39void VMSR(ARMul_State* state, ARMword reg, ARMword Rt);
40void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value); 39void VMOVBRS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword n, ARMword* value);
41void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); 40void VMOVBRRD(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
42void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2); 41void VMOVBRRSS(ARMul_State* state, ARMword to_arm, ARMword t, ARMword t2, ARMword n, ARMword* value1, ARMword* value2);
43void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm); 42void VMOVI(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
44void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm); 43void VMOVR(ARMul_State* state, ARMword single, ARMword d, ARMword imm);
45
diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
index 67fe63aa4..8efcbab1c 100644
--- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp
@@ -995,7 +995,7 @@ VMOVBRS_INST:
995#ifdef VFP_INTERPRETER_STRUCT 995#ifdef VFP_INTERPRETER_STRUCT
996struct vmsr_inst { 996struct vmsr_inst {
997 unsigned int reg; 997 unsigned int reg;
998 unsigned int Rd; 998 unsigned int Rt;
999}; 999};
1000#endif 1000#endif
1001#ifdef VFP_INTERPRETER_TRANS 1001#ifdef VFP_INTERPRETER_TRANS
@@ -1009,7 +1009,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
1009 inst_base->br = NON_BRANCH; 1009 inst_base->br = NON_BRANCH;
1010 1010
1011 inst_cream->reg = BITS(inst, 16, 19); 1011 inst_cream->reg = BITS(inst, 16, 19);
1012 inst_cream->Rd = BITS(inst, 12, 15); 1012 inst_cream->Rt = BITS(inst, 12, 15);
1013 1013
1014 return inst_base; 1014 return inst_base;
1015} 1015}
@@ -1017,15 +1017,30 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmsr)(unsigned int inst, int index)
1017#ifdef VFP_INTERPRETER_IMPL 1017#ifdef VFP_INTERPRETER_IMPL
1018VMSR_INST: 1018VMSR_INST:
1019{ 1019{
1020 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1020 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1021 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled , 1021 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled ,
1022 and in privileged mode */ 1022 and in privileged mode */
1023 /* Exceptions must be checked, according to v7 ref manual */ 1023 /* Exceptions must be checked, according to v7 ref manual */
1024 CHECK_VFP_ENABLED; 1024 CHECK_VFP_ENABLED;
1025 1025
1026 vmsr_inst *inst_cream = (vmsr_inst *)inst_base->component; 1026 vmsr_inst* const inst_cream = (vmsr_inst*)inst_base->component;
1027
1028 unsigned int reg = inst_cream->reg;
1029 unsigned int rt = inst_cream->Rt;
1027 1030
1028 VMSR(cpu, inst_cream->reg, inst_cream->Rd); 1031 if (reg == 1)
1032 {
1033 cpu->VFP[VFP_FPSCR] = cpu->Reg[rt];
1034 }
1035 else if (InAPrivilegedMode(cpu))
1036 {
1037 if (reg == 8)
1038 cpu->VFP[VFP_FPEXC] = cpu->Reg[rt];
1039 else if (reg == 9)
1040 cpu->VFP[VFP_FPINST] = cpu->Reg[rt];
1041 else if (reg == 10)
1042 cpu->VFP[VFP_FPINST2] = cpu->Reg[rt];
1043 }
1029 } 1044 }
1030 cpu->Reg[15] += GET_INST_SIZE(cpu); 1045 cpu->Reg[15] += GET_INST_SIZE(cpu);
1031 INC_PC(sizeof(vmsr_inst)); 1046 INC_PC(sizeof(vmsr_inst));
@@ -1111,19 +1126,22 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmrs)(unsigned int inst, int index)
1111#ifdef VFP_INTERPRETER_IMPL 1126#ifdef VFP_INTERPRETER_IMPL
1112VMRS_INST: 1127VMRS_INST:
1113{ 1128{
1114 if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { 1129 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
1115 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled, 1130 /* FIXME: special case for access to FPSID and FPEXC, VFP must be disabled,
1116 and in privileged mode */ 1131 and in privileged mode */
1117 /* Exceptions must be checked, according to v7 ref manual */ 1132 /* Exceptions must be checked, according to v7 ref manual */
1118 CHECK_VFP_ENABLED; 1133 CHECK_VFP_ENABLED;
1119 1134
1120 vmrs_inst *inst_cream = (vmrs_inst *)inst_base->component; 1135 vmrs_inst* const inst_cream = (vmrs_inst*)inst_base->component;
1121 1136
1122 if (inst_cream->reg == 1) /* FPSCR */ 1137 unsigned int reg = inst_cream->reg;
1138 unsigned int rt = inst_cream->Rt;
1139
1140 if (reg == 1) // FPSCR
1123 { 1141 {
1124 if (inst_cream->Rt != 15) 1142 if (rt != 15)
1125 { 1143 {
1126 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSCR]; 1144 cpu->Reg[rt] = cpu->VFP[VFP_FPSCR];
1127 } 1145 }
1128 else 1146 else
1129 { 1147 {
@@ -1133,25 +1151,26 @@ VMRS_INST:
1133 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1; 1151 cpu->VFlag = (cpu->VFP[VFP_FPSCR] >> 28) & 1;
1134 } 1152 }
1135 } 1153 }
1136 else 1154 else if (reg == 0)
1137 { 1155 {
1138 switch (inst_cream->reg) 1156 cpu->Reg[rt] = cpu->VFP[VFP_FPSID];
1139 { 1157 }
1140 case 0: 1158 else if (reg == 6)
1141 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; 1159 {
1142 break; 1160 cpu->Reg[rt] = cpu->VFP[VFP_MVFR1];
1143 case 6: 1161 }
1144 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1]; 1162 else if (reg == 7)
1145 break; 1163 {
1146 case 7: 1164 cpu->Reg[rt] = cpu->VFP[VFP_MVFR0];
1147 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0]; 1165 }
1148 break; 1166 else if (InAPrivilegedMode(cpu))
1149 case 8: 1167 {
1150 cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; 1168 if (reg == 8)
1151 break; 1169 cpu->Reg[rt] = cpu->VFP[VFP_FPEXC];
1152 default: 1170 else if (reg == 9)
1153 break; 1171 cpu->Reg[rt] = cpu->VFP[VFP_FPINST];
1154 } 1172 else if (reg == 10)
1173 cpu->Reg[rt] = cpu->VFP[VFP_FPINST2];
1155 } 1174 }
1156 } 1175 }
1157 cpu->Reg[15] += GET_INST_SIZE(cpu); 1176 cpu->Reg[15] += GET_INST_SIZE(cpu);
diff --git a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
index 5a655a6f2..e5d339252 100644
--- a/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
+++ b/src/core/arm/skyeye_common/vfp/vfpsingle.cpp
@@ -53,6 +53,8 @@
53 53
54#include <cinttypes> 54#include <cinttypes>
55 55
56#include "common/common_funcs.h"
57#include "common/common_types.h"
56#include "common/logging/log.h" 58#include "common/logging/log.h"
57 59
58#include "core/arm/skyeye_common/vfp/vfp_helper.h" 60#include "core/arm/skyeye_common/vfp/vfp_helper.h"
@@ -1246,7 +1248,7 @@ u32 vfp_single_cpdo(ARMul_State* state, u32 inst, u32 fpscr)
1246 1248
1247 if (!fop->fn) { 1249 if (!fop->fn) {
1248 LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]); 1250 LOG_CRITICAL(Core_ARM11, "could not find single op %d, inst=0x%x@0x%x", FEXT_TO_IDX(inst), inst, state->Reg[15]);
1249 exit(-1); 1251 Crash();
1250 goto invalid; 1252 goto invalid;
1251 } 1253 }
1252 1254
diff --git a/src/core/core.cpp b/src/core/core.cpp
index 79038cd52..dddc16708 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -2,15 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/common_types.h"
6#include "common/logging/log.h" 5#include "common/logging/log.h"
7 6
8#include "core/core.h" 7#include "core/core.h"
9#include "core/core_timing.h" 8#include "core/core_timing.h"
10 9
11#include "core/settings.h"
12#include "core/arm/arm_interface.h" 10#include "core/arm/arm_interface.h"
13#include "core/arm/disassembler/arm_disasm.h"
14#include "core/arm/dyncom/arm_dyncom.h" 11#include "core/arm/dyncom/arm_dyncom.h"
15#include "core/hle/hle.h" 12#include "core/hle/hle.h"
16#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index e53c2e606..20f2da0fe 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -3,12 +3,12 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <atomic> 5#include <atomic>
6#include <cstdio>
7#include <mutex> 6#include <mutex>
8#include <vector> 7#include <vector>
9 8
10#include "common/assert.h"
11#include "common/chunk_file.h" 9#include "common/chunk_file.h"
10#include "common/logging/log.h"
11#include "common/string_util.h"
12 12
13#include "core/arm/arm_interface.h" 13#include "core/arm/arm_interface.h"
14#include "core/core.h" 14#include "core/core.h"
@@ -502,7 +502,7 @@ void Advance() {
502 Core::g_app_core->down_count += diff; 502 Core::g_app_core->down_count += diff;
503 } 503 }
504 if (advance_callback) 504 if (advance_callback)
505 advance_callback(cycles_executed); 505 advance_callback(static_cast<int>(cycles_executed));
506} 506}
507 507
508void LogPendingEvents() { 508void LogPendingEvents() {
diff --git a/src/core/file_sys/archive_backend.cpp b/src/core/file_sys/archive_backend.cpp
index 45a559ce8..3f81447df 100644
--- a/src/core/file_sys/archive_backend.cpp
+++ b/src/core/file_sys/archive_backend.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstddef>
6#include <iomanip>
5#include <sstream> 7#include <sstream>
6 8
7#include "common/logging/log.h" 9#include "common/logging/log.h"
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index e50c58a52..92dad8e6f 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -2,17 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6#include <vector>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
9#include "common/logging/log.h" 10#include "common/logging/log.h"
10#include "common/make_unique.h" 11#include "common/make_unique.h"
12#include "common/string_util.h"
11 13
12#include "core/file_sys/archive_extsavedata.h" 14#include "core/file_sys/archive_extsavedata.h"
13#include "core/file_sys/disk_archive.h" 15#include "core/file_sys/disk_archive.h"
14#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
15#include "core/settings.h"
16 17
17//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
18// FileSys namespace 19// FileSys namespace
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index ef0b27bde..ec8d770fc 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -4,10 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8 11
9#include "core/file_sys/disk_archive.h" 12#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 13#include "core/hle/result.h"
11 14
12//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 16// FileSys namespace
diff --git a/src/core/file_sys/archive_romfs.cpp b/src/core/file_sys/archive_romfs.cpp
index d4a12ed10..696b51a94 100644
--- a/src/core/file_sys/archive_romfs.cpp
+++ b/src/core/file_sys/archive_romfs.cpp
@@ -2,30 +2,30 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <memory> 6#include <memory>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/make_unique.h" 10#include "common/make_unique.h"
11 11
12#include "core/file_sys/archive_romfs.h" 12#include "core/file_sys/archive_romfs.h"
13#include "core/file_sys/ivfc_archive.h"
13 14
14//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace 16// FileSys namespace
16 17
17namespace FileSys { 18namespace FileSys {
18 19
19ArchiveFactory_RomFS::ArchiveFactory_RomFS(const Loader::AppLoader& app_loader) 20ArchiveFactory_RomFS::ArchiveFactory_RomFS(Loader::AppLoader& app_loader) {
20 : romfs_data(std::make_shared<std::vector<u8>>()) {
21 // Load the RomFS from the app 21 // Load the RomFS from the app
22 if (Loader::ResultStatus::Success != app_loader.ReadRomFS(*romfs_data)) { 22 if (Loader::ResultStatus::Success != app_loader.ReadRomFS(romfs_file, data_offset, data_size)) {
23 LOG_ERROR(Service_FS, "Unable to read RomFS!"); 23 LOG_ERROR(Service_FS, "Unable to read RomFS!");
24 } 24 }
25} 25}
26 26
27ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) { 27ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_RomFS::Open(const Path& path) {
28 auto archive = Common::make_unique<IVFCArchive>(romfs_data); 28 auto archive = Common::make_unique<IVFCArchive>(romfs_file, data_offset, data_size);
29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 29 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
30} 30}
31 31
diff --git a/src/core/file_sys/archive_romfs.h b/src/core/file_sys/archive_romfs.h
index 409bc670a..2bedfa9c6 100644
--- a/src/core/file_sys/archive_romfs.h
+++ b/src/core/file_sys/archive_romfs.h
@@ -5,11 +5,13 @@
5#pragma once 5#pragma once
6 6
7#include <memory> 7#include <memory>
8#include <string>
8#include <vector> 9#include <vector>
9 10
10#include "common/common_types.h" 11#include "common/common_types.h"
11 12
12#include "core/file_sys/ivfc_archive.h" 13#include "core/file_sys/archive_backend.h"
14#include "core/hle/result.h"
13#include "core/loader/loader.h" 15#include "core/loader/loader.h"
14 16
15//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -20,14 +22,16 @@ namespace FileSys {
20/// File system interface to the RomFS archive 22/// File system interface to the RomFS archive
21class ArchiveFactory_RomFS final : public ArchiveFactory { 23class ArchiveFactory_RomFS final : public ArchiveFactory {
22public: 24public:
23 ArchiveFactory_RomFS(const Loader::AppLoader& app_loader); 25 ArchiveFactory_RomFS(Loader::AppLoader& app_loader);
24 26
25 std::string GetName() const override { return "RomFS"; } 27 std::string GetName() const override { return "RomFS"; }
26 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override; 28 ResultVal<std::unique_ptr<ArchiveBackend>> Open(const Path& path) override;
27 ResultCode Format(const Path& path) override; 29 ResultCode Format(const Path& path) override;
28 30
29private: 31private:
30 std::shared_ptr<std::vector<u8>> romfs_data; 32 std::shared_ptr<FileUtil::IOFile> romfs_file;
33 u64 data_offset;
34 u64 data_size;
31}; 35};
32 36
33} // namespace FileSys 37} // namespace FileSys
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index a92309377..12876899f 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -2,18 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/file_util.h" 8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/make_unique.h" 10#include "common/make_unique.h"
11#include "common/string_util.h"
11 12
12#include "core/file_sys/archive_savedata.h" 13#include "core/file_sys/archive_savedata.h"
13#include "core/file_sys/disk_archive.h" 14#include "core/file_sys/disk_archive.h"
14#include "core/hle/kernel/process.h" 15#include "core/hle/kernel/process.h"
15#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
16#include "core/settings.h"
17 17
18//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
19// FileSys namespace 19// FileSys namespace
@@ -37,7 +37,7 @@ ArchiveFactory_SaveData::ArchiveFactory_SaveData(const std::string& sdmc_directo
37} 37}
38 38
39ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) { 39ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const Path& path) {
40 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id); 40 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
41 if (!FileUtil::Exists(concrete_mount_point)) { 41 if (!FileUtil::Exists(concrete_mount_point)) {
42 // When a SaveData archive is created for the first time, it is not yet formatted 42 // When a SaveData archive is created for the first time, it is not yet formatted
43 // and the save file/directory structure expected by the game has not yet been initialized. 43 // and the save file/directory structure expected by the game has not yet been initialized.
@@ -52,7 +52,7 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveData::Open(const P
52} 52}
53 53
54ResultCode ArchiveFactory_SaveData::Format(const Path& path) { 54ResultCode ArchiveFactory_SaveData::Format(const Path& path) {
55 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->program_id); 55 std::string concrete_mount_point = GetSaveDataPath(mount_point, Kernel::g_current_process->codeset->program_id);
56 FileUtil::DeleteDirRecursively(concrete_mount_point); 56 FileUtil::DeleteDirRecursively(concrete_mount_point);
57 FileUtil::CreateFullPath(concrete_mount_point); 57 FileUtil::CreateFullPath(concrete_mount_point);
58 return RESULT_SUCCESS; 58 return RESULT_SUCCESS;
diff --git a/src/core/file_sys/archive_savedata.h b/src/core/file_sys/archive_savedata.h
index db17afc92..1f65297dd 100644
--- a/src/core/file_sys/archive_savedata.h
+++ b/src/core/file_sys/archive_savedata.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include <memory>
8#include <string>
8 9
9#include "core/file_sys/disk_archive.h" 10#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 14// FileSys namespace
diff --git a/src/core/file_sys/archive_savedatacheck.cpp b/src/core/file_sys/archive_savedatacheck.cpp
index e7e4fbf1d..ea1dfe2c7 100644
--- a/src/core/file_sys/archive_savedatacheck.cpp
+++ b/src/core/file_sys/archive_savedatacheck.cpp
@@ -2,11 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <vector>
7
8#include "common/common_types.h"
5#include "common/file_util.h" 9#include "common/file_util.h"
6#include "common/logging/log.h" 10#include "common/logging/log.h"
7#include "common/make_unique.h" 11#include "common/make_unique.h"
12#include "common/string_util.h"
8 13
9#include "core/file_sys/archive_savedatacheck.h" 14#include "core/file_sys/archive_savedatacheck.h"
15#include "core/file_sys/ivfc_archive.h"
10#include "core/hle/service/fs/archive.h" 16#include "core/hle/service/fs/archive.h"
11 17
12//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -31,17 +37,14 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_SaveDataCheck::Open(co
31 auto vec = path.AsBinary(); 37 auto vec = path.AsBinary();
32 const u32* data = reinterpret_cast<u32*>(vec.data()); 38 const u32* data = reinterpret_cast<u32*>(vec.data());
33 std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]); 39 std::string file_path = GetSaveDataCheckPath(mount_point, data[1], data[0]);
34 FileUtil::IOFile file(file_path, "rb"); 40 auto file = std::make_shared<FileUtil::IOFile>(file_path, "rb");
35 41
36 if (!file.IsOpen()) { 42 if (!file->IsOpen()) {
37 return ResultCode(-1); // TODO(Subv): Find the right error code 43 return ResultCode(-1); // TODO(Subv): Find the right error code
38 } 44 }
39 auto size = file.GetSize(); 45 auto size = file->GetSize();
40 auto raw_data = std::make_shared<std::vector<u8>>(size);
41 file.ReadBytes(raw_data->data(), size);
42 file.Close();
43 46
44 auto archive = Common::make_unique<IVFCArchive>(std::move(raw_data)); 47 auto archive = Common::make_unique<IVFCArchive>(file, 0, size);
45 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive)); 48 return MakeResult<std::unique_ptr<ArchiveBackend>>(std::move(archive));
46} 49}
47 50
diff --git a/src/core/file_sys/archive_savedatacheck.h b/src/core/file_sys/archive_savedatacheck.h
index f78a6f02e..b14aefe8b 100644
--- a/src/core/file_sys/archive_savedatacheck.h
+++ b/src/core/file_sys/archive_savedatacheck.h
@@ -4,12 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <memory>
8#include <string>
8 9
9#include "common/common_types.h" 10#include "core/file_sys/archive_backend.h"
10 11#include "core/hle/result.h"
11#include "core/file_sys/ivfc_archive.h"
12#include "core/loader/loader.h"
13 12
14//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
15// FileSys namespace 14// FileSys namespace
diff --git a/src/core/file_sys/archive_sdmc.cpp b/src/core/file_sys/archive_sdmc.cpp
index c1234a186..5c825f429 100644
--- a/src/core/file_sys/archive_sdmc.cpp
+++ b/src/core/file_sys/archive_sdmc.cpp
@@ -2,9 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6 6
7#include "common/common_types.h"
8#include "common/file_util.h" 7#include "common/file_util.h"
9#include "common/logging/log.h" 8#include "common/logging/log.h"
10#include "common/make_unique.h" 9#include "common/make_unique.h"
diff --git a/src/core/file_sys/archive_sdmc.h b/src/core/file_sys/archive_sdmc.h
index 1becf6c0f..10b273bdb 100644
--- a/src/core/file_sys/archive_sdmc.h
+++ b/src/core/file_sys/archive_sdmc.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/common_types.h" 7#include <memory>
8#include <string>
8 9
9#include "core/file_sys/disk_archive.h" 10#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 11#include "core/hle/result.h"
11 12
12//////////////////////////////////////////////////////////////////////////////////////////////////// 13////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 14// FileSys namespace
diff --git a/src/core/file_sys/archive_systemsavedata.cpp b/src/core/file_sys/archive_systemsavedata.cpp
index 4fe785c97..896f89529 100644
--- a/src/core/file_sys/archive_systemsavedata.cpp
+++ b/src/core/file_sys/archive_systemsavedata.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6#include <vector>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
9#include "common/make_unique.h" 10#include "common/make_unique.h"
11#include "common/string_util.h"
10 12
11#include "core/file_sys/archive_systemsavedata.h" 13#include "core/file_sys/archive_systemsavedata.h"
14#include "core/file_sys/disk_archive.h"
12#include "core/hle/service/fs/archive.h" 15#include "core/hle/service/fs/archive.h"
13#include "core/settings.h"
14 16
15//////////////////////////////////////////////////////////////////////////////////////////////////// 17////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace 18// FileSys namespace
diff --git a/src/core/file_sys/archive_systemsavedata.h b/src/core/file_sys/archive_systemsavedata.h
index 3431fed88..afc689848 100644
--- a/src/core/file_sys/archive_systemsavedata.h
+++ b/src/core/file_sys/archive_systemsavedata.h
@@ -4,10 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8 11
9#include "core/file_sys/disk_archive.h" 12#include "core/file_sys/archive_backend.h"
10#include "core/loader/loader.h" 13#include "core/hle/result.h"
11 14
12//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
13// FileSys namespace 16// FileSys namespace
diff --git a/src/core/file_sys/disk_archive.cpp b/src/core/file_sys/disk_archive.cpp
index 9980cced1..1096fd34d 100644
--- a/src/core/file_sys/disk_archive.cpp
+++ b/src/core/file_sys/disk_archive.cpp
@@ -2,7 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <sys/stat.h> 5#include <algorithm>
6#include <cstdio>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h" 9#include "common/file_util.h"
@@ -10,7 +11,6 @@
10#include "common/make_unique.h" 11#include "common/make_unique.h"
11 12
12#include "core/file_sys/disk_archive.h" 13#include "core/file_sys/disk_archive.h"
13#include "core/settings.h"
14 14
15//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace 16// FileSys namespace
@@ -105,12 +105,12 @@ bool DiskFile::Open() {
105 return true; 105 return true;
106} 106}
107 107
108size_t DiskFile::Read(const u64 offset, const u32 length, u8* buffer) const { 108size_t DiskFile::Read(const u64 offset, const size_t length, u8* buffer) const {
109 file->Seek(offset, SEEK_SET); 109 file->Seek(offset, SEEK_SET);
110 return file->ReadBytes(buffer, length); 110 return file->ReadBytes(buffer, length);
111} 111}
112 112
113size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { 113size_t DiskFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
114 file->Seek(offset, SEEK_SET); 114 file->Seek(offset, SEEK_SET);
115 size_t written = file->WriteBytes(buffer, length); 115 size_t written = file->WriteBytes(buffer, length);
116 if (flush) 116 if (flush)
@@ -118,8 +118,8 @@ size_t DiskFile::Write(const u64 offset, const u32 length, const u32 flush, cons
118 return written; 118 return written;
119} 119}
120 120
121size_t DiskFile::GetSize() const { 121u64 DiskFile::GetSize() const {
122 return static_cast<size_t>(file->GetSize()); 122 return file->GetSize();
123} 123}
124 124
125bool DiskFile::SetSize(const u64 size) const { 125bool DiskFile::SetSize(const u64 size) const {
diff --git a/src/core/file_sys/disk_archive.h b/src/core/file_sys/disk_archive.h
index a22d3837a..c5da07508 100644
--- a/src/core/file_sys/disk_archive.h
+++ b/src/core/file_sys/disk_archive.h
@@ -4,13 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8#include <memory>
9#include <string>
10#include <vector>
11
7#include "common/common_types.h" 12#include "common/common_types.h"
8#include "common/file_util.h" 13#include "common/file_util.h"
9 14
10#include "core/file_sys/archive_backend.h" 15#include "core/file_sys/archive_backend.h"
11#include "core/file_sys/directory_backend.h" 16#include "core/file_sys/directory_backend.h"
12#include "core/file_sys/file_backend.h" 17#include "core/file_sys/file_backend.h"
13#include "core/loader/loader.h" 18#include "core/hle/result.h"
14 19
15//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
16// FileSys namespace 21// FileSys namespace
@@ -50,10 +55,10 @@ public:
50 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode); 55 DiskFile(const DiskArchive& archive, const Path& path, const Mode mode);
51 56
52 bool Open() override; 57 bool Open() override;
53 size_t Read(const u64 offset, const u32 length, u8* buffer) const override; 58 size_t Read(u64 offset, size_t length, u8* buffer) const override;
54 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; 59 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
55 size_t GetSize() const override; 60 u64 GetSize() const override;
56 bool SetSize(const u64 size) const override; 61 bool SetSize(u64 size) const override;
57 bool Close() const override; 62 bool Close() const override;
58 63
59 void Flush() const override { 64 void Flush() const override {
diff --git a/src/core/file_sys/file_backend.h b/src/core/file_sys/file_backend.h
index 0fcff1845..df7165df3 100644
--- a/src/core/file_sys/file_backend.h
+++ b/src/core/file_sys/file_backend.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -29,7 +31,7 @@ public:
29 * @param buffer Buffer to read data into 31 * @param buffer Buffer to read data into
30 * @return Number of bytes read 32 * @return Number of bytes read
31 */ 33 */
32 virtual size_t Read(const u64 offset, const u32 length, u8* buffer) const = 0; 34 virtual size_t Read(u64 offset, size_t length, u8* buffer) const = 0;
33 35
34 /** 36 /**
35 * Write data to the file 37 * Write data to the file
@@ -39,20 +41,20 @@ public:
39 * @param buffer Buffer to read data from 41 * @param buffer Buffer to read data from
40 * @return Number of bytes written 42 * @return Number of bytes written
41 */ 43 */
42 virtual size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const = 0; 44 virtual size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const = 0;
43 45
44 /** 46 /**
45 * Get the size of the file in bytes 47 * Get the size of the file in bytes
46 * @return Size of the file in bytes 48 * @return Size of the file in bytes
47 */ 49 */
48 virtual size_t GetSize() const = 0; 50 virtual u64 GetSize() const = 0;
49 51
50 /** 52 /**
51 * Set the size of the file in bytes 53 * Set the size of the file in bytes
52 * @param size New size of the file 54 * @param size New size of the file
53 * @return true if successful 55 * @return true if successful
54 */ 56 */
55 virtual bool SetSize(const u64 size) const = 0; 57 virtual bool SetSize(u64 size) const = 0;
56 58
57 /** 59 /**
58 * Close the file 60 * Close the file
diff --git a/src/core/file_sys/ivfc_archive.cpp b/src/core/file_sys/ivfc_archive.cpp
index 2d2509d16..e16aa1491 100644
--- a/src/core/file_sys/ivfc_archive.cpp
+++ b/src/core/file_sys/ivfc_archive.cpp
@@ -2,10 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include <memory> 6#include <memory>
6 7
7#include "common/common_types.h" 8#include "common/common_types.h"
8#include "common/file_util.h"
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/make_unique.h" 10#include "common/make_unique.h"
11 11
@@ -16,15 +16,12 @@
16 16
17namespace FileSys { 17namespace FileSys {
18 18
19IVFCArchive::IVFCArchive(std::shared_ptr<const std::vector<u8>> data) : data(data) {
20}
21
22std::string IVFCArchive::GetName() const { 19std::string IVFCArchive::GetName() const {
23 return "IVFC"; 20 return "IVFC";
24} 21}
25 22
26std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const { 23std::unique_ptr<FileBackend> IVFCArchive::OpenFile(const Path& path, const Mode mode) const {
27 return Common::make_unique<IVFCFile>(data); 24 return Common::make_unique<IVFCFile>(romfs_file, data_offset, data_size);
28} 25}
29 26
30bool IVFCArchive::DeleteFile(const Path& path) const { 27bool IVFCArchive::DeleteFile(const Path& path) const {
@@ -64,19 +61,21 @@ std::unique_ptr<DirectoryBackend> IVFCArchive::OpenDirectory(const Path& path) c
64 61
65//////////////////////////////////////////////////////////////////////////////////////////////////// 62////////////////////////////////////////////////////////////////////////////////////////////////////
66 63
67size_t IVFCFile::Read(const u64 offset, const u32 length, u8* buffer) const { 64size_t IVFCFile::Read(const u64 offset, const size_t length, u8* buffer) const {
68 LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length); 65 LOG_TRACE(Service_FS, "called offset=%llu, length=%d", offset, length);
69 memcpy(buffer, data->data() + offset, length); 66 romfs_file->Seek(data_offset + offset, SEEK_SET);
70 return length; 67 size_t read_length = (size_t)std::min((u64)length, data_size - offset);
68
69 return romfs_file->ReadBytes(buffer, read_length);
71} 70}
72 71
73size_t IVFCFile::Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const { 72size_t IVFCFile::Write(const u64 offset, const size_t length, const bool flush, const u8* buffer) const {
74 LOG_ERROR(Service_FS, "Attempted to write to IVFC file"); 73 LOG_ERROR(Service_FS, "Attempted to write to IVFC file");
75 return 0; 74 return 0;
76} 75}
77 76
78size_t IVFCFile::GetSize() const { 77u64 IVFCFile::GetSize() const {
79 return sizeof(u8) * data->size(); 78 return data_size;
80} 79}
81 80
82bool IVFCFile::SetSize(const u64 size) const { 81bool IVFCFile::SetSize(const u64 size) const {
diff --git a/src/core/file_sys/ivfc_archive.h b/src/core/file_sys/ivfc_archive.h
index 10415798d..c15a6c4ae 100644
--- a/src/core/file_sys/ivfc_archive.h
+++ b/src/core/file_sys/ivfc_archive.h
@@ -4,15 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
7#include <memory> 8#include <memory>
9#include <string>
8#include <vector> 10#include <vector>
9 11
10#include "common/common_types.h" 12#include "common/common_types.h"
13#include "common/file_util.h"
11 14
12#include "core/file_sys/archive_backend.h" 15#include "core/file_sys/archive_backend.h"
13#include "core/file_sys/directory_backend.h" 16#include "core/file_sys/directory_backend.h"
14#include "core/file_sys/file_backend.h" 17#include "core/file_sys/file_backend.h"
15#include "core/loader/loader.h" 18#include "core/hle/result.h"
16 19
17//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
18// FileSys namespace 21// FileSys namespace
@@ -26,7 +29,8 @@ namespace FileSys {
26 */ 29 */
27class IVFCArchive : public ArchiveBackend { 30class IVFCArchive : public ArchiveBackend {
28public: 31public:
29 IVFCArchive(std::shared_ptr<const std::vector<u8>> data); 32 IVFCArchive(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
33 : romfs_file(file), data_offset(offset), data_size(size) {}
30 34
31 std::string GetName() const override; 35 std::string GetName() const override;
32 36
@@ -40,23 +44,28 @@ public:
40 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override; 44 std::unique_ptr<DirectoryBackend> OpenDirectory(const Path& path) const override;
41 45
42protected: 46protected:
43 std::shared_ptr<const std::vector<u8>> data; 47 std::shared_ptr<FileUtil::IOFile> romfs_file;
48 u64 data_offset;
49 u64 data_size;
44}; 50};
45 51
46class IVFCFile : public FileBackend { 52class IVFCFile : public FileBackend {
47public: 53public:
48 IVFCFile(std::shared_ptr<const std::vector<u8>> data) : data(data) {} 54 IVFCFile(std::shared_ptr<FileUtil::IOFile> file, u64 offset, u64 size)
55 : romfs_file(file), data_offset(offset), data_size(size) {}
49 56
50 bool Open() override { return true; } 57 bool Open() override { return true; }
51 size_t Read(const u64 offset, const u32 length, u8* buffer) const override; 58 size_t Read(u64 offset, size_t length, u8* buffer) const override;
52 size_t Write(const u64 offset, const u32 length, const u32 flush, const u8* buffer) const override; 59 size_t Write(u64 offset, size_t length, bool flush, const u8* buffer) const override;
53 size_t GetSize() const override; 60 u64 GetSize() const override;
54 bool SetSize(const u64 size) const override; 61 bool SetSize(u64 size) const override;
55 bool Close() const override { return false; } 62 bool Close() const override { return false; }
56 void Flush() const override { } 63 void Flush() const override { }
57 64
58private: 65private:
59 std::shared_ptr<const std::vector<u8>> data; 66 std::shared_ptr<FileUtil::IOFile> romfs_file;
67 u64 data_offset;
68 u64 data_size;
60}; 69};
61 70
62class IVFCDirectory : public DirectoryBackend { 71class IVFCDirectory : public DirectoryBackend {
diff --git a/src/core/hle/applets/applet.cpp b/src/core/hle/applets/applet.cpp
new file mode 100644
index 000000000..826f6cbb6
--- /dev/null
+++ b/src/core/hle/applets/applet.cpp
@@ -0,0 +1,101 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstddef>
6#include <memory>
7#include <type_traits>
8#include <unordered_map>
9
10#include "common/assert.h"
11#include "common/common_types.h"
12
13#include "core/core_timing.h"
14#include "core/hle/applets/applet.h"
15#include "core/hle/applets/swkbd.h"
16#include "core/hle/result.h"
17#include "core/hle/service/apt/apt.h"
18
19////////////////////////////////////////////////////////////////////////////////////////////////////
20
21// Specializes std::hash for AppletId, so that we can use it in std::unordered_map.
22// Workaround for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
23namespace std {
24 template <>
25 struct hash<Service::APT::AppletId> {
26 typedef Service::APT::AppletId argument_type;
27 typedef std::size_t result_type;
28
29 result_type operator()(const argument_type& id_code) const {
30 typedef std::underlying_type<argument_type>::type Type;
31 return std::hash<Type>()(static_cast<Type>(id_code));
32 }
33 };
34}
35
36namespace HLE {
37namespace Applets {
38
39static std::unordered_map<Service::APT::AppletId, std::shared_ptr<Applet>> applets;
40static u32 applet_update_event = -1; ///< The CoreTiming event identifier for the Applet update callback.
41/// The interval at which the Applet update callback will be called, 16.6ms
42static const u64 applet_update_interval_us = 16666;
43
44ResultCode Applet::Create(Service::APT::AppletId id) {
45 switch (id) {
46 case Service::APT::AppletId::SoftwareKeyboard1:
47 case Service::APT::AppletId::SoftwareKeyboard2:
48 applets[id] = std::make_shared<SoftwareKeyboard>(id);
49 break;
50 default:
51 // TODO(Subv): Find the right error code
52 return ResultCode(ErrorDescription::NotFound, ErrorModule::Applet, ErrorSummary::NotSupported, ErrorLevel::Permanent);
53 }
54
55 return RESULT_SUCCESS;
56}
57
58std::shared_ptr<Applet> Applet::Get(Service::APT::AppletId id) {
59 auto itr = applets.find(id);
60 if (itr != applets.end())
61 return itr->second;
62 return nullptr;
63}
64
65/// Handles updating the current Applet every time it's called.
66static void AppletUpdateEvent(u64 applet_id, int cycles_late) {
67 Service::APT::AppletId id = static_cast<Service::APT::AppletId>(applet_id);
68 std::shared_ptr<Applet> applet = Applet::Get(id);
69 ASSERT_MSG(applet != nullptr, "Applet doesn't exist! applet_id=%08X", id);
70
71 applet->Update();
72
73 // If the applet is still running after the last update, reschedule the event
74 if (applet->IsRunning()) {
75 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us) - cycles_late,
76 applet_update_event, applet_id);
77 } else {
78 // Otherwise the applet has terminated, in which case we should clean it up
79 applets[id] = nullptr;
80 }
81}
82
83ResultCode Applet::Start(const Service::APT::AppletStartupParameter& parameter) {
84 ResultCode result = StartImpl(parameter);
85 if (result.IsError())
86 return result;
87 // Schedule the update event
88 CoreTiming::ScheduleEvent(usToCycles(applet_update_interval_us), applet_update_event, static_cast<u64>(id));
89 return result;
90}
91
92void Init() {
93 // Register the applet update callback
94 applet_update_event = CoreTiming::RegisterEvent("HLE Applet Update Event", AppletUpdateEvent);
95}
96
97void Shutdown() {
98}
99
100}
101} // namespace
diff --git a/src/core/hle/applets/applet.h b/src/core/hle/applets/applet.h
new file mode 100644
index 000000000..b235d0b8a
--- /dev/null
+++ b/src/core/hle/applets/applet.h
@@ -0,0 +1,77 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <memory>
8
9#include "core/hle/result.h"
10#include "core/hle/service/apt/apt.h"
11
12namespace HLE {
13namespace Applets {
14
15class Applet {
16public:
17 virtual ~Applet() { }
18 Applet(Service::APT::AppletId id) : id(id) { }
19
20 /**
21 * Creates an instance of the Applet subclass identified by the parameter.
22 * and stores it in a global map.
23 * @param id Id of the applet to create.
24 * @returns ResultCode Whether the operation was successful or not.
25 */
26 static ResultCode Create(Service::APT::AppletId id);
27
28 /**
29 * Retrieves the Applet instance identified by the specified id.
30 * @param id Id of the Applet to retrieve.
31 * @returns Requested Applet or nullptr if not found.
32 */
33 static std::shared_ptr<Applet> Get(Service::APT::AppletId id);
34
35 /**
36 * Handles a parameter from the application.
37 * @param parameter Parameter data to handle.
38 * @returns ResultCode Whether the operation was successful or not.
39 */
40 virtual ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) = 0;
41
42 /**
43 * Handles the Applet start event, triggered from the application.
44 * @param parameter Parameter data to handle.
45 * @returns ResultCode Whether the operation was successful or not.
46 */
47 ResultCode Start(const Service::APT::AppletStartupParameter& parameter);
48
49 /**
50 * Whether the applet is currently executing instead of the host application or not.
51 */
52 virtual bool IsRunning() const = 0;
53
54 /**
55 * Handles an update tick for the Applet, lets it update the screen, send commands, etc.
56 */
57 virtual void Update() = 0;
58
59protected:
60 /**
61 * Handles the Applet start event, triggered from the application.
62 * @param parameter Parameter data to handle.
63 * @returns ResultCode Whether the operation was successful or not.
64 */
65 virtual ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) = 0;
66
67 Service::APT::AppletId id; ///< Id of this Applet
68};
69
70/// Initializes the HLE applets
71void Init();
72
73/// Shuts down the HLE applets
74void Shutdown();
75
76}
77} // namespace
diff --git a/src/core/hle/applets/swkbd.cpp b/src/core/hle/applets/swkbd.cpp
new file mode 100644
index 000000000..1db6b5a17
--- /dev/null
+++ b/src/core/hle/applets/swkbd.cpp
@@ -0,0 +1,113 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6#include <string>
7
8#include "common/assert.h"
9#include "common/logging/log.h"
10#include "common/string_util.h"
11
12#include "core/hle/applets/swkbd.h"
13#include "core/hle/kernel/kernel.h"
14#include "core/hle/kernel/shared_memory.h"
15#include "core/hle/service/hid/hid.h"
16#include "core/hle/service/gsp_gpu.h"
17#include "core/hle/result.h"
18#include "core/memory.h"
19
20#include "video_core/video_core.h"
21
22////////////////////////////////////////////////////////////////////////////////////////////////////
23
24namespace HLE {
25namespace Applets {
26
27SoftwareKeyboard::SoftwareKeyboard(Service::APT::AppletId id) : Applet(id), started(false) {
28 // Create the SharedMemory that will hold the framebuffer data
29 // TODO(Subv): What size should we use here?
30 using Kernel::MemoryPermission;
31 framebuffer_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, "SoftwareKeyboard Memory");
32}
33
34ResultCode SoftwareKeyboard::ReceiveParameter(Service::APT::MessageParameter const& parameter) {
35 if (parameter.signal != static_cast<u32>(Service::APT::SignalType::LibAppJustStarted)) {
36 LOG_ERROR(Service_APT, "unsupported signal %u", parameter.signal);
37 UNIMPLEMENTED();
38 // TODO(Subv): Find the right error code
39 return ResultCode(-1);
40 }
41
42 Service::APT::MessageParameter result;
43 // The buffer passed in parameter contains the data returned by GSPGPU::ImportDisplayCaptureInfo
44 result.signal = static_cast<u32>(Service::APT::SignalType::LibAppFinished);
45 result.data = nullptr;
46 result.buffer_size = 0;
47 result.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
48 result.sender_id = static_cast<u32>(id);
49 result.object = framebuffer_memory;
50
51 Service::APT::SendParameter(result);
52 return RESULT_SUCCESS;
53}
54
55ResultCode SoftwareKeyboard::StartImpl(Service::APT::AppletStartupParameter const& parameter) {
56 ASSERT_MSG(parameter.buffer_size == sizeof(config), "The size of the parameter (SoftwareKeyboardConfig) is wrong");
57
58 memcpy(&config, parameter.data, parameter.buffer_size);
59 text_memory = boost::static_pointer_cast<Kernel::SharedMemory, Kernel::Object>(parameter.object);
60
61 // TODO(Subv): Verify if this is the correct behavior
62 memset(text_memory->GetPointer(), 0, text_memory->size);
63
64 DrawScreenKeyboard();
65
66 started = true;
67 return RESULT_SUCCESS;
68}
69
70void SoftwareKeyboard::Update() {
71 // TODO(Subv): Handle input using the touch events from the HID module
72
73 // TODO(Subv): Remove this hardcoded text
74 std::u16string text = Common::UTF8ToUTF16("Citra");
75 memcpy(text_memory->GetPointer(), text.c_str(), text.length() * sizeof(char16_t));
76
77 // TODO(Subv): Ask for input and write it to the shared memory
78 // TODO(Subv): Find out what are the possible values for the return code,
79 // some games seem to check for a hardcoded 2
80 config.return_code = 2;
81 config.text_length = 6;
82 config.text_offset = 0;
83
84 // TODO(Subv): We're finalizing the applet immediately after it's started,
85 // but we should defer this call until after all the input has been collected.
86 Finalize();
87}
88
89void SoftwareKeyboard::DrawScreenKeyboard() {
90 auto bottom_screen = GSP_GPU::GetFrameBufferInfo(0, 1);
91 auto info = bottom_screen->framebuffer_info[bottom_screen->index];
92
93 // TODO(Subv): Draw the HLE keyboard, for now just zero-fill the framebuffer
94 memset(Memory::GetPointer(info.address_left), 0, info.stride * 320);
95
96 GSP_GPU::SetBufferSwap(1, info);
97}
98
99void SoftwareKeyboard::Finalize() {
100 // Let the application know that we're closing
101 Service::APT::MessageParameter message;
102 message.buffer_size = sizeof(SoftwareKeyboardConfig);
103 message.data = reinterpret_cast<u8*>(&config);
104 message.signal = static_cast<u32>(Service::APT::SignalType::LibAppClosed);
105 message.destination_id = static_cast<u32>(Service::APT::AppletId::Application);
106 message.sender_id = static_cast<u32>(id);
107 Service::APT::SendParameter(message);
108
109 started = false;
110}
111
112}
113} // namespace
diff --git a/src/core/hle/applets/swkbd.h b/src/core/hle/applets/swkbd.h
new file mode 100644
index 000000000..cb95b8d90
--- /dev/null
+++ b/src/core/hle/applets/swkbd.h
@@ -0,0 +1,90 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include "common/common_types.h"
8#include "common/common_funcs.h"
9
10#include "core/hle/applets/applet.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/result.h"
14#include "core/hle/service/apt/apt.h"
15
16namespace HLE {
17namespace Applets {
18
19struct SoftwareKeyboardConfig {
20 INSERT_PADDING_WORDS(0x8);
21
22 u16 max_text_length; ///< Maximum length of the input text
23
24 INSERT_PADDING_BYTES(0x6E);
25
26 char16_t display_text[65]; ///< Text to display when asking the user for input
27
28 INSERT_PADDING_BYTES(0xE);
29
30 u32 default_text_offset; ///< Offset of the default text in the output SharedMemory
31
32 INSERT_PADDING_WORDS(0x3);
33
34 u32 shared_memory_size; ///< Size of the SharedMemory
35
36 INSERT_PADDING_WORDS(0x1);
37
38 u32 return_code; ///< Return code of the SoftwareKeyboard, usually 2, other values are unknown
39
40 INSERT_PADDING_WORDS(0x2);
41
42 u32 text_offset; ///< Offset in the SharedMemory where the output text starts
43 u16 text_length; ///< Length in characters of the output text
44
45 INSERT_PADDING_BYTES(0x2B6);
46};
47
48/**
49 * The size of this structure (0x400) has been verified via reverse engineering of multiple games
50 * that use the software keyboard.
51 */
52static_assert(sizeof(SoftwareKeyboardConfig) == 0x400, "Software Keyboard Config size is wrong");
53
54class SoftwareKeyboard final : public Applet {
55public:
56 SoftwareKeyboard(Service::APT::AppletId id);
57 ~SoftwareKeyboard() {}
58
59 ResultCode ReceiveParameter(const Service::APT::MessageParameter& parameter) override;
60 ResultCode StartImpl(const Service::APT::AppletStartupParameter& parameter) override;
61 void Update() override;
62 bool IsRunning() const override { return started; }
63
64 /**
65 * Draws a keyboard to the current bottom screen framebuffer.
66 */
67 void DrawScreenKeyboard();
68
69 /**
70 * Sends the LibAppletClosing signal to the application,
71 * along with the relevant data buffers.
72 */
73 void Finalize();
74
75 /// TODO(Subv): Find out what this is actually used for.
76 /// It is believed that the application stores the current screen image here.
77 Kernel::SharedPtr<Kernel::SharedMemory> framebuffer_memory;
78
79 /// SharedMemory where the output text will be stored
80 Kernel::SharedPtr<Kernel::SharedMemory> text_memory;
81
82 /// Configuration of this instance of the SoftwareKeyboard, as received from the application
83 SoftwareKeyboardConfig config;
84
85 /// Whether this applet is currently running instead of the host application or not.
86 bool started;
87};
88
89}
90} // namespace
diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h
index ea0777438..1a0518926 100644
--- a/src/core/hle/function_wrappers.h
+++ b/src/core/hle/function_wrappers.h
@@ -87,8 +87,28 @@ template<ResultCode func(u32, s64)> void Wrap() {
87 } 87 }
88} 88}
89 89
90template<ResultCode func(void*, void*, u32)> void Wrap(){ 90template<ResultCode func(MemoryInfo*, PageInfo*, u32)> void Wrap() {
91 FuncReturn(func(Memory::GetPointer(PARAM(0)), Memory::GetPointer(PARAM(1)), PARAM(2)).raw); 91 MemoryInfo memory_info = {};
92 PageInfo page_info = {};
93 u32 retval = func(&memory_info, &page_info, PARAM(2)).raw;
94 Core::g_app_core->SetReg(1, memory_info.base_address);
95 Core::g_app_core->SetReg(2, memory_info.size);
96 Core::g_app_core->SetReg(3, memory_info.permission);
97 Core::g_app_core->SetReg(4, memory_info.state);
98 Core::g_app_core->SetReg(5, page_info.flags);
99 FuncReturn(retval);
100}
101
102template<ResultCode func(MemoryInfo*, PageInfo*, Handle, u32)> void Wrap() {
103 MemoryInfo memory_info = {};
104 PageInfo page_info = {};
105 u32 retval = func(&memory_info, &page_info, PARAM(2), PARAM(3)).raw;
106 Core::g_app_core->SetReg(1, memory_info.base_address);
107 Core::g_app_core->SetReg(2, memory_info.size);
108 Core::g_app_core->SetReg(3, memory_info.permission);
109 Core::g_app_core->SetReg(4, memory_info.state);
110 Core::g_app_core->SetReg(5, page_info.flags);
111 FuncReturn(retval);
92} 112}
93 113
94template<ResultCode func(s32*, u32)> void Wrap(){ 114template<ResultCode func(s32*, u32)> void Wrap(){
diff --git a/src/core/hle/hle.cpp b/src/core/hle/hle.cpp
index fdeb9a028..cd0a400dc 100644
--- a/src/core/hle/hle.cpp
+++ b/src/core/hle/hle.cpp
@@ -10,7 +10,6 @@
10#include "core/hle/hle.h" 10#include "core/hle/hle.h"
11#include "core/hle/config_mem.h" 11#include "core/hle/config_mem.h"
12#include "core/hle/shared_page.h" 12#include "core/hle/shared_page.h"
13#include "core/hle/kernel/thread.h"
14#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
15 14
16//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp
index f338f3266..53feebbc0 100644
--- a/src/core/hle/kernel/event.cpp
+++ b/src/core/hle/kernel/event.cpp
@@ -21,7 +21,7 @@ SharedPtr<Event> Event::Create(ResetType reset_type, std::string name) {
21 SharedPtr<Event> evt(new Event); 21 SharedPtr<Event> evt(new Event);
22 22
23 evt->signaled = false; 23 evt->signaled = false;
24 evt->reset_type = evt->intitial_reset_type = reset_type; 24 evt->reset_type = reset_type;
25 evt->name = std::move(name); 25 evt->name = std::move(name);
26 26
27 return evt; 27 return evt;
diff --git a/src/core/hle/kernel/event.h b/src/core/hle/kernel/event.h
index fba960d2a..89d405236 100644
--- a/src/core/hle/kernel/event.h
+++ b/src/core/hle/kernel/event.h
@@ -26,7 +26,6 @@ public:
26 static const HandleType HANDLE_TYPE = HandleType::Event; 26 static const HandleType HANDLE_TYPE = HandleType::Event;
27 HandleType GetHandleType() const override { return HANDLE_TYPE; } 27 HandleType GetHandleType() const override { return HANDLE_TYPE; }
28 28
29 ResetType intitial_reset_type; ///< ResetType specified at Event initialization
30 ResetType reset_type; ///< Current ResetType 29 ResetType reset_type; ///< Current ResetType
31 30
32 bool signaled; ///< Whether the event has already been signaled 31 bool signaled; ///< Whether the event has already been signaled
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index 20e11da16..5711c0405 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -7,8 +7,6 @@
7#include "common/assert.h" 7#include "common/assert.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/arm/arm_interface.h"
11#include "core/core.h"
12#include "core/hle/kernel/kernel.h" 10#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/resource_limit.h" 11#include "core/hle/kernel/resource_limit.h"
14#include "core/hle/kernel/process.h" 12#include "core/hle/kernel/process.h"
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 64595f758..4d4276f7a 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -4,10 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <boost/intrusive_ptr.hpp> 7#include <boost/smart_ptr/intrusive_ptr.hpp>
8 8
9#include <algorithm>
9#include <array> 10#include <array>
10#include <memory> 11#include <cstddef>
11#include <string> 12#include <string>
12#include <vector> 13#include <vector>
13 14
@@ -16,8 +17,6 @@
16#include "core/hle/hle.h" 17#include "core/hle/hle.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18 19
19struct ApplicationInfo;
20
21namespace Kernel { 20namespace Kernel {
22 21
23class Thread; 22class Thread;
@@ -48,6 +47,7 @@ enum class HandleType : u32 {
48 Semaphore = 10, 47 Semaphore = 10,
49 Timer = 11, 48 Timer = 11,
50 ResourceLimit = 12, 49 ResourceLimit = 12,
50 CodeSet = 13,
51}; 51};
52 52
53enum { 53enum {
@@ -86,6 +86,7 @@ public:
86 case HandleType::Process: 86 case HandleType::Process:
87 case HandleType::AddressArbiter: 87 case HandleType::AddressArbiter:
88 case HandleType::ResourceLimit: 88 case HandleType::ResourceLimit:
89 case HandleType::CodeSet:
89 return false; 90 return false;
90 } 91 }
91 } 92 }
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp
index b0e75ba59..a7892c652 100644
--- a/src/core/hle/kernel/process.cpp
+++ b/src/core/hle/kernel/process.cpp
@@ -5,24 +5,39 @@
5#include "common/assert.h" 5#include "common/assert.h"
6#include "common/common_funcs.h" 6#include "common/common_funcs.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8#include "common/make_unique.h"
8 9
9#include "core/hle/kernel/process.h" 10#include "core/hle/kernel/process.h"
10#include "core/hle/kernel/resource_limit.h" 11#include "core/hle/kernel/resource_limit.h"
11#include "core/hle/kernel/thread.h" 12#include "core/hle/kernel/thread.h"
13#include "core/hle/kernel/vm_manager.h"
14#include "core/mem_map.h"
12#include "core/memory.h" 15#include "core/memory.h"
13 16
14namespace Kernel { 17namespace Kernel {
15 18
19SharedPtr<CodeSet> CodeSet::Create(std::string name, u64 program_id) {
20 SharedPtr<CodeSet> codeset(new CodeSet);
21
22 codeset->name = std::move(name);
23 codeset->program_id = program_id;
24
25 return codeset;
26}
27
28CodeSet::CodeSet() {}
29CodeSet::~CodeSet() {}
30
16u32 Process::next_process_id; 31u32 Process::next_process_id;
17 32
18SharedPtr<Process> Process::Create(std::string name, u64 program_id) { 33SharedPtr<Process> Process::Create(SharedPtr<CodeSet> code_set) {
19 SharedPtr<Process> process(new Process); 34 SharedPtr<Process> process(new Process);
20 35
21 process->name = std::move(name); 36 process->codeset = std::move(code_set);
22 process->program_id = program_id;
23
24 process->flags.raw = 0; 37 process->flags.raw = 0;
25 process->flags.memory_region = MemoryRegion::APPLICATION; 38 process->flags.memory_region = MemoryRegion::APPLICATION;
39 process->address_space = Common::make_unique<VMManager>();
40 Memory::InitLegacyAddressSpace(*process->address_space);
26 41
27 return process; 42 return process;
28} 43}
@@ -87,8 +102,19 @@ void Process::ParseKernelCaps(const u32* kernel_caps, size_t len) {
87 } 102 }
88} 103}
89 104
90void Process::Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size) { 105void Process::Run(s32 main_thread_priority, u32 stack_size) {
91 Kernel::SetupMainThread(entry_point, main_thread_priority); 106 auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions, MemoryState memory_state) {
107 auto vma = address_space->MapMemoryBlock(segment.addr, codeset->memory,
108 segment.offset, segment.size, memory_state).Unwrap();
109 address_space->Reprotect(vma, permissions);
110 };
111
112 MapSegment(codeset->code, VMAPermission::ReadExecute, MemoryState::Code);
113 MapSegment(codeset->rodata, VMAPermission::Read, MemoryState::Code);
114 MapSegment(codeset->data, VMAPermission::ReadWrite, MemoryState::Private);
115
116 address_space->LogLayout();
117 Kernel::SetupMainThread(codeset->entrypoint, main_thread_priority);
92} 118}
93 119
94Kernel::Process::Process() {} 120Kernel::Process::Process() {}
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index 7b8a68610..83d3aceae 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -5,6 +5,9 @@
5#pragma once 5#pragma once
6 6
7#include <bitset> 7#include <bitset>
8#include <cstddef>
9#include <memory>
10#include <string>
8 11
9#include <boost/container/static_vector.hpp> 12#include <boost/container/static_vector.hpp>
10 13
@@ -12,7 +15,6 @@
12#include "common/common_types.h" 15#include "common/common_types.h"
13 16
14#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
15#include "core/hle/result.h"
16 18
17namespace Kernel { 19namespace Kernel {
18 20
@@ -46,23 +48,51 @@ union ProcessFlags {
46}; 48};
47 49
48class ResourceLimit; 50class ResourceLimit;
51class VMManager;
52
53struct CodeSet final : public Object {
54 static SharedPtr<CodeSet> Create(std::string name, u64 program_id);
55
56 std::string GetTypeName() const override { return "CodeSet"; }
57 std::string GetName() const override { return name; }
58
59 static const HandleType HANDLE_TYPE = HandleType::CodeSet;
60 HandleType GetHandleType() const override { return HANDLE_TYPE; }
61
62 /// Name of the process
63 std::string name;
64 /// Title ID corresponding to the process
65 u64 program_id;
66
67 std::shared_ptr<std::vector<u8>> memory;
68
69 struct Segment {
70 size_t offset = 0;
71 VAddr addr = 0;
72 u32 size = 0;
73 };
74
75 Segment code, rodata, data;
76 VAddr entrypoint;
77
78private:
79 CodeSet();
80 ~CodeSet() override;
81};
49 82
50class Process final : public Object { 83class Process final : public Object {
51public: 84public:
52 static SharedPtr<Process> Create(std::string name, u64 program_id); 85 static SharedPtr<Process> Create(SharedPtr<CodeSet> code_set);
53 86
54 std::string GetTypeName() const override { return "Process"; } 87 std::string GetTypeName() const override { return "Process"; }
55 std::string GetName() const override { return name; } 88 std::string GetName() const override { return codeset->name; }
56 89
57 static const HandleType HANDLE_TYPE = HandleType::Process; 90 static const HandleType HANDLE_TYPE = HandleType::Process;
58 HandleType GetHandleType() const override { return HANDLE_TYPE; } 91 HandleType GetHandleType() const override { return HANDLE_TYPE; }
59 92
60 static u32 next_process_id; 93 static u32 next_process_id;
61 94
62 /// Name of the process 95 SharedPtr<CodeSet> codeset;
63 std::string name;
64 /// Title ID corresponding to the process
65 u64 program_id;
66 /// Resource limit descriptor for this process 96 /// Resource limit descriptor for this process
67 SharedPtr<ResourceLimit> resource_limit; 97 SharedPtr<ResourceLimit> resource_limit;
68 98
@@ -80,6 +110,7 @@ public:
80 110
81 /// Bitmask of the used TLS slots 111 /// Bitmask of the used TLS slots
82 std::bitset<300> used_tls_slots; 112 std::bitset<300> used_tls_slots;
113 std::unique_ptr<VMManager> address_space;
83 114
84 /** 115 /**
85 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them 116 * Parses a list of kernel capability descriptors (as found in the ExHeader) and applies them
@@ -90,7 +121,7 @@ public:
90 /** 121 /**
91 * Applies address space changes and launches the process main thread. 122 * Applies address space changes and launches the process main thread.
92 */ 123 */
93 void Run(VAddr entry_point, s32 main_thread_priority, u32 stack_size); 124 void Run(s32 main_thread_priority, u32 stack_size);
94 125
95private: 126private:
96 Process(); 127 Process();
diff --git a/src/core/hle/kernel/session.h b/src/core/hle/kernel/session.h
index 257da9105..adaffcafe 100644
--- a/src/core/hle/kernel/session.h
+++ b/src/core/hle/kernel/session.h
@@ -4,8 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
9#include "common/assert.h"
10#include "common/common_types.h"
11
7#include "core/hle/kernel/kernel.h" 12#include "core/hle/kernel/kernel.h"
8#include "core/hle/kernel/thread.h" 13#include "core/hle/kernel/thread.h"
14#include "core/hle/result.h"
9#include "core/memory.h" 15#include "core/memory.h"
10 16
11namespace IPC { 17namespace IPC {
diff --git a/src/core/hle/kernel/shared_memory.h b/src/core/hle/kernel/shared_memory.h
index 204266896..7a2922776 100644
--- a/src/core/hle/kernel/shared_memory.h
+++ b/src/core/hle/kernel/shared_memory.h
@@ -4,9 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9#include "core/hle/kernel/kernel.h" 11#include "core/hle/kernel/kernel.h"
12#include "core/hle/result.h"
10 13
11namespace Kernel { 14namespace Kernel {
12 15
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 4729a7fe0..8b49fc7df 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -37,6 +37,10 @@ void Thread::Acquire() {
37 ASSERT_MSG(!ShouldWait(), "object unavailable!"); 37 ASSERT_MSG(!ShouldWait(), "object unavailable!");
38} 38}
39 39
40// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
41// us to simply use a pool index or similar.
42static Kernel::HandleTable wakeup_callback_handle_table;
43
40// Lists all thread ids that aren't deleted/etc. 44// Lists all thread ids that aren't deleted/etc.
41static std::vector<SharedPtr<Thread>> thread_list; 45static std::vector<SharedPtr<Thread>> thread_list;
42 46
@@ -93,6 +97,8 @@ void Thread::Stop() {
93 97
94 // Cancel any outstanding wakeup events for this thread 98 // Cancel any outstanding wakeup events for this thread
95 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); 99 CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle);
100 wakeup_callback_handle_table.Close(callback_handle);
101 callback_handle = 0;
96 102
97 // Clean up thread from ready queue 103 // Clean up thread from ready queue
98 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess) 104 // This is only needed when the thread is termintated forcefully (SVC TerminateProcess)
@@ -108,6 +114,7 @@ void Thread::Stop() {
108 for (auto& wait_object : wait_objects) { 114 for (auto& wait_object : wait_objects) {
109 wait_object->RemoveWaitingThread(this); 115 wait_object->RemoveWaitingThread(this);
110 } 116 }
117 wait_objects.clear();
111 118
112 Kernel::g_current_process->used_tls_slots[tls_index] = false; 119 Kernel::g_current_process->used_tls_slots[tls_index] = false;
113 120
@@ -210,6 +217,14 @@ static void SwitchContext(Thread* new_thread) {
210 new_thread->context.pc -= thumb_mode ? 2 : 4; 217 new_thread->context.pc -= thumb_mode ? 2 : 4;
211 } 218 }
212 219
220 // Clean up the thread's wait_objects, they'll be restored if needed during
221 // the svcWaitSynchronization call
222 for (int i = 0; i < new_thread->wait_objects.size(); ++i) {
223 SharedPtr<WaitObject> object = new_thread->wait_objects[i];
224 object->RemoveWaitingThread(new_thread);
225 }
226 new_thread->wait_objects.clear();
227
213 ready_queue.remove(new_thread->current_priority, new_thread); 228 ready_queue.remove(new_thread->current_priority, new_thread);
214 new_thread->status = THREADSTATUS_RUNNING; 229 new_thread->status = THREADSTATUS_RUNNING;
215 230
@@ -268,10 +283,6 @@ void WaitCurrentThread_ArbitrateAddress(VAddr wait_address) {
268 thread->status = THREADSTATUS_WAIT_ARB; 283 thread->status = THREADSTATUS_WAIT_ARB;
269} 284}
270 285
271// TODO(yuriks): This can be removed if Thread objects are explicitly pooled in the future, allowing
272// us to simply use a pool index or similar.
273static Kernel::HandleTable wakeup_callback_handle_table;
274
275/** 286/**
276 * Callback that will wake up the thread it was scheduled for 287 * Callback that will wake up the thread it was scheduled for
277 * @param thread_handle The handle of the thread that's been awoken 288 * @param thread_handle The handle of the thread that's been awoken
@@ -503,12 +514,16 @@ void ThreadingInit() {
503 514
504 current_thread = nullptr; 515 current_thread = nullptr;
505 next_thread_id = 1; 516 next_thread_id = 1;
506
507 thread_list.clear();
508 ready_queue.clear();
509} 517}
510 518
511void ThreadingShutdown() { 519void ThreadingShutdown() {
520 current_thread = nullptr;
521
522 for (auto& t : thread_list) {
523 t->Stop();
524 }
525 thread_list.clear();
526 ready_queue.clear();
512} 527}
513 528
514} // namespace 529} // namespace
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index b8160bb2c..1ff1d9b97 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -13,6 +13,7 @@
13 13
14#include "core/core.h" 14#include "core/core.h"
15 15
16#include "core/hle/hle.h"
16#include "core/hle/kernel/kernel.h" 17#include "core/hle/kernel/kernel.h"
17#include "core/hle/result.h" 18#include "core/hle/result.h"
18 19
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
index b2dd21542..205cc7b53 100644
--- a/src/core/hle/kernel/vm_manager.cpp
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -2,6 +2,8 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <iterator>
6
5#include "common/assert.h" 7#include "common/assert.h"
6 8
7#include "core/hle/kernel/vm_manager.h" 9#include "core/hle/kernel/vm_manager.h"
@@ -33,6 +35,10 @@ VMManager::VMManager() {
33 Reset(); 35 Reset();
34} 36}
35 37
38VMManager::~VMManager() {
39 Reset();
40}
41
36void VMManager::Reset() { 42void VMManager::Reset() {
37 vma_map.clear(); 43 vma_map.clear();
38 44
@@ -128,6 +134,16 @@ void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
128 MergeAdjacent(iter); 134 MergeAdjacent(iter);
129} 135}
130 136
137void VMManager::LogLayout() const {
138 for (const auto& p : vma_map) {
139 const VirtualMemoryArea& vma = p.second;
140 LOG_DEBUG(Kernel, "%08X - %08X size: %8X %c%c%c", vma.base, vma.base + vma.size, vma.size,
141 (u8)vma.permissions & (u8)VMAPermission::Read ? 'R' : '-',
142 (u8)vma.permissions & (u8)VMAPermission::Write ? 'W' : '-',
143 (u8)vma.permissions & (u8)VMAPermission::Execute ? 'X' : '-');
144 }
145}
146
131VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { 147VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
132 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given 148 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
133 // non-const access to its container. 149 // non-const access to its container.
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
index 22b724603..b3795a94a 100644
--- a/src/core/hle/kernel/vm_manager.h
+++ b/src/core/hle/kernel/vm_manager.h
@@ -6,7 +6,6 @@
6 6
7#include <map> 7#include <map>
8#include <memory> 8#include <memory>
9#include <string>
10#include <vector> 9#include <vector>
11 10
12#include "common/common_types.h" 11#include "common/common_types.h"
@@ -102,7 +101,7 @@ struct VirtualMemoryArea {
102 * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ 101 * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/
103 * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ 102 * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/
104 */ 103 */
105class VMManager { 104class VMManager final {
106 // TODO(yuriks): Make page tables switchable to support multiple VMManagers 105 // TODO(yuriks): Make page tables switchable to support multiple VMManagers
107public: 106public:
108 /** 107 /**
@@ -122,6 +121,7 @@ public:
122 using VMAHandle = decltype(vma_map)::const_iterator; 121 using VMAHandle = decltype(vma_map)::const_iterator;
123 122
124 VMManager(); 123 VMManager();
124 ~VMManager();
125 125
126 /// Clears the address space map, re-initializing with a single free area. 126 /// Clears the address space map, re-initializing with a single free area.
127 void Reset(); 127 void Reset();
@@ -169,6 +169,9 @@ public:
169 /// Changes the permissions of the given VMA. 169 /// Changes the permissions of the given VMA.
170 void Reprotect(VMAHandle vma, VMAPermission new_perms); 170 void Reprotect(VMAHandle vma, VMAPermission new_perms);
171 171
172 /// Dumps the address space layout to the log, for debugging
173 void LogLayout() const;
174
172private: 175private:
173 using VMAIter = decltype(vma_map)::iterator; 176 using VMAIter = decltype(vma_map)::iterator;
174 177
diff --git a/src/core/hle/result.h b/src/core/hle/result.h
index ce633d841..cb2d681e0 100644
--- a/src/core/hle/result.h
+++ b/src/core/hle/result.h
@@ -4,7 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <new>
8#include <type_traits> 8#include <type_traits>
9#include <utility> 9#include <utility>
10 10
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 57dc1ece7..7332478fb 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -38,6 +38,15 @@ void GetTitleIDList(Service::Interface* self) {
38 LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); 38 LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type);
39} 39}
40 40
41void GetNumContentInfos(Service::Interface* self) {
42 u32* cmd_buff = Kernel::GetCommandBuffer();
43
44 cmd_buff[1] = RESULT_SUCCESS.raw;
45 cmd_buff[2] = 1; // Number of content infos plus one
46
47 LOG_WARNING(Service_AM, "(STUBBED) called");
48}
49
41void Init() { 50void Init() {
42 using namespace Kernel; 51 using namespace Kernel;
43 52
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h
index 063b8bd09..0b78f5393 100644
--- a/src/core/hle/service/am/am.h
+++ b/src/core/hle/service/am/am.h
@@ -37,6 +37,19 @@ void TitleIDListGetTotal(Service::Interface* self);
37 */ 37 */
38void GetTitleIDList(Service::Interface* self); 38void GetTitleIDList(Service::Interface* self);
39 39
40/**
41 * AM::GetNumContentInfos service function
42 * Inputs:
43 * 0 : Command header (0x100100C0)
44 * 1 : Unknown
45 * 2 : Unknown
46 * 3 : Unknown
47 * Outputs:
48 * 1 : Result, 0 on success, otherwise error code
49 * 2 : Number of content infos plus one
50 */
51void GetNumContentInfos(Service::Interface* self);
52
40/// Initialize AM service 53/// Initialize AM service
41void Init(); 54void Init();
42 55
diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp
index c6fc81bc3..f40a87cb4 100644
--- a/src/core/hle/service/am/am_app.cpp
+++ b/src/core/hle/service/am/am_app.cpp
@@ -9,11 +9,19 @@
9namespace Service { 9namespace Service {
10namespace AM { 10namespace AM {
11 11
12// Empty arrays are illegal -- commented out until an entry is added. 12const Interface::FunctionInfo FunctionTable[] = {
13//const Interface::FunctionInfo FunctionTable[] = { }; 13 {0x100100C0, GetNumContentInfos, "GetNumContentInfos"},
14 {0x10020104, nullptr, "FindContentInfos"},
15 {0x10030142, nullptr, "ListContentInfos"},
16 {0x10040102, nullptr, "DeleteContents"},
17 {0x10050084, nullptr, "GetDataTitleInfos"},
18 {0x10070102, nullptr, "ListDataTitleTicketInfos"},
19 {0x100900C0, nullptr, "IsDataTitleInUse"},
20 {0x100A0000, nullptr, "IsExternalTitleDatabaseInitialized"},
21};
14 22
15AM_APP_Interface::AM_APP_Interface() { 23AM_APP_Interface::AM_APP_Interface() {
16 //Register(FunctionTable); 24 Register(FunctionTable);
17} 25}
18 26
19} // namespace AM 27} // namespace AM
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index b454a2709..7b6ab4ce0 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -6,6 +6,7 @@
6#include "common/file_util.h" 6#include "common/file_util.h"
7#include "common/logging/log.h" 7#include "common/logging/log.h"
8 8
9#include "core/hle/applets/applet.h"
9#include "core/hle/service/service.h" 10#include "core/hle/service/service.h"
10#include "core/hle/service/apt/apt.h" 11#include "core/hle/service/apt/apt.h"
11#include "core/hle/service/apt/apt_a.h" 12#include "core/hle/service/apt/apt_a.h"
@@ -34,12 +35,21 @@ static Kernel::SharedPtr<Kernel::SharedMemory> shared_font_mem;
34 35
35static Kernel::SharedPtr<Kernel::Mutex> lock; 36static Kernel::SharedPtr<Kernel::Mutex> lock;
36static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event 37static Kernel::SharedPtr<Kernel::Event> notification_event; ///< APT notification event
37static Kernel::SharedPtr<Kernel::Event> start_event; ///< APT start event 38static Kernel::SharedPtr<Kernel::Event> parameter_event; ///< APT parameter event
38 39
39static std::vector<u8> shared_font; 40static std::vector<u8> shared_font;
40 41
41static u32 cpu_percent; ///< CPU time available to the running application 42static u32 cpu_percent; ///< CPU time available to the running application
42 43
44/// Parameter data to be returned in the next call to Glance/ReceiveParameter
45static MessageParameter next_parameter;
46
47void SendParameter(const MessageParameter& parameter) {
48 next_parameter = parameter;
49 // Signal the event to let the application know that a new parameter is ready to be read
50 parameter_event->Signal();
51}
52
43void Initialize(Service::Interface* self) { 53void Initialize(Service::Interface* self) {
44 u32* cmd_buff = Kernel::GetCommandBuffer(); 54 u32* cmd_buff = Kernel::GetCommandBuffer();
45 u32 app_id = cmd_buff[1]; 55 u32 app_id = cmd_buff[1];
@@ -47,18 +57,18 @@ void Initialize(Service::Interface* self) {
47 57
48 cmd_buff[2] = IPC::MoveHandleDesc(2); 58 cmd_buff[2] = IPC::MoveHandleDesc(2);
49 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom(); 59 cmd_buff[3] = Kernel::g_handle_table.Create(notification_event).MoveFrom();
50 cmd_buff[4] = Kernel::g_handle_table.Create(start_event).MoveFrom(); 60 cmd_buff[4] = Kernel::g_handle_table.Create(parameter_event).MoveFrom();
51 61
52 // TODO(bunnei): Check if these events are cleared every time Initialize is called. 62 // TODO(bunnei): Check if these events are cleared every time Initialize is called.
53 notification_event->Clear(); 63 notification_event->Clear();
54 start_event->Clear(); 64 parameter_event->Clear();
55 65
56 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock"); 66 ASSERT_MSG((nullptr != lock), "Cannot initialize without lock");
57 lock->Release(); 67 lock->Release();
58 68
59 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 69 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
60 70
61 LOG_TRACE(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags); 71 LOG_DEBUG(Service_APT, "called app_id=0x%08X, flags=0x%08X", app_id, flags);
62} 72}
63 73
64void GetSharedFont(Service::Interface* self) { 74void GetSharedFont(Service::Interface* self) {
@@ -85,9 +95,6 @@ void GetSharedFont(Service::Interface* self) {
85void NotifyToWait(Service::Interface* self) { 95void NotifyToWait(Service::Interface* self) {
86 u32* cmd_buff = Kernel::GetCommandBuffer(); 96 u32* cmd_buff = Kernel::GetCommandBuffer();
87 u32 app_id = cmd_buff[1]; 97 u32 app_id = cmd_buff[1];
88 // TODO(Subv): Verify this, it seems to get SWKBD and Home Menu further.
89 start_event->Signal();
90
91 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 98 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
92 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id); 99 LOG_WARNING(Service_APT, "(STUBBED) app_id=%u", app_id);
93} 100}
@@ -100,7 +107,7 @@ void GetLockHandle(Service::Interface* self) {
100 107
101 // Not sure what these parameters are used for, but retail apps check that they are 0 after 108 // Not sure what these parameters are used for, but retail apps check that they are 0 after
102 // GetLockHandle has been called. 109 // GetLockHandle has been called.
103 cmd_buff[2] = 0; 110 cmd_buff[2] = 0; // Applet Attributes, this value is passed to Enable.
104 cmd_buff[3] = 0; 111 cmd_buff[3] = 0;
105 cmd_buff[4] = 0; 112 cmd_buff[4] = 0;
106 113
@@ -110,9 +117,10 @@ void GetLockHandle(Service::Interface* self) {
110 117
111void Enable(Service::Interface* self) { 118void Enable(Service::Interface* self) {
112 u32* cmd_buff = Kernel::GetCommandBuffer(); 119 u32* cmd_buff = Kernel::GetCommandBuffer();
113 u32 unk = cmd_buff[1]; // TODO(bunnei): What is this field used for? 120 u32 attributes = cmd_buff[1];
114 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
115 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 122 parameter_event->Signal(); // Let the application know that it has been started
123 LOG_WARNING(Service_APT, "(STUBBED) called attributes=0x%08X", attributes);
116} 124}
117 125
118void GetAppletManInfo(Service::Interface* self) { 126void GetAppletManInfo(Service::Interface* self) {
@@ -121,8 +129,8 @@ void GetAppletManInfo(Service::Interface* self) {
121 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 129 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
122 cmd_buff[2] = 0; 130 cmd_buff[2] = 0;
123 cmd_buff[3] = 0; 131 cmd_buff[3] = 0;
124 cmd_buff[4] = static_cast<u32>(AppID::HomeMenu); // Home menu AppID 132 cmd_buff[4] = static_cast<u32>(AppletId::HomeMenu); // Home menu AppID
125 cmd_buff[5] = static_cast<u32>(AppID::Application); // TODO(purpasmart96): Do this correctly 133 cmd_buff[5] = static_cast<u32>(AppletId::Application); // TODO(purpasmart96): Do this correctly
126 134
127 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk); 135 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X", unk);
128} 136}
@@ -131,7 +139,13 @@ void IsRegistered(Service::Interface* self) {
131 u32* cmd_buff = Kernel::GetCommandBuffer(); 139 u32* cmd_buff = Kernel::GetCommandBuffer();
132 u32 app_id = cmd_buff[1]; 140 u32 app_id = cmd_buff[1];
133 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 141 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
134 cmd_buff[2] = 1; // Set to registered 142 /// TODO(Subv): It is currently unknown what this value (0x400) means,
143 /// but i believe it is used as a global "LibraryApplet" id, to verify if there's
144 /// any LibApplet currently running. This is not verified.
145 if (app_id != 0x400)
146 cmd_buff[2] = 1; // Set to registered
147 else
148 cmd_buff[2] = 0; // Set to not registered
135 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id); 149 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X", app_id);
136} 150}
137 151
@@ -145,50 +159,82 @@ void InquireNotification(Service::Interface* self) {
145 159
146void SendParameter(Service::Interface* self) { 160void SendParameter(Service::Interface* self) {
147 u32* cmd_buff = Kernel::GetCommandBuffer(); 161 u32* cmd_buff = Kernel::GetCommandBuffer();
148 u32 src_app_id = cmd_buff[1]; 162 u32 src_app_id = cmd_buff[1];
149 u32 dst_app_id = cmd_buff[2]; 163 u32 dst_app_id = cmd_buff[2];
150 u32 signal_type = cmd_buff[3]; 164 u32 signal_type = cmd_buff[3];
151 u32 buffer_size = cmd_buff[4]; 165 u32 buffer_size = cmd_buff[4];
152 u32 value = cmd_buff[5]; 166 u32 value = cmd_buff[5];
153 u32 handle = cmd_buff[6]; 167 u32 handle = cmd_buff[6];
154 u32 size = cmd_buff[7]; 168 u32 size = cmd_buff[7];
155 u32 in_param_buffer_ptr = cmd_buff[8]; 169 u32 buffer = cmd_buff[8];
170
171 std::shared_ptr<HLE::Applets::Applet> dest_applet = HLE::Applets::Applet::Get(static_cast<AppletId>(dst_app_id));
172
173 if (dest_applet == nullptr) {
174 LOG_ERROR(Service_APT, "Unknown applet id=0x%08X", dst_app_id);
175 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
176 return;
177 }
156 178
157 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 179 MessageParameter param;
180 param.buffer_size = buffer_size;
181 param.destination_id = dst_app_id;
182 param.sender_id = src_app_id;
183 param.object = Kernel::g_handle_table.GetGeneric(handle);
184 param.signal = signal_type;
185 param.data = Memory::GetPointer(buffer);
186
187 cmd_buff[1] = dest_applet->ReceiveParameter(param).raw;
158 188
159 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," 189 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
160 "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X", 190 "buffer_size=0x%08X, value=0x%08X, handle=0x%08X, size=0x%08X, in_param_buffer_ptr=0x%08X",
161 src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, in_param_buffer_ptr); 191 src_app_id, dst_app_id, signal_type, buffer_size, value, handle, size, buffer);
162} 192}
163 193
164void ReceiveParameter(Service::Interface* self) { 194void ReceiveParameter(Service::Interface* self) {
165 u32* cmd_buff = Kernel::GetCommandBuffer(); 195 u32* cmd_buff = Kernel::GetCommandBuffer();
166 u32 app_id = cmd_buff[1]; 196 u32 app_id = cmd_buff[1];
167 u32 buffer_size = cmd_buff[2]; 197 u32 buffer_size = cmd_buff[2];
198 VAddr buffer = cmd_buff[0x104 >> 2];
199
168 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 200 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
169 cmd_buff[2] = 0; 201 cmd_buff[2] = next_parameter.sender_id;
170 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 202 cmd_buff[3] = next_parameter.signal; // Signal type
171 cmd_buff[4] = 0x10; // Parameter buffer size (16) 203 cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
172 cmd_buff[5] = 0; 204 cmd_buff[5] = 0x10;
173 cmd_buff[6] = 0; 205 cmd_buff[6] = 0;
174 cmd_buff[7] = 0; 206 if (next_parameter.object != nullptr)
175 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 207 cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
208 cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
209 cmd_buff[8] = buffer;
210
211 if (next_parameter.data)
212 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
213
214 LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
176} 215}
177 216
178void GlanceParameter(Service::Interface* self) { 217void GlanceParameter(Service::Interface* self) {
179 u32* cmd_buff = Kernel::GetCommandBuffer(); 218 u32* cmd_buff = Kernel::GetCommandBuffer();
180 u32 app_id = cmd_buff[1]; 219 u32 app_id = cmd_buff[1];
181 u32 buffer_size = cmd_buff[2]; 220 u32 buffer_size = cmd_buff[2];
221 VAddr buffer = cmd_buff[0x104 >> 2];
182 222
183 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 223 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
184 cmd_buff[2] = 0; 224 cmd_buff[2] = next_parameter.sender_id;
185 cmd_buff[3] = static_cast<u32>(SignalType::AppJustStarted); // Signal type 225 cmd_buff[3] = next_parameter.signal; // Signal type
186 cmd_buff[4] = 0x10; // Parameter buffer size (16) 226 cmd_buff[4] = next_parameter.buffer_size; // Parameter buffer size
187 cmd_buff[5] = 0; 227 cmd_buff[5] = 0x10;
188 cmd_buff[6] = 0; 228 cmd_buff[6] = 0;
189 cmd_buff[7] = 0; 229 if (next_parameter.object != nullptr)
230 cmd_buff[6] = Kernel::g_handle_table.Create(next_parameter.object).MoveFrom();
231 cmd_buff[7] = (next_parameter.buffer_size << 14) | 2;
232 cmd_buff[8] = buffer;
190 233
191 LOG_WARNING(Service_APT, "(STUBBED) called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size); 234 if (next_parameter.data)
235 memcpy(Memory::GetPointer(buffer), next_parameter.data, std::min(buffer_size, next_parameter.buffer_size));
236
237 LOG_WARNING(Service_APT, "called app_id=0x%08X, buffer_size=0x%08X", app_id, buffer_size);
192} 238}
193 239
194void CancelParameter(Service::Interface* self) { 240void CancelParameter(Service::Interface* self) {
@@ -240,7 +286,7 @@ void AppletUtility(Service::Interface* self) {
240 u32* cmd_buff = Kernel::GetCommandBuffer(); 286 u32* cmd_buff = Kernel::GetCommandBuffer();
241 287
242 // These are from 3dbrew - I'm not really sure what they're used for. 288 // These are from 3dbrew - I'm not really sure what they're used for.
243 u32 unk = cmd_buff[1]; 289 u32 command = cmd_buff[1];
244 u32 buffer1_size = cmd_buff[2]; 290 u32 buffer1_size = cmd_buff[2];
245 u32 buffer2_size = cmd_buff[3]; 291 u32 buffer2_size = cmd_buff[3];
246 u32 buffer1_addr = cmd_buff[5]; 292 u32 buffer1_addr = cmd_buff[5];
@@ -248,8 +294,8 @@ void AppletUtility(Service::Interface* self) {
248 294
249 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 295 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
250 296
251 LOG_WARNING(Service_APT, "(STUBBED) called unk=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, " 297 LOG_WARNING(Service_APT, "(STUBBED) called command=0x%08X, buffer1_size=0x%08X, buffer2_size=0x%08X, "
252 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", unk, buffer1_size, buffer2_size, 298 "buffer1_addr=0x%08X, buffer2_addr=0x%08X", command, buffer1_size, buffer2_size,
253 buffer1_addr, buffer2_addr); 299 buffer1_addr, buffer2_addr);
254} 300}
255 301
@@ -281,11 +327,41 @@ void GetAppCpuTimeLimit(Service::Interface* self) {
281 LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value); 327 LOG_WARNING(Service_APT, "(STUBBED) called value=%u", value);
282} 328}
283 329
330void PrepareToStartLibraryApplet(Service::Interface* self) {
331 u32* cmd_buff = Kernel::GetCommandBuffer();
332 AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
333 cmd_buff[1] = HLE::Applets::Applet::Create(applet_id).raw;
334 LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
335}
336
337void StartLibraryApplet(Service::Interface* self) {
338 u32* cmd_buff = Kernel::GetCommandBuffer();
339 AppletId applet_id = static_cast<AppletId>(cmd_buff[1]);
340 std::shared_ptr<HLE::Applets::Applet> applet = HLE::Applets::Applet::Get(applet_id);
341
342 LOG_DEBUG(Service_APT, "called applet_id=%08X", applet_id);
343
344 if (applet == nullptr) {
345 LOG_ERROR(Service_APT, "unknown applet id=%08X", applet_id);
346 cmd_buff[1] = -1; // TODO(Subv): Find the right error code
347 return;
348 }
349
350 AppletStartupParameter parameter;
351 parameter.buffer_size = cmd_buff[2];
352 parameter.object = Kernel::g_handle_table.GetGeneric(cmd_buff[4]);
353 parameter.data = Memory::GetPointer(cmd_buff[6]);
354
355 cmd_buff[1] = applet->Start(parameter).raw;
356}
357
284void Init() { 358void Init() {
285 AddService(new APT_A_Interface); 359 AddService(new APT_A_Interface);
286 AddService(new APT_S_Interface); 360 AddService(new APT_S_Interface);
287 AddService(new APT_U_Interface); 361 AddService(new APT_U_Interface);
288 362
363 HLE::Applets::Init();
364
289 // Load the shared system font (if available). 365 // Load the shared system font (if available).
290 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header 366 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
291 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided 367 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
@@ -318,7 +394,10 @@ void Init() {
318 394
319 // TODO(bunnei): Check if these are created in Initialize or on APT process startup. 395 // TODO(bunnei): Check if these are created in Initialize or on APT process startup.
320 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification"); 396 notification_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Notification");
321 start_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start"); 397 parameter_event = Kernel::Event::Create(RESETTYPE_ONESHOT, "APT_U:Start");
398
399 next_parameter.signal = static_cast<u32>(SignalType::AppJustStarted);
400 next_parameter.destination_id = 0x300;
322} 401}
323 402
324void Shutdown() { 403void Shutdown() {
@@ -326,7 +405,11 @@ void Shutdown() {
326 shared_font_mem = nullptr; 405 shared_font_mem = nullptr;
327 lock = nullptr; 406 lock = nullptr;
328 notification_event = nullptr; 407 notification_event = nullptr;
329 start_event = nullptr; 408 parameter_event = nullptr;
409
410 next_parameter.object = nullptr;
411
412 HLE::Applets::Shutdown();
330} 413}
331 414
332} // namespace APT 415} // namespace APT
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index a03e1712a..72972d05b 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -4,13 +4,33 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include "common/common_types.h"
8#include "core/hle/result.h" 8
9#include "core/hle/service/service.h" 9#include "core/hle/kernel/kernel.h"
10 10
11namespace Service { 11namespace Service {
12
13class Interface;
14
12namespace APT { 15namespace APT {
13 16
17/// Holds information about the parameters used in Send/Glance/ReceiveParameter
18struct MessageParameter {
19 u32 sender_id = 0;
20 u32 destination_id = 0;
21 u32 signal = 0;
22 u32 buffer_size = 0;
23 Kernel::SharedPtr<Kernel::Object> object = nullptr;
24 u8* data = nullptr;
25};
26
27/// Holds information about the parameters used in StartLibraryApplet
28struct AppletStartupParameter {
29 u32 buffer_size = 0;
30 Kernel::SharedPtr<Kernel::Object> object = nullptr;
31 u8* data = nullptr;
32};
33
14/// Signals used by APT functions 34/// Signals used by APT functions
15enum class SignalType : u32 { 35enum class SignalType : u32 {
16 None = 0x0, 36 None = 0x0,
@@ -23,7 +43,7 @@ enum class SignalType : u32 {
23}; 43};
24 44
25/// App Id's used by APT functions 45/// App Id's used by APT functions
26enum class AppID : u32 { 46enum class AppletId : u32 {
27 HomeMenu = 0x101, 47 HomeMenu = 0x101,
28 AlternateMenu = 0x103, 48 AlternateMenu = 0x103,
29 Camera = 0x110, 49 Camera = 0x110,
@@ -45,6 +65,9 @@ enum class AppID : u32 {
45 SoftwareKeyboard2 = 0x401, 65 SoftwareKeyboard2 = 0x401,
46}; 66};
47 67
68/// Send a parameter to the currently-running application, which will read it via ReceiveParameter
69void SendParameter(const MessageParameter& parameter);
70
48/** 71/**
49 * APT::Initialize service function 72 * APT::Initialize service function
50 * Service function that initializes the APT process for the running application 73 * Service function that initializes the APT process for the running application
@@ -249,6 +272,33 @@ void SetAppCpuTimeLimit(Service::Interface* self);
249 */ 272 */
250void GetAppCpuTimeLimit(Service::Interface* self); 273void GetAppCpuTimeLimit(Service::Interface* self);
251 274
275/**
276 * APT::PrepareToStartLibraryApplet service function
277 * Inputs:
278 * 0 : Command header [0x00180040]
279 * 1 : Id of the applet to start
280 * Outputs:
281 * 0 : Return header
282 * 1 : Result of function, 0 on success, otherwise error code
283 */
284void PrepareToStartLibraryApplet(Service::Interface* self);
285
286/**
287 * APT::StartLibraryApplet service function
288 * Inputs:
289 * 0 : Command header [0x001E0084]
290 * 1 : Id of the applet to start
291 * 2 : Buffer size
292 * 3 : Always 0?
293 * 4 : Handle passed to the applet
294 * 5 : (Size << 14) | 2
295 * 6 : Input buffer virtual address
296 * Outputs:
297 * 0 : Return header
298 * 1 : Result of function, 0 on success, otherwise error code
299 */
300void StartLibraryApplet(Service::Interface* self);
301
252/// Initialize the APT service 302/// Initialize the APT service
253void Init(); 303void Init();
254 304
diff --git a/src/core/hle/service/apt/apt_a.cpp b/src/core/hle/service/apt/apt_a.cpp
index 864934245..88de339f9 100644
--- a/src/core/hle/service/apt/apt_a.cpp
+++ b/src/core/hle/service/apt/apt_a.cpp
@@ -10,19 +10,24 @@ namespace Service {
10namespace APT { 10namespace APT {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010040, GetLockHandle, "GetLockHandle?"}, 13 {0x00010040, GetLockHandle, "GetLockHandle?"},
14 {0x00020080, Initialize, "Initialize?"}, 14 {0x00020080, Initialize, "Initialize?"},
15 {0x00030040, Enable, "Enable?"}, 15 {0x00030040, Enable, "Enable?"},
16 {0x00040040, nullptr, "Finalize?"}, 16 {0x00040040, nullptr, "Finalize?"},
17 {0x00050040, nullptr, "GetAppletManInfo?"}, 17 {0x00050040, nullptr, "GetAppletManInfo?"},
18 {0x00060040, nullptr, "GetAppletInfo?"}, 18 {0x00060040, nullptr, "GetAppletInfo?"},
19 {0x000D0080, ReceiveParameter, "ReceiveParameter?"}, 19 {0x00090040, IsRegistered, "IsRegistered"},
20 {0x000E0080, GlanceParameter, "GlanceParameter?"}, 20 {0x000C0104, SendParameter, "SendParameter"},
21 {0x003B0040, nullptr, "CancelLibraryApplet?"}, 21 {0x000D0080, ReceiveParameter, "ReceiveParameter"},
22 {0x00430040, NotifyToWait, "NotifyToWait?"}, 22 {0x000E0080, GlanceParameter, "GlanceParameter"},
23 {0x00440000, GetSharedFont, "GetSharedFont?"}, 23 {0x000F0100, CancelParameter, "CancelParameter"},
24 {0x004B00C2, AppletUtility, "AppletUtility?"}, 24 {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
25 {0x00550040, nullptr, "WriteInputToNsState?"}, 25 {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
26 {0x003B0040, nullptr, "CancelLibraryApplet?"},
27 {0x00430040, NotifyToWait, "NotifyToWait?"},
28 {0x00440000, GetSharedFont, "GetSharedFont?"},
29 {0x004B00C2, AppletUtility, "AppletUtility?"},
30 {0x00550040, nullptr, "WriteInputToNsState?"},
26}; 31};
27 32
28APT_A_Interface::APT_A_Interface() { 33APT_A_Interface::APT_A_Interface() {
diff --git a/src/core/hle/service/apt/apt_u.cpp b/src/core/hle/service/apt/apt_u.cpp
index d006b5930..b724cd72b 100644
--- a/src/core/hle/service/apt/apt_u.cpp
+++ b/src/core/hle/service/apt/apt_u.cpp
@@ -35,13 +35,13 @@ const Interface::FunctionInfo FunctionTable[] = {
35 {0x00150140, nullptr, "PrepareToStartApplication"}, 35 {0x00150140, nullptr, "PrepareToStartApplication"},
36 {0x00160040, nullptr, "PreloadLibraryApplet"}, 36 {0x00160040, nullptr, "PreloadLibraryApplet"},
37 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"}, 37 {0x00170040, nullptr, "FinishPreloadingLibraryApplet"},
38 {0x00180040, nullptr, "PrepareToStartLibraryApplet"}, 38 {0x00180040, PrepareToStartLibraryApplet, "PrepareToStartLibraryApplet"},
39 {0x00190040, nullptr, "PrepareToStartSystemApplet"}, 39 {0x00190040, nullptr, "PrepareToStartSystemApplet"},
40 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"}, 40 {0x001A0000, nullptr, "PrepareToStartNewestHomeMenu"},
41 {0x001B00C4, nullptr, "StartApplication"}, 41 {0x001B00C4, nullptr, "StartApplication"},
42 {0x001C0000, nullptr, "WakeupApplication"}, 42 {0x001C0000, nullptr, "WakeupApplication"},
43 {0x001D0000, nullptr, "CancelApplication"}, 43 {0x001D0000, nullptr, "CancelApplication"},
44 {0x001E0084, nullptr, "StartLibraryApplet"}, 44 {0x001E0084, StartLibraryApplet, "StartLibraryApplet"},
45 {0x001F0084, nullptr, "StartSystemApplet"}, 45 {0x001F0084, nullptr, "StartSystemApplet"},
46 {0x00200044, nullptr, "StartNewestHomeMenu"}, 46 {0x00200044, nullptr, "StartNewestHomeMenu"},
47 {0x00210000, nullptr, "OrderToCloseApplication"}, 47 {0x00210000, nullptr, "OrderToCloseApplication"},
diff --git a/src/core/hle/service/cfg/cfg_s.cpp b/src/core/hle/service/cfg/cfg_s.cpp
index af4adba84..a329514a6 100644
--- a/src/core/hle/service/cfg/cfg_s.cpp
+++ b/src/core/hle/service/cfg/cfg_s.cpp
@@ -11,7 +11,9 @@ namespace CFG {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"}, 13 {0x00010082, GetConfigInfoBlk2, "GetConfigInfoBlk2"},
14 {0x00020000, nullptr, "SecureInfoGetRegion"}, 14 {0x00020000, SecureInfoGetRegion, "SecureInfoGetRegion"},
15 {0x00030040, GenHashConsoleUnique, "GenHashConsoleUnique"},
16 {0x00050000, GetSystemModel, "GetSystemModel"},
15 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"}, 17 {0x04010082, GetConfigInfoBlk8, "GetConfigInfoBlk8"},
16 {0x04020082, nullptr, "SetConfigInfoBlk4"}, 18 {0x04020082, nullptr, "SetConfigInfoBlk4"},
17 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"}, 19 {0x04030000, UpdateConfigNANDSavegame, "UpdateConfigNANDSavegame"},
diff --git a/src/core/hle/service/dsp_dsp.cpp b/src/core/hle/service/dsp_dsp.cpp
index fafb43a2f..a8cb15d60 100644
--- a/src/core/hle/service/dsp_dsp.cpp
+++ b/src/core/hle/service/dsp_dsp.cpp
@@ -310,4 +310,9 @@ Interface::Interface() {
310 Register(FunctionTable); 310 Register(FunctionTable);
311} 311}
312 312
313Interface::~Interface() {
314 semaphore_event = nullptr;
315 interrupt_event = nullptr;
316}
317
313} // namespace 318} // namespace
diff --git a/src/core/hle/service/dsp_dsp.h b/src/core/hle/service/dsp_dsp.h
index fa13bfb7c..b6f611db5 100644
--- a/src/core/hle/service/dsp_dsp.h
+++ b/src/core/hle/service/dsp_dsp.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -14,6 +16,7 @@ namespace DSP_DSP {
14class Interface : public Service::Interface { 16class Interface : public Service::Interface {
15public: 17public:
16 Interface(); 18 Interface();
19 ~Interface() override;
17 20
18 std::string GetPortName() const override { 21 std::string GetPortName() const override {
19 return "dsp::DSP"; 22 return "dsp::DSP";
diff --git a/src/core/hle/service/frd/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp
index 439c7282e..3a5897d06 100644
--- a/src/core/hle/service/frd/frd_u.cpp
+++ b/src/core/hle/service/frd/frd_u.cpp
@@ -10,15 +10,26 @@ namespace Service {
10namespace FRD { 10namespace FRD {
11 11
12const Interface::FunctionInfo FunctionTable[] = { 12const Interface::FunctionInfo FunctionTable[] = {
13 {0x00010000, nullptr, "HasLoggedIn"},
14 {0x00030000, nullptr, "Login"},
15 {0x00040000, nullptr, "Logout"},
13 {0x00050000, nullptr, "GetFriendKey"}, 16 {0x00050000, nullptr, "GetFriendKey"},
14 {0x00080000, nullptr, "GetMyPresence"}, 17 {0x00080000, nullptr, "GetMyPresence"},
18 {0x00090000, nullptr, "GetMyScreenName"},
15 {0x00100040, nullptr, "GetPassword"}, 19 {0x00100040, nullptr, "GetPassword"},
20 {0x00110080, nullptr, "GetFriendKeyList"},
16 {0x00190042, nullptr, "GetFriendFavoriteGame"}, 21 {0x00190042, nullptr, "GetFriendFavoriteGame"},
17 {0x001A00C4, nullptr, "GetFriendInfo"}, 22 {0x001A00C4, nullptr, "GetFriendInfo"},
18 {0x001B0080, nullptr, "IsOnFriendList"}, 23 {0x001B0080, nullptr, "IsOnFriendList"},
19 {0x001C0042, nullptr, "DecodeLocalFriendCode"}, 24 {0x001C0042, nullptr, "DecodeLocalFriendCode"},
20 {0x001D0002, nullptr, "SetCurrentlyPlayingText"}, 25 {0x001D0002, nullptr, "SetCurrentlyPlayingText"},
21 {0x00320042, nullptr, "SetClientSdkVersion"} 26 {0x00230000, nullptr, "GetLastResponseResult"},
27 {0x00270040, nullptr, "ResultToErrorCode"},
28 {0x00280244, nullptr, "RequestGameAuthentication"},
29 {0x00290000, nullptr, "GetGameAuthenticationData"},
30 {0x002A0204, nullptr, "RequestServiceLocator"},
31 {0x002B0000, nullptr, "GetServiceLocatorData"},
32 {0x00320042, nullptr, "SetClientSdkVersion"},
22}; 33};
23 34
24FRD_U_Interface::FRD_U_Interface() { 35FRD_U_Interface::FRD_U_Interface() {
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 4e275cb13..6c0df67c3 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -2,29 +2,35 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstddef>
6#include <system_error>
7#include <type_traits>
5#include <memory> 8#include <memory>
6#include <unordered_map> 9#include <unordered_map>
10#include <utility>
7 11
8#include <boost/container/flat_map.hpp> 12#include <boost/container/flat_map.hpp>
9 13
14#include "common/assert.h"
10#include "common/common_types.h" 15#include "common/common_types.h"
11#include "common/file_util.h" 16#include "common/file_util.h"
12#include "common/logging/log.h" 17#include "common/logging/log.h"
13#include "common/make_unique.h" 18#include "common/make_unique.h"
14#include "common/math_util.h"
15 19
16#include "core/file_sys/archive_backend.h" 20#include "core/file_sys/archive_backend.h"
17#include "core/file_sys/archive_extsavedata.h" 21#include "core/file_sys/archive_extsavedata.h"
18#include "core/file_sys/archive_romfs.h"
19#include "core/file_sys/archive_savedata.h" 22#include "core/file_sys/archive_savedata.h"
20#include "core/file_sys/archive_savedatacheck.h" 23#include "core/file_sys/archive_savedatacheck.h"
21#include "core/file_sys/archive_sdmc.h" 24#include "core/file_sys/archive_sdmc.h"
22#include "core/file_sys/archive_systemsavedata.h" 25#include "core/file_sys/archive_systemsavedata.h"
23#include "core/file_sys/directory_backend.h" 26#include "core/file_sys/directory_backend.h"
27#include "core/file_sys/file_backend.h"
28#include "core/hle/hle.h"
24#include "core/hle/service/service.h" 29#include "core/hle/service/service.h"
25#include "core/hle/service/fs/archive.h" 30#include "core/hle/service/fs/archive.h"
26#include "core/hle/service/fs/fs_user.h" 31#include "core/hle/service/fs/fs_user.h"
27#include "core/hle/result.h" 32#include "core/hle/result.h"
33#include "core/memory.h"
28 34
29// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map. 35// Specializes std::hash for ArchiveIdCode, so that we can use it in std::unordered_map.
30// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970 36// Workaroung for libstdc++ bug: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=60970
@@ -110,7 +116,7 @@ ResultVal<bool> File::SyncRequest() {
110 u32 address = cmd_buff[6]; 116 u32 address = cmd_buff[6];
111 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x", 117 LOG_TRACE(Service_FS, "Write %s %s: offset=0x%llx length=%d address=0x%x, flush=0x%x",
112 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush); 118 GetTypeName().c_str(), GetName().c_str(), offset, length, address, flush);
113 cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush, Memory::GetPointer(address))); 119 cmd_buff[2] = static_cast<u32>(backend->Write(offset, length, flush != 0, Memory::GetPointer(address)));
114 break; 120 break;
115 } 121 }
116 122
diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h
index 357b6b096..f61125953 100644
--- a/src/core/hle/service/fs/archive.h
+++ b/src/core/hle/service/fs/archive.h
@@ -4,22 +4,25 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8#include <string>
9
7#include "common/common_types.h" 10#include "common/common_types.h"
8 11
9#include "core/file_sys/archive_backend.h" 12#include "core/file_sys/archive_backend.h"
10#include "core/hle/kernel/kernel.h"
11#include "core/hle/kernel/session.h" 13#include "core/hle/kernel/session.h"
12#include "core/hle/result.h" 14#include "core/hle/result.h"
13 15
16namespace FileSys {
17class DirectoryBackend;
18class FileBackend;
19}
20
14/// The unique system identifier hash, also known as ID0 21/// The unique system identifier hash, also known as ID0
15extern const std::string SYSTEM_ID; 22extern const std::string SYSTEM_ID;
16/// The scrambled SD card CID, also known as ID1 23/// The scrambled SD card CID, also known as ID1
17extern const std::string SDCARD_ID; 24extern const std::string SDCARD_ID;
18 25
19namespace Kernel {
20 class Session;
21}
22
23namespace Service { 26namespace Service {
24namespace FS { 27namespace FS {
25 28
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index 0ad44e55e..ae52083f9 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -115,7 +115,8 @@ static void OpenFileDirectly(Service::Interface* self) {
115 115
116 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path); 116 ResultVal<ArchiveHandle> archive_handle = OpenArchive(archive_id, archive_path);
117 if (archive_handle.Failed()) { 117 if (archive_handle.Failed()) {
118 LOG_ERROR(Service_FS, "failed to get a handle for archive"); 118 LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
119 archive_id, archive_path.DebugStr().c_str());
119 cmd_buff[1] = archive_handle.Code().raw; 120 cmd_buff[1] = archive_handle.Code().raw;
120 cmd_buff[3] = 0; 121 cmd_buff[3] = 0;
121 return; 122 return;
@@ -128,7 +129,8 @@ static void OpenFileDirectly(Service::Interface* self) {
128 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom(); 129 cmd_buff[3] = Kernel::g_handle_table.Create(*file_res).MoveFrom();
129 } else { 130 } else {
130 cmd_buff[3] = 0; 131 cmd_buff[3] = 0;
131 LOG_ERROR(Service_FS, "failed to get a handle for file %s", file_path.DebugStr().c_str()); 132 LOG_ERROR(Service_FS, "failed to get a handle for file %s mode=%u attributes=%d",
133 file_path.DebugStr().c_str(), mode.hex, attributes);
132 } 134 }
133} 135}
134 136
@@ -347,7 +349,8 @@ static void OpenDirectory(Service::Interface* self) {
347 if (dir_res.Succeeded()) { 349 if (dir_res.Succeeded()) {
348 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom(); 350 cmd_buff[3] = Kernel::g_handle_table.Create(*dir_res).MoveFrom();
349 } else { 351 } else {
350 LOG_ERROR(Service_FS, "failed to get a handle for directory"); 352 LOG_ERROR(Service_FS, "failed to get a handle for directory type=%d size=%d data=%s",
353 dirname_type, dirname_size, dir_path.DebugStr().c_str());
351 } 354 }
352} 355}
353 356
@@ -382,7 +385,8 @@ static void OpenArchive(Service::Interface* self) {
382 cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF; 385 cmd_buff[3] = (*handle >> 32) & 0xFFFFFFFF;
383 } else { 386 } else {
384 cmd_buff[2] = cmd_buff[3] = 0; 387 cmd_buff[2] = cmd_buff[3] = 0;
385 LOG_ERROR(Service_FS, "failed to get a handle for archive"); 388 LOG_ERROR(Service_FS, "failed to get a handle for archive archive_id=0x%08X archive_path=%s",
389 archive_id, archive_path.DebugStr().c_str());
386 } 390 }
387} 391}
388 392
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 4b0b4229d..e93c1b436 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -9,14 +9,17 @@
9#include "core/hle/kernel/event.h" 9#include "core/hle/kernel/event.h"
10#include "core/hle/kernel/shared_memory.h" 10#include "core/hle/kernel/shared_memory.h"
11#include "core/hle/result.h" 11#include "core/hle/result.h"
12#include "gsp_gpu.h"
13#include "core/hw/hw.h" 12#include "core/hw/hw.h"
14#include "core/hw/gpu.h" 13#include "core/hw/gpu.h"
15#include "core/hw/lcd.h" 14#include "core/hw/lcd.h"
16 15
17#include "video_core/gpu_debugger.h" 16#include "video_core/gpu_debugger.h"
17#include "video_core/debug_utils/debug_utils.h"
18#include "video_core/renderer_base.h"
18#include "video_core/video_core.h" 19#include "video_core/video_core.h"
19 20
21#include "gsp_gpu.h"
22
20// Main graphics debugger object - TODO: Here is probably not the best place for this 23// Main graphics debugger object - TODO: Here is probably not the best place for this
21GraphicsDebugger g_debugger; 24GraphicsDebugger g_debugger;
22 25
@@ -40,7 +43,7 @@ static inline u8* GetCommandBuffer(u32 thread_id) {
40 return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer))); 43 return g_shared_memory->GetPointer(0x800 + (thread_id * sizeof(CommandBuffer)));
41} 44}
42 45
43static inline FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) { 46FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index) {
44 DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index"); 47 DEBUG_ASSERT_MSG(screen_index < 2, "Invalid screen index");
45 48
46 // For each thread there are two FrameBufferUpdate fields 49 // For each thread there are two FrameBufferUpdate fields
@@ -203,7 +206,7 @@ static void ReadHWRegs(Service::Interface* self) {
203 } 206 }
204} 207}
205 208
206static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { 209void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
207 u32 base_address = 0x400000; 210 u32 base_address = 0x400000;
208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 211 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 212 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
@@ -224,6 +227,9 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
224 &info.format); 227 &info.format);
225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 228 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
226 &info.shown_fb); 229 &info.shown_fb);
230
231 if (Pica::g_debug_context)
232 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::BufferSwapped, nullptr);
227} 233}
228 234
229/** 235/**
@@ -347,7 +353,7 @@ void SignalInterrupt(InterruptId interrupt_id) {
347/// Executes the next GSP command 353/// Executes the next GSP command
348static void ExecuteCommand(const Command& command, u32 thread_id) { 354static void ExecuteCommand(const Command& command, u32 thread_id) {
349 // Utility function to convert register ID to address 355 // Utility function to convert register ID to address
350 auto WriteGPURegister = [](u32 id, u32 data) { 356 static auto WriteGPURegister = [](u32 id, u32 data) {
351 GPU::Write<u32>(0x1EF00000 + 4 * id, data); 357 GPU::Write<u32>(0x1EF00000 + 4 * id, data);
352 }; 358 };
353 359
@@ -389,19 +395,24 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
389 case CommandId::SET_MEMORY_FILL: 395 case CommandId::SET_MEMORY_FILL:
390 { 396 {
391 auto& params = command.memory_fill; 397 auto& params = command.memory_fill;
392 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)), 398
393 Memory::VirtualToPhysicalAddress(params.start1) >> 3); 399 if (params.start1 != 0) {
394 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)), 400 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_start)),
395 Memory::VirtualToPhysicalAddress(params.end1) >> 3); 401 Memory::VirtualToPhysicalAddress(params.start1) >> 3);
396 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1); 402 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].address_end)),
397 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1); 403 Memory::VirtualToPhysicalAddress(params.end1) >> 3);
398 404 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].value_32bit)), params.value1);
399 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)), 405 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[0].control)), params.control1);
400 Memory::VirtualToPhysicalAddress(params.start2) >> 3); 406 }
401 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)), 407
402 Memory::VirtualToPhysicalAddress(params.end2) >> 3); 408 if (params.start2 != 0) {
403 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2); 409 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_start)),
404 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2); 410 Memory::VirtualToPhysicalAddress(params.start2) >> 3);
411 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].address_end)),
412 Memory::VirtualToPhysicalAddress(params.end2) >> 3);
413 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].value_32bit)), params.value2);
414 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(memory_fill_config[1].control)), params.control2);
415 }
405 break; 416 break;
406 } 417 }
407 418
@@ -446,6 +457,9 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
446 default: 457 default:
447 LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value()); 458 LOG_ERROR(Service_GSP, "unknown command 0x%08X", (int)command.id.Value());
448 } 459 }
460
461 if (Pica::g_debug_context)
462 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::GSPCommandProcessed, (void*)&command);
449} 463}
450 464
451/** 465/**
@@ -582,7 +596,7 @@ const Interface::FunctionInfo FunctionTable[] = {
582Interface::Interface() { 596Interface::Interface() {
583 Register(FunctionTable); 597 Register(FunctionTable);
584 598
585 g_interrupt_event = 0; 599 g_interrupt_event = nullptr;
586 600
587 using Kernel::MemoryPermission; 601 using Kernel::MemoryPermission;
588 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite, 602 g_shared_memory = Kernel::SharedMemory::Create(0x1000, MemoryPermission::ReadWrite,
@@ -591,4 +605,9 @@ Interface::Interface() {
591 g_thread_id = 0; 605 g_thread_id = 0;
592} 606}
593 607
608Interface::~Interface() {
609 g_interrupt_event = nullptr;
610 g_shared_memory = nullptr;
611}
612
594} // namespace 613} // namespace
diff --git a/src/core/hle/service/gsp_gpu.h b/src/core/hle/service/gsp_gpu.h
index a435d418a..c89d0a467 100644
--- a/src/core/hle/service/gsp_gpu.h
+++ b/src/core/hle/service/gsp_gpu.h
@@ -5,8 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <string>
8 9
9#include "common/bit_field.h" 10#include "common/bit_field.h"
11#include "common/common_types.h"
12
10#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
11 14
12//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -158,6 +161,7 @@ static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrec
158class Interface : public Service::Interface { 161class Interface : public Service::Interface {
159public: 162public:
160 Interface(); 163 Interface();
164 ~Interface() override;
161 165
162 std::string GetPortName() const override { 166 std::string GetPortName() const override {
163 return "gsp::Gpu"; 167 return "gsp::Gpu";
@@ -170,4 +174,14 @@ public:
170 */ 174 */
171void SignalInterrupt(InterruptId interrupt_id); 175void SignalInterrupt(InterruptId interrupt_id);
172 176
177void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info);
178
179/**
180 * Retrieves the framebuffer info stored in the GSP shared memory for the
181 * specified screen index and thread id.
182 * @param thread_id GSP thread id of the process that accesses the structure that we are requesting.
183 * @param screen_index Index of the screen we are requesting (Top = 0, Bottom = 1).
184 * @returns FramebufferUpdate Information about the specified framebuffer.
185 */
186FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
173} // namespace 187} // namespace
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index c7c1bb5ab..70caa7d80 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include "common/logging/log.h" 5#include "common/logging/log.h"
6#include "common/emu_window.h"
6 7
7#include "core/hle/service/service.h" 8#include "core/hle/service/service.h"
8#include "core/hle/service/hid/hid.h" 9#include "core/hle/service/hid/hid.h"
diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h
index 68e2bcee0..d50d479f8 100644
--- a/src/core/hle/service/hid/hid.h
+++ b/src/core/hle/service/hid/hid.h
@@ -6,16 +6,18 @@
6 6
7#include <array> 7#include <array>
8 8
9#include "core/hle/kernel/kernel.h" 9#ifndef _MSC_VER
10#include "core/hle/service/service.h" 10#include <cstddef>
11#include "common/bit_field.h" 11#endif
12 12
13namespace Kernel { 13#include "common/bit_field.h"
14 class SharedMemory; 14#include "common/common_funcs.h"
15 class Event; 15#include "common/common_types.h"
16}
17 16
18namespace Service { 17namespace Service {
18
19class Interface;
20
19namespace HID { 21namespace HID {
20 22
21/** 23/**
diff --git a/src/core/hle/service/nwm_uds.cpp b/src/core/hle/service/nwm_uds.cpp
index 25b01860e..18b22956f 100644
--- a/src/core/hle/service/nwm_uds.cpp
+++ b/src/core/hle/service/nwm_uds.cpp
@@ -125,4 +125,8 @@ Interface::Interface() {
125 Register(FunctionTable); 125 Register(FunctionTable);
126} 126}
127 127
128Interface::~Interface() {
129 handle_event = nullptr;
130}
131
128} // namespace 132} // namespace
diff --git a/src/core/hle/service/nwm_uds.h b/src/core/hle/service/nwm_uds.h
index 82abdff28..0ced2359c 100644
--- a/src/core/hle/service/nwm_uds.h
+++ b/src/core/hle/service/nwm_uds.h
@@ -16,6 +16,7 @@ namespace NWM_UDS {
16class Interface : public Service::Interface { 16class Interface : public Service::Interface {
17public: 17public:
18 Interface(); 18 Interface();
19 ~Interface() override;
19 20
20 std::string GetPortName() const override { 21 std::string GetPortName() const override {
21 return "nwm::UDS"; 22 return "nwm::UDS";
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index d681cc3dc..0de0b13a3 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -54,7 +54,7 @@ static std::string MakeFunctionString(const char* name, const char* port_name, c
54 54
55 std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name); 55 std::string function_string = Common::StringFromFormat("function '%s': port=%s", name, port_name);
56 for (int i = 1; i <= num_params; ++i) { 56 for (int i = 1; i <= num_params; ++i) {
57 function_string += Common::StringFromFormat(", cmd_buff[%i]=%u", i, cmd_buff[i]); 57 function_string += Common::StringFromFormat(", cmd_buff[%i]=0x%X", i, cmd_buff[i]);
58 } 58 }
59 return function_string; 59 return function_string;
60} 60}
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h
index 77bfb9ff1..f31135212 100644
--- a/src/core/hle/service/service.h
+++ b/src/core/hle/service/service.h
@@ -4,6 +4,7 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
7#include <string> 8#include <string>
8#include <unordered_map> 9#include <unordered_map>
9 10
@@ -11,8 +12,8 @@
11 12
12#include "common/common_types.h" 13#include "common/common_types.h"
13 14
14#include "core/hle/kernel/kernel.h"
15#include "core/hle/kernel/session.h" 15#include "core/hle/kernel/session.h"
16#include "core/hle/result.h"
16 17
17//////////////////////////////////////////////////////////////////////////////////////////////////// 18////////////////////////////////////////////////////////////////////////////////////////////////////
18// Namespace Service 19// Namespace Service
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 1e0f5df9b..d0e166fdf 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -2,40 +2,47 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstring>
7#include <unordered_map>
8
9#include "common/assert.h"
10#include "common/bit_field.h"
11#include "common/common_types.h"
5#include "common/logging/log.h" 12#include "common/logging/log.h"
6#include "common/platform.h" 13#include "common/scope_exit.h"
7
8#if EMU_PLATFORM == PLATFORM_WINDOWS
9#include <winsock2.h>
10#include <ws2tcpip.h>
11
12// MinGW does not define several errno constants
13#ifndef _MSC_VER
14#define EBADMSG 104
15#define ENODATA 120
16#define ENOMSG 122
17#define ENOSR 124
18#define ENOSTR 125
19#define ETIME 137
20#define EIDRM 2001
21#define ENOLINK 2002
22#endif // _MSC_VER
23 14
15#include "core/hle/kernel/session.h"
16#include "core/hle/result.h"
17#include "core/hle/service/soc_u.h"
18#include "core/memory.h"
19
20#ifdef _WIN32
21 #include <winsock2.h>
22 #include <ws2tcpip.h>
23
24 // MinGW does not define several errno constants
25 #ifndef _MSC_VER
26 #define EBADMSG 104
27 #define ENODATA 120
28 #define ENOMSG 122
29 #define ENOSR 124
30 #define ENOSTR 125
31 #define ETIME 137
32 #define EIDRM 2001
33 #define ENOLINK 2002
34 #endif // _MSC_VER
24#else 35#else
25#include <sys/socket.h> 36 #include <cerrno>
26#include <netinet/in.h> 37 #include <fcntl.h>
27#include <netdb.h> 38 #include <netinet/in.h>
28#include <arpa/inet.h> 39 #include <netdb.h>
29#include <fcntl.h> 40 #include <poll.h>
30#include <poll.h> 41 #include <sys/socket.h>
42 #include <unistd.h>
31#endif 43#endif
32 44
33#include "common/scope_exit.h" 45#ifdef _WIN32
34#include "core/hle/hle.h"
35#include "core/hle/service/soc_u.h"
36#include <unordered_map>
37
38#if EMU_PLATFORM == PLATFORM_WINDOWS
39# define WSAEAGAIN WSAEWOULDBLOCK 46# define WSAEAGAIN WSAEWOULDBLOCK
40# define WSAEMULTIHOP -1 // Invalid dummy value 47# define WSAEMULTIHOP -1 // Invalid dummy value
41# define ERRNO(x) WSA##x 48# define ERRNO(x) WSA##x
@@ -328,6 +335,7 @@ static void Socket(Service::Interface* self) {
328 if ((s32)socket_handle == SOCKET_ERROR_VALUE) 335 if ((s32)socket_handle == SOCKET_ERROR_VALUE)
329 result = TranslateError(GET_ERRNO); 336 result = TranslateError(GET_ERRNO);
330 337
338 cmd_buffer[0] = IPC::MakeHeader(2, 2, 0);
331 cmd_buffer[1] = result; 339 cmd_buffer[1] = result;
332 cmd_buffer[2] = socket_handle; 340 cmd_buffer[2] = socket_handle;
333} 341}
@@ -351,8 +359,9 @@ static void Bind(Service::Interface* self) {
351 if (res != 0) 359 if (res != 0)
352 result = TranslateError(GET_ERRNO); 360 result = TranslateError(GET_ERRNO);
353 361
354 cmd_buffer[2] = res; 362 cmd_buffer[0] = IPC::MakeHeader(5, 2, 0);
355 cmd_buffer[1] = result; 363 cmd_buffer[1] = result;
364 cmd_buffer[2] = res;
356} 365}
357 366
358static void Fcntl(Service::Interface* self) { 367static void Fcntl(Service::Interface* self) {
@@ -369,7 +378,7 @@ static void Fcntl(Service::Interface* self) {
369 }); 378 });
370 379
371 if (ctr_cmd == 3) { // F_GETFL 380 if (ctr_cmd == 3) { // F_GETFL
372#if EMU_PLATFORM == PLATFORM_WINDOWS 381#ifdef _WIN32
373 posix_ret = 0; 382 posix_ret = 0;
374 auto iter = open_sockets.find(socket_handle); 383 auto iter = open_sockets.find(socket_handle);
375 if (iter != open_sockets.end() && iter->second.blocking == false) 384 if (iter != open_sockets.end() && iter->second.blocking == false)
@@ -386,7 +395,7 @@ static void Fcntl(Service::Interface* self) {
386 posix_ret |= 4; // O_NONBLOCK 395 posix_ret |= 4; // O_NONBLOCK
387#endif 396#endif
388 } else if (ctr_cmd == 4) { // F_SETFL 397 } else if (ctr_cmd == 4) { // F_SETFL
389#if EMU_PLATFORM == PLATFORM_WINDOWS 398#ifdef _WIN32
390 unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0; 399 unsigned long tmp = (ctr_arg & 4 /* O_NONBLOCK */) ? 1 : 0;
391 int ret = ioctlsocket(socket_handle, FIONBIO, &tmp); 400 int ret = ioctlsocket(socket_handle, FIONBIO, &tmp);
392 if (ret == SOCKET_ERROR_VALUE) { 401 if (ret == SOCKET_ERROR_VALUE) {
@@ -434,8 +443,9 @@ static void Listen(Service::Interface* self) {
434 if (ret != 0) 443 if (ret != 0)
435 result = TranslateError(GET_ERRNO); 444 result = TranslateError(GET_ERRNO);
436 445
437 cmd_buffer[2] = ret; 446 cmd_buffer[0] = IPC::MakeHeader(3, 2, 0);
438 cmd_buffer[1] = result; 447 cmd_buffer[1] = result;
448 cmd_buffer[2] = ret;
439} 449}
440 450
441static void Accept(Service::Interface* self) { 451static void Accept(Service::Interface* self) {
@@ -460,8 +470,10 @@ static void Accept(Service::Interface* self) {
460 Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len); 470 Memory::WriteBlock(cmd_buffer[0x104 >> 2], (const u8*)&ctr_addr, max_addr_len);
461 } 471 }
462 472
463 cmd_buffer[2] = ret; 473 cmd_buffer[0] = IPC::MakeHeader(4, 2, 2);
464 cmd_buffer[1] = result; 474 cmd_buffer[1] = result;
475 cmd_buffer[2] = ret;
476 cmd_buffer[3] = IPC::StaticBufferDesc(static_cast<u32>(max_addr_len), 0);
465} 477}
466 478
467static void GetHostId(Service::Interface* self) { 479static void GetHostId(Service::Interface* self) {
@@ -669,26 +681,29 @@ static void Connect(Service::Interface* self) {
669 int result = 0; 681 int result = 0;
670 if (ret != 0) 682 if (ret != 0)
671 result = TranslateError(GET_ERRNO); 683 result = TranslateError(GET_ERRNO);
672 cmd_buffer[2] = ret; 684
685 cmd_buffer[0] = IPC::MakeHeader(6, 2, 0);
673 cmd_buffer[1] = result; 686 cmd_buffer[1] = result;
687 cmd_buffer[2] = ret;
674} 688}
675 689
676static void InitializeSockets(Service::Interface* self) { 690static void InitializeSockets(Service::Interface* self) {
677 // TODO(Subv): Implement 691 // TODO(Subv): Implement
678#if EMU_PLATFORM == PLATFORM_WINDOWS 692#ifdef _WIN32
679 WSADATA data; 693 WSADATA data;
680 WSAStartup(MAKEWORD(2, 2), &data); 694 WSAStartup(MAKEWORD(2, 2), &data);
681#endif 695#endif
682 696
683 u32* cmd_buffer = Kernel::GetCommandBuffer(); 697 u32* cmd_buffer = Kernel::GetCommandBuffer();
684 cmd_buffer[1] = 0; 698 cmd_buffer[0] = IPC::MakeHeader(1, 1, 0);
699 cmd_buffer[1] = RESULT_SUCCESS.raw;
685} 700}
686 701
687static void ShutdownSockets(Service::Interface* self) { 702static void ShutdownSockets(Service::Interface* self) {
688 // TODO(Subv): Implement 703 // TODO(Subv): Implement
689 CleanupSockets(); 704 CleanupSockets();
690 705
691#if EMU_PLATFORM == PLATFORM_WINDOWS 706#ifdef _WIN32
692 WSACleanup(); 707 WSACleanup();
693#endif 708#endif
694 709
@@ -739,7 +754,7 @@ Interface::Interface() {
739 754
740Interface::~Interface() { 755Interface::~Interface() {
741 CleanupSockets(); 756 CleanupSockets();
742#if EMU_PLATFORM == PLATFORM_WINDOWS 757#ifdef _WIN32
743 WSACleanup(); 758 WSACleanup();
744#endif 759#endif
745} 760}
diff --git a/src/core/hle/service/soc_u.h b/src/core/hle/service/soc_u.h
index 483b3111b..a091f597c 100644
--- a/src/core/hle/service/soc_u.h
+++ b/src/core/hle/service/soc_u.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <string>
8
7#include "core/hle/service/service.h" 9#include "core/hle/service/service.h"
8 10
9//////////////////////////////////////////////////////////////////////////////////////////////////// 11////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/service/srv.cpp b/src/core/hle/service/srv.cpp
index 6c49fa6cf..3b8c7c0e4 100644
--- a/src/core/hle/service/srv.cpp
+++ b/src/core/hle/service/srv.cpp
@@ -68,4 +68,8 @@ Interface::Interface() {
68 Register(FunctionTable); 68 Register(FunctionTable);
69} 69}
70 70
71Interface::~Interface() {
72 event_handle = nullptr;
73}
74
71} // namespace 75} // namespace
diff --git a/src/core/hle/service/srv.h b/src/core/hle/service/srv.h
index 653aba5cb..96c89b025 100644
--- a/src/core/hle/service/srv.h
+++ b/src/core/hle/service/srv.h
@@ -13,6 +13,7 @@ namespace SRV {
13class Interface : public Service::Interface { 13class Interface : public Service::Interface {
14public: 14public:
15 Interface(); 15 Interface();
16 ~Interface() override;
16 17
17 std::string GetPortName() const override { 18 std::string GetPortName() const override {
18 return "srv:"; 19 return "srv:";
diff --git a/src/core/hle/service/y2r_u.cpp b/src/core/hle/service/y2r_u.cpp
index ac1967da8..6e7dafaad 100644
--- a/src/core/hle/service/y2r_u.cpp
+++ b/src/core/hle/service/y2r_u.cpp
@@ -12,6 +12,7 @@
12#include "core/hw/y2r.h" 12#include "core/hw/y2r.h"
13#include "core/mem_map.h" 13#include "core/mem_map.h"
14 14
15#include "video_core/renderer_base.h"
15#include "video_core/utils.h" 16#include "video_core/utils.h"
16#include "video_core/video_core.h" 17#include "video_core/video_core.h"
17 18
@@ -409,4 +410,8 @@ Interface::Interface() {
409 Register(FunctionTable); 410 Register(FunctionTable);
410} 411}
411 412
413Interface::~Interface() {
414 completion_event = nullptr;
415}
416
412} // namespace 417} // namespace
diff --git a/src/core/hle/service/y2r_u.h b/src/core/hle/service/y2r_u.h
index 7df47fcb9..3965a5545 100644
--- a/src/core/hle/service/y2r_u.h
+++ b/src/core/hle/service/y2r_u.h
@@ -5,9 +5,11 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <string>
8 9
9#include "common/common_types.h" 10#include "common/common_types.h"
10 11
12#include "core/hle/result.h"
11#include "core/hle/service/service.h" 13#include "core/hle/service/service.h"
12 14
13//////////////////////////////////////////////////////////////////////////////////////////////////// 15////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -110,6 +112,7 @@ struct ConversionConfiguration {
110class Interface : public Service::Interface { 112class Interface : public Service::Interface {
111public: 113public:
112 Interface(); 114 Interface();
115 ~Interface() override;
113 116
114 std::string GetPortName() const override { 117 std::string GetPortName() const override {
115 return "y2r:u"; 118 return "y2r:u";
diff --git a/src/core/hle/shared_page.cpp b/src/core/hle/shared_page.cpp
index 4014eee98..26d87c7e2 100644
--- a/src/core/hle/shared_page.cpp
+++ b/src/core/hle/shared_page.cpp
@@ -4,12 +4,6 @@
4 4
5#include <cstring> 5#include <cstring>
6 6
7#include "common/common_types.h"
8#include "common/common_funcs.h"
9
10#include "core/core.h"
11#include "core/memory.h"
12#include "core/hle/config_mem.h"
13#include "core/hle/shared_page.h" 7#include "core/hle/shared_page.h"
14 8
15//////////////////////////////////////////////////////////////////////////////////////////////////// 9////////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/src/core/hle/shared_page.h b/src/core/hle/shared_page.h
index fd2ab66a2..db6a5340b 100644
--- a/src/core/hle/shared_page.h
+++ b/src/core/hle/shared_page.h
@@ -10,9 +10,12 @@
10 * write access, according to 3dbrew; this is not emulated) 10 * write access, according to 3dbrew; this is not emulated)
11 */ 11 */
12 12
13#include "common/common_funcs.h"
13#include "common/common_types.h" 14#include "common/common_types.h"
14#include "common/swap.h" 15#include "common/swap.h"
15 16
17#include "core/memory.h"
18
16//////////////////////////////////////////////////////////////////////////////////////////////////// 19////////////////////////////////////////////////////////////////////////////////////////////////////
17 20
18namespace SharedPage { 21namespace SharedPage {
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index cc414743a..bb64fdfb7 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -22,6 +22,7 @@
22#include "core/hle/kernel/shared_memory.h" 22#include "core/hle/kernel/shared_memory.h"
23#include "core/hle/kernel/thread.h" 23#include "core/hle/kernel/thread.h"
24#include "core/hle/kernel/timer.h" 24#include "core/hle/kernel/timer.h"
25#include "core/hle/kernel/vm_manager.h"
25 26
26#include "core/hle/function_wrappers.h" 27#include "core/hle/function_wrappers.h"
27#include "core/hle/result.h" 28#include "core/hle/result.h"
@@ -529,12 +530,33 @@ static ResultCode ReleaseSemaphore(s32* count, Handle handle, s32 release_count)
529 return RESULT_SUCCESS; 530 return RESULT_SUCCESS;
530} 531}
531 532
532/// Query memory 533/// Query process memory
533static ResultCode QueryMemory(void* info, void* out, u32 addr) { 534static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* page_info, Handle process_handle, u32 addr) {
534 LOG_ERROR(Kernel_SVC, "(UNIMPLEMENTED) called addr=0x%08X", addr); 535 using Kernel::Process;
536 Kernel::SharedPtr<Process> process = Kernel::g_handle_table.Get<Process>(process_handle);
537 if (process == nullptr)
538 return ERR_INVALID_HANDLE;
539
540 auto vma = process->address_space->FindVMA(addr);
541
542 if (vma == process->address_space->vma_map.end())
543 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage);
544
545 memory_info->base_address = vma->second.base;
546 memory_info->permission = static_cast<u32>(vma->second.permissions);
547 memory_info->size = vma->second.size;
548 memory_info->state = static_cast<u32>(vma->second.meminfo_state);
549
550 page_info->flags = 0;
551 LOG_TRACE(Kernel_SVC, "called process=0x%08X addr=0x%08X", process_handle, addr);
535 return RESULT_SUCCESS; 552 return RESULT_SUCCESS;
536} 553}
537 554
555/// Query memory
556static ResultCode QueryMemory(MemoryInfo* memory_info, PageInfo* page_info, u32 addr) {
557 return QueryProcessMemory(memory_info, page_info, Kernel::CurrentProcess, addr);
558}
559
538/// Create an event 560/// Create an event
539static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) { 561static ResultCode CreateEvent(Handle* out_handle, u32 reset_type) {
540 using Kernel::Event; 562 using Kernel::Event;
@@ -806,13 +828,12 @@ static const FunctionDef SVC_Table[] = {
806 {0x7A, nullptr, "AddCodeSegment"}, 828 {0x7A, nullptr, "AddCodeSegment"},
807 {0x7B, nullptr, "Backdoor"}, 829 {0x7B, nullptr, "Backdoor"},
808 {0x7C, nullptr, "KernelSetState"}, 830 {0x7C, nullptr, "KernelSetState"},
809 {0x7D, nullptr, "QueryProcessMemory"}, 831 {0x7D, HLE::Wrap<QueryProcessMemory>, "QueryProcessMemory"},
810}; 832};
811 833
812Common::Profiling::TimingCategory profiler_svc("SVC Calls"); 834Common::Profiling::TimingCategory profiler_svc("SVC Calls");
813 835
814static const FunctionDef* GetSVCInfo(u32 opcode) { 836static const FunctionDef* GetSVCInfo(u32 func_num) {
815 u32 func_num = opcode & 0xFFFFFF; // 8 bits
816 if (func_num >= ARRAY_SIZE(SVC_Table)) { 837 if (func_num >= ARRAY_SIZE(SVC_Table)) {
817 LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num); 838 LOG_ERROR(Kernel_SVC, "unknown svc=0x%02X", func_num);
818 return nullptr; 839 return nullptr;
@@ -820,10 +841,10 @@ static const FunctionDef* GetSVCInfo(u32 opcode) {
820 return &SVC_Table[func_num]; 841 return &SVC_Table[func_num];
821} 842}
822 843
823void CallSVC(u32 opcode) { 844void CallSVC(u32 immediate) {
824 Common::Profiling::ScopeTimer timer_svc(profiler_svc); 845 Common::Profiling::ScopeTimer timer_svc(profiler_svc);
825 846
826 const FunctionDef *info = GetSVCInfo(opcode); 847 const FunctionDef* info = GetSVCInfo(immediate);
827 if (info) { 848 if (info) {
828 if (info->func) { 849 if (info->func) {
829 info->func(); 850 info->func();
diff --git a/src/core/hle/svc.h b/src/core/hle/svc.h
index 4389aa73d..12de9ffbe 100644
--- a/src/core/hle/svc.h
+++ b/src/core/hle/svc.h
@@ -41,6 +41,6 @@ enum ArbitrationType {
41 41
42namespace SVC { 42namespace SVC {
43 43
44void CallSVC(u32 opcode); 44void CallSVC(u32 immediate);
45 45
46} // namespace 46} // namespace
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 7471def57..3ccbc03b2 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -2,17 +2,18 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include <type_traits>
7
5#include "common/color.h" 8#include "common/color.h"
6#include "common/common_types.h" 9#include "common/common_types.h"
7 10#include "common/logging/log.h"
8#include "core/arm/arm_interface.h" 11#include "common/vector_math.h"
9 12
10#include "core/settings.h" 13#include "core/settings.h"
11#include "core/core.h"
12#include "core/memory.h" 14#include "core/memory.h"
13#include "core/core_timing.h" 15#include "core/core_timing.h"
14 16
15#include "core/hle/hle.h"
16#include "core/hle/service/gsp_gpu.h" 17#include "core/hle/service/gsp_gpu.h"
17#include "core/hle/service/dsp_dsp.h" 18#include "core/hle/service/dsp_dsp.h"
18#include "core/hle/service/hid/hid.h" 19#include "core/hle/service/hid/hid.h"
@@ -20,10 +21,17 @@
20#include "core/hw/hw.h" 21#include "core/hw/hw.h"
21#include "core/hw/gpu.h" 22#include "core/hw/gpu.h"
22 23
24#include "core/tracer/recorder.h"
25
23#include "video_core/command_processor.h" 26#include "video_core/command_processor.h"
27#include "video_core/hwrasterizer_base.h"
28#include "video_core/renderer_base.h"
24#include "video_core/utils.h" 29#include "video_core/utils.h"
25#include "video_core/video_core.h" 30#include "video_core/video_core.h"
26 31
32#include "video_core/debug_utils/debug_utils.h"
33
34
27namespace GPU { 35namespace GPU {
28 36
29Regs g_regs; 37Regs g_regs;
@@ -53,6 +61,29 @@ inline void Read(T &var, const u32 raw_addr) {
53 var = g_regs[addr / 4]; 61 var = g_regs[addr / 4];
54} 62}
55 63
64static Math::Vec4<u8> DecodePixel(Regs::PixelFormat input_format, const u8* src_pixel) {
65 switch (input_format) {
66 case Regs::PixelFormat::RGBA8:
67 return Color::DecodeRGBA8(src_pixel);
68
69 case Regs::PixelFormat::RGB8:
70 return Color::DecodeRGB8(src_pixel);
71
72 case Regs::PixelFormat::RGB565:
73 return Color::DecodeRGB565(src_pixel);
74
75 case Regs::PixelFormat::RGB5A1:
76 return Color::DecodeRGB5A1(src_pixel);
77
78 case Regs::PixelFormat::RGBA4:
79 return Color::DecodeRGBA4(src_pixel);
80
81 default:
82 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", input_format);
83 return {0, 0, 0, 0};
84 }
85}
86
56template <typename T> 87template <typename T>
57inline void Write(u32 addr, const T data) { 88inline void Write(u32 addr, const T data) {
58 addr -= HW::VADDR_GPU; 89 addr -= HW::VADDR_GPU;
@@ -75,39 +106,43 @@ inline void Write(u32 addr, const T data) {
75 const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger)); 106 const bool is_second_filler = (index != GPU_REG_INDEX(memory_fill_config[0].trigger));
76 auto& config = g_regs.memory_fill_config[is_second_filler]; 107 auto& config = g_regs.memory_fill_config[is_second_filler];
77 108
78 if (config.address_start && config.trigger) { 109 if (config.trigger) {
79 u8* start = Memory::GetPhysicalPointer(config.GetStartAddress()); 110 if (config.address_start) { // Some games pass invalid values here
80 u8* end = Memory::GetPhysicalPointer(config.GetEndAddress()); 111 u8* start = Memory::GetPhysicalPointer(config.GetStartAddress());
81 112 u8* end = Memory::GetPhysicalPointer(config.GetEndAddress());
82 if (config.fill_24bit) { 113
83 // fill with 24-bit values 114 if (config.fill_24bit) {
84 for (u8* ptr = start; ptr < end; ptr += 3) { 115 // fill with 24-bit values
85 ptr[0] = config.value_24bit_r; 116 for (u8* ptr = start; ptr < end; ptr += 3) {
86 ptr[1] = config.value_24bit_g; 117 ptr[0] = config.value_24bit_r;
87 ptr[2] = config.value_24bit_b; 118 ptr[1] = config.value_24bit_g;
119 ptr[2] = config.value_24bit_b;
120 }
121 } else if (config.fill_32bit) {
122 // fill with 32-bit values
123 for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
124 *ptr = config.value_32bit;
125 } else {
126 // fill with 16-bit values
127 for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
128 *ptr = config.value_16bit;
88 } 129 }
89 } else if (config.fill_32bit) {
90 // fill with 32-bit values
91 for (u32* ptr = (u32*)start; ptr < (u32*)end; ++ptr)
92 *ptr = config.value_32bit;
93 } else {
94 // fill with 16-bit values
95 for (u16* ptr = (u16*)start; ptr < (u16*)end; ++ptr)
96 *ptr = config.value_16bit;
97 }
98 130
99 LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress()); 131 LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
100 132
101 config.trigger = 0; 133 if (!is_second_filler) {
102 config.finished = 1; 134 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
135 } else {
136 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
137 }
103 138
104 if (!is_second_filler) { 139 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress());
105 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
106 } else {
107 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
108 } 140 }
109 141
110 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetStartAddress(), config.GetEndAddress() - config.GetStartAddress()); 142 // Reset "trigger" flag and set the "finish" flag
143 // NOTE: This was confirmed to happen on hardware even if "address_start" is zero.
144 config.trigger = 0;
145 config.finished = 1;
111 } 146 }
112 break; 147 break;
113 } 148 }
@@ -116,6 +151,10 @@ inline void Write(u32 addr, const T data) {
116 { 151 {
117 const auto& config = g_regs.display_transfer_config; 152 const auto& config = g_regs.display_transfer_config;
118 if (config.trigger & 1) { 153 if (config.trigger & 1) {
154
155 if (Pica::g_debug_context)
156 Pica::g_debug_context->OnEvent(Pica::DebugContext::Event::IncomingDisplayTransfer, nullptr);
157
119 u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress()); 158 u8* src_pointer = Memory::GetPhysicalPointer(config.GetPhysicalInputAddress());
120 u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress()); 159 u8* dst_pointer = Memory::GetPhysicalPointer(config.GetPhysicalOutputAddress());
121 160
@@ -125,11 +164,18 @@ inline void Write(u32 addr, const T data) {
125 break; 164 break;
126 } 165 }
127 166
128 unsigned horizontal_scale = (config.scaling != config.NoScale) ? 2 : 1; 167 if (config.output_tiled &&
129 unsigned vertical_scale = (config.scaling == config.ScaleXY) ? 2 : 1; 168 (config.scaling == config.ScaleXY || config.scaling == config.ScaleX)) {
169 LOG_CRITICAL(HW_GPU, "Scaling is only implemented on tiled input");
170 UNIMPLEMENTED();
171 break;
172 }
130 173
131 u32 output_width = config.output_width / horizontal_scale; 174 bool horizontal_scale = config.scaling != config.NoScale;
132 u32 output_height = config.output_height / vertical_scale; 175 bool vertical_scale = config.scaling == config.ScaleXY;
176
177 u32 output_width = config.output_width >> horizontal_scale;
178 u32 output_height = config.output_height >> vertical_scale;
133 179
134 u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format); 180 u32 input_size = config.input_width * config.input_height * GPU::Regs::BytesPerPixel(config.input_format);
135 u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format); 181 u32 output_size = output_width * output_height * GPU::Regs::BytesPerPixel(config.output_format);
@@ -153,16 +199,14 @@ inline void Write(u32 addr, const T data) {
153 break; 199 break;
154 } 200 }
155 201
156 // TODO(Subv): Implement the box filter when scaling is enabled
157 // right now we're just skipping the extra pixels.
158 for (u32 y = 0; y < output_height; ++y) { 202 for (u32 y = 0; y < output_height; ++y) {
159 for (u32 x = 0; x < output_width; ++x) { 203 for (u32 x = 0; x < output_width; ++x) {
160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; 204 Math::Vec4<u8> src_color;
161 205
162 // Calculate the [x,y] position of the input image 206 // Calculate the [x,y] position of the input image
163 // based on the current output position and the scale 207 // based on the current output position and the scale
164 u32 input_x = x * horizontal_scale; 208 u32 input_x = x << horizontal_scale;
165 u32 input_y = y * vertical_scale; 209 u32 input_y = y << vertical_scale;
166 210
167 if (config.flip_vertically) { 211 if (config.flip_vertically) {
168 // Flip the y value of the output data, 212 // Flip the y value of the output data,
@@ -177,46 +221,49 @@ inline void Write(u32 addr, const T data) {
177 u32 dst_offset; 221 u32 dst_offset;
178 222
179 if (config.output_tiled) { 223 if (config.output_tiled) {
180 // Interpret the input as linear and the output as tiled 224 if (!config.dont_swizzle) {
181 u32 coarse_y = y & ~7; 225 // Interpret the input as linear and the output as tiled
182 u32 stride = output_width * dst_bytes_per_pixel; 226 u32 coarse_y = y & ~7;
183 227 u32 stride = output_width * dst_bytes_per_pixel;
184 src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel; 228
185 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride; 229 src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
230 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + coarse_y * stride;
231 } else {
232 // Both input and output are linear
233 src_offset = (input_x + input_y * config.input_width) * src_bytes_per_pixel;
234 dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
235 }
186 } else { 236 } else {
187 // Interpret the input as tiled and the output as linear 237 if (!config.dont_swizzle) {
188 u32 coarse_y = input_y & ~7; 238 // Interpret the input as tiled and the output as linear
189 u32 stride = config.input_width * src_bytes_per_pixel; 239 u32 coarse_y = input_y & ~7;
190 240 u32 stride = config.input_width * src_bytes_per_pixel;
191 src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride; 241
192 dst_offset = (x + y * output_width) * dst_bytes_per_pixel; 242 src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + coarse_y * stride;
243 dst_offset = (x + y * output_width) * dst_bytes_per_pixel;
244 } else {
245 // Both input and output are tiled
246 u32 out_coarse_y = y & ~7;
247 u32 out_stride = output_width * dst_bytes_per_pixel;
248
249 u32 in_coarse_y = input_y & ~7;
250 u32 in_stride = config.input_width * src_bytes_per_pixel;
251
252 src_offset = VideoCore::GetMortonOffset(input_x, input_y, src_bytes_per_pixel) + in_coarse_y * in_stride;
253 dst_offset = VideoCore::GetMortonOffset(x, y, dst_bytes_per_pixel) + out_coarse_y * out_stride;
254 }
193 } 255 }
194 256
195 const u8* src_pixel = src_pointer + src_offset; 257 const u8* src_pixel = src_pointer + src_offset;
196 switch (config.input_format) { 258 src_color = DecodePixel(config.input_format, src_pixel);
197 case Regs::PixelFormat::RGBA8: 259 if (config.scaling == config.ScaleX) {
198 src_color = Color::DecodeRGBA8(src_pixel); 260 Math::Vec4<u8> pixel = DecodePixel(config.input_format, src_pixel + src_bytes_per_pixel);
199 break; 261 src_color = ((src_color + pixel) / 2).Cast<u8>();
200 262 } else if (config.scaling == config.ScaleXY) {
201 case Regs::PixelFormat::RGB8: 263 Math::Vec4<u8> pixel1 = DecodePixel(config.input_format, src_pixel + 1 * src_bytes_per_pixel);
202 src_color = Color::DecodeRGB8(src_pixel); 264 Math::Vec4<u8> pixel2 = DecodePixel(config.input_format, src_pixel + 2 * src_bytes_per_pixel);
203 break; 265 Math::Vec4<u8> pixel3 = DecodePixel(config.input_format, src_pixel + 3 * src_bytes_per_pixel);
204 266 src_color = (((src_color + pixel1) + (pixel2 + pixel3)) / 4).Cast<u8>();
205 case Regs::PixelFormat::RGB565:
206 src_color = Color::DecodeRGB565(src_pixel);
207 break;
208
209 case Regs::PixelFormat::RGB5A1:
210 src_color = Color::DecodeRGB5A1(src_pixel);
211 break;
212
213 case Regs::PixelFormat::RGBA4:
214 src_color = Color::DecodeRGBA4(src_pixel);
215 break;
216
217 default:
218 LOG_ERROR(HW_GPU, "Unknown source framebuffer format %x", config.input_format.Value());
219 break;
220 } 267 }
221 268
222 u8* dst_pixel = dst_pointer + dst_offset; 269 u8* dst_pixel = dst_pointer + dst_offset;
@@ -254,6 +301,7 @@ inline void Write(u32 addr, const T data) {
254 config.GetPhysicalOutputAddress(), output_width, output_height, 301 config.GetPhysicalOutputAddress(), output_width, output_height,
255 config.output_format.Value(), config.flags); 302 config.output_format.Value(), config.flags);
256 303
304 g_regs.display_transfer_config.trigger = 0;
257 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF); 305 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
258 306
259 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size); 307 VideoCore::g_renderer->hw_rasterizer->NotifyFlush(config.GetPhysicalOutputAddress(), output_size);
@@ -268,7 +316,14 @@ inline void Write(u32 addr, const T data) {
268 if (config.trigger & 1) 316 if (config.trigger & 1)
269 { 317 {
270 u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress()); 318 u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
319
320 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
321 Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size * sizeof(u32), config.GetPhysicalAddress());
322 }
323
271 Pica::CommandProcessor::ProcessCommandList(buffer, config.size); 324 Pica::CommandProcessor::ProcessCommandList(buffer, config.size);
325
326 g_regs.command_processor_config.trigger = 0;
272 } 327 }
273 break; 328 break;
274 } 329 }
@@ -276,6 +331,13 @@ inline void Write(u32 addr, const T data) {
276 default: 331 default:
277 break; 332 break;
278 } 333 }
334
335 // Notify tracer about the register write
336 // This is happening *after* handling the write to make sure we properly catch all memory reads.
337 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
338 // addr + GPU VBase - IO VBase + IO PBase
339 Pica::g_debug_context->recorder->RegisterWritten<T>(addr + 0x1EF00000 - 0x1EC00000 + 0x10100000, data);
340 }
279} 341}
280 342
281// Explicitly instantiate template functions because we aren't defining this in the header: 343// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/hw/gpu.h b/src/core/hw/gpu.h
index 699bcd2a5..daad506fe 100644
--- a/src/core/hw/gpu.h
+++ b/src/core/hw/gpu.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <type_traits>
8 9
9#include "common/assert.h" 10#include "common/assert.h"
10#include "common/bit_field.h" 11#include "common/bit_field.h"
@@ -202,6 +203,7 @@ struct Regs {
202 BitField< 0, 1, u32> flip_vertically; // flips input data vertically 203 BitField< 0, 1, u32> flip_vertically; // flips input data vertically
203 BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format 204 BitField< 1, 1, u32> output_tiled; // Converts from linear to tiled format
204 BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing 205 BitField< 3, 1, u32> raw_copy; // Copies the data without performing any processing
206 BitField< 5, 1, u32> dont_swizzle;
205 BitField< 8, 3, PixelFormat> input_format; 207 BitField< 8, 3, PixelFormat> input_format;
206 BitField<12, 3, PixelFormat> output_format; 208 BitField<12, 3, PixelFormat> output_format;
207 209
diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp
index c7006a498..b5fdbf9c1 100644
--- a/src/core/hw/hw.cpp
+++ b/src/core/hw/hw.cpp
@@ -15,6 +15,21 @@ template <typename T>
15inline void Read(T &var, const u32 addr) { 15inline void Read(T &var, const u32 addr) {
16 switch (addr & 0xFFFFF000) { 16 switch (addr & 0xFFFFF000) {
17 case VADDR_GPU: 17 case VADDR_GPU:
18 case VADDR_GPU + 0x1000:
19 case VADDR_GPU + 0x2000:
20 case VADDR_GPU + 0x3000:
21 case VADDR_GPU + 0x4000:
22 case VADDR_GPU + 0x5000:
23 case VADDR_GPU + 0x6000:
24 case VADDR_GPU + 0x7000:
25 case VADDR_GPU + 0x8000:
26 case VADDR_GPU + 0x9000:
27 case VADDR_GPU + 0xA000:
28 case VADDR_GPU + 0xB000:
29 case VADDR_GPU + 0xC000:
30 case VADDR_GPU + 0xD000:
31 case VADDR_GPU + 0xE000:
32 case VADDR_GPU + 0xF000:
18 GPU::Read(var, addr); 33 GPU::Read(var, addr);
19 break; 34 break;
20 case VADDR_LCD: 35 case VADDR_LCD:
@@ -29,6 +44,21 @@ template <typename T>
29inline void Write(u32 addr, const T data) { 44inline void Write(u32 addr, const T data) {
30 switch (addr & 0xFFFFF000) { 45 switch (addr & 0xFFFFF000) {
31 case VADDR_GPU: 46 case VADDR_GPU:
47 case VADDR_GPU + 0x1000:
48 case VADDR_GPU + 0x2000:
49 case VADDR_GPU + 0x3000:
50 case VADDR_GPU + 0x4000:
51 case VADDR_GPU + 0x5000:
52 case VADDR_GPU + 0x6000:
53 case VADDR_GPU + 0x7000:
54 case VADDR_GPU + 0x8000:
55 case VADDR_GPU + 0x9000:
56 case VADDR_GPU + 0xA000:
57 case VADDR_GPU + 0xB000:
58 case VADDR_GPU + 0xC000:
59 case VADDR_GPU + 0xD000:
60 case VADDR_GPU + 0xE000:
61 case VADDR_GPU + 0xF000:
32 GPU::Write(addr, data); 62 GPU::Write(addr, data);
33 break; 63 break;
34 case VADDR_LCD: 64 case VADDR_LCD:
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 963c8d981..6f93709e3 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -7,11 +7,12 @@
7#include "common/common_types.h" 7#include "common/common_types.h"
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/arm/arm_interface.h"
11#include "core/hle/hle.h"
12#include "core/hw/hw.h" 10#include "core/hw/hw.h"
13#include "core/hw/lcd.h" 11#include "core/hw/lcd.h"
14 12
13#include "core/tracer/recorder.h"
14#include "video_core/debug_utils/debug_utils.h"
15
15namespace LCD { 16namespace LCD {
16 17
17Regs g_regs; 18Regs g_regs;
@@ -42,6 +43,13 @@ inline void Write(u32 addr, const T data) {
42 } 43 }
43 44
44 g_regs[index] = static_cast<u32>(data); 45 g_regs[index] = static_cast<u32>(data);
46
47 // Notify tracer about the register write
48 // This is happening *after* handling the write to make sure we properly catch all memory reads.
49 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
50 // addr + GPU VBase - IO VBase + IO PBase
51 Pica::g_debug_context->recorder->RegisterWritten<T>(addr + HW::VADDR_LCD - 0x1EC00000 + 0x10100000, data);
52 }
45} 53}
46 54
47// Explicitly instantiate template functions because we aren't defining this in the header: 55// Explicitly instantiate template functions because we aren't defining this in the header:
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index 8631eb201..bcce6d8cf 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -5,6 +5,7 @@
5#pragma once 5#pragma once
6 6
7#include <cstddef> 7#include <cstddef>
8#include <type_traits>
8 9
9#include "common/bit_field.h" 10#include "common/bit_field.h"
10#include "common/common_funcs.h" 11#include "common/common_funcs.h"
diff --git a/src/core/hw/y2r.cpp b/src/core/hw/y2r.cpp
index 5b7fb39e1..f80e26ecd 100644
--- a/src/core/hw/y2r.cpp
+++ b/src/core/hw/y2r.cpp
@@ -2,8 +2,10 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
5#include <array> 6#include <array>
6#include <numeric> 7#include <cstddef>
8#include <memory>
7 9
8#include "common/assert.h" 10#include "common/assert.h"
9#include "common/color.h" 11#include "common/color.h"
@@ -109,7 +111,7 @@ static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data
109 while (output < unit_end) { 111 while (output < unit_end) {
110 u32 color = *input++; 112 u32 color = *input++;
111 Math::Vec4<u8> col_vec{ 113 Math::Vec4<u8> col_vec{
112 (color >> 24) & 0xFF, (color >> 16) & 0xFF, (color >> 8) & 0xFF, alpha, 114 (u8)(color >> 24), (u8)(color >> 16), (u8)(color >> 8), alpha
113 }; 115 };
114 116
115 switch (output_format) { 117 switch (output_format) {
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index 14aeebebb..530837d08 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -19,7 +19,7 @@
19 19
20namespace Loader { 20namespace Loader {
21 21
22/** 22/*
23 * File layout: 23 * File layout:
24 * - File header 24 * - File header
25 * - Code, rodata and data relocation table headers 25 * - Code, rodata and data relocation table headers
@@ -39,13 +39,16 @@ namespace Loader {
39 * The entrypoint is always the start of the code segment. 39 * The entrypoint is always the start of the code segment.
40 * The BSS section must be cleared manually by the application. 40 * The BSS section must be cleared manually by the application.
41 */ 41 */
42
42enum THREEDSX_Error { 43enum THREEDSX_Error {
43 ERROR_NONE = 0, 44 ERROR_NONE = 0,
44 ERROR_READ = 1, 45 ERROR_READ = 1,
45 ERROR_FILE = 2, 46 ERROR_FILE = 2,
46 ERROR_ALLOC = 3 47 ERROR_ALLOC = 3
47}; 48};
49
48static const u32 RELOCBUFSIZE = 512; 50static const u32 RELOCBUFSIZE = 512;
51static const unsigned int NUM_SEGMENTS = 3;
49 52
50// File header 53// File header
51#pragma pack(1) 54#pragma pack(1)
@@ -98,7 +101,10 @@ static u32 TranslateAddr(u32 addr, const THREEloadinfo *loadinfo, u32* offsets)
98 return loadinfo->seg_addrs[2] + addr - offsets[1]; 101 return loadinfo->seg_addrs[2] + addr - offsets[1];
99} 102}
100 103
101static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr) 104using Kernel::SharedPtr;
105using Kernel::CodeSet;
106
107static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr, SharedPtr<CodeSet>* out_codeset)
102{ 108{
103 if (!file.IsOpen()) 109 if (!file.IsOpen())
104 return ERROR_FILE; 110 return ERROR_FILE;
@@ -116,15 +122,13 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
116 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF; 122 loadinfo.seg_sizes[1] = (hdr.rodata_seg_size + 0xFFF) &~0xFFF;
117 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF; 123 loadinfo.seg_sizes[2] = (hdr.data_seg_size + 0xFFF) &~0xFFF;
118 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] }; 124 u32 offsets[2] = { loadinfo.seg_sizes[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] };
119 u32 data_load_size = (hdr.data_seg_size - hdr.bss_size + 0xFFF) &~0xFFF; 125 u32 n_reloc_tables = hdr.reloc_hdr_size / sizeof(u32);
120 u32 bss_load_size = loadinfo.seg_sizes[2] - data_load_size; 126 std::vector<u8> program_image(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]);
121 u32 n_reloc_tables = hdr.reloc_hdr_size / 4;
122 std::vector<u8> all_mem(loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2] + 3 * n_reloc_tables);
123 127
124 loadinfo.seg_addrs[0] = base_addr; 128 loadinfo.seg_addrs[0] = base_addr;
125 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0]; 129 loadinfo.seg_addrs[1] = loadinfo.seg_addrs[0] + loadinfo.seg_sizes[0];
126 loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1]; 130 loadinfo.seg_addrs[2] = loadinfo.seg_addrs[1] + loadinfo.seg_sizes[1];
127 loadinfo.seg_ptrs[0] = &all_mem[0]; 131 loadinfo.seg_ptrs[0] = program_image.data();
128 loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0]; 132 loadinfo.seg_ptrs[1] = loadinfo.seg_ptrs[0] + loadinfo.seg_sizes[0];
129 loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1]; 133 loadinfo.seg_ptrs[2] = loadinfo.seg_ptrs[1] + loadinfo.seg_sizes[1];
130 134
@@ -132,10 +136,9 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
132 file.Seek(hdr.header_size, SEEK_SET); 136 file.Seek(hdr.header_size, SEEK_SET);
133 137
134 // Read the relocation headers 138 // Read the relocation headers
135 u32* relocs = (u32*)(loadinfo.seg_ptrs[2] + hdr.data_seg_size); 139 std::vector<u32> relocs(n_reloc_tables * NUM_SEGMENTS);
136 140 for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
137 for (unsigned current_segment : {0, 1, 2}) { 141 size_t size = n_reloc_tables * sizeof(u32);
138 size_t size = n_reloc_tables * 4;
139 if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size) 142 if (file.ReadBytes(&relocs[current_segment * n_reloc_tables], size) != size)
140 return ERROR_READ; 143 return ERROR_READ;
141 } 144 }
@@ -152,7 +155,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
152 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size); 155 memset((char*)loadinfo.seg_ptrs[2] + hdr.data_seg_size - hdr.bss_size, 0, hdr.bss_size);
153 156
154 // Relocate the segments 157 // Relocate the segments
155 for (unsigned current_segment : {0, 1, 2}) { 158 for (unsigned int current_segment = 0; current_segment < NUM_SEGMENTS; ++current_segment) {
156 for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) { 159 for (unsigned current_segment_reloc_table = 0; current_segment_reloc_table < n_reloc_tables; current_segment_reloc_table++) {
157 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table]; 160 u32 n_relocs = relocs[current_segment * n_reloc_tables + current_segment_reloc_table];
158 if (current_segment_reloc_table >= 2) { 161 if (current_segment_reloc_table >= 2) {
@@ -160,7 +163,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
160 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR); 163 file.Seek(n_relocs*sizeof(THREEDSX_Reloc), SEEK_CUR);
161 continue; 164 continue;
162 } 165 }
163 static THREEDSX_Reloc reloc_table[RELOCBUFSIZE]; 166 THREEDSX_Reloc reloc_table[RELOCBUFSIZE];
164 167
165 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment]; 168 u32* pos = (u32*)loadinfo.seg_ptrs[current_segment];
166 const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4); 169 const u32* end_pos = pos + (loadinfo.seg_sizes[current_segment] / 4);
@@ -179,7 +182,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
179 pos += table.skip; 182 pos += table.skip;
180 s32 num_patches = table.patch; 183 s32 num_patches = table.patch;
181 while (0 < num_patches && pos < end_pos) { 184 while (0 < num_patches && pos < end_pos) {
182 u32 in_addr = (char*)pos - (char*)&all_mem[0]; 185 u32 in_addr = (u8*)pos - program_image.data();
183 u32 addr = TranslateAddr(*pos, &loadinfo, offsets); 186 u32 addr = TranslateAddr(*pos, &loadinfo, offsets);
184 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n", 187 LOG_TRACE(Loader, "Patching %08X <-- rel(%08X,%d) (%08X)\n",
185 base_addr + in_addr, addr, current_segment_reloc_table, *pos); 188 base_addr + in_addr, addr, current_segment_reloc_table, *pos);
@@ -188,7 +191,7 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
188 *pos = (addr); 191 *pos = (addr);
189 break; 192 break;
190 case 1: 193 case 1:
191 *pos = (addr - in_addr); 194 *pos = static_cast<u32>(addr - in_addr);
192 break; 195 break;
193 default: 196 default:
194 break; //this should never happen 197 break; //this should never happen
@@ -201,14 +204,29 @@ static THREEDSX_Error Load3DSXFile(FileUtil::IOFile& file, u32 base_addr)
201 } 204 }
202 } 205 }
203 206
204 // Write the data 207 // Create the CodeSet
205 memcpy(Memory::GetPointer(base_addr), &all_mem[0], loadinfo.seg_sizes[0] + loadinfo.seg_sizes[1] + loadinfo.seg_sizes[2]); 208 SharedPtr<CodeSet> code_set = CodeSet::Create("", 0);
209
210 code_set->code.offset = loadinfo.seg_ptrs[0] - program_image.data();
211 code_set->code.addr = loadinfo.seg_addrs[0];
212 code_set->code.size = loadinfo.seg_sizes[0];
213
214 code_set->rodata.offset = loadinfo.seg_ptrs[1] - program_image.data();
215 code_set->rodata.addr = loadinfo.seg_addrs[1];
216 code_set->rodata.size = loadinfo.seg_sizes[1];
206 217
207 LOG_DEBUG(Loader, "CODE: %u pages\n", loadinfo.seg_sizes[0] / 0x1000); 218 code_set->data.offset = loadinfo.seg_ptrs[2] - program_image.data();
208 LOG_DEBUG(Loader, "RODATA: %u pages\n", loadinfo.seg_sizes[1] / 0x1000); 219 code_set->data.addr = loadinfo.seg_addrs[2];
209 LOG_DEBUG(Loader, "DATA: %u pages\n", data_load_size / 0x1000); 220 code_set->data.size = loadinfo.seg_sizes[2];
210 LOG_DEBUG(Loader, "BSS: %u pages\n", bss_load_size / 0x1000);
211 221
222 code_set->entrypoint = code_set->code.addr;
223 code_set->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
224
225 LOG_DEBUG(Loader, "code size: 0x%X", loadinfo.seg_sizes[0]);
226 LOG_DEBUG(Loader, "rodata size: 0x%X", loadinfo.seg_sizes[1]);
227 LOG_DEBUG(Loader, "data size: 0x%X (including 0x%X of bss)", loadinfo.seg_sizes[2], hdr.bss_size);
228
229 *out_codeset = code_set;
212 return ERROR_NONE; 230 return ERROR_NONE;
213} 231}
214 232
@@ -228,19 +246,22 @@ ResultStatus AppLoader_THREEDSX::Load() {
228 if (is_loaded) 246 if (is_loaded)
229 return ResultStatus::ErrorAlreadyLoaded; 247 return ResultStatus::ErrorAlreadyLoaded;
230 248
231 if (!file->IsOpen()) 249 if (!file.IsOpen())
250 return ResultStatus::Error;
251
252 SharedPtr<CodeSet> codeset;
253 if (Load3DSXFile(file, Memory::PROCESS_IMAGE_VADDR, &codeset) != ERROR_NONE)
232 return ResultStatus::Error; 254 return ResultStatus::Error;
255 codeset->name = filename;
233 256
234 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 257 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
235 Kernel::g_current_process->svc_access_mask.set(); 258 Kernel::g_current_process->svc_access_mask.set();
236 Kernel::g_current_process->address_mappings = default_address_mappings; 259 Kernel::g_current_process->address_mappings = default_address_mappings;
237 260
238 // Attach the default resource limit (APPLICATION) to the process 261 // Attach the default resource limit (APPLICATION) to the process
239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 262 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
240 263
241 Load3DSXFile(*file, Memory::PROCESS_IMAGE_VADDR); 264 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
242
243 Kernel::g_current_process->Run(Memory::PROCESS_IMAGE_VADDR, 48, Kernel::DEFAULT_STACK_SIZE);
244 265
245 is_loaded = true; 266 is_loaded = true;
246 return ResultStatus::Success; 267 return ResultStatus::Success;
diff --git a/src/core/loader/3dsx.h b/src/core/loader/3dsx.h
index 096b3ec20..a0aa0c533 100644
--- a/src/core/loader/3dsx.h
+++ b/src/core/loader/3dsx.h
@@ -17,7 +17,7 @@ namespace Loader {
17/// Loads an 3DSX file 17/// Loads an 3DSX file
18class AppLoader_THREEDSX final : public AppLoader { 18class AppLoader_THREEDSX final : public AppLoader {
19public: 19public:
20 AppLoader_THREEDSX(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename) 20 AppLoader_THREEDSX(FileUtil::IOFile&& file, std::string filename)
21 : AppLoader(std::move(file)), filename(std::move(filename)) {} 21 : AppLoader(std::move(file)), filename(std::move(filename)) {}
22 22
23 /** 23 /**
diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp
index f00753a79..5d7264f12 100644
--- a/src/core/loader/elf.cpp
+++ b/src/core/loader/elf.cpp
@@ -2,6 +2,7 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
5#include <string> 6#include <string>
6#include <memory> 7#include <memory>
7 8
@@ -10,11 +11,14 @@
10#include "common/logging/log.h" 11#include "common/logging/log.h"
11#include "common/symbols.h" 12#include "common/symbols.h"
12 13
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/resource_limit.h" 15#include "core/hle/kernel/resource_limit.h"
15#include "core/loader/elf.h" 16#include "core/loader/elf.h"
16#include "core/memory.h" 17#include "core/memory.h"
17 18
19using Kernel::SharedPtr;
20using Kernel::CodeSet;
21
18//////////////////////////////////////////////////////////////////////////////////////////////////// 22////////////////////////////////////////////////////////////////////////////////////////////////////
19// ELF Header Constants 23// ELF Header Constants
20 24
@@ -96,6 +100,12 @@ enum ElfSectionFlags
96#define PT_LOPROC 0x70000000 100#define PT_LOPROC 0x70000000
97#define PT_HIPROC 0x7FFFFFFF 101#define PT_HIPROC 0x7FFFFFFF
98 102
103// Segment flags
104#define PF_X 0x1
105#define PF_W 0x2
106#define PF_R 0x4
107#define PF_MASKPROC 0xF0000000
108
99typedef unsigned int Elf32_Addr; 109typedef unsigned int Elf32_Addr;
100typedef unsigned short Elf32_Half; 110typedef unsigned short Elf32_Half;
101typedef unsigned int Elf32_Off; 111typedef unsigned int Elf32_Off;
@@ -192,7 +202,7 @@ public:
192 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); } 202 ElfMachine GetMachine() const { return (ElfMachine)(header->e_machine); }
193 u32 GetEntryPoint() const { return entryPoint; } 203 u32 GetEntryPoint() const { return entryPoint; }
194 u32 GetFlags() const { return (u32)(header->e_flags); } 204 u32 GetFlags() const { return (u32)(header->e_flags); }
195 void LoadInto(u32 vaddr); 205 SharedPtr<CodeSet> LoadInto(u32 vaddr);
196 bool LoadSymbols(); 206 bool LoadSymbols();
197 207
198 int GetNumSegments() const { return (int)(header->e_phnum); } 208 int GetNumSegments() const { return (int)(header->e_phnum); }
@@ -248,7 +258,7 @@ const char *ElfReader::GetSectionName(int section) const {
248 return nullptr; 258 return nullptr;
249} 259}
250 260
251void ElfReader::LoadInto(u32 vaddr) { 261SharedPtr<CodeSet> ElfReader::LoadInto(u32 vaddr) {
252 LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx); 262 LOG_DEBUG(Loader, "String section: %i", header->e_shstrndx);
253 263
254 // Should we relocate? 264 // Should we relocate?
@@ -263,22 +273,63 @@ void ElfReader::LoadInto(u32 vaddr) {
263 LOG_DEBUG(Loader, "%i segments:", header->e_phnum); 273 LOG_DEBUG(Loader, "%i segments:", header->e_phnum);
264 274
265 // First pass : Get the bits into RAM 275 // First pass : Get the bits into RAM
266 u32 segment_addr[32];
267 u32 base_addr = relocate ? vaddr : 0; 276 u32 base_addr = relocate ? vaddr : 0;
268 277
269 for (unsigned i = 0; i < header->e_phnum; i++) { 278 u32 total_image_size = 0;
270 Elf32_Phdr* p = segments + i; 279 for (unsigned int i = 0; i < header->e_phnum; ++i) {
271 LOG_DEBUG(Loader, "Type: %i Vaddr: %08x Filesz: %i Memsz: %i ", p->p_type, p->p_vaddr, 280 Elf32_Phdr* p = &segments[i];
281 if (p->p_type == PT_LOAD) {
282 total_image_size += (p->p_memsz + 0xFFF) & ~0xFFF;
283 }
284 }
285
286 std::vector<u8> program_image(total_image_size);
287 size_t current_image_position = 0;
288
289 SharedPtr<CodeSet> codeset = CodeSet::Create("", 0);
290
291 for (unsigned int i = 0; i < header->e_phnum; ++i) {
292 Elf32_Phdr* p = &segments[i];
293 LOG_DEBUG(Loader, "Type: %i Vaddr: %08X Filesz: %8X Memsz: %8X ", p->p_type, p->p_vaddr,
272 p->p_filesz, p->p_memsz); 294 p->p_filesz, p->p_memsz);
273 295
274 if (p->p_type == PT_LOAD) { 296 if (p->p_type == PT_LOAD) {
275 segment_addr[i] = base_addr + p->p_vaddr; 297 CodeSet::Segment* codeset_segment;
276 memcpy(Memory::GetPointer(segment_addr[i]), GetSegmentPtr(i), p->p_filesz); 298 u32 permission_flags = p->p_flags & (PF_R | PF_W | PF_X);
277 LOG_DEBUG(Loader, "Loadable Segment Copied to %08x, size %08x", segment_addr[i], 299 if (permission_flags == (PF_R | PF_X)) {
278 p->p_memsz); 300 codeset_segment = &codeset->code;
301 } else if (permission_flags == (PF_R)) {
302 codeset_segment = &codeset->rodata;
303 } else if (permission_flags == (PF_R | PF_W)) {
304 codeset_segment = &codeset->data;
305 } else {
306 LOG_ERROR(Loader, "Unexpected ELF PT_LOAD segment id %u with flags %X", i, p->p_flags);
307 continue;
308 }
309
310 if (codeset_segment->size != 0) {
311 LOG_ERROR(Loader, "ELF has more than one segment of the same type. Skipping extra segment (id %i)", i);
312 continue;
313 }
314
315 u32 segment_addr = base_addr + p->p_vaddr;
316 u32 aligned_size = (p->p_memsz + 0xFFF) & ~0xFFF;
317
318 codeset_segment->offset = current_image_position;
319 codeset_segment->addr = segment_addr;
320 codeset_segment->size = aligned_size;
321
322 memcpy(&program_image[current_image_position], GetSegmentPtr(i), p->p_filesz);
323 current_image_position += aligned_size;
279 } 324 }
280 } 325 }
326
327 codeset->entrypoint = base_addr + header->e_entry;
328 codeset->memory = std::make_shared<std::vector<u8>>(std::move(program_image));
329
281 LOG_DEBUG(Loader, "Done loading."); 330 LOG_DEBUG(Loader, "Done loading.");
331
332 return codeset;
282} 333}
283 334
284SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const { 335SectionID ElfReader::GetSectionByName(const char *name, int firstSection) const {
@@ -340,29 +391,29 @@ ResultStatus AppLoader_ELF::Load() {
340 if (is_loaded) 391 if (is_loaded)
341 return ResultStatus::ErrorAlreadyLoaded; 392 return ResultStatus::ErrorAlreadyLoaded;
342 393
343 if (!file->IsOpen()) 394 if (!file.IsOpen())
344 return ResultStatus::Error; 395 return ResultStatus::Error;
345 396
346 // Reset read pointer in case this file has been read before. 397 // Reset read pointer in case this file has been read before.
347 file->Seek(0, SEEK_SET); 398 file.Seek(0, SEEK_SET);
348 399
349 u32 size = static_cast<u32>(file->GetSize()); 400 size_t size = file.GetSize();
350 std::unique_ptr<u8[]> buffer(new u8[size]); 401 std::unique_ptr<u8[]> buffer(new u8[size]);
351 if (file->ReadBytes(&buffer[0], size) != size) 402 if (file.ReadBytes(&buffer[0], size) != size)
352 return ResultStatus::Error; 403 return ResultStatus::Error;
353 404
354 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 405 ElfReader elf_reader(&buffer[0]);
406 SharedPtr<CodeSet> codeset = elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
407 codeset->name = filename;
408
409 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
355 Kernel::g_current_process->svc_access_mask.set(); 410 Kernel::g_current_process->svc_access_mask.set();
356 Kernel::g_current_process->address_mappings = default_address_mappings; 411 Kernel::g_current_process->address_mappings = default_address_mappings;
357 412
358 // Attach the default resource limit (APPLICATION) to the process 413 // Attach the default resource limit (APPLICATION) to the process
359 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 414 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
360 415
361 ElfReader elf_reader(&buffer[0]); 416 Kernel::g_current_process->Run(48, Kernel::DEFAULT_STACK_SIZE);
362 elf_reader.LoadInto(Memory::PROCESS_IMAGE_VADDR);
363 // TODO: Fill application title
364
365 Kernel::g_current_process->Run(elf_reader.GetEntryPoint(), 48, Kernel::DEFAULT_STACK_SIZE);
366 417
367 is_loaded = true; 418 is_loaded = true;
368 return ResultStatus::Success; 419 return ResultStatus::Success;
diff --git a/src/core/loader/elf.h b/src/core/loader/elf.h
index 32841606a..c6a5ebe99 100644
--- a/src/core/loader/elf.h
+++ b/src/core/loader/elf.h
@@ -17,7 +17,7 @@ namespace Loader {
17/// Loads an ELF/AXF file 17/// Loads an ELF/AXF file
18class AppLoader_ELF final : public AppLoader { 18class AppLoader_ELF final : public AppLoader {
19public: 19public:
20 AppLoader_ELF(std::unique_ptr<FileUtil::IOFile>&& file, std::string filename) 20 AppLoader_ELF(FileUtil::IOFile&& file, std::string filename)
21 : AppLoader(std::move(file)), filename(std::move(filename)) { } 21 : AppLoader(std::move(file)), filename(std::move(filename)) { }
22 22
23 /** 23 /**
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index 8b14edf00..9ef2f8900 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -2,10 +2,12 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <memory>
5#include <string> 6#include <string>
6 7
7#include "common/logging/log.h" 8#include "common/logging/log.h"
8#include "common/make_unique.h" 9#include "common/make_unique.h"
10#include "common/string_util.h"
9 11
10#include "core/file_sys/archive_romfs.h" 12#include "core/file_sys/archive_romfs.h"
11#include "core/hle/kernel/process.h" 13#include "core/hle/kernel/process.h"
@@ -88,8 +90,8 @@ static const char* GetFileTypeString(FileType type) {
88} 90}
89 91
90ResultStatus LoadFile(const std::string& filename) { 92ResultStatus LoadFile(const std::string& filename) {
91 std::unique_ptr<FileUtil::IOFile> file(new FileUtil::IOFile(filename, "rb")); 93 FileUtil::IOFile file(filename, "rb");
92 if (!file->IsOpen()) { 94 if (!file.IsOpen()) {
93 LOG_ERROR(Loader, "Failed to load file %s", filename.c_str()); 95 LOG_ERROR(Loader, "Failed to load file %s", filename.c_str());
94 return ResultStatus::Error; 96 return ResultStatus::Error;
95 } 97 }
@@ -97,7 +99,7 @@ ResultStatus LoadFile(const std::string& filename) {
97 std::string filename_filename, filename_extension; 99 std::string filename_filename, filename_extension;
98 Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension); 100 Common::SplitPath(filename, nullptr, &filename_filename, &filename_extension);
99 101
100 FileType type = IdentifyFile(*file); 102 FileType type = IdentifyFile(file);
101 FileType filename_type = GuessFromExtension(filename_extension); 103 FileType filename_type = GuessFromExtension(filename_extension);
102 104
103 if (type != filename_type) { 105 if (type != filename_type) {
@@ -122,7 +124,7 @@ ResultStatus LoadFile(const std::string& filename) {
122 case FileType::CXI: 124 case FileType::CXI:
123 case FileType::CCI: 125 case FileType::CCI:
124 { 126 {
125 AppLoader_NCCH app_loader(std::move(file)); 127 AppLoader_NCCH app_loader(std::move(file), filename);
126 128
127 // Load application and RomFS 129 // Load application and RomFS
128 if (ResultStatus::Success == app_loader.Load()) { 130 if (ResultStatus::Success == app_loader.Load()) {
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h
index 87e16fb98..a37d3348c 100644
--- a/src/core/loader/loader.h
+++ b/src/core/loader/loader.h
@@ -4,12 +4,18 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <algorithm>
8#include <initializer_list>
9#include <memory>
10#include <string>
7#include <vector> 11#include <vector>
8 12
9#include "common/common_types.h" 13#include "common/common_types.h"
10#include "common/file_util.h" 14#include "common/file_util.h"
11 15
12#include "core/hle/kernel/process.h" 16namespace Kernel {
17struct AddressMapping;
18}
13 19
14//////////////////////////////////////////////////////////////////////////////////////////////////// 20////////////////////////////////////////////////////////////////////////////////////////////////////
15// Loader namespace 21// Loader namespace
@@ -46,7 +52,7 @@ static inline u32 MakeMagic(char a, char b, char c, char d) {
46/// Interface for loading an application 52/// Interface for loading an application
47class AppLoader : NonCopyable { 53class AppLoader : NonCopyable {
48public: 54public:
49 AppLoader(std::unique_ptr<FileUtil::IOFile>&& file) : file(std::move(file)) { } 55 AppLoader(FileUtil::IOFile&& file) : file(std::move(file)) { }
50 virtual ~AppLoader() { } 56 virtual ~AppLoader() { }
51 57
52 /** 58 /**
@@ -60,7 +66,7 @@ public:
60 * @param buffer Reference to buffer to store data 66 * @param buffer Reference to buffer to store data
61 * @return ResultStatus result of function 67 * @return ResultStatus result of function
62 */ 68 */
63 virtual ResultStatus ReadCode(std::vector<u8>& buffer) const { 69 virtual ResultStatus ReadCode(std::vector<u8>& buffer) {
64 return ResultStatus::ErrorNotImplemented; 70 return ResultStatus::ErrorNotImplemented;
65 } 71 }
66 72
@@ -69,7 +75,7 @@ public:
69 * @param buffer Reference to buffer to store data 75 * @param buffer Reference to buffer to store data
70 * @return ResultStatus result of function 76 * @return ResultStatus result of function
71 */ 77 */
72 virtual ResultStatus ReadIcon(std::vector<u8>& buffer) const { 78 virtual ResultStatus ReadIcon(std::vector<u8>& buffer) {
73 return ResultStatus::ErrorNotImplemented; 79 return ResultStatus::ErrorNotImplemented;
74 } 80 }
75 81
@@ -78,7 +84,7 @@ public:
78 * @param buffer Reference to buffer to store data 84 * @param buffer Reference to buffer to store data
79 * @return ResultStatus result of function 85 * @return ResultStatus result of function
80 */ 86 */
81 virtual ResultStatus ReadBanner(std::vector<u8>& buffer) const { 87 virtual ResultStatus ReadBanner(std::vector<u8>& buffer) {
82 return ResultStatus::ErrorNotImplemented; 88 return ResultStatus::ErrorNotImplemented;
83 } 89 }
84 90
@@ -87,22 +93,25 @@ public:
87 * @param buffer Reference to buffer to store data 93 * @param buffer Reference to buffer to store data
88 * @return ResultStatus result of function 94 * @return ResultStatus result of function
89 */ 95 */
90 virtual ResultStatus ReadLogo(std::vector<u8>& buffer) const { 96 virtual ResultStatus ReadLogo(std::vector<u8>& buffer) {
91 return ResultStatus::ErrorNotImplemented; 97 return ResultStatus::ErrorNotImplemented;
92 } 98 }
93 99
94 /** 100 /**
95 * Get the RomFS of the application 101 * Get the RomFS of the application
96 * @param buffer Reference to buffer to store data 102 * Since the RomFS can be huge, we return a file reference instead of copying to a buffer
103 * @param romfs_file The file containing the RomFS
104 * @param offset The offset the romfs begins on
105 * @param size The size of the romfs
97 * @return ResultStatus result of function 106 * @return ResultStatus result of function
98 */ 107 */
99 virtual ResultStatus ReadRomFS(std::vector<u8>& buffer) const { 108 virtual ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
100 return ResultStatus::ErrorNotImplemented; 109 return ResultStatus::ErrorNotImplemented;
101 } 110 }
102 111
103protected: 112protected:
104 std::unique_ptr<FileUtil::IOFile> file; 113 FileUtil::IOFile file;
105 bool is_loaded = false; 114 bool is_loaded = false;
106}; 115};
107 116
108/** 117/**
diff --git a/src/core/loader/ncch.cpp b/src/core/loader/ncch.cpp
index 08993c4fa..094d74100 100644
--- a/src/core/loader/ncch.cpp
+++ b/src/core/loader/ncch.cpp
@@ -3,6 +3,7 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm> 5#include <algorithm>
6#include <cstring>
6#include <memory> 7#include <memory>
7 8
8#include "common/logging/log.h" 9#include "common/logging/log.h"
@@ -10,7 +11,7 @@
10#include "common/string_util.h" 11#include "common/string_util.h"
11#include "common/swap.h" 12#include "common/swap.h"
12 13
13#include "core/hle/kernel/kernel.h" 14#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/resource_limit.h" 15#include "core/hle/kernel/resource_limit.h"
15#include "core/loader/ncch.h" 16#include "core/loader/ncch.h"
16#include "core/memory.h" 17#include "core/memory.h"
@@ -116,7 +117,10 @@ FileType AppLoader_NCCH::IdentifyType(FileUtil::IOFile& file) {
116 return FileType::Error; 117 return FileType::Error;
117} 118}
118 119
119ResultStatus AppLoader_NCCH::LoadExec() const { 120ResultStatus AppLoader_NCCH::LoadExec() {
121 using Kernel::SharedPtr;
122 using Kernel::CodeSet;
123
120 if (!is_loaded) 124 if (!is_loaded)
121 return ResultStatus::ErrorNotLoaded; 125 return ResultStatus::ErrorNotLoaded;
122 126
@@ -125,7 +129,30 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
125 std::string process_name = Common::StringFromFixedZeroTerminatedBuffer( 129 std::string process_name = Common::StringFromFixedZeroTerminatedBuffer(
126 (const char*)exheader_header.codeset_info.name, 8); 130 (const char*)exheader_header.codeset_info.name, 8);
127 u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]); 131 u64 program_id = *reinterpret_cast<u64_le const*>(&ncch_header.program_id[0]);
128 Kernel::g_current_process = Kernel::Process::Create(process_name, program_id); 132
133 SharedPtr<CodeSet> codeset = CodeSet::Create(process_name, program_id);
134
135 codeset->code.offset = 0;
136 codeset->code.addr = exheader_header.codeset_info.text.address;
137 codeset->code.size = exheader_header.codeset_info.text.num_max_pages * Memory::PAGE_SIZE;
138
139 codeset->rodata.offset = codeset->code.offset + codeset->code.size;
140 codeset->rodata.addr = exheader_header.codeset_info.ro.address;
141 codeset->rodata.size = exheader_header.codeset_info.ro.num_max_pages * Memory::PAGE_SIZE;
142
143 // TODO(yuriks): Not sure if the bss size is added to the page-aligned .data size or just
144 // to the regular size. Playing it safe for now.
145 u32 bss_page_size = (exheader_header.codeset_info.bss_size + 0xFFF) & ~0xFFF;
146 code.resize(code.size() + bss_page_size, 0);
147
148 codeset->data.offset = codeset->rodata.offset + codeset->rodata.size;
149 codeset->data.addr = exheader_header.codeset_info.data.address;
150 codeset->data.size = exheader_header.codeset_info.data.num_max_pages * Memory::PAGE_SIZE + bss_page_size;
151
152 codeset->entrypoint = codeset->code.addr;
153 codeset->memory = std::make_shared<std::vector<u8>>(std::move(code));
154
155 Kernel::g_current_process = Kernel::Process::Create(std::move(codeset));
129 156
130 // Attach a resource limit to the process based on the resource limit category 157 // Attach a resource limit to the process based on the resource limit category
131 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory( 158 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(
@@ -136,18 +163,16 @@ ResultStatus AppLoader_NCCH::LoadExec() const {
136 std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps)); 163 std::copy_n(exheader_header.arm11_kernel_caps.descriptors, kernel_caps.size(), begin(kernel_caps));
137 Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size()); 164 Kernel::g_current_process->ParseKernelCaps(kernel_caps.data(), kernel_caps.size());
138 165
139 Memory::WriteBlock(entry_point, &code[0], code.size());
140
141 s32 priority = exheader_header.arm11_system_local_caps.priority; 166 s32 priority = exheader_header.arm11_system_local_caps.priority;
142 u32 stack_size = exheader_header.codeset_info.stack_size; 167 u32 stack_size = exheader_header.codeset_info.stack_size;
143 Kernel::g_current_process->Run(entry_point, priority, stack_size); 168 Kernel::g_current_process->Run(priority, stack_size);
144 return ResultStatus::Success; 169 return ResultStatus::Success;
145 } 170 }
146 return ResultStatus::Error; 171 return ResultStatus::Error;
147} 172}
148 173
149ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const { 174ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>& buffer) {
150 if (!file->IsOpen()) 175 if (!file.IsOpen())
151 return ResultStatus::Error; 176 return ResultStatus::Error;
152 177
153 LOG_DEBUG(Loader, "%d sections:", kMaxSections); 178 LOG_DEBUG(Loader, "%d sections:", kMaxSections);
@@ -161,7 +186,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
161 section.offset, section.size, section.name); 186 section.offset, section.size, section.name);
162 187
163 s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset); 188 s64 section_offset = (section.offset + exefs_offset + sizeof(ExeFs_Header) + ncch_offset);
164 file->Seek(section_offset, SEEK_SET); 189 file.Seek(section_offset, SEEK_SET);
165 190
166 if (is_compressed) { 191 if (is_compressed) {
167 // Section is compressed, read compressed .code section... 192 // Section is compressed, read compressed .code section...
@@ -172,7 +197,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
172 return ResultStatus::ErrorMemoryAllocationFailed; 197 return ResultStatus::ErrorMemoryAllocationFailed;
173 } 198 }
174 199
175 if (file->ReadBytes(&temp_buffer[0], section.size) != section.size) 200 if (file.ReadBytes(&temp_buffer[0], section.size) != section.size)
176 return ResultStatus::Error; 201 return ResultStatus::Error;
177 202
178 // Decompress .code section... 203 // Decompress .code section...
@@ -183,7 +208,7 @@ ResultStatus AppLoader_NCCH::LoadSectionExeFS(const char* name, std::vector<u8>&
183 } else { 208 } else {
184 // Section is uncompressed... 209 // Section is uncompressed...
185 buffer.resize(section.size); 210 buffer.resize(section.size);
186 if (file->ReadBytes(&buffer[0], section.size) != section.size) 211 if (file.ReadBytes(&buffer[0], section.size) != section.size)
187 return ResultStatus::Error; 212 return ResultStatus::Error;
188 } 213 }
189 return ResultStatus::Success; 214 return ResultStatus::Success;
@@ -196,21 +221,21 @@ ResultStatus AppLoader_NCCH::Load() {
196 if (is_loaded) 221 if (is_loaded)
197 return ResultStatus::ErrorAlreadyLoaded; 222 return ResultStatus::ErrorAlreadyLoaded;
198 223
199 if (!file->IsOpen()) 224 if (!file.IsOpen())
200 return ResultStatus::Error; 225 return ResultStatus::Error;
201 226
202 // Reset read pointer in case this file has been read before. 227 // Reset read pointer in case this file has been read before.
203 file->Seek(0, SEEK_SET); 228 file.Seek(0, SEEK_SET);
204 229
205 if (file->ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header)) 230 if (file.ReadBytes(&ncch_header, sizeof(NCCH_Header)) != sizeof(NCCH_Header))
206 return ResultStatus::Error; 231 return ResultStatus::Error;
207 232
208 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)... 233 // Skip NCSD header and load first NCCH (NCSD is just a container of NCCH files)...
209 if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) { 234 if (MakeMagic('N', 'C', 'S', 'D') == ncch_header.magic) {
210 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!"); 235 LOG_WARNING(Loader, "Only loading the first (bootable) NCCH within the NCSD file!");
211 ncch_offset = 0x4000; 236 ncch_offset = 0x4000;
212 file->Seek(ncch_offset, SEEK_SET); 237 file.Seek(ncch_offset, SEEK_SET);
213 file->ReadBytes(&ncch_header, sizeof(NCCH_Header)); 238 file.ReadBytes(&ncch_header, sizeof(NCCH_Header));
214 } 239 }
215 240
216 // Verify we are loading the correct file type... 241 // Verify we are loading the correct file type...
@@ -219,7 +244,7 @@ ResultStatus AppLoader_NCCH::Load() {
219 244
220 // Read ExHeader... 245 // Read ExHeader...
221 246
222 if (file->ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header)) 247 if (file.ReadBytes(&exheader_header, sizeof(ExHeader_Header)) != sizeof(ExHeader_Header))
223 return ResultStatus::Error; 248 return ResultStatus::Error;
224 249
225 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1; 250 is_compressed = (exheader_header.codeset_info.flags.flag & 1) == 1;
@@ -239,7 +264,6 @@ ResultStatus AppLoader_NCCH::Load() {
239 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size); 264 LOG_DEBUG(Loader, "Bss size: 0x%08X", bss_size);
240 LOG_DEBUG(Loader, "Core version: %d" , core_version); 265 LOG_DEBUG(Loader, "Core version: %d" , core_version);
241 LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority); 266 LOG_DEBUG(Loader, "Thread priority: 0x%X" , priority);
242 LOG_DEBUG(Loader, "Resource limit descriptor: 0x%08X", exheader_header.arm11_system_local_caps.resource_limit_descriptor);
243 LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category); 267 LOG_DEBUG(Loader, "Resource limit category: %d" , resource_limit_category);
244 268
245 // Read ExeFS... 269 // Read ExeFS...
@@ -250,8 +274,8 @@ ResultStatus AppLoader_NCCH::Load() {
250 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset); 274 LOG_DEBUG(Loader, "ExeFS offset: 0x%08X", exefs_offset);
251 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size); 275 LOG_DEBUG(Loader, "ExeFS size: 0x%08X", exefs_size);
252 276
253 file->Seek(exefs_offset + ncch_offset, SEEK_SET); 277 file.Seek(exefs_offset + ncch_offset, SEEK_SET);
254 if (file->ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header)) 278 if (file.ReadBytes(&exefs_header, sizeof(ExeFs_Header)) != sizeof(ExeFs_Header))
255 return ResultStatus::Error; 279 return ResultStatus::Error;
256 280
257 is_loaded = true; // Set state to loaded 281 is_loaded = true; // Set state to loaded
@@ -259,24 +283,24 @@ ResultStatus AppLoader_NCCH::Load() {
259 return LoadExec(); // Load the executable into memory for booting 283 return LoadExec(); // Load the executable into memory for booting
260} 284}
261 285
262ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) const { 286ResultStatus AppLoader_NCCH::ReadCode(std::vector<u8>& buffer) {
263 return LoadSectionExeFS(".code", buffer); 287 return LoadSectionExeFS(".code", buffer);
264} 288}
265 289
266ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) const { 290ResultStatus AppLoader_NCCH::ReadIcon(std::vector<u8>& buffer) {
267 return LoadSectionExeFS("icon", buffer); 291 return LoadSectionExeFS("icon", buffer);
268} 292}
269 293
270ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) const { 294ResultStatus AppLoader_NCCH::ReadBanner(std::vector<u8>& buffer) {
271 return LoadSectionExeFS("banner", buffer); 295 return LoadSectionExeFS("banner", buffer);
272} 296}
273 297
274ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) const { 298ResultStatus AppLoader_NCCH::ReadLogo(std::vector<u8>& buffer) {
275 return LoadSectionExeFS("logo", buffer); 299 return LoadSectionExeFS("logo", buffer);
276} 300}
277 301
278ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const { 302ResultStatus AppLoader_NCCH::ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) {
279 if (!file->IsOpen()) 303 if (!file.IsOpen())
280 return ResultStatus::Error; 304 return ResultStatus::Error;
281 305
282 // Check if the NCCH has a RomFS... 306 // Check if the NCCH has a RomFS...
@@ -287,12 +311,17 @@ ResultStatus AppLoader_NCCH::ReadRomFS(std::vector<u8>& buffer) const {
287 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset); 311 LOG_DEBUG(Loader, "RomFS offset: 0x%08X", romfs_offset);
288 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size); 312 LOG_DEBUG(Loader, "RomFS size: 0x%08X", romfs_size);
289 313
290 buffer.resize(romfs_size); 314 if (file.GetSize () < romfs_offset + romfs_size)
315 return ResultStatus::Error;
291 316
292 file->Seek(romfs_offset, SEEK_SET); 317 // We reopen the file, to allow its position to be independent from file's
293 if (file->ReadBytes(&buffer[0], romfs_size) != romfs_size) 318 romfs_file = std::make_shared<FileUtil::IOFile>(filepath, "rb");
319 if (!romfs_file->IsOpen())
294 return ResultStatus::Error; 320 return ResultStatus::Error;
295 321
322 offset = romfs_offset;
323 size = romfs_size;
324
296 return ResultStatus::Success; 325 return ResultStatus::Success;
297 } 326 }
298 LOG_DEBUG(Loader, "NCCH has no RomFS"); 327 LOG_DEBUG(Loader, "NCCH has no RomFS");
diff --git a/src/core/loader/ncch.h b/src/core/loader/ncch.h
index 29e39d2c0..b4374a476 100644
--- a/src/core/loader/ncch.h
+++ b/src/core/loader/ncch.h
@@ -163,7 +163,8 @@ namespace Loader {
163/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI) 163/// Loads an NCCH file (e.g. from a CCI, or the first NCCH in a CXI)
164class AppLoader_NCCH final : public AppLoader { 164class AppLoader_NCCH final : public AppLoader {
165public: 165public:
166 AppLoader_NCCH(std::unique_ptr<FileUtil::IOFile>&& file) : AppLoader(std::move(file)) { } 166 AppLoader_NCCH(FileUtil::IOFile&& file, const std::string& filepath)
167 : AppLoader(std::move(file)), filepath(filepath) { }
167 168
168 /** 169 /**
169 * Returns the type of the file 170 * Returns the type of the file
@@ -183,35 +184,35 @@ public:
183 * @param buffer Reference to buffer to store data 184 * @param buffer Reference to buffer to store data
184 * @return ResultStatus result of function 185 * @return ResultStatus result of function
185 */ 186 */
186 ResultStatus ReadCode(std::vector<u8>& buffer) const override; 187 ResultStatus ReadCode(std::vector<u8>& buffer) override;
187 188
188 /** 189 /**
189 * Get the icon (typically icon section) of the application 190 * Get the icon (typically icon section) of the application
190 * @param buffer Reference to buffer to store data 191 * @param buffer Reference to buffer to store data
191 * @return ResultStatus result of function 192 * @return ResultStatus result of function
192 */ 193 */
193 ResultStatus ReadIcon(std::vector<u8>& buffer) const override; 194 ResultStatus ReadIcon(std::vector<u8>& buffer) override;
194 195
195 /** 196 /**
196 * Get the banner (typically banner section) of the application 197 * Get the banner (typically banner section) of the application
197 * @param buffer Reference to buffer to store data 198 * @param buffer Reference to buffer to store data
198 * @return ResultStatus result of function 199 * @return ResultStatus result of function
199 */ 200 */
200 ResultStatus ReadBanner(std::vector<u8>& buffer) const override; 201 ResultStatus ReadBanner(std::vector<u8>& buffer) override;
201 202
202 /** 203 /**
203 * Get the logo (typically logo section) of the application 204 * Get the logo (typically logo section) of the application
204 * @param buffer Reference to buffer to store data 205 * @param buffer Reference to buffer to store data
205 * @return ResultStatus result of function 206 * @return ResultStatus result of function
206 */ 207 */
207 ResultStatus ReadLogo(std::vector<u8>& buffer) const override; 208 ResultStatus ReadLogo(std::vector<u8>& buffer) override;
208 209
209 /** 210 /**
210 * Get the RomFS of the application 211 * Get the RomFS of the application
211 * @param buffer Reference to buffer to store data 212 * @param buffer Reference to buffer to store data
212 * @return ResultStatus result of function 213 * @return ResultStatus result of function
213 */ 214 */
214 ResultStatus ReadRomFS(std::vector<u8>& buffer) const override; 215 ResultStatus ReadRomFS(std::shared_ptr<FileUtil::IOFile>& romfs_file, u64& offset, u64& size) override;
215 216
216private: 217private:
217 218
@@ -221,13 +222,13 @@ private:
221 * @param buffer Vector to read data into 222 * @param buffer Vector to read data into
222 * @return ResultStatus result of function 223 * @return ResultStatus result of function
223 */ 224 */
224 ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer) const; 225 ResultStatus LoadSectionExeFS(const char* name, std::vector<u8>& buffer);
225 226
226 /** 227 /**
227 * Loads .code section into memory for booting 228 * Loads .code section into memory for booting
228 * @return ResultStatus result of function 229 * @return ResultStatus result of function
229 */ 230 */
230 ResultStatus LoadExec() const; 231 ResultStatus LoadExec();
231 232
232 bool is_compressed = false; 233 bool is_compressed = false;
233 234
@@ -244,6 +245,8 @@ private:
244 NCCH_Header ncch_header; 245 NCCH_Header ncch_header;
245 ExeFs_Header exefs_header; 246 ExeFs_Header exefs_header;
246 ExHeader_Header exheader_header; 247 ExHeader_Header exheader_header;
248
249 std::string filepath;
247}; 250};
248 251
249} // namespace Loader 252} // namespace Loader
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index bf814b945..cbe993fbe 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -3,13 +3,14 @@
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <map> 5#include <map>
6#include <memory>
7#include <utility>
8#include <vector>
6 9
7#include "common/common_types.h" 10#include "common/common_types.h"
8#include "common/logging/log.h" 11#include "common/logging/log.h"
9 12
10#include "core/hle/config_mem.h" 13#include "core/hle/config_mem.h"
11#include "core/hle/kernel/kernel.h"
12#include "core/hle/kernel/shared_memory.h"
13#include "core/hle/kernel/vm_manager.h" 14#include "core/hle/kernel/vm_manager.h"
14#include "core/hle/result.h" 15#include "core/hle/result.h"
15#include "core/hle/shared_page.h" 16#include "core/hle/shared_page.h"
@@ -31,7 +32,6 @@ struct MemoryArea {
31 32
32// We don't declare the IO regions in here since its handled by other means. 33// We don't declare the IO regions in here since its handled by other means.
33static MemoryArea memory_areas[] = { 34static MemoryArea memory_areas[] = {
34 {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory) 35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory 36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory) 37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
@@ -131,13 +131,13 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
131 return addr | 0x80000000; 131 return addr | 0x80000000;
132} 132}
133 133
134// TODO(yuriks): Move this into Process
135static Kernel::VMManager address_space;
136
137void Init() { 134void Init() {
138 using namespace Kernel;
139
140 InitMemoryMap(); 135 InitMemoryMap();
136 LOG_DEBUG(HW_Memory, "initialized OK");
137}
138
139void InitLegacyAddressSpace(Kernel::VMManager& address_space) {
140 using namespace Kernel;
141 141
142 for (MemoryArea& area : memory_areas) { 142 for (MemoryArea& area : memory_areas) {
143 auto block = std::make_shared<std::vector<u8>>(area.size); 143 auto block = std::make_shared<std::vector<u8>>(area.size);
@@ -151,14 +151,11 @@ void Init() {
151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, 151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); 152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
153 address_space.Reprotect(shared_page_vma, VMAPermission::Read); 153 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
154
155 LOG_DEBUG(HW_Memory, "initialized OK");
156} 154}
157 155
158void Shutdown() { 156void Shutdown() {
159 heap_map.clear(); 157 heap_map.clear();
160 heap_linear_map.clear(); 158 heap_linear_map.clear();
161 address_space.Reset();
162 159
163 LOG_DEBUG(HW_Memory, "shutdown OK"); 160 LOG_DEBUG(HW_Memory, "shutdown OK");
164} 161}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index ba50914a8..229ef82c5 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -6,9 +6,14 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9namespace Kernel {
10class VMManager;
11}
12
9namespace Memory { 13namespace Memory {
10 14
11void Init(); 15void Init();
16void InitLegacyAddressSpace(Kernel::VMManager& address_space);
12void Shutdown(); 17void Shutdown();
13 18
14/** 19/**
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 28844a915..1f66bb27d 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -9,9 +9,6 @@
9#include "common/logging/log.h" 9#include "common/logging/log.h"
10#include "common/swap.h" 10#include "common/swap.h"
11 11
12#include "core/hle/config_mem.h"
13#include "core/hle/shared_page.h"
14#include "core/hw/hw.h"
15#include "core/mem_map.h" 12#include "core/mem_map.h"
16#include "core/memory.h" 13#include "core/memory.h"
17#include "core/memory_setup.h" 14#include "core/memory_setup.h"
@@ -62,14 +59,12 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
62 while (base != end) { 59 while (base != end) {
63 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); 60 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
64 61
65 if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
66 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
67 }
68 current_page_table->attributes[base] = type; 62 current_page_table->attributes[base] = type;
69 current_page_table->pointers[base] = memory; 63 current_page_table->pointers[base] = memory;
70 64
71 base += 1; 65 base += 1;
72 memory += PAGE_SIZE; 66 if (memory != nullptr)
67 memory += PAGE_SIZE;
73 } 68 }
74} 69}
75 70
diff --git a/src/core/memory.h b/src/core/memory.h
index 0b8ff9ec4..418609de0 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -4,6 +4,8 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <cstddef>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9namespace Memory { 11namespace Memory {
diff --git a/src/core/tracer/citrace.h b/src/core/tracer/citrace.h
new file mode 100644
index 000000000..5deb6ce9e
--- /dev/null
+++ b/src/core/tracer/citrace.h
@@ -0,0 +1,101 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <cstdint>
8
9namespace CiTrace {
10
11// NOTE: Things are stored in little-endian
12
13#pragma pack(1)
14
15struct CTHeader {
16 static const char* ExpectedMagicWord() {
17 return "CiTr";
18 }
19
20 static uint32_t ExpectedVersion() {
21 return 1;
22 }
23
24 char magic[4];
25 uint32_t version;
26 uint32_t header_size;
27
28 struct {
29 // NOTE: Register range sizes are technically hardware-constants, but the actual limits
30 // aren't known. Hence we store the presumed limits along the offsets.
31 // Sizes are given in uint32_t units.
32 uint32_t gpu_registers;
33 uint32_t gpu_registers_size;
34 uint32_t lcd_registers;
35 uint32_t lcd_registers_size;
36 uint32_t pica_registers;
37 uint32_t pica_registers_size;
38 uint32_t default_attributes;
39 uint32_t default_attributes_size;
40 uint32_t vs_program_binary;
41 uint32_t vs_program_binary_size;
42 uint32_t vs_swizzle_data;
43 uint32_t vs_swizzle_data_size;
44 uint32_t vs_float_uniforms;
45 uint32_t vs_float_uniforms_size;
46 uint32_t gs_program_binary;
47 uint32_t gs_program_binary_size;
48 uint32_t gs_swizzle_data;
49 uint32_t gs_swizzle_data_size;
50 uint32_t gs_float_uniforms;
51 uint32_t gs_float_uniforms_size;
52
53 // Other things we might want to store here:
54 // - Initial framebuffer data, maybe even a full copy of FCRAM/VRAM
55 // - Lookup tables for fragment lighting
56 // - Lookup tables for procedural textures
57 } initial_state_offsets;
58
59 uint32_t stream_offset;
60 uint32_t stream_size;
61};
62
63enum CTStreamElementType : uint32_t {
64 FrameMarker = 0xE1,
65 MemoryLoad = 0xE2,
66 RegisterWrite = 0xE3,
67};
68
69struct CTMemoryLoad {
70 uint32_t file_offset;
71 uint32_t size;
72 uint32_t physical_address;
73 uint32_t pad;
74};
75
76struct CTRegisterWrite {
77 uint32_t physical_address;
78
79 enum : uint32_t {
80 SIZE_8 = 0xD1,
81 SIZE_16 = 0xD2,
82 SIZE_32 = 0xD3,
83 SIZE_64 = 0xD4
84 } size;
85
86 // TODO: Make it clearer which bits of this member are used for sizes other than 32 bits
87 uint64_t value;
88};
89
90struct CTStreamElement {
91 CTStreamElementType type;
92
93 union {
94 CTMemoryLoad memory_load;
95 CTRegisterWrite register_write;
96 };
97};
98
99#pragma pack()
100
101}
diff --git a/src/core/tracer/recorder.cpp b/src/core/tracer/recorder.cpp
new file mode 100644
index 000000000..656706c0c
--- /dev/null
+++ b/src/core/tracer/recorder.cpp
@@ -0,0 +1,187 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include <cstring>
6
7#include "common/assert.h"
8#include "common/file_util.h"
9#include "common/logging/log.h"
10
11#include "recorder.h"
12
13namespace CiTrace {
14
15Recorder::Recorder(const InitialState& initial_state) : initial_state(initial_state) {
16
17}
18
19void Recorder::Finish(const std::string& filename) {
20 // Setup CiTrace header
21 CTHeader header;
22 std::memcpy(header.magic, CTHeader::ExpectedMagicWord(), 4);
23 header.version = CTHeader::ExpectedVersion();
24 header.header_size = sizeof(CTHeader);
25
26 // Calculate file offsets
27 auto& initial = header.initial_state_offsets;
28
29 initial.gpu_registers_size = initial_state.gpu_registers.size();
30 initial.lcd_registers_size = initial_state.lcd_registers.size();
31 initial.pica_registers_size = initial_state.pica_registers.size();
32 initial.default_attributes_size = initial_state.default_attributes.size();
33 initial.vs_program_binary_size = initial_state.vs_program_binary.size();
34 initial.vs_swizzle_data_size = initial_state.vs_swizzle_data.size();
35 initial.vs_float_uniforms_size = initial_state.vs_float_uniforms.size();
36 initial.gs_program_binary_size = initial_state.gs_program_binary.size();
37 initial.gs_swizzle_data_size = initial_state.gs_swizzle_data.size();
38 initial.gs_float_uniforms_size = initial_state.gs_float_uniforms.size();
39 header.stream_size = stream.size();
40
41 initial.gpu_registers = sizeof(header);
42 initial.lcd_registers = initial.gpu_registers + initial.gpu_registers_size * sizeof(u32);
43 initial.pica_registers = initial.lcd_registers + initial.lcd_registers_size * sizeof(u32);;
44 initial.default_attributes = initial.pica_registers + initial.pica_registers_size * sizeof(u32);
45 initial.vs_program_binary = initial.default_attributes + initial.default_attributes_size * sizeof(u32);
46 initial.vs_swizzle_data = initial.vs_program_binary + initial.vs_program_binary_size * sizeof(u32);
47 initial.vs_float_uniforms = initial.vs_swizzle_data + initial.vs_swizzle_data_size * sizeof(u32);
48 initial.gs_program_binary = initial.vs_float_uniforms + initial.vs_float_uniforms_size * sizeof(u32);
49 initial.gs_swizzle_data = initial.gs_program_binary + initial.gs_program_binary_size * sizeof(u32);
50 initial.gs_float_uniforms = initial.gs_swizzle_data + initial.gs_swizzle_data_size * sizeof(u32);
51 header.stream_offset = initial.gs_float_uniforms + initial.gs_float_uniforms_size * sizeof(u32);
52
53 // Iterate through stream elements, update relevant stream element data
54 for (auto& stream_element : stream) {
55 switch (stream_element.data.type) {
56 case MemoryLoad:
57 {
58 auto& file_offset = memory_regions[stream_element.hash];
59 if (!stream_element.uses_existing_data) {
60 file_offset = header.stream_offset;
61 }
62 stream_element.data.memory_load.file_offset = file_offset;
63 break;
64 }
65
66 default:
67 // Other commands don't use any extra data
68 DEBUG_ASSERT(stream_element.extra_data.size() == 0);
69 break;
70 }
71 header.stream_offset += stream_element.extra_data.size();
72 }
73
74 try {
75 // Open file and write header
76 FileUtil::IOFile file(filename, "wb");
77 size_t written = file.WriteObject(header);
78 if (written != 1 || file.Tell() != initial.gpu_registers)
79 throw "Failed to write header";
80
81 // Write initial state
82 written = file.WriteArray(initial_state.gpu_registers.data(), initial_state.gpu_registers.size());
83 if (written != initial_state.gpu_registers.size() || file.Tell() != initial.lcd_registers)
84 throw "Failed to write GPU registers";
85
86 written = file.WriteArray(initial_state.lcd_registers.data(), initial_state.lcd_registers.size());
87 if (written != initial_state.lcd_registers.size() || file.Tell() != initial.pica_registers)
88 throw "Failed to write LCD registers";
89
90 written = file.WriteArray(initial_state.pica_registers.data(), initial_state.pica_registers.size());
91 if (written != initial_state.pica_registers.size() || file.Tell() != initial.default_attributes)
92 throw "Failed to write Pica registers";
93
94 written = file.WriteArray(initial_state.default_attributes.data(), initial_state.default_attributes.size());
95 if (written != initial_state.default_attributes.size() || file.Tell() != initial.vs_program_binary)
96 throw "Failed to write default vertex attributes";
97
98 written = file.WriteArray(initial_state.vs_program_binary.data(), initial_state.vs_program_binary.size());
99 if (written != initial_state.vs_program_binary.size() || file.Tell() != initial.vs_swizzle_data)
100 throw "Failed to write vertex shader program binary";
101
102 written = file.WriteArray(initial_state.vs_swizzle_data.data(), initial_state.vs_swizzle_data.size());
103 if (written != initial_state.vs_swizzle_data.size() || file.Tell() != initial.vs_float_uniforms)
104 throw "Failed to write vertex shader swizzle data";
105
106 written = file.WriteArray(initial_state.vs_float_uniforms.data(), initial_state.vs_float_uniforms.size());
107 if (written != initial_state.vs_float_uniforms.size() || file.Tell() != initial.gs_program_binary)
108 throw "Failed to write vertex shader float uniforms";
109
110 written = file.WriteArray(initial_state.gs_program_binary.data(), initial_state.gs_program_binary.size());
111 if (written != initial_state.gs_program_binary.size() || file.Tell() != initial.gs_swizzle_data)
112 throw "Failed to write geomtry shader program binary";
113
114 written = file.WriteArray(initial_state.gs_swizzle_data.data(), initial_state.gs_swizzle_data.size());
115 if (written != initial_state.gs_swizzle_data.size() || file.Tell() != initial.gs_float_uniforms)
116 throw "Failed to write geometry shader swizzle data";
117
118 written = file.WriteArray(initial_state.gs_float_uniforms.data(), initial_state.gs_float_uniforms.size());
119 if (written != initial_state.gs_float_uniforms.size() || file.Tell() != initial.gs_float_uniforms + sizeof(u32) * initial.gs_float_uniforms_size)
120 throw "Failed to write geometry shader float uniforms";
121
122 // Iterate through stream elements, write "extra data"
123 for (const auto& stream_element : stream) {
124 if (stream_element.extra_data.size() == 0)
125 continue;
126
127 written = file.WriteBytes(stream_element.extra_data.data(), stream_element.extra_data.size());
128 if (written != stream_element.extra_data.size())
129 throw "Failed to write extra data";
130 }
131
132 if (file.Tell() != header.stream_offset)
133 throw "Unexpected end of extra data";
134
135 // Write actual stream elements
136 for (const auto& stream_element : stream) {
137 if (1 != file.WriteObject(stream_element.data))
138 throw "Failed to write stream element";
139 }
140 } catch(const char* str) {
141 LOG_ERROR(HW_GPU, "Writing CiTrace file failed: %s", str);
142 }
143}
144
145void Recorder::FrameFinished() {
146 stream.push_back( { FrameMarker } );
147}
148
149void Recorder::MemoryAccessed(const u8* data, u32 size, u32 physical_address) {
150 StreamElement element = { MemoryLoad };
151 element.data.memory_load.size = size;
152 element.data.memory_load.physical_address = physical_address;
153
154 // Compute hash over given memory region to check if the contents are already stored internally
155 boost::crc_32_type result;
156 result.process_bytes(data, size);
157 element.hash = result.checksum();
158
159 element.uses_existing_data = (memory_regions.find(element.hash) != memory_regions.end());
160 if (!element.uses_existing_data) {
161 element.extra_data.resize(size);
162 memcpy(element.extra_data.data(), data, size);
163 memory_regions.insert({element.hash, 0}); // file offset will be initialized in Finish()
164 }
165
166 stream.push_back(element);
167}
168
169template<typename T>
170void Recorder::RegisterWritten(u32 physical_address, T value) {
171 StreamElement element = { RegisterWrite };
172 element.data.register_write.size = (sizeof(T) == 1) ? CTRegisterWrite::SIZE_8
173 : (sizeof(T) == 2) ? CTRegisterWrite::SIZE_16
174 : (sizeof(T) == 4) ? CTRegisterWrite::SIZE_32
175 : CTRegisterWrite::SIZE_64;
176 element.data.register_write.physical_address = physical_address;
177 element.data.register_write.value = value;
178
179 stream.push_back(element);
180}
181
182template void Recorder::RegisterWritten(u32,u8);
183template void Recorder::RegisterWritten(u32,u16);
184template void Recorder::RegisterWritten(u32,u32);
185template void Recorder::RegisterWritten(u32,u64);
186
187}
diff --git a/src/core/tracer/recorder.h b/src/core/tracer/recorder.h
new file mode 100644
index 000000000..6e4b70015
--- /dev/null
+++ b/src/core/tracer/recorder.h
@@ -0,0 +1,90 @@
1// Copyright 2015 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#pragma once
6
7#include <unordered_map>
8#include <vector>
9
10#include <boost/crc.hpp>
11
12#include "common/common_types.h"
13
14#include "citrace.h"
15
16namespace CiTrace {
17
18class Recorder {
19public:
20 struct InitialState {
21 std::vector<u32> gpu_registers;
22 std::vector<u32> lcd_registers;
23 std::vector<u32> pica_registers;
24 std::vector<u32> default_attributes;
25 std::vector<u32> vs_program_binary;
26 std::vector<u32> vs_swizzle_data;
27 std::vector<u32> vs_float_uniforms;
28 std::vector<u32> gs_program_binary;
29 std::vector<u32> gs_swizzle_data;
30 std::vector<u32> gs_float_uniforms;
31 };
32
33 /**
34 * Recorder constructor
35 * @param default_attributes Pointer to an array of 32-bit-aligned 24-bit floating point values.
36 * @param vs_float_uniforms Pointer to an array of 32-bit-aligned 24-bit floating point values.
37 */
38 Recorder(const InitialState& initial_state);
39
40 /// Finish recording of this Citrace and save it using the given filename.
41 void Finish(const std::string& filename);
42
43 /// Mark end of a frame
44 void FrameFinished();
45
46 /**
47 * Store a copy of the given memory range in the recording.
48 * @note Use this whenever the GPU is about to access a particular memory region.
49 * @note The implementation will make sure to minimize redundant memory updates.
50 */
51 void MemoryAccessed(const u8* data, u32 size, u32 physical_address);
52
53 /**
54 * Record a register write.
55 * @note Use this whenever a GPU-related MMIO register has been written to.
56 */
57 template<typename T>
58 void RegisterWritten(u32 physical_address, T value);
59
60private:
61 // Initial state of recording start
62 InitialState initial_state;
63
64 // Command stream
65 struct StreamElement {
66 CTStreamElement data;
67
68 /**
69 * Extra data to store along "core" data.
70 * This is e.g. used for data used in MemoryUpdates.
71 */
72 std::vector<u8> extra_data;
73
74 /// Optional CRC hash (e.g. for hashing memory regions)
75 boost::crc_32_type::value_type hash;
76
77 /// If true, refer to data already written to the output file instead of extra_data
78 bool uses_existing_data;
79 };
80
81 std::vector<StreamElement> stream;
82
83 /**
84 * Internal cache which maps hashes of memory contents to file offsets at which those memory
85 * contents are stored.
86 */
87 std::unordered_map<boost::crc_32_type::value_type /*hash*/, u32 /*file_offset*/> memory_regions;
88};
89
90} // namespace
diff --git a/src/video_core/clipper.cpp b/src/video_core/clipper.cpp
index 943f3eb35..558b49d60 100644
--- a/src/video_core/clipper.cpp
+++ b/src/video_core/clipper.cpp
@@ -94,7 +94,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
94 // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value. 94 // NOTE: We clip against a w=epsilon plane to guarantee that the output has a positive w value.
95 // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest 95 // TODO: Not sure if this is a valid approach. Also should probably instead use the smallest
96 // epsilon possible within float24 accuracy. 96 // epsilon possible within float24 accuracy.
97 static const float24 EPSILON = float24::FromFloat32(0.00001); 97 static const float24 EPSILON = float24::FromFloat32(0.00001f);
98 static const float24 f0 = float24::FromFloat32(0.0); 98 static const float24 f0 = float24::FromFloat32(0.0);
99 static const float24 f1 = float24::FromFloat32(1.0); 99 static const float24 f1 = float24::FromFloat32(1.0);
100 static const std::array<ClippingEdge, 7> clipping_edges = {{ 100 static const std::array<ClippingEdge, 7> clipping_edges = {{
@@ -153,7 +153,7 @@ void ProcessTriangle(OutputVertex &v0, OutputVertex &v1, OutputVertex &v2) {
153 "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), " 153 "Triangle %lu/%lu at position (%.3f, %.3f, %.3f, %.3f), "
154 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and " 154 "(%.3f, %.3f, %.3f, %.3f), (%.3f, %.3f, %.3f, %.3f) and "
155 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)", 155 "screen position (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f), (%.2f, %.2f, %.2f)",
156 i, output_list->size(), 156 i + 1, output_list->size() - 2,
157 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(), 157 vtx0.pos.x.ToFloat32(), vtx0.pos.y.ToFloat32(), vtx0.pos.z.ToFloat32(), vtx0.pos.w.ToFloat32(),
158 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(), 158 vtx1.pos.x.ToFloat32(), vtx1.pos.y.ToFloat32(), vtx1.pos.z.ToFloat32(), vtx1.pos.w.ToFloat32(),
159 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(), 159 vtx2.pos.x.ToFloat32(), vtx2.pos.y.ToFloat32(), vtx2.pos.z.ToFloat32(), vtx2.pos.w.ToFloat32(),
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index b46fadd9f..43ae06181 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -6,18 +6,20 @@
6 6
7#include "common/profiler.h" 7#include "common/profiler.h"
8 8
9#include "core/hle/service/gsp_gpu.h"
10#include "core/hw/gpu.h"
11#include "core/settings.h"
12
13#include "debug_utils/debug_utils.h"
14
9#include "clipper.h" 15#include "clipper.h"
10#include "command_processor.h" 16#include "command_processor.h"
11#include "math.h" 17#include "math.h"
12#include "pica.h" 18#include "pica.h"
13#include "primitive_assembly.h" 19#include "primitive_assembly.h"
20#include "renderer_base.h"
14#include "vertex_shader.h" 21#include "vertex_shader.h"
15#include "video_core.h" 22#include "video_core.h"
16#include "core/hle/service/gsp_gpu.h"
17#include "core/hw/gpu.h"
18#include "core/settings.h"
19
20#include "debug_utils/debug_utils.h"
21 23
22namespace Pica { 24namespace Pica {
23 25
@@ -43,12 +45,12 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
43 if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq)) 45 if (GPU::g_skip_frame && id != PICA_REG_INDEX(trigger_irq))
44 return; 46 return;
45 47
46 // TODO: Figure out how register masking acts on e.g. vs_uniform_setup.set_value 48 // TODO: Figure out how register masking acts on e.g. vs.uniform_setup.set_value
47 u32 old_value = regs[id]; 49 u32 old_value = regs[id];
48 regs[id] = (old_value & ~mask) | (value & mask); 50 regs[id] = (old_value & ~mask) | (value & mask);
49 51
50 if (g_debug_context) 52 if (g_debug_context)
51 g_debug_context->OnEvent(DebugContext::Event::CommandLoaded, reinterpret_cast<void*>(&id)); 53 g_debug_context->OnEvent(DebugContext::Event::PicaCommandLoaded, reinterpret_cast<void*>(&id));
52 54
53 DebugUtils::OnPicaRegWrite(id, regs[id]); 55 DebugUtils::OnPicaRegWrite(id, regs[id]);
54 56
@@ -58,10 +60,50 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); 60 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
59 break; 61 break;
60 62
63 // Load default vertex input attributes
64 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
65 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
66 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
67 {
68 // TODO: Does actual hardware indeed keep an intermediate buffer or does
69 // it directly write the values?
70 default_attr_write_buffer[default_attr_counter++] = value;
71
72 // Default attributes are written in a packed format such that four float24 values are encoded in
73 // three 32-bit numbers. We write to internal memory once a full such vector is
74 // written.
75 if (default_attr_counter >= 3) {
76 default_attr_counter = 0;
77
78 auto& setup = regs.vs_default_attributes_setup;
79
80 if (setup.index >= 16) {
81 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
82 break;
83 }
84
85 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
86
87 // NOTE: The destination component order indeed is "backwards"
88 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
89 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
90 attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
91 attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
92
93 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
94 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
95 attribute.w.ToFloat32());
96
97 // TODO: Verify that this actually modifies the register!
98 setup.index = setup.index + 1;
99 }
100 break;
101 }
102
61 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): 103 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
62 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): 104 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
63 { 105 {
64 unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); 106 unsigned index = static_cast<unsigned>(id - PICA_REG_INDEX(command_buffer.trigger[0]));
65 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); 107 u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index));
66 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; 108 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
67 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); 109 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
@@ -121,12 +163,55 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
121 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value()); 163 PrimitiveAssembler<VertexShader::OutputVertex> primitive_assembler(regs.triangle_topology.Value());
122 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value()); 164 PrimitiveAssembler<DebugUtils::GeometryDumper::Vertex> dumping_primitive_assembler(regs.triangle_topology.Value());
123 165
166 if (g_debug_context) {
167 for (int i = 0; i < 3; ++i) {
168 const auto texture = regs.GetTextures()[i];
169 if (!texture.enabled)
170 continue;
171
172 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
173 if (g_debug_context && Pica::g_debug_context->recorder)
174 g_debug_context->recorder->MemoryAccessed(texture_data, Pica::Regs::NibblesPerPixel(texture.format) * texture.config.width / 2 * texture.config.height, texture.config.GetPhysicalAddress());
175 }
176 }
177
178 class {
179 /// Combine overlapping and close ranges
180 void SimplifyRanges() {
181 for (auto it = ranges.begin(); it != ranges.end(); ++it) {
182 // NOTE: We add 32 to the range end address to make sure "close" ranges are combined, too
183 auto it2 = std::next(it);
184 while (it2 != ranges.end() && it->first + it->second + 32 >= it2->first) {
185 it->second = std::max(it->second, it2->first + it2->second - it->first);
186 it2 = ranges.erase(it2);
187 }
188 }
189 }
190
191 public:
192 /// Record a particular memory access in the list
193 void AddAccess(u32 paddr, u32 size) {
194 // Create new range or extend existing one
195 ranges[paddr] = std::max(ranges[paddr], size);
196
197 // Simplify ranges...
198 SimplifyRanges();
199 }
200
201 /// Map of accessed ranges (mapping start address to range size)
202 std::map<u32, u32> ranges;
203 } memory_accesses;
204
124 for (unsigned int index = 0; index < regs.num_vertices; ++index) 205 for (unsigned int index = 0; index < regs.num_vertices; ++index)
125 { 206 {
126 unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index; 207 unsigned int vertex = is_indexed ? (index_u16 ? index_address_16[index] : index_address_8[index]) : index;
127 208
128 if (is_indexed) { 209 if (is_indexed) {
129 // TODO: Implement some sort of vertex cache! 210 // TODO: Implement some sort of vertex cache!
211 if (g_debug_context && Pica::g_debug_context->recorder) {
212 int size = index_u16 ? 2 : 1;
213 memory_accesses.AddAccess(base_address + index_info.offset + size * index, size);
214 }
130 } 215 }
131 216
132 // Initialize data for the current vertex 217 // Initialize data for the current vertex
@@ -149,7 +234,14 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
149 234
150 // Load per-vertex data from the loader arrays 235 // Load per-vertex data from the loader arrays
151 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 236 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
152 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); 237 u32 source_addr = vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i];
238 const u8* srcdata = Memory::GetPhysicalPointer(source_addr);
239
240 if (g_debug_context && Pica::g_debug_context->recorder) {
241 memory_accesses.AddAccess(source_addr,
242 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::FLOAT) ? 4
243 : (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::SHORT) ? 2 : 1);
244 }
153 245
154 const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata : 246 const float srcval = (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::BYTE) ? *(s8*)srcdata :
155 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata : 247 (vertex_attribute_formats[i] == Regs::VertexAttributeFormat::UBYTE) ? *(u8*)srcdata :
@@ -190,7 +282,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
190 &geometry_dumper, _1, _2, _3)); 282 &geometry_dumper, _1, _2, _3));
191 283
192 // Send to vertex shader 284 // Send to vertex shader
193 VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes()); 285 VertexShader::OutputVertex output = VertexShader::RunShader(input, attribute_config.GetNumTotalAttributes(), g_state.regs.vs, g_state.vs);
194 286
195 if (is_indexed) { 287 if (is_indexed) {
196 // TODO: Add processed vertex to vertex cache! 288 // TODO: Add processed vertex to vertex cache!
@@ -211,47 +303,53 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
211 } 303 }
212 } 304 }
213 305
306 for (auto& range : memory_accesses.ranges) {
307 g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
308 range.second, range.first);
309 }
310
214 if (Settings::values.use_hw_renderer) { 311 if (Settings::values.use_hw_renderer) {
215 VideoCore::g_renderer->hw_rasterizer->DrawTriangles(); 312 VideoCore::g_renderer->hw_rasterizer->DrawTriangles();
216 } 313 }
217 314
218 geometry_dumper.Dump(); 315 geometry_dumper.Dump();
219 316
220 if (g_debug_context) 317 if (g_debug_context) {
221 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr); 318 g_debug_context->OnEvent(DebugContext::Event::FinishedPrimitiveBatch, nullptr);
319 }
222 320
223 break; 321 break;
224 } 322 }
225 323
226 case PICA_REG_INDEX(vs_bool_uniforms): 324 case PICA_REG_INDEX(vs.bool_uniforms):
227 for (unsigned i = 0; i < 16; ++i) 325 for (unsigned i = 0; i < 16; ++i)
228 g_state.vs.uniforms.b[i] = (regs.vs_bool_uniforms.Value() & (1 << i)) != 0; 326 g_state.vs.uniforms.b[i] = (regs.vs.bool_uniforms.Value() & (1 << i)) != 0;
229 327
230 break; 328 break;
231 329
232 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1): 330 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1):
233 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[1], 0x2b2): 331 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[1], 0x2b2):
234 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[2], 0x2b3): 332 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[2], 0x2b3):
235 case PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[3], 0x2b4): 333 case PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[3], 0x2b4):
236 { 334 {
237 int index = (id - PICA_REG_INDEX_WORKAROUND(vs_int_uniforms[0], 0x2b1)); 335 int index = (id - PICA_REG_INDEX_WORKAROUND(vs.int_uniforms[0], 0x2b1));
238 auto values = regs.vs_int_uniforms[index]; 336 auto values = regs.vs.int_uniforms[index];
239 g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w); 337 g_state.vs.uniforms.i[index] = Math::Vec4<u8>(values.x, values.y, values.z, values.w);
240 LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x", 338 LOG_TRACE(HW_GPU, "Set integer uniform %d to %02x %02x %02x %02x",
241 index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value()); 339 index, values.x.Value(), values.y.Value(), values.z.Value(), values.w.Value());
242 break; 340 break;
243 } 341 }
244 342
245 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[0], 0x2c1): 343 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[0], 0x2c1):
246 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[1], 0x2c2): 344 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[1], 0x2c2):
247 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[2], 0x2c3): 345 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[2], 0x2c3):
248 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[3], 0x2c4): 346 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[3], 0x2c4):
249 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[4], 0x2c5): 347 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[4], 0x2c5):
250 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[5], 0x2c6): 348 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[5], 0x2c6):
251 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[6], 0x2c7): 349 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[6], 0x2c7):
252 case PICA_REG_INDEX_WORKAROUND(vs_uniform_setup.set_value[7], 0x2c8): 350 case PICA_REG_INDEX_WORKAROUND(vs.uniform_setup.set_value[7], 0x2c8):
253 { 351 {
254 auto& uniform_setup = regs.vs_uniform_setup; 352 auto& uniform_setup = regs.vs.uniform_setup;
255 353
256 // TODO: Does actual hardware indeed keep an intermediate buffer or does 354 // TODO: Does actual hardware indeed keep an intermediate buffer or does
257 // it directly write the values? 355 // it directly write the values?
@@ -293,73 +391,33 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
293 break; 391 break;
294 } 392 }
295 393
296 // Load default vertex input attributes
297 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
298 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
299 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[2], 0x235):
300 {
301 // TODO: Does actual hardware indeed keep an intermediate buffer or does
302 // it directly write the values?
303 default_attr_write_buffer[default_attr_counter++] = value;
304
305 // Default attributes are written in a packed format such that four float24 values are encoded in
306 // three 32-bit numbers. We write to internal memory once a full such vector is
307 // written.
308 if (default_attr_counter >= 3) {
309 default_attr_counter = 0;
310
311 auto& setup = regs.vs_default_attributes_setup;
312
313 if (setup.index >= 16) {
314 LOG_ERROR(HW_GPU, "Invalid VS default attribute index %d", (int)setup.index);
315 break;
316 }
317
318 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
319
320 // NOTE: The destination component order indeed is "backwards"
321 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
322 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
323 attribute.y = float24::FromRawFloat24(((default_attr_write_buffer[1] & 0xFFFF) << 8) | ((default_attr_write_buffer[2] >> 24) & 0xFF));
324 attribute.x = float24::FromRawFloat24(default_attr_write_buffer[2] & 0xFFFFFF);
325
326 LOG_TRACE(HW_GPU, "Set default VS attribute %x to (%f %f %f %f)", (int)setup.index,
327 attribute.x.ToFloat32(), attribute.y.ToFloat32(), attribute.z.ToFloat32(),
328 attribute.w.ToFloat32());
329
330 // TODO: Verify that this actually modifies the register!
331 setup.index = setup.index + 1;
332 }
333 break;
334 }
335
336 // Load shader program code 394 // Load shader program code
337 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[0], 0x2cc): 395 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[0], 0x2cc):
338 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[1], 0x2cd): 396 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[1], 0x2cd):
339 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[2], 0x2ce): 397 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[2], 0x2ce):
340 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[3], 0x2cf): 398 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[3], 0x2cf):
341 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[4], 0x2d0): 399 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[4], 0x2d0):
342 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[5], 0x2d1): 400 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[5], 0x2d1):
343 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[6], 0x2d2): 401 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[6], 0x2d2):
344 case PICA_REG_INDEX_WORKAROUND(vs_program.set_word[7], 0x2d3): 402 case PICA_REG_INDEX_WORKAROUND(vs.program.set_word[7], 0x2d3):
345 { 403 {
346 g_state.vs.program_code[regs.vs_program.offset] = value; 404 g_state.vs.program_code[regs.vs.program.offset] = value;
347 regs.vs_program.offset++; 405 regs.vs.program.offset++;
348 break; 406 break;
349 } 407 }
350 408
351 // Load swizzle pattern data 409 // Load swizzle pattern data
352 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[0], 0x2d6): 410 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[0], 0x2d6):
353 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[1], 0x2d7): 411 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[1], 0x2d7):
354 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[2], 0x2d8): 412 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[2], 0x2d8):
355 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[3], 0x2d9): 413 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[3], 0x2d9):
356 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[4], 0x2da): 414 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[4], 0x2da):
357 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[5], 0x2db): 415 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[5], 0x2db):
358 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[6], 0x2dc): 416 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[6], 0x2dc):
359 case PICA_REG_INDEX_WORKAROUND(vs_swizzle_patterns.set_word[7], 0x2dd): 417 case PICA_REG_INDEX_WORKAROUND(vs.swizzle_patterns.set_word[7], 0x2dd):
360 { 418 {
361 g_state.vs.swizzle_data[regs.vs_swizzle_patterns.offset] = value; 419 g_state.vs.swizzle_data[regs.vs.swizzle_patterns.offset] = value;
362 regs.vs_swizzle_patterns.offset++; 420 regs.vs.swizzle_patterns.offset++;
363 break; 421 break;
364 } 422 }
365 423
@@ -370,7 +428,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
370 VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id); 428 VideoCore::g_renderer->hw_rasterizer->NotifyPicaRegisterChanged(id);
371 429
372 if (g_debug_context) 430 if (g_debug_context)
373 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); 431 g_debug_context->OnEvent(DebugContext::Event::PicaCommandProcessed, reinterpret_cast<void*>(&id));
374} 432}
375 433
376void ProcessCommandList(const u32* list, u32 size) { 434void ProcessCommandList(const u32* list, u32 size) {
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h
index bb3d4150f..022a71f5e 100644
--- a/src/video_core/command_processor.h
+++ b/src/video_core/command_processor.h
@@ -4,11 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <type_traits>
8
7#include "common/bit_field.h" 9#include "common/bit_field.h"
8#include "common/common_types.h" 10#include "common/common_types.h"
9 11
10#include "pica.h"
11
12namespace Pica { 12namespace Pica {
13 13
14namespace CommandProcessor { 14namespace CommandProcessor {
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7b8ab72b6..c3f8321c6 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -23,6 +23,7 @@
23#include "common/vector_math.h" 23#include "common/vector_math.h"
24 24
25#include "video_core/pica.h" 25#include "video_core/pica.h"
26#include "video_core/renderer_base.h"
26#include "video_core/utils.h" 27#include "video_core/utils.h"
27#include "video_core/video_core.h" 28#include "video_core/video_core.h"
28 29
@@ -84,7 +85,7 @@ void GeometryDumper::AddTriangle(Vertex& v0, Vertex& v1, Vertex& v2) {
84 vertices.push_back(v1); 85 vertices.push_back(v1);
85 vertices.push_back(v2); 86 vertices.push_back(v2);
86 87
87 int num_vertices = vertices.size(); 88 int num_vertices = (int)vertices.size();
88 faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 }); 89 faces.push_back({ num_vertices-3, num_vertices-2, num_vertices-1 });
89} 90}
90 91
@@ -240,8 +241,8 @@ void DumpShader(const u32* binary_data, u32 binary_size, const u32* swizzle_data
240 241
241 dvle.main_offset_words = main_offset; 242 dvle.main_offset_words = main_offset;
242 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset; 243 dvle.output_register_table_offset = write_offset - dvlb.dvle_offset;
243 dvle.output_register_table_size = output_info_table.size(); 244 dvle.output_register_table_size = static_cast<uint32_t>(output_info_table.size());
244 QueueForWriting((u8*)output_info_table.data(), output_info_table.size() * sizeof(OutputRegisterInfo)); 245 QueueForWriting((u8*)output_info_table.data(), static_cast<u32>(output_info_table.size() * sizeof(OutputRegisterInfo)));
245 246
246 // TODO: Create a label table for "main" 247 // TODO: Create a label table for "main"
247 248
@@ -496,31 +497,31 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
496 // Lookup base value 497 // Lookup base value
497 Math::Vec3<int> ret; 498 Math::Vec3<int> ret;
498 if (differential_mode) { 499 if (differential_mode) {
499 ret.r() = differential.r; 500 ret.r() = static_cast<int>(differential.r);
500 ret.g() = differential.g; 501 ret.g() = static_cast<int>(differential.g);
501 ret.b() = differential.b; 502 ret.b() = static_cast<int>(differential.b);
502 if (x >= 2) { 503 if (x >= 2) {
503 ret.r() += differential.dr; 504 ret.r() += static_cast<int>(differential.dr);
504 ret.g() += differential.dg; 505 ret.g() += static_cast<int>(differential.dg);
505 ret.b() += differential.db; 506 ret.b() += static_cast<int>(differential.db);
506 } 507 }
507 ret.r() = Color::Convert5To8(ret.r()); 508 ret.r() = Color::Convert5To8(ret.r());
508 ret.g() = Color::Convert5To8(ret.g()); 509 ret.g() = Color::Convert5To8(ret.g());
509 ret.b() = Color::Convert5To8(ret.b()); 510 ret.b() = Color::Convert5To8(ret.b());
510 } else { 511 } else {
511 if (x < 2) { 512 if (x < 2) {
512 ret.r() = Color::Convert4To8(separate.r1); 513 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r1));
513 ret.g() = Color::Convert4To8(separate.g1); 514 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g1));
514 ret.b() = Color::Convert4To8(separate.b1); 515 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b1));
515 } else { 516 } else {
516 ret.r() = Color::Convert4To8(separate.r2); 517 ret.r() = Color::Convert4To8(static_cast<u8>(separate.r2));
517 ret.g() = Color::Convert4To8(separate.g2); 518 ret.g() = Color::Convert4To8(static_cast<u8>(separate.g2));
518 ret.b() = Color::Convert4To8(separate.b2); 519 ret.b() = Color::Convert4To8(static_cast<u8>(separate.b2));
519 } 520 }
520 } 521 }
521 522
522 // Add modifier 523 // Add modifier
523 unsigned table_index = (x < 2) ? table_index_1.Value() : table_index_2.Value(); 524 unsigned table_index = static_cast<int>((x < 2) ? table_index_1.Value() : table_index_2.Value());
524 525
525 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{ 526 static const std::array<std::array<u8, 2>, 8> etc1_modifier_table = {{
526 { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 }, 527 { 2, 8 }, { 5, 17 }, { 9, 29 }, { 13, 42 },
diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h
index 7926d64ec..3f109dcb7 100644
--- a/src/video_core/debug_utils/debug_utils.h
+++ b/src/video_core/debug_utils/debug_utils.h
@@ -14,6 +14,8 @@
14 14
15#include "common/vector_math.h" 15#include "common/vector_math.h"
16 16
17#include "core/tracer/recorder.h"
18
17#include "video_core/pica.h" 19#include "video_core/pica.h"
18 20
19namespace Pica { 21namespace Pica {
@@ -23,11 +25,14 @@ public:
23 enum class Event { 25 enum class Event {
24 FirstEvent = 0, 26 FirstEvent = 0,
25 27
26 CommandLoaded = FirstEvent, 28 PicaCommandLoaded = FirstEvent,
27 CommandProcessed, 29 PicaCommandProcessed,
28 IncomingPrimitiveBatch, 30 IncomingPrimitiveBatch,
29 FinishedPrimitiveBatch, 31 FinishedPrimitiveBatch,
30 VertexLoaded, 32 VertexLoaded,
33 IncomingDisplayTransfer,
34 GSPCommandProcessed,
35 BufferSwapped,
31 36
32 NumEvents 37 NumEvents
33 }; 38 };
@@ -129,6 +134,8 @@ public:
129 Event active_breakpoint; 134 Event active_breakpoint;
130 bool at_breakpoint = false; 135 bool at_breakpoint = false;
131 136
137 std::shared_ptr<CiTrace::Recorder> recorder = nullptr;
138
132private: 139private:
133 /** 140 /**
134 * Private default constructor to make sure people always construct this through Construct() 141 * Private default constructor to make sure people always construct this through Construct()
diff --git a/src/video_core/hwrasterizer_base.h b/src/video_core/hwrasterizer_base.h
index dec193f8b..c8746c608 100644
--- a/src/video_core/hwrasterizer_base.h
+++ b/src/video_core/hwrasterizer_base.h
@@ -4,8 +4,13 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/emu_window.h" 7#include "common/common_types.h"
8#include "video_core/vertex_shader.h" 8
9namespace Pica {
10namespace VertexShader {
11struct OutputVertex;
12}
13}
9 14
10class HWRasterizer { 15class HWRasterizer {
11public: 16public:
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index 9628a7589..38599a7a3 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -5,10 +5,10 @@
5#pragma once 5#pragma once
6 6
7#include <array> 7#include <array>
8#include <cmath>
8#include <cstddef> 9#include <cstddef>
9#include <initializer_list>
10#include <map> 10#include <map>
11#include <vector> 11#include <string>
12 12
13#include "common/assert.h" 13#include "common/assert.h"
14#include "common/bit_field.h" 14#include "common/bit_field.h"
@@ -114,11 +114,22 @@ struct Regs {
114 struct TextureConfig { 114 struct TextureConfig {
115 enum WrapMode : u32 { 115 enum WrapMode : u32 {
116 ClampToEdge = 0, 116 ClampToEdge = 0,
117 ClampToBorder = 1,
117 Repeat = 2, 118 Repeat = 2,
118 MirroredRepeat = 3, 119 MirroredRepeat = 3,
119 }; 120 };
120 121
121 INSERT_PADDING_WORDS(0x1); 122 enum TextureFilter : u32 {
123 Nearest = 0,
124 Linear = 1
125 };
126
127 union {
128 BitField< 0, 8, u32> r;
129 BitField< 8, 8, u32> g;
130 BitField<16, 8, u32> b;
131 BitField<24, 8, u32> a;
132 } border_color;
122 133
123 union { 134 union {
124 BitField< 0, 16, u32> height; 135 BitField< 0, 16, u32> height;
@@ -126,8 +137,10 @@ struct Regs {
126 }; 137 };
127 138
128 union { 139 union {
129 BitField< 8, 2, WrapMode> wrap_s; 140 BitField< 1, 1, TextureFilter> mag_filter;
130 BitField<12, 2, WrapMode> wrap_t; 141 BitField< 2, 1, TextureFilter> min_filter;
142 BitField< 8, 2, WrapMode> wrap_t;
143 BitField<12, 2, WrapMode> wrap_s;
131 }; 144 };
132 145
133 INSERT_PADDING_WORDS(0x1); 146 INSERT_PADDING_WORDS(0x1);
@@ -194,6 +207,7 @@ struct Regs {
194 case TextureFormat::IA8: 207 case TextureFormat::IA8:
195 return 4; 208 return 4;
196 209
210 case TextureFormat::I4:
197 case TextureFormat::A4: 211 case TextureFormat::A4:
198 return 1; 212 return 1;
199 213
@@ -284,6 +298,7 @@ struct Regs {
284 AddSigned = 3, 298 AddSigned = 3,
285 Lerp = 4, 299 Lerp = 4,
286 Subtract = 5, 300 Subtract = 5,
301 Dot3_RGB = 6,
287 302
288 MultiplyThenAdd = 8, 303 MultiplyThenAdd = 8,
289 AddThenMultiply = 9, 304 AddThenMultiply = 9,
@@ -414,6 +429,11 @@ struct Regs {
414 GreaterThanOrEqual = 7, 429 GreaterThanOrEqual = 7,
415 }; 430 };
416 431
432 enum class StencilAction : u32 {
433 Keep = 0,
434 Xor = 5,
435 };
436
417 struct { 437 struct {
418 union { 438 union {
419 // If false, logic blending is used 439 // If false, logic blending is used
@@ -448,15 +468,35 @@ struct Regs {
448 BitField< 8, 8, u32> ref; 468 BitField< 8, 8, u32> ref;
449 } alpha_test; 469 } alpha_test;
450 470
451 union { 471 struct {
452 BitField< 0, 1, u32> stencil_test_enable; 472 union {
453 BitField< 4, 3, CompareFunc> stencil_test_func; 473 // If true, enable stencil testing
454 BitField< 8, 8, u32> stencil_replacement_value; 474 BitField< 0, 1, u32> enable;
455 BitField<16, 8, u32> stencil_reference_value;
456 BitField<24, 8, u32> stencil_mask;
457 } stencil_test;
458 475
459 INSERT_PADDING_WORDS(0x1); 476 // Comparison operation for stencil testing
477 BitField< 4, 3, CompareFunc> func;
478
479 // Value to calculate the new stencil value from
480 BitField< 8, 8, u32> replacement_value;
481
482 // Value to compare against for stencil testing
483 BitField<16, 8, u32> reference_value;
484
485 // Mask to apply on stencil test inputs
486 BitField<24, 8, u32> mask;
487 };
488
489 union {
490 // Action to perform when the stencil test fails
491 BitField< 0, 3, StencilAction> action_stencil_fail;
492
493 // Action to perform when stencil testing passed but depth testing fails
494 BitField< 4, 3, StencilAction> action_depth_fail;
495
496 // Action to perform when both stencil and depth testing pass
497 BitField< 8, 3, StencilAction> action_depth_pass;
498 };
499 } stencil_test;
460 500
461 union { 501 union {
462 BitField< 0, 1, u32> depth_test_enable; 502 BitField< 0, 1, u32> depth_test_enable;
@@ -506,7 +546,7 @@ struct Regs {
506 struct { 546 struct {
507 INSERT_PADDING_WORDS(0x6); 547 INSERT_PADDING_WORDS(0x6);
508 548
509 DepthFormat depth_format; 549 DepthFormat depth_format; // TODO: Should be a BitField!
510 BitField<16, 3, ColorFormat> color_format; 550 BitField<16, 3, ColorFormat> color_format;
511 551
512 INSERT_PADDING_WORDS(0x4); 552 INSERT_PADDING_WORDS(0x4);
@@ -752,112 +792,119 @@ struct Regs {
752 INSERT_PADDING_WORDS(0x20); 792 INSERT_PADDING_WORDS(0x20);
753 793
754 enum class TriangleTopology : u32 { 794 enum class TriangleTopology : u32 {
755 List = 0, 795 List = 0,
756 Strip = 1, 796 Strip = 1,
757 Fan = 2, 797 Fan = 2,
758 ListIndexed = 3, // TODO: No idea if this is correct 798 Shader = 3, // Programmable setup unit implemented in a geometry shader
759 }; 799 };
760 800
761 BitField<8, 2, TriangleTopology> triangle_topology; 801 BitField<8, 2, TriangleTopology> triangle_topology;
762 802
763 INSERT_PADDING_WORDS(0x51); 803 INSERT_PADDING_WORDS(0x21);
764 804
765 BitField<0, 16, u32> vs_bool_uniforms; 805 struct ShaderConfig {
766 union { 806 BitField<0, 16, u32> bool_uniforms;
767 BitField< 0, 8, u32> x;
768 BitField< 8, 8, u32> y;
769 BitField<16, 8, u32> z;
770 BitField<24, 8, u32> w;
771 } vs_int_uniforms[4];
772 807
773 INSERT_PADDING_WORDS(0x5); 808 union {
809 BitField< 0, 8, u32> x;
810 BitField< 8, 8, u32> y;
811 BitField<16, 8, u32> z;
812 BitField<24, 8, u32> w;
813 } int_uniforms[4];
774 814
775 // Offset to shader program entry point (in words) 815 INSERT_PADDING_WORDS(0x5);
776 BitField<0, 16, u32> vs_main_offset;
777 816
778 union { 817 // Offset to shader program entry point (in words)
779 BitField< 0, 4, u64> attribute0_register; 818 BitField<0, 16, u32> main_offset;
780 BitField< 4, 4, u64> attribute1_register; 819
781 BitField< 8, 4, u64> attribute2_register; 820 union {
782 BitField<12, 4, u64> attribute3_register; 821 BitField< 0, 4, u64> attribute0_register;
783 BitField<16, 4, u64> attribute4_register; 822 BitField< 4, 4, u64> attribute1_register;
784 BitField<20, 4, u64> attribute5_register; 823 BitField< 8, 4, u64> attribute2_register;
785 BitField<24, 4, u64> attribute6_register; 824 BitField<12, 4, u64> attribute3_register;
786 BitField<28, 4, u64> attribute7_register; 825 BitField<16, 4, u64> attribute4_register;
787 BitField<32, 4, u64> attribute8_register; 826 BitField<20, 4, u64> attribute5_register;
788 BitField<36, 4, u64> attribute9_register; 827 BitField<24, 4, u64> attribute6_register;
789 BitField<40, 4, u64> attribute10_register; 828 BitField<28, 4, u64> attribute7_register;
790 BitField<44, 4, u64> attribute11_register; 829 BitField<32, 4, u64> attribute8_register;
791 BitField<48, 4, u64> attribute12_register; 830 BitField<36, 4, u64> attribute9_register;
792 BitField<52, 4, u64> attribute13_register; 831 BitField<40, 4, u64> attribute10_register;
793 BitField<56, 4, u64> attribute14_register; 832 BitField<44, 4, u64> attribute11_register;
794 BitField<60, 4, u64> attribute15_register; 833 BitField<48, 4, u64> attribute12_register;
795 834 BitField<52, 4, u64> attribute13_register;
796 int GetRegisterForAttribute(int attribute_index) const { 835 BitField<56, 4, u64> attribute14_register;
797 u64 fields[] = { 836 BitField<60, 4, u64> attribute15_register;
798 attribute0_register, attribute1_register, attribute2_register, attribute3_register, 837
799 attribute4_register, attribute5_register, attribute6_register, attribute7_register, 838 int GetRegisterForAttribute(int attribute_index) const {
800 attribute8_register, attribute9_register, attribute10_register, attribute11_register, 839 u64 fields[] = {
801 attribute12_register, attribute13_register, attribute14_register, attribute15_register, 840 attribute0_register, attribute1_register, attribute2_register, attribute3_register,
841 attribute4_register, attribute5_register, attribute6_register, attribute7_register,
842 attribute8_register, attribute9_register, attribute10_register, attribute11_register,
843 attribute12_register, attribute13_register, attribute14_register, attribute15_register,
844 };
845 return (int)fields[attribute_index];
846 }
847 } input_register_map;
848
849 // OUTMAP_MASK, 0x28E, CODETRANSFER_END
850 INSERT_PADDING_WORDS(0x3);
851
852 struct {
853 enum Format : u32
854 {
855 FLOAT24 = 0,
856 FLOAT32 = 1
802 }; 857 };
803 return (int)fields[attribute_index];
804 }
805 } vs_input_register_map;
806 858
807 INSERT_PADDING_WORDS(0x3); 859 bool IsFloat32() const {
860 return format == FLOAT32;
861 }
808 862
809 struct { 863 union {
810 enum Format : u32 864 // Index of the next uniform to write to
811 { 865 // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices
812 FLOAT24 = 0, 866 // TODO: Maybe the uppermost index is for the geometry shader? Investigate!
813 FLOAT32 = 1 867 BitField<0, 7, u32> index;
814 };
815 868
816 bool IsFloat32() const { 869 BitField<31, 1, Format> format;
817 return format == FLOAT32; 870 };
818 }
819 871
820 union { 872 // Writing to these registers sets the current uniform.
821 // Index of the next uniform to write to 873 u32 set_value[8];
822 // TODO: ctrulib uses 8 bits for this, however that seems to yield lots of invalid indices
823 BitField<0, 7, u32> index;
824 874
825 BitField<31, 1, Format> format; 875 } uniform_setup;
826 };
827 876
828 // Writing to these registers sets the "current" uniform. 877 INSERT_PADDING_WORDS(0x2);
829 // TODO: It's not clear how the hardware stores what the "current" uniform is.
830 u32 set_value[8];
831 878
832 } vs_uniform_setup; 879 struct {
880 // Offset of the next instruction to write code to.
881 // Incremented with each instruction write.
882 u32 offset;
833 883
834 INSERT_PADDING_WORDS(0x2); 884 // Writing to these registers sets the "current" word in the shader program.
885 u32 set_word[8];
886 } program;
835 887
836 struct { 888 INSERT_PADDING_WORDS(0x1);
837 // Offset of the next instruction to write code to.
838 // Incremented with each instruction write.
839 u32 offset;
840 889
841 // Writing to these registers sets the "current" word in the shader program. 890 // This register group is used to load an internal table of swizzling patterns,
842 // TODO: It's not clear how the hardware stores what the "current" word is. 891 // which are indexed by each shader instruction to specify vector component swizzling.
843 u32 set_word[8]; 892 struct {
844 } vs_program; 893 // Offset of the next swizzle pattern to write code to.
894 // Incremented with each instruction write.
895 u32 offset;
845 896
846 INSERT_PADDING_WORDS(0x1); 897 // Writing to these registers sets the current swizzle pattern in the table.
898 u32 set_word[8];
899 } swizzle_patterns;
847 900
848 // This register group is used to load an internal table of swizzling patterns, 901 INSERT_PADDING_WORDS(0x2);
849 // which are indexed by each shader instruction to specify vector component swizzling. 902 };
850 struct {
851 // Offset of the next swizzle pattern to write code to.
852 // Incremented with each instruction write.
853 u32 offset;
854 903
855 // Writing to these registers sets the "current" swizzle pattern in the table. 904 ShaderConfig gs;
856 // TODO: It's not clear how the hardware stores what the "current" swizzle pattern is. 905 ShaderConfig vs;
857 u32 set_word[8];
858 } vs_swizzle_patterns;
859 906
860 INSERT_PADDING_WORDS(0x22); 907 INSERT_PADDING_WORDS(0x20);
861 908
862 // Map register indices to names readable by humans 909 // Map register indices to names readable by humans
863 // Used for debugging purposes, so performance is not an issue here 910 // Used for debugging purposes, so performance is not an issue here
@@ -866,7 +913,7 @@ struct Regs {
866 913
867 #define ADD_FIELD(name) \ 914 #define ADD_FIELD(name) \
868 do { \ 915 do { \
869 map.insert({PICA_REG_INDEX(name), #name}); \ 916 map.insert({static_cast<u32>(PICA_REG_INDEX(name)), #name}); \
870 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \ 917 /* TODO: change to Regs::name when VS2015 and other compilers support it */ \
871 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \ 918 for (u32 i = PICA_REG_INDEX(name) + 1; i < PICA_REG_INDEX(name) + sizeof(Regs().name) / 4; ++i) \
872 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \ 919 map.insert({i, #name + std::string("+") + std::to_string(i-PICA_REG_INDEX(name))}); \
@@ -904,13 +951,20 @@ struct Regs {
904 ADD_FIELD(vs_default_attributes_setup); 951 ADD_FIELD(vs_default_attributes_setup);
905 ADD_FIELD(command_buffer); 952 ADD_FIELD(command_buffer);
906 ADD_FIELD(triangle_topology); 953 ADD_FIELD(triangle_topology);
907 ADD_FIELD(vs_bool_uniforms); 954 ADD_FIELD(gs.bool_uniforms);
908 ADD_FIELD(vs_int_uniforms); 955 ADD_FIELD(gs.int_uniforms);
909 ADD_FIELD(vs_main_offset); 956 ADD_FIELD(gs.main_offset);
910 ADD_FIELD(vs_input_register_map); 957 ADD_FIELD(gs.input_register_map);
911 ADD_FIELD(vs_uniform_setup); 958 ADD_FIELD(gs.uniform_setup);
912 ADD_FIELD(vs_program); 959 ADD_FIELD(gs.program);
913 ADD_FIELD(vs_swizzle_patterns); 960 ADD_FIELD(gs.swizzle_patterns);
961 ADD_FIELD(vs.bool_uniforms);
962 ADD_FIELD(vs.int_uniforms);
963 ADD_FIELD(vs.main_offset);
964 ADD_FIELD(vs.input_register_map);
965 ADD_FIELD(vs.uniform_setup);
966 ADD_FIELD(vs.program);
967 ADD_FIELD(vs.swizzle_patterns);
914 968
915 #undef ADD_FIELD 969 #undef ADD_FIELD
916 970
@@ -982,17 +1036,14 @@ ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
982ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); 1036ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
983ASSERT_REG_POSITION(command_buffer, 0x238); 1037ASSERT_REG_POSITION(command_buffer, 0x238);
984ASSERT_REG_POSITION(triangle_topology, 0x25e); 1038ASSERT_REG_POSITION(triangle_topology, 0x25e);
985ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); 1039ASSERT_REG_POSITION(gs, 0x280);
986ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); 1040ASSERT_REG_POSITION(vs, 0x2b0);
987ASSERT_REG_POSITION(vs_main_offset, 0x2ba);
988ASSERT_REG_POSITION(vs_input_register_map, 0x2bb);
989ASSERT_REG_POSITION(vs_uniform_setup, 0x2c0);
990ASSERT_REG_POSITION(vs_program, 0x2cb);
991ASSERT_REG_POSITION(vs_swizzle_patterns, 0x2d5);
992 1041
993#undef ASSERT_REG_POSITION 1042#undef ASSERT_REG_POSITION
994#endif // !defined(_MSC_VER) 1043#endif // !defined(_MSC_VER)
995 1044
1045static_assert(sizeof(Regs::ShaderConfig) == 0x30 * sizeof(u32), "ShaderConfig structure has incorrect size");
1046
996// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway. 1047// The total number of registers is chosen arbitrarily, but let's make sure it's not some odd value anyway.
997static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be"); 1048static_assert(sizeof(Regs) <= 0x300 * sizeof(u32), "Register set structure larger than it should be");
998static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be"); 1049static_assert(sizeof(Regs) >= 0x300 * sizeof(u32), "Register set structure smaller than it should be");
@@ -1014,7 +1065,7 @@ struct float24 {
1014 u32 mantissa = hex & 0xFFFF; 1065 u32 mantissa = hex & 0xFFFF;
1015 u32 exponent = (hex >> 16) & 0x7F; 1066 u32 exponent = (hex >> 16) & 0x7F;
1016 u32 sign = hex >> 23; 1067 u32 sign = hex >> 23;
1017 ret.value = powf(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * powf(2.0f, -16.f)); 1068 ret.value = std::pow(2.0f, (float)exponent-63.0f) * (1.0f + mantissa * std::pow(2.0f, -16.f));
1018 if (sign) 1069 if (sign)
1019 ret.value = -ret.value; 1070 ret.value = -ret.value;
1020 } 1071 }
@@ -1102,7 +1153,7 @@ struct State {
1102 Regs regs; 1153 Regs regs;
1103 1154
1104 /// Vertex shader memory 1155 /// Vertex shader memory
1105 struct { 1156 struct ShaderSetup {
1106 struct { 1157 struct {
1107 Math::Vec4<float24> f[96]; 1158 Math::Vec4<float24> f[96];
1108 std::array<bool, 16> b; 1159 std::array<bool, 16> b;
@@ -1113,7 +1164,10 @@ struct State {
1113 1164
1114 std::array<u32, 1024> program_code; 1165 std::array<u32, 1024> program_code;
1115 std::array<u32, 1024> swizzle_data; 1166 std::array<u32, 1024> swizzle_data;
1116 } vs; 1167 };
1168
1169 ShaderSetup vs;
1170 ShaderSetup gs;
1117 1171
1118 /// Current Pica command list 1172 /// Current Pica command list
1119 struct { 1173 struct {
diff --git a/src/video_core/primitive_assembly.cpp b/src/video_core/primitive_assembly.cpp
index 0120f2896..2f22bdcce 100644
--- a/src/video_core/primitive_assembly.cpp
+++ b/src/video_core/primitive_assembly.cpp
@@ -20,8 +20,9 @@ template<typename VertexType>
20void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler) 20void PrimitiveAssembler<VertexType>::SubmitVertex(VertexType& vtx, TriangleHandler triangle_handler)
21{ 21{
22 switch (topology) { 22 switch (topology) {
23 // TODO: Figure out what's different with TriangleTopology::Shader.
23 case Regs::TriangleTopology::List: 24 case Regs::TriangleTopology::List:
24 case Regs::TriangleTopology::ListIndexed: 25 case Regs::TriangleTopology::Shader:
25 if (buffer_index < 2) { 26 if (buffer_index < 2) {
26 buffer[buffer_index++] = vtx; 27 buffer[buffer_index++] = vtx;
27 } else { 28 } else {
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 59d156ee7..e2b90ad1c 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -126,6 +126,30 @@ static u32 GetDepth(int x, int y) {
126 } 126 }
127} 127}
128 128
129static u8 GetStencil(int x, int y) {
130 const auto& framebuffer = g_state.regs.framebuffer;
131 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
132 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
133
134 y = framebuffer.height - y;
135
136 const u32 coarse_y = y & ~7;
137 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
138 u32 stride = framebuffer.width * bytes_per_pixel;
139
140 u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
141 u8* src_pixel = depth_buffer + src_offset;
142
143 switch (framebuffer.depth_format) {
144 case Regs::DepthFormat::D24S8:
145 return Color::DecodeD24S8(src_pixel).y;
146
147 default:
148 LOG_WARNING(HW_GPU, "GetStencil called for function which doesn't have a stencil component (format %u)", framebuffer.depth_format);
149 return 0;
150 }
151}
152
129static void SetDepth(int x, int y, u32 value) { 153static void SetDepth(int x, int y, u32 value) {
130 const auto& framebuffer = g_state.regs.framebuffer; 154 const auto& framebuffer = g_state.regs.framebuffer;
131 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress(); 155 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
@@ -144,13 +168,15 @@ static void SetDepth(int x, int y, u32 value) {
144 case Regs::DepthFormat::D16: 168 case Regs::DepthFormat::D16:
145 Color::EncodeD16(value, dst_pixel); 169 Color::EncodeD16(value, dst_pixel);
146 break; 170 break;
171
147 case Regs::DepthFormat::D24: 172 case Regs::DepthFormat::D24:
148 Color::EncodeD24(value, dst_pixel); 173 Color::EncodeD24(value, dst_pixel);
149 break; 174 break;
175
150 case Regs::DepthFormat::D24S8: 176 case Regs::DepthFormat::D24S8:
151 // TODO(Subv): Implement the stencil buffer 177 Color::EncodeD24X8(value, dst_pixel);
152 Color::EncodeD24S8(value, 0, dst_pixel);
153 break; 178 break;
179
154 default: 180 default:
155 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format); 181 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
156 UNIMPLEMENTED(); 182 UNIMPLEMENTED();
@@ -158,6 +184,53 @@ static void SetDepth(int x, int y, u32 value) {
158 } 184 }
159} 185}
160 186
187static void SetStencil(int x, int y, u8 value) {
188 const auto& framebuffer = g_state.regs.framebuffer;
189 const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
190 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
191
192 y = framebuffer.height - y;
193
194 const u32 coarse_y = y & ~7;
195 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(framebuffer.depth_format);
196 u32 stride = framebuffer.width * bytes_per_pixel;
197
198 u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * stride;
199 u8* dst_pixel = depth_buffer + dst_offset;
200
201 switch (framebuffer.depth_format) {
202 case Pica::Regs::DepthFormat::D16:
203 case Pica::Regs::DepthFormat::D24:
204 // Nothing to do
205 break;
206
207 case Pica::Regs::DepthFormat::D24S8:
208 Color::EncodeX24S8(value, dst_pixel);
209 break;
210
211 default:
212 LOG_CRITICAL(HW_GPU, "Unimplemented depth format %u", framebuffer.depth_format);
213 UNIMPLEMENTED();
214 break;
215 }
216}
217
218// TODO: Should the stencil mask be applied to the "dest" or "ref" operands? Most likely not!
219static u8 PerformStencilAction(Regs::StencilAction action, u8 dest, u8 ref) {
220 switch (action) {
221 case Regs::StencilAction::Keep:
222 return dest;
223
224 case Regs::StencilAction::Xor:
225 return dest ^ ref;
226
227 default:
228 LOG_CRITICAL(HW_GPU, "Unknown stencil action %x", (int)action);
229 UNIMPLEMENTED();
230 return 0;
231 }
232}
233
161// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values 234// NOTE: Assuming that rasterizer coordinates are 12.4 fixed-point values
162struct Fix12P4 { 235struct Fix12P4 {
163 Fix12P4() {} 236 Fix12P4() {}
@@ -276,6 +349,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
276 auto textures = regs.GetTextures(); 349 auto textures = regs.GetTextures();
277 auto tev_stages = regs.GetTevStages(); 350 auto tev_stages = regs.GetTevStages();
278 351
352 bool stencil_action_enable = g_state.regs.output_merger.stencil_test.enable && g_state.regs.framebuffer.depth_format == Regs::DepthFormat::D24S8;
353 const auto stencil_test = g_state.regs.output_merger.stencil_test;
354
279 // Enter rasterization loop, starting at the center of the topleft bounding box corner. 355 // Enter rasterization loop, starting at the center of the topleft bounding box corner.
280 // TODO: Not sure if looping through x first might be faster 356 // TODO: Not sure if looping through x first might be faster
281 for (u16 y = min_y + 8; y < max_y; y += 0x10) { 357 for (u16 y = min_y + 8; y < max_y; y += 0x10) {
@@ -349,6 +425,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
349 val = std::min(val, (int)size - 1); 425 val = std::min(val, (int)size - 1);
350 return val; 426 return val;
351 427
428 case Regs::TextureConfig::ClampToBorder:
429 return val;
430
352 case Regs::TextureConfig::Repeat: 431 case Regs::TextureConfig::Repeat:
353 return (int)((unsigned)val % size); 432 return (int)((unsigned)val % size);
354 433
@@ -367,17 +446,24 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
367 } 446 }
368 }; 447 };
369 448
370 // Textures are laid out from bottom to top, hence we invert the t coordinate. 449 if ((texture.config.wrap_s == Regs::TextureConfig::ClampToBorder && (s < 0 || s >= texture.config.width))
371 // NOTE: This may not be the right place for the inversion. 450 || (texture.config.wrap_t == Regs::TextureConfig::ClampToBorder && (t < 0 || t >= texture.config.height))) {
372 // TODO: Check if this applies to ETC textures, too. 451 auto border_color = texture.config.border_color;
373 s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width); 452 texture_color[i] = { border_color.r, border_color.g, border_color.b, border_color.a };
374 t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height); 453 } else {
375 454 // Textures are laid out from bottom to top, hence we invert the t coordinate.
376 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress()); 455 // NOTE: This may not be the right place for the inversion.
377 auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format); 456 // TODO: Check if this applies to ETC textures, too.
378 457 s = GetWrappedTexCoord(texture.config.wrap_s, s, texture.config.width);
379 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info); 458 t = texture.config.height - 1 - GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
380 DebugUtils::DumpTexture(texture.config, texture_data); 459
460 u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
461 auto info = DebugUtils::TextureInfo::FromPicaRegister(texture.config, texture.format);
462
463 // TODO: Apply the min and mag filters to the texture
464 texture_color[i] = DebugUtils::LookupTexture(texture_data, s, t, info);
465 DebugUtils::DumpTexture(texture.config, texture_data);
466 }
381 } 467 }
382 468
383 // Texture environment - consists of 6 stages of color and alpha combining. 469 // Texture environment - consists of 6 stages of color and alpha combining.
@@ -556,7 +642,18 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
556 result = (result * input[2].Cast<int>()) / 255; 642 result = (result * input[2].Cast<int>()) / 255;
557 return result.Cast<u8>(); 643 return result.Cast<u8>();
558 } 644 }
559 645 case Operation::Dot3_RGB:
646 {
647 // Not fully accurate.
648 // Worst case scenario seems to yield a +/-3 error
649 // Some HW results indicate that the per-component computation can't have a higher precision than 1/256,
650 // while dot3_rgb( (0x80,g0,b0),(0x7F,g1,b1) ) and dot3_rgb( (0x80,g0,b0),(0x80,g1,b1) ) give different results
651 int result = ((input[0].r() * 2 - 255) * (input[1].r() * 2 - 255) + 128) / 256 +
652 ((input[0].g() * 2 - 255) * (input[1].g() * 2 - 255) + 128) / 256 +
653 ((input[0].b() * 2 - 255) * (input[1].b() * 2 - 255) + 128) / 256;
654 result = std::max(0, std::min(255, result));
655 return { (u8)result, (u8)result, (u8)result };
656 }
560 default: 657 default:
561 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op); 658 LOG_ERROR(HW_GPU, "Unknown color combiner operation %d\n", (int)op);
562 UNIMPLEMENTED(); 659 UNIMPLEMENTED();
@@ -638,6 +735,7 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
638 } 735 }
639 736
640 const auto& output_merger = regs.output_merger; 737 const auto& output_merger = regs.output_merger;
738 // TODO: Does alpha testing happen before or after stencil?
641 if (output_merger.alpha_test.enable) { 739 if (output_merger.alpha_test.enable) {
642 bool pass = false; 740 bool pass = false;
643 741
@@ -679,6 +777,54 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
679 continue; 777 continue;
680 } 778 }
681 779
780 u8 old_stencil = 0;
781 if (stencil_action_enable) {
782 old_stencil = GetStencil(x >> 4, y >> 4);
783 u8 dest = old_stencil & stencil_test.mask;
784 u8 ref = stencil_test.reference_value & stencil_test.mask;
785
786 bool pass = false;
787 switch (stencil_test.func) {
788 case Regs::CompareFunc::Never:
789 pass = false;
790 break;
791
792 case Regs::CompareFunc::Always:
793 pass = true;
794 break;
795
796 case Regs::CompareFunc::Equal:
797 pass = (ref == dest);
798 break;
799
800 case Regs::CompareFunc::NotEqual:
801 pass = (ref != dest);
802 break;
803
804 case Regs::CompareFunc::LessThan:
805 pass = (ref < dest);
806 break;
807
808 case Regs::CompareFunc::LessThanOrEqual:
809 pass = (ref <= dest);
810 break;
811
812 case Regs::CompareFunc::GreaterThan:
813 pass = (ref > dest);
814 break;
815
816 case Regs::CompareFunc::GreaterThanOrEqual:
817 pass = (ref >= dest);
818 break;
819 }
820
821 if (!pass) {
822 u8 new_stencil = PerformStencilAction(stencil_test.action_stencil_fail, old_stencil, stencil_test.replacement_value);
823 SetStencil(x >> 4, y >> 4, new_stencil);
824 continue;
825 }
826 }
827
682 // TODO: Does depth indeed only get written even if depth testing is enabled? 828 // TODO: Does depth indeed only get written even if depth testing is enabled?
683 if (output_merger.depth_test_enable) { 829 if (output_merger.depth_test_enable) {
684 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format); 830 unsigned num_bits = Regs::DepthBitsPerPixel(regs.framebuffer.depth_format);
@@ -723,11 +869,22 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
723 break; 869 break;
724 } 870 }
725 871
726 if (!pass) 872 if (!pass) {
873 if (stencil_action_enable) {
874 u8 new_stencil = PerformStencilAction(stencil_test.action_depth_fail, old_stencil, stencil_test.replacement_value);
875 SetStencil(x >> 4, y >> 4, new_stencil);
876 }
727 continue; 877 continue;
878 }
728 879
729 if (output_merger.depth_write_enable) 880 if (output_merger.depth_write_enable)
730 SetDepth(x >> 4, y >> 4, z); 881 SetDepth(x >> 4, y >> 4, z);
882
883 if (stencil_action_enable) {
884 // TODO: What happens if stencil testing is enabled, but depth testing is not? Will stencil get updated anyway?
885 u8 new_stencil = PerformStencilAction(stencil_test.action_depth_pass, old_stencil, stencil_test.replacement_value);
886 SetStencil(x >> 4, y >> 4, new_stencil);
887 }
731 } 888 }
732 889
733 auto dest = GetPixel(x >> 4, y >> 4); 890 auto dest = GetPixel(x >> 4, y >> 4);
diff --git a/src/video_core/renderer_base.h b/src/video_core/renderer_base.h
index 5757ac75d..6587bcf27 100644
--- a/src/video_core/renderer_base.h
+++ b/src/video_core/renderer_base.h
@@ -4,10 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <memory>
8
7#include "common/common_types.h" 9#include "common/common_types.h"
8 10
9#include "video_core/hwrasterizer_base.h" 11#include "video_core/hwrasterizer_base.h"
10 12
13class EmuWindow;
14
11class RendererBase : NonCopyable { 15class RendererBase : NonCopyable {
12public: 16public:
13 17
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 518f79331..2db845da6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -2,10 +2,15 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6#include <memory>
7
5#include "common/color.h" 8#include "common/color.h"
9#include "common/math_util.h"
6 10
7#include "core/settings.h"
8#include "core/hw/gpu.h" 11#include "core/hw/gpu.h"
12#include "core/memory.h"
13#include "core/settings.h"
9 14
10#include "video_core/pica.h" 15#include "video_core/pica.h"
11#include "video_core/utils.h" 16#include "video_core/utils.h"
@@ -16,8 +21,6 @@
16 21
17#include "generated/gl_3_2_core.h" 22#include "generated/gl_3_2_core.h"
18 23
19#include <memory>
20
21static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) { 24static bool IsPassThroughTevStage(const Pica::Regs::TevStageConfig& stage) {
22 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace && 25 return (stage.color_op == Pica::Regs::TevStageConfig::Operation::Replace &&
23 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace && 26 stage.alpha_op == Pica::Regs::TevStageConfig::Operation::Replace &&
@@ -813,12 +816,16 @@ void RasterizerOpenGL::ReloadColorBuffer() {
813} 816}
814 817
815void RasterizerOpenGL::ReloadDepthBuffer() { 818void RasterizerOpenGL::ReloadDepthBuffer() {
819 PAddr depth_buffer_addr = Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress();
820
821 if (depth_buffer_addr == 0)
822 return;
823
816 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil 824 // TODO: Appears to work, but double-check endianness of depth values and order of depth-stencil
817 u8* depth_buffer = Memory::GetPhysicalPointer(Pica::g_state.regs.framebuffer.GetDepthBufferPhysicalAddress()); 825 u8* depth_buffer = Memory::GetPhysicalPointer(depth_buffer_addr);
818 826
819 if (depth_buffer == nullptr) { 827 if (depth_buffer == nullptr)
820 return; 828 return;
821 }
822 829
823 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format); 830 u32 bytes_per_pixel = Pica::Regs::BytesPerDepthPixel(fb_depth_texture.format);
824 831
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index d7d422b1f..ae7b26fc6 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -4,7 +4,12 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector>
8
9#include "common/common_types.h"
10
7#include "video_core/hwrasterizer_base.h" 11#include "video_core/hwrasterizer_base.h"
12#include "video_core/vertex_shader.h"
8 13
9#include "gl_state.h" 14#include "gl_state.h"
10#include "gl_rasterizer_cache.h" 15#include "gl_rasterizer_cache.h"
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
index 2e4110a88..dc3ffdf22 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp
@@ -31,12 +31,18 @@ void RasterizerCacheOpenGL::LoadAndBindTexture(OpenGLState &state, unsigned text
31 state.texture_units[texture_unit].texture_2d = new_texture->texture.handle; 31 state.texture_units[texture_unit].texture_2d = new_texture->texture.handle;
32 state.Apply(); 32 state.Apply();
33 33
34 // TODO: Need to choose filters that correspond to PICA once register is declared 34 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, PicaToGL::TextureFilterMode(config.config.mag_filter));
35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 35 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, PicaToGL::TextureFilterMode(config.config.min_filter));
36 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
37 36
38 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, PicaToGL::WrapMode(config.config.wrap_s)); 37 GLenum wrap_s = PicaToGL::WrapMode(config.config.wrap_s);
39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, PicaToGL::WrapMode(config.config.wrap_t)); 38 GLenum wrap_t = PicaToGL::WrapMode(config.config.wrap_t);
39 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
40 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
41
42 if (wrap_s == GL_CLAMP_TO_BORDER || wrap_t == GL_CLAMP_TO_BORDER) {
43 auto border_color = PicaToGL::ColorRGBA8((u8*)&config.config.border_color.r);
44 glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, border_color.data());
45 }
40 46
41 const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format); 47 const auto info = Pica::DebugUtils::TextureInfo::FromPicaRegister(config.config, config.format);
42 48
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 3526e16d5..9efc15337 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -147,20 +147,17 @@ void OpenGLState::Apply() {
147 147
148 // Textures 148 // Textures
149 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { 149 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
150 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { 150 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d ||
151 texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
152
151 glActiveTexture(GL_TEXTURE0 + texture_index); 153 glActiveTexture(GL_TEXTURE0 + texture_index);
152 154
153 if (texture_units[texture_index].enabled_2d) { 155 if (texture_units[texture_index].enabled_2d) {
154 glEnable(GL_TEXTURE_2D); 156 glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
155 } else { 157 } else {
156 glDisable(GL_TEXTURE_2D); 158 glBindTexture(GL_TEXTURE_2D, 0);
157 } 159 }
158 } 160 }
159
160 if (texture_units[texture_index].texture_2d != cur_state.texture_units[texture_index].texture_2d) {
161 glActiveTexture(GL_TEXTURE0 + texture_index);
162 glBindTexture(GL_TEXTURE_2D, texture_units[texture_index].texture_2d);
163 }
164 } 161 }
165 162
166 // Framebuffer 163 // Framebuffer
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index e566f9f7a..3b562da86 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -12,10 +12,37 @@
12 12
13namespace PicaToGL { 13namespace PicaToGL {
14 14
15inline GLenum TextureFilterMode(Pica::Regs::TextureConfig::TextureFilter mode) {
16 static const GLenum filter_mode_table[] = {
17 GL_NEAREST, // TextureFilter::Nearest
18 GL_LINEAR // TextureFilter::Linear
19 };
20
21 // Range check table for input
22 if (mode >= ARRAY_SIZE(filter_mode_table)) {
23 LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
24 UNREACHABLE();
25
26 return GL_LINEAR;
27 }
28
29 GLenum gl_mode = filter_mode_table[mode];
30
31 // Check for dummy values indicating an unknown mode
32 if (gl_mode == 0) {
33 LOG_CRITICAL(Render_OpenGL, "Unknown texture filtering mode %d", mode);
34 UNIMPLEMENTED();
35
36 return GL_LINEAR;
37 }
38
39 return gl_mode;
40}
41
15inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) { 42inline GLenum WrapMode(Pica::Regs::TextureConfig::WrapMode mode) {
16 static const GLenum wrap_mode_table[] = { 43 static const GLenum wrap_mode_table[] = {
17 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge 44 GL_CLAMP_TO_EDGE, // WrapMode::ClampToEdge
18 0, // Unknown 45 GL_CLAMP_TO_BORDER,// WrapMode::ClampToBorder
19 GL_REPEAT, // WrapMode::Repeat 46 GL_REPEAT, // WrapMode::Repeat
20 GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat 47 GL_MIRRORED_REPEAT // WrapMode::MirroredRepeat
21 }; 48 };
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 3399ca123..96e12839a 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -2,22 +2,27 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <algorithm>
6#include <cstddef>
7#include <cstdlib>
8
9#include "common/assert.h"
10#include "common/emu_window.h"
11#include "common/logging/log.h"
12#include "common/profiler_reporting.h"
13
5#include "core/hw/gpu.h" 14#include "core/hw/gpu.h"
6#include "core/hw/hw.h" 15#include "core/hw/hw.h"
7#include "core/hw/lcd.h" 16#include "core/hw/lcd.h"
8#include "core/memory.h" 17#include "core/memory.h"
9#include "core/settings.h" 18#include "core/settings.h"
10 19
11#include "common/emu_window.h"
12#include "common/logging/log.h"
13#include "common/profiler_reporting.h"
14
15#include "video_core/video_core.h" 20#include "video_core/video_core.h"
16#include "video_core/renderer_opengl/renderer_opengl.h" 21#include "video_core/renderer_opengl/renderer_opengl.h"
17#include "video_core/renderer_opengl/gl_shader_util.h" 22#include "video_core/renderer_opengl/gl_shader_util.h"
18#include "video_core/renderer_opengl/gl_shaders.h" 23#include "video_core/renderer_opengl/gl_shaders.h"
19 24
20#include <algorithm> 25#include "video_core/debug_utils/debug_utils.h"
21 26
22/** 27/**
23 * Vertex structure that the drawn screen rectangles are composed of. 28 * Vertex structure that the drawn screen rectangles are composed of.
@@ -126,6 +131,10 @@ void RendererOpenGL::SwapBuffers() {
126 hw_rasterizer->Reset(); 131 hw_rasterizer->Reset();
127 } 132 }
128 } 133 }
134
135 if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
136 Pica::g_debug_context->recorder->FrameFinished();
137 }
129} 138}
130 139
131/** 140/**
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 87006a832..b77503806 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -221,7 +221,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
221 for (int i = 0; i < num_components; ++i) 221 for (int i = 0; i < num_components; ++i)
222 dot = dot + src1[i] * src2[i]; 222 dot = dot + src1[i] * src2[i];
223 223
224 for (int i = 0; i < num_components; ++i) { 224 for (int i = 0; i < 4; ++i) {
225 if (!swizzle.DestComponentEnabled(i)) 225 if (!swizzle.DestComponentEnabled(i))
226 continue; 226 continue;
227 227
@@ -546,20 +546,18 @@ static void ProcessShaderCode(VertexShaderState& state) {
546 546
547static Common::Profiling::TimingCategory shader_category("Vertex Shader"); 547static Common::Profiling::TimingCategory shader_category("Vertex Shader");
548 548
549OutputVertex RunShader(const InputVertex& input, int num_attributes) { 549OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup) {
550 Common::Profiling::ScopeTimer timer(shader_category); 550 Common::Profiling::ScopeTimer timer(shader_category);
551 551
552 const auto& regs = g_state.regs;
553 const auto& vs = g_state.vs;
554 VertexShaderState state; 552 VertexShaderState state;
555 553
556 const u32* main = &vs.program_code[regs.vs_main_offset]; 554 const u32* main = &setup.program_code[config.main_offset];
557 state.program_counter = (u32*)main; 555 state.program_counter = (u32*)main;
558 state.debug.max_offset = 0; 556 state.debug.max_offset = 0;
559 state.debug.max_opdesc_id = 0; 557 state.debug.max_opdesc_id = 0;
560 558
561 // Setup input register table 559 // Setup input register table
562 const auto& attribute_register_map = regs.vs_input_register_map; 560 const auto& attribute_register_map = config.input_register_map;
563 float24 dummy_register; 561 float24 dummy_register;
564 boost::fill(state.input_register_table, &dummy_register); 562 boost::fill(state.input_register_table, &dummy_register);
565 563
@@ -584,16 +582,16 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
584 state.conditional_code[1] = false; 582 state.conditional_code[1] = false;
585 583
586 ProcessShaderCode(state); 584 ProcessShaderCode(state);
587 DebugUtils::DumpShader(vs.program_code.data(), state.debug.max_offset, vs.swizzle_data.data(), 585 DebugUtils::DumpShader(setup.program_code.data(), state.debug.max_offset, setup.swizzle_data.data(),
588 state.debug.max_opdesc_id, regs.vs_main_offset, 586 state.debug.max_opdesc_id, config.main_offset,
589 regs.vs_output_attributes); 587 g_state.regs.vs_output_attributes); // TODO: Don't hardcode VS here
590 588
591 // Setup output data 589 // Setup output data
592 OutputVertex ret; 590 OutputVertex ret;
593 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to 591 // TODO(neobrain): Under some circumstances, up to 16 attributes may be output. We need to
594 // figure out what those circumstances are and enable the remaining outputs then. 592 // figure out what those circumstances are and enable the remaining outputs then.
595 for (int i = 0; i < 7; ++i) { 593 for (int i = 0; i < 7; ++i) {
596 const auto& output_register_map = regs.vs_output_attributes[i]; 594 const auto& output_register_map = g_state.regs.vs_output_attributes[i]; // TODO: Don't hardcode VS here
597 595
598 u32 semantics[4] = { 596 u32 semantics[4] = {
599 output_register_map.map_x, output_register_map.map_y, 597 output_register_map.map_x, output_register_map.map_y,
diff --git a/src/video_core/vertex_shader.h b/src/video_core/vertex_shader.h
index 7471a6de8..97f9250dd 100644
--- a/src/video_core/vertex_shader.h
+++ b/src/video_core/vertex_shader.h
@@ -4,11 +4,10 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <initializer_list> 7#include <type_traits>
8 8
9#include <common/common_types.h> 9#include "common/vector_math.h"
10 10
11#include "math.h"
12#include "pica.h" 11#include "pica.h"
13 12
14namespace Pica { 13namespace Pica {
@@ -66,7 +65,7 @@ struct OutputVertex {
66static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD"); 65static_assert(std::is_pod<OutputVertex>::value, "Structure is not POD");
67static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size"); 66static_assert(sizeof(OutputVertex) == 32 * sizeof(float), "OutputVertex has invalid size");
68 67
69OutputVertex RunShader(const InputVertex& input, int num_attributes); 68OutputVertex RunShader(const InputVertex& input, int num_attributes, const Regs::ShaderConfig& config, const State::ShaderSetup& setup);
70 69
71} // namespace 70} // namespace
72 71
diff --git a/src/video_core/video_core.h b/src/video_core/video_core.h
index 3f24df7bd..14b33c9dd 100644
--- a/src/video_core/video_core.h
+++ b/src/video_core/video_core.h
@@ -4,12 +4,11 @@
4 4
5#pragma once 5#pragma once
6 6
7#include "common/emu_window.h"
8
9#include "renderer_base.h"
10
11#include <atomic> 7#include <atomic>
12 8
9class EmuWindow;
10class RendererBase;
11
13//////////////////////////////////////////////////////////////////////////////////////////////////// 12////////////////////////////////////////////////////////////////////////////////////////////////////
14// Video Core namespace 13// Video Core namespace
15 14