summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-x.travis-build.sh8
-rw-r--r--.travis-upload.sh6
-rw-r--r--.travis.yml2
-rw-r--r--CMakeLists.txt4
-rw-r--r--Doxyfile124
-rw-r--r--README.md2
-rw-r--r--appveyor.yml4
-rw-r--r--src/citra/resource.hbin898 -> 431 bytes
-rw-r--r--src/citra_qt/CMakeLists.txt6
-rw-r--r--src/citra_qt/bootmanager.cpp2
-rw-r--r--src/citra_qt/bootmanager.h2
-rw-r--r--src/citra_qt/debugger/callstack.cpp2
-rw-r--r--src/citra_qt/main.cpp2
-rw-r--r--src/citra_qt/main.ui17
-rw-r--r--src/common/emu_window.cpp2
-rw-r--r--src/common/file_util.cpp2
-rw-r--r--src/common/swap.h2
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/arm/disassembler/arm_disasm.cpp2
-rw-r--r--src/core/arm/dyncom/arm_dyncom_interpreter.cpp32
-rw-r--r--src/core/arm/dyncom/arm_dyncom_thumb.cpp2
-rw-r--r--src/core/arm/interpreter/armsupp.cpp2
-rw-r--r--src/core/arm/skyeye_common/armdefs.h6
-rw-r--r--src/core/arm/skyeye_common/vfp/vfp_helper.h4
-rw-r--r--src/core/core_timing.cpp2
-rw-r--r--src/core/core_timing.h2
-rw-r--r--src/core/file_sys/archive_extsavedata.cpp4
-rw-r--r--src/core/file_sys/archive_extsavedata.h4
-rw-r--r--src/core/file_sys/archive_savedata.cpp2
-rw-r--r--src/core/hle/kernel/resource_limit.h8
-rw-r--r--src/core/hle/kernel/semaphore.cpp2
-rw-r--r--src/core/hle/kernel/thread.cpp8
-rw-r--r--src/core/hle/kernel/thread.h2
-rw-r--r--src/core/hle/kernel/timer.cpp2
-rw-r--r--src/core/hle/kernel/vm_manager.cpp245
-rw-r--r--src/core/hle/kernel/vm_manager.h200
-rw-r--r--src/core/hle/service/apt/apt.cpp4
-rw-r--r--src/core/hle/service/apt/apt.h8
-rw-r--r--src/core/hle/service/boss_p.h2
-rw-r--r--src/core/hle/service/boss_u.h2
-rw-r--r--src/core/hle/service/cam_u.cpp2
-rw-r--r--src/core/hle/service/cfg/cfg.cpp4
-rw-r--r--src/core/hle/service/fs/archive.cpp6
-rw-r--r--src/core/hle/service/fs/fs_user.cpp6
-rw-r--r--src/core/hle/service/gsp_gpu.cpp24
-rw-r--r--src/core/hle/service/hid/hid.cpp2
-rw-r--r--src/core/hle/service/hid/hid_spvr.cpp2
-rw-r--r--src/core/hle/service/hid/hid_user.h2
-rw-r--r--src/core/hle/service/ptm/ptm.h6
-rw-r--r--src/core/hle/service/ptm/ptm_play.cpp2
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/soc_u.cpp30
-rw-r--r--src/core/hle/svc.cpp4
-rw-r--r--src/core/hw/gpu.cpp10
-rw-r--r--src/core/hw/lcd.cpp2
-rw-r--r--src/core/hw/lcd.h2
-rw-r--r--src/core/loader/3dsx.cpp2
-rw-r--r--src/core/mem_map.cpp55
-rw-r--r--src/core/mem_map.h8
-rw-r--r--src/core/memory.cpp12
-rw-r--r--src/core/memory.h2
-rw-r--r--src/core/memory_setup.h7
-rw-r--r--src/video_core/command_processor.cpp78
-rw-r--r--src/video_core/debug_utils/debug_utils.cpp2
-rw-r--r--src/video_core/math.h2
-rw-r--r--src/video_core/pica.h86
-rw-r--r--src/video_core/rasterizer.cpp78
-rw-r--r--src/video_core/renderer_opengl/generated/gl_3_2_core.c16
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp12
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shaders.h24
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp13
-rw-r--r--src/video_core/renderer_opengl/gl_state.h4
-rw-r--r--src/video_core/renderer_opengl/pica_to_gl.h31
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp2
-rw-r--r--src/video_core/vertex_shader.cpp33
76 files changed, 986 insertions, 324 deletions
diff --git a/.travis-build.sh b/.travis-build.sh
index 21582c689..14dfd64d8 100755
--- a/.travis-build.sh
+++ b/.travis-build.sh
@@ -3,10 +3,16 @@
3set -e 3set -e
4set -x 4set -x
5 5
6if grep -r '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis* dist/*.desktop \
7 dist/*.svg dist/*.xml; then
8 echo Trailing whitespace found, aborting
9 exit 1
10fi
11
6#if OS is linux or is not set 12#if OS is linux or is not set
7if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then 13if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then
8 mkdir build && cd build 14 mkdir build && cd build
9 cmake -DUSE_QT5=OFF .. 15 cmake -DUSE_QT5=OFF ..
10 make -j4 16 make -j4
11elif [ "$TRAVIS_OS_NAME" = "osx" ]; then 17elif [ "$TRAVIS_OS_NAME" = "osx" ]; then
12 export Qt5_DIR=$(brew --prefix)/opt/qt5 18 export Qt5_DIR=$(brew --prefix)/opt/qt5
diff --git a/.travis-upload.sh b/.travis-upload.sh
index 4b9446a96..0904b646a 100644
--- a/.travis-upload.sh
+++ b/.travis-upload.sh
@@ -6,7 +6,7 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
6 REV_NAME="citra-${GITDATE}-${GITREV}-linux-amd64" 6 REV_NAME="citra-${GITDATE}-${GITREV}-linux-amd64"
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 10 sudo apt-get -qq install lftp
11 cp build/src/citra/citra "$REV_NAME" 11 cp build/src/citra/citra "$REV_NAME"
12 cp build/src/citra_qt/citra-qt "$REV_NAME" 12 cp build/src/citra_qt/citra-qt "$REV_NAME"
@@ -14,7 +14,7 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
14 REV_NAME="citra-${GITDATE}-${GITREV}-osx-amd64" 14 REV_NAME="citra-${GITDATE}-${GITREV}-osx-amd64"
15 UPLOAD_DIR="/citra/nightly/osx-amd64" 15 UPLOAD_DIR="/citra/nightly/osx-amd64"
16 mkdir "$REV_NAME" 16 mkdir "$REV_NAME"
17 17
18 brew install lftp 18 brew install lftp
19 cp build/src/citra/Release/citra "$REV_NAME" 19 cp build/src/citra/Release/citra "$REV_NAME"
20 cp -r build/src/citra_qt/Release/citra-qt.app "$REV_NAME" 20 cp -r build/src/citra_qt/Release/citra-qt.app "$REV_NAME"
@@ -22,7 +22,7 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then
22 # move qt libs into app bundle for deployment 22 # move qt libs into app bundle for deployment
23 $(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/citra-qt.app" 23 $(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/citra-qt.app"
24 fi 24 fi
25 25
26 ARCHIVE_NAME="${REV_NAME}.tar.xz" 26 ARCHIVE_NAME="${REV_NAME}.tar.xz"
27 tar -cJvf "$ARCHIVE_NAME" "$REV_NAME" 27 tar -cJvf "$ARCHIVE_NAME" "$REV_NAME"
28 lftp -c "open -u citra-builds,$BUILD_PASSWORD sftp://builds.citra-emu.org; put -O '$UPLOAD_DIR' '$ARCHIVE_NAME'" 28 lftp -c "open -u citra-builds,$BUILD_PASSWORD sftp://builds.citra-emu.org; put -O '$UPLOAD_DIR' '$ARCHIVE_NAME'"
diff --git a/.travis.yml b/.travis.yml
index b878cc160..5c882a574 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -6,7 +6,7 @@ language: cpp
6 6
7env: 7env:
8 global: 8 global:
9 - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" 9 - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg="
10 10
11before_install: 11before_install:
12 - sh .travis-deps.sh 12 - sh .travis-deps.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9fb311b11..75f519a1d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -38,7 +38,7 @@ else()
38 set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) 38 set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE)
39 set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) 39 set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE)
40 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) 40 set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE)
41 41
42 set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) 42 set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE)
43 set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG" CACHE STRING "" FORCE) 43 set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG" CACHE STRING "" FORCE)
44endif() 44endif()
@@ -130,7 +130,7 @@ IF (APPLE)
130 FIND_LIBRARY(IOKIT_LIBRARY IOKit) # GLFW dependency 130 FIND_LIBRARY(IOKIT_LIBRARY IOKit) # GLFW dependency
131 FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo) # GLFW dependency 131 FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo) # GLFW dependency
132 set(PLATFORM_LIBRARIES iconv ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) 132 set(PLATFORM_LIBRARIES iconv ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY})
133 133
134 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") 134 set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
135 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") 135 set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++")
136ELSEIF(MINGW) 136ELSEIF(MINGW)
diff --git a/Doxyfile b/Doxyfile
index 92faa0b2a..6ddf2cf21 100644
--- a/Doxyfile
+++ b/Doxyfile
@@ -38,7 +38,7 @@ PROJECT_NAME = Citra
38# could be handy for archiving the generated documentation or if some version 38# could be handy for archiving the generated documentation or if some version
39# control system is used. 39# control system is used.
40 40
41PROJECT_NUMBER = 41PROJECT_NUMBER =
42 42
43# Using the PROJECT_BRIEF tag one can provide an optional one line description 43# Using the PROJECT_BRIEF tag one can provide an optional one line description
44# for a project that appears at the top of each page and should give viewer a 44# for a project that appears at the top of each page and should give viewer a
@@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES
162# will be relative from the directory where doxygen is started. 162# will be relative from the directory where doxygen is started.
163# This tag requires that the tag FULL_PATH_NAMES is set to YES. 163# This tag requires that the tag FULL_PATH_NAMES is set to YES.
164 164
165STRIP_FROM_PATH = 165STRIP_FROM_PATH =
166 166
167# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the 167# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
168# path mentioned in the documentation of a class, which tells the reader which 168# path mentioned in the documentation of a class, which tells the reader which
@@ -171,7 +171,7 @@ STRIP_FROM_PATH =
171# specify the list of include paths that are normally passed to the compiler 171# specify the list of include paths that are normally passed to the compiler
172# using the -I flag. 172# using the -I flag.
173 173
174STRIP_FROM_INC_PATH = 174STRIP_FROM_INC_PATH =
175 175
176# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but 176# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
177# less readable) file names. This can be useful is your file systems doesn't 177# less readable) file names. This can be useful is your file systems doesn't
@@ -238,13 +238,13 @@ TAB_SIZE = 4
238# "Side Effects:". You can put \n's in the value part of an alias to insert 238# "Side Effects:". You can put \n's in the value part of an alias to insert
239# newlines. 239# newlines.
240 240
241ALIASES = 241ALIASES =
242 242
243# This tag can be used to specify a number of word-keyword mappings (TCL only). 243# This tag can be used to specify a number of word-keyword mappings (TCL only).
244# A mapping has the form "name=value". For example adding "class=itcl::class" 244# A mapping has the form "name=value". For example adding "class=itcl::class"
245# will allow you to use the command class in the itcl::class meaning. 245# will allow you to use the command class in the itcl::class meaning.
246 246
247TCL_SUBST = 247TCL_SUBST =
248 248
249# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources 249# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
250# only. Doxygen will then generate output that is more tailored for C. For 250# only. Doxygen will then generate output that is more tailored for C. For
@@ -291,7 +291,7 @@ OPTIMIZE_OUTPUT_VHDL = NO
291# Note that for custom extensions you also need to set FILE_PATTERNS otherwise 291# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
292# the files are not read by doxygen. 292# the files are not read by doxygen.
293 293
294EXTENSION_MAPPING = 294EXTENSION_MAPPING =
295 295
296# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments 296# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
297# according to the Markdown format, which allows for more readable 297# according to the Markdown format, which allows for more readable
@@ -627,7 +627,7 @@ GENERATE_DEPRECATEDLIST= YES
627# sections, marked by \if <section_label> ... \endif and \cond <section_label> 627# sections, marked by \if <section_label> ... \endif and \cond <section_label>
628# ... \endcond blocks. 628# ... \endcond blocks.
629 629
630ENABLED_SECTIONS = 630ENABLED_SECTIONS =
631 631
632# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the 632# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
633# initial value of a variable or macro / define can have for it to appear in the 633# initial value of a variable or macro / define can have for it to appear in the
@@ -669,7 +669,7 @@ SHOW_NAMESPACES = YES
669# by doxygen. Whatever the program writes to standard output is used as the file 669# by doxygen. Whatever the program writes to standard output is used as the file
670# version. For an example see the documentation. 670# version. For an example see the documentation.
671 671
672FILE_VERSION_FILTER = 672FILE_VERSION_FILTER =
673 673
674# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed 674# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
675# by doxygen. The layout file controls the global structure of the generated 675# by doxygen. The layout file controls the global structure of the generated
@@ -682,7 +682,7 @@ FILE_VERSION_FILTER =
682# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE 682# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
683# tag is left empty. 683# tag is left empty.
684 684
685LAYOUT_FILE = 685LAYOUT_FILE =
686 686
687# The CITE_BIB_FILES tag can be used to specify one or more bib files containing 687# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
688# the reference definitions. This must be a list of .bib files. The .bib 688# the reference definitions. This must be a list of .bib files. The .bib
@@ -692,7 +692,7 @@ LAYOUT_FILE =
692# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the 692# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
693# search path. See also \cite for info how to create references. 693# search path. See also \cite for info how to create references.
694 694
695CITE_BIB_FILES = 695CITE_BIB_FILES =
696 696
697#--------------------------------------------------------------------------- 697#---------------------------------------------------------------------------
698# Configuration options related to warning and progress messages 698# Configuration options related to warning and progress messages
@@ -751,7 +751,7 @@ WARN_FORMAT = "$file:$line: $text"
751# messages should be written. If left blank the output is written to standard 751# messages should be written. If left blank the output is written to standard
752# error (stderr). 752# error (stderr).
753 753
754WARN_LOGFILE = 754WARN_LOGFILE =
755 755
756#--------------------------------------------------------------------------- 756#---------------------------------------------------------------------------
757# Configuration options related to the input files 757# Configuration options related to the input files
@@ -807,7 +807,7 @@ RECURSIVE = YES
807# Note that relative paths are relative to the directory from which doxygen is 807# Note that relative paths are relative to the directory from which doxygen is
808# run. 808# run.
809 809
810EXCLUDE = 810EXCLUDE =
811 811
812# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or 812# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
813# directories that are symbolic links (a Unix file system feature) are excluded 813# directories that are symbolic links (a Unix file system feature) are excluded
@@ -823,7 +823,7 @@ EXCLUDE_SYMLINKS = NO
823# Note that the wildcards are matched against the file with absolute path, so to 823# Note that the wildcards are matched against the file with absolute path, so to
824# exclude all test directories for example use the pattern */test/* 824# exclude all test directories for example use the pattern */test/*
825 825
826EXCLUDE_PATTERNS = 826EXCLUDE_PATTERNS =
827 827
828# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names 828# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
829# (namespaces, classes, functions, etc.) that should be excluded from the 829# (namespaces, classes, functions, etc.) that should be excluded from the
@@ -834,13 +834,13 @@ EXCLUDE_PATTERNS =
834# Note that the wildcards are matched against the file with absolute path, so to 834# Note that the wildcards are matched against the file with absolute path, so to
835# exclude all test directories use the pattern */test/* 835# exclude all test directories use the pattern */test/*
836 836
837EXCLUDE_SYMBOLS = 837EXCLUDE_SYMBOLS =
838 838
839# The EXAMPLE_PATH tag can be used to specify one or more files or directories 839# The EXAMPLE_PATH tag can be used to specify one or more files or directories
840# that contain example code fragments that are included (see the \include 840# that contain example code fragments that are included (see the \include
841# command). 841# command).
842 842
843EXAMPLE_PATH = 843EXAMPLE_PATH =
844 844
845# If the value of the EXAMPLE_PATH tag contains directories, you can use the 845# If the value of the EXAMPLE_PATH tag contains directories, you can use the
846# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and 846# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
@@ -860,7 +860,7 @@ EXAMPLE_RECURSIVE = NO
860# that contain images that are to be included in the documentation (see the 860# that contain images that are to be included in the documentation (see the
861# \image command). 861# \image command).
862 862
863IMAGE_PATH = 863IMAGE_PATH =
864 864
865# The INPUT_FILTER tag can be used to specify a program that doxygen should 865# The INPUT_FILTER tag can be used to specify a program that doxygen should
866# invoke to filter for each input file. Doxygen will invoke the filter program 866# invoke to filter for each input file. Doxygen will invoke the filter program
@@ -877,7 +877,7 @@ IMAGE_PATH =
877# code is scanned, but not when the output code is generated. If lines are added 877# code is scanned, but not when the output code is generated. If lines are added
878# or removed, the anchors will not be placed correctly. 878# or removed, the anchors will not be placed correctly.
879 879
880INPUT_FILTER = 880INPUT_FILTER =
881 881
882# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern 882# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
883# basis. Doxygen will compare the file name with each pattern and apply the 883# basis. Doxygen will compare the file name with each pattern and apply the
@@ -886,7 +886,7 @@ INPUT_FILTER =
886# filters are used. If the FILTER_PATTERNS tag is empty or if none of the 886# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
887# patterns match the file name, INPUT_FILTER is applied. 887# patterns match the file name, INPUT_FILTER is applied.
888 888
889FILTER_PATTERNS = 889FILTER_PATTERNS =
890 890
891# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using 891# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
892# INPUT_FILTER ) will also be used to filter the input files that are used for 892# INPUT_FILTER ) will also be used to filter the input files that are used for
@@ -901,14 +901,14 @@ FILTER_SOURCE_FILES = NO
901# *.ext= (so without naming a filter). 901# *.ext= (so without naming a filter).
902# This tag requires that the tag FILTER_SOURCE_FILES is set to YES. 902# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
903 903
904FILTER_SOURCE_PATTERNS = 904FILTER_SOURCE_PATTERNS =
905 905
906# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that 906# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
907# is part of the input, its contents will be placed on the main page 907# is part of the input, its contents will be placed on the main page
908# (index.html). This can be useful if you have a project on for instance GitHub 908# (index.html). This can be useful if you have a project on for instance GitHub
909# and want to reuse the introduction page also for the doxygen output. 909# and want to reuse the introduction page also for the doxygen output.
910 910
911USE_MDFILE_AS_MAINPAGE = 911USE_MDFILE_AS_MAINPAGE =
912 912
913#--------------------------------------------------------------------------- 913#---------------------------------------------------------------------------
914# Configuration options related to source browsing 914# Configuration options related to source browsing
@@ -1013,7 +1013,7 @@ CLANG_ASSISTED_PARSING = NO
1013# specified with INPUT and INCLUDE_PATH. 1013# specified with INPUT and INCLUDE_PATH.
1014# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. 1014# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
1015 1015
1016CLANG_OPTIONS = 1016CLANG_OPTIONS =
1017 1017
1018#--------------------------------------------------------------------------- 1018#---------------------------------------------------------------------------
1019# Configuration options related to the alphabetical class index 1019# Configuration options related to the alphabetical class index
@@ -1039,7 +1039,7 @@ COLS_IN_ALPHA_INDEX = 5
1039# while generating the index headers. 1039# while generating the index headers.
1040# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. 1040# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
1041 1041
1042IGNORE_PREFIX = 1042IGNORE_PREFIX =
1043 1043
1044#--------------------------------------------------------------------------- 1044#---------------------------------------------------------------------------
1045# Configuration options related to the HTML output 1045# Configuration options related to the HTML output
@@ -1083,7 +1083,7 @@ HTML_FILE_EXTENSION = .html
1083# of the possible markers and block names see the documentation. 1083# of the possible markers and block names see the documentation.
1084# This tag requires that the tag GENERATE_HTML is set to YES. 1084# This tag requires that the tag GENERATE_HTML is set to YES.
1085 1085
1086HTML_HEADER = 1086HTML_HEADER =
1087 1087
1088# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each 1088# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
1089# generated HTML page. If the tag is left blank doxygen will generate a standard 1089# generated HTML page. If the tag is left blank doxygen will generate a standard
@@ -1093,7 +1093,7 @@ HTML_HEADER =
1093# that doxygen normally uses. 1093# that doxygen normally uses.
1094# This tag requires that the tag GENERATE_HTML is set to YES. 1094# This tag requires that the tag GENERATE_HTML is set to YES.
1095 1095
1096HTML_FOOTER = 1096HTML_FOOTER =
1097 1097
1098# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style 1098# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
1099# sheet that is used by each HTML page. It can be used to fine-tune the look of 1099# sheet that is used by each HTML page. It can be used to fine-tune the look of
@@ -1105,7 +1105,7 @@ HTML_FOOTER =
1105# obsolete. 1105# obsolete.
1106# This tag requires that the tag GENERATE_HTML is set to YES. 1106# This tag requires that the tag GENERATE_HTML is set to YES.
1107 1107
1108HTML_STYLESHEET = 1108HTML_STYLESHEET =
1109 1109
1110# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined 1110# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
1111# cascading style sheets that are included after the standard style sheets 1111# cascading style sheets that are included after the standard style sheets
@@ -1118,7 +1118,7 @@ HTML_STYLESHEET =
1118# list). For an example see the documentation. 1118# list). For an example see the documentation.
1119# This tag requires that the tag GENERATE_HTML is set to YES. 1119# This tag requires that the tag GENERATE_HTML is set to YES.
1120 1120
1121HTML_EXTRA_STYLESHEET = 1121HTML_EXTRA_STYLESHEET =
1122 1122
1123# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or 1123# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
1124# other source files which should be copied to the HTML output directory. Note 1124# other source files which should be copied to the HTML output directory. Note
@@ -1128,7 +1128,7 @@ HTML_EXTRA_STYLESHEET =
1128# files will be copied as-is; there are no commands or markers available. 1128# files will be copied as-is; there are no commands or markers available.
1129# This tag requires that the tag GENERATE_HTML is set to YES. 1129# This tag requires that the tag GENERATE_HTML is set to YES.
1130 1130
1131HTML_EXTRA_FILES = 1131HTML_EXTRA_FILES =
1132 1132
1133# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen 1133# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
1134# will adjust the colors in the stylesheet and background images according to 1134# will adjust the colors in the stylesheet and background images according to
@@ -1256,7 +1256,7 @@ GENERATE_HTMLHELP = NO
1256# written to the html output directory. 1256# written to the html output directory.
1257# This tag requires that the tag GENERATE_HTMLHELP is set to YES. 1257# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1258 1258
1259CHM_FILE = 1259CHM_FILE =
1260 1260
1261# The HHC_LOCATION tag can be used to specify the location (absolute path 1261# The HHC_LOCATION tag can be used to specify the location (absolute path
1262# including file name) of the HTML help compiler ( hhc.exe). If non-empty 1262# including file name) of the HTML help compiler ( hhc.exe). If non-empty
@@ -1264,7 +1264,7 @@ CHM_FILE =
1264# The file has to be specified with full path. 1264# The file has to be specified with full path.
1265# This tag requires that the tag GENERATE_HTMLHELP is set to YES. 1265# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1266 1266
1267HHC_LOCATION = 1267HHC_LOCATION =
1268 1268
1269# The GENERATE_CHI flag controls if a separate .chi index file is generated ( 1269# The GENERATE_CHI flag controls if a separate .chi index file is generated (
1270# YES) or that it should be included in the master .chm file ( NO). 1270# YES) or that it should be included in the master .chm file ( NO).
@@ -1277,7 +1277,7 @@ GENERATE_CHI = NO
1277# and project file content. 1277# and project file content.
1278# This tag requires that the tag GENERATE_HTMLHELP is set to YES. 1278# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
1279 1279
1280CHM_INDEX_ENCODING = 1280CHM_INDEX_ENCODING =
1281 1281
1282# The BINARY_TOC flag controls whether a binary table of contents is generated ( 1282# The BINARY_TOC flag controls whether a binary table of contents is generated (
1283# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it 1283# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
@@ -1308,7 +1308,7 @@ GENERATE_QHP = NO
1308# the HTML output folder. 1308# the HTML output folder.
1309# This tag requires that the tag GENERATE_QHP is set to YES. 1309# This tag requires that the tag GENERATE_QHP is set to YES.
1310 1310
1311QCH_FILE = 1311QCH_FILE =
1312 1312
1313# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help 1313# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
1314# Project output. For more information please see Qt Help Project / Namespace 1314# Project output. For more information please see Qt Help Project / Namespace
@@ -1333,7 +1333,7 @@ QHP_VIRTUAL_FOLDER = doc
1333# filters). 1333# filters).
1334# This tag requires that the tag GENERATE_QHP is set to YES. 1334# This tag requires that the tag GENERATE_QHP is set to YES.
1335 1335
1336QHP_CUST_FILTER_NAME = 1336QHP_CUST_FILTER_NAME =
1337 1337
1338# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the 1338# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
1339# custom filter to add. For more information please see Qt Help Project / Custom 1339# custom filter to add. For more information please see Qt Help Project / Custom
@@ -1341,21 +1341,21 @@ QHP_CUST_FILTER_NAME =
1341# filters). 1341# filters).
1342# This tag requires that the tag GENERATE_QHP is set to YES. 1342# This tag requires that the tag GENERATE_QHP is set to YES.
1343 1343
1344QHP_CUST_FILTER_ATTRS = 1344QHP_CUST_FILTER_ATTRS =
1345 1345
1346# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this 1346# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
1347# project's filter section matches. Qt Help Project / Filter Attributes (see: 1347# project's filter section matches. Qt Help Project / Filter Attributes (see:
1348# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). 1348# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
1349# This tag requires that the tag GENERATE_QHP is set to YES. 1349# This tag requires that the tag GENERATE_QHP is set to YES.
1350 1350
1351QHP_SECT_FILTER_ATTRS = 1351QHP_SECT_FILTER_ATTRS =
1352 1352
1353# The QHG_LOCATION tag can be used to specify the location of Qt's 1353# The QHG_LOCATION tag can be used to specify the location of Qt's
1354# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the 1354# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
1355# generated .qhp file. 1355# generated .qhp file.
1356# This tag requires that the tag GENERATE_QHP is set to YES. 1356# This tag requires that the tag GENERATE_QHP is set to YES.
1357 1357
1358QHG_LOCATION = 1358QHG_LOCATION =
1359 1359
1360# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be 1360# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
1361# generated, together with the HTML files, they form an Eclipse help plugin. To 1361# generated, together with the HTML files, they form an Eclipse help plugin. To
@@ -1488,7 +1488,7 @@ MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
1488# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols 1488# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
1489# This tag requires that the tag USE_MATHJAX is set to YES. 1489# This tag requires that the tag USE_MATHJAX is set to YES.
1490 1490
1491MATHJAX_EXTENSIONS = 1491MATHJAX_EXTENSIONS =
1492 1492
1493# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces 1493# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
1494# of code that will be used on startup of the MathJax code. See the MathJax site 1494# of code that will be used on startup of the MathJax code. See the MathJax site
@@ -1496,7 +1496,7 @@ MATHJAX_EXTENSIONS =
1496# example see the documentation. 1496# example see the documentation.
1497# This tag requires that the tag USE_MATHJAX is set to YES. 1497# This tag requires that the tag USE_MATHJAX is set to YES.
1498 1498
1499MATHJAX_CODEFILE = 1499MATHJAX_CODEFILE =
1500 1500
1501# When the SEARCHENGINE tag is enabled doxygen will generate a search box for 1501# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
1502# the HTML output. The underlying search engine uses javascript and DHTML and 1502# the HTML output. The underlying search engine uses javascript and DHTML and
@@ -1556,7 +1556,7 @@ EXTERNAL_SEARCH = NO
1556# Searching" for details. 1556# Searching" for details.
1557# This tag requires that the tag SEARCHENGINE is set to YES. 1557# This tag requires that the tag SEARCHENGINE is set to YES.
1558 1558
1559SEARCHENGINE_URL = 1559SEARCHENGINE_URL =
1560 1560
1561# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed 1561# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
1562# search data is written to a file for indexing by an external tool. With the 1562# search data is written to a file for indexing by an external tool. With the
@@ -1572,7 +1572,7 @@ SEARCHDATA_FILE = searchdata.xml
1572# projects and redirect the results back to the right project. 1572# projects and redirect the results back to the right project.
1573# This tag requires that the tag SEARCHENGINE is set to YES. 1573# This tag requires that the tag SEARCHENGINE is set to YES.
1574 1574
1575EXTERNAL_SEARCH_ID = 1575EXTERNAL_SEARCH_ID =
1576 1576
1577# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen 1577# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
1578# projects other than the one defined by this configuration file, but that are 1578# projects other than the one defined by this configuration file, but that are
@@ -1582,7 +1582,7 @@ EXTERNAL_SEARCH_ID =
1582# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... 1582# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
1583# This tag requires that the tag SEARCHENGINE is set to YES. 1583# This tag requires that the tag SEARCHENGINE is set to YES.
1584 1584
1585EXTRA_SEARCH_MAPPINGS = 1585EXTRA_SEARCH_MAPPINGS =
1586 1586
1587#--------------------------------------------------------------------------- 1587#---------------------------------------------------------------------------
1588# Configuration options related to the LaTeX output 1588# Configuration options related to the LaTeX output
@@ -1643,7 +1643,7 @@ PAPER_TYPE = a4
1643# If left blank no extra packages will be included. 1643# If left blank no extra packages will be included.
1644# This tag requires that the tag GENERATE_LATEX is set to YES. 1644# This tag requires that the tag GENERATE_LATEX is set to YES.
1645 1645
1646EXTRA_PACKAGES = 1646EXTRA_PACKAGES =
1647 1647
1648# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the 1648# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
1649# generated LaTeX document. The header should contain everything until the first 1649# generated LaTeX document. The header should contain everything until the first
@@ -1659,7 +1659,7 @@ EXTRA_PACKAGES =
1659# HTML_HEADER. 1659# HTML_HEADER.
1660# This tag requires that the tag GENERATE_LATEX is set to YES. 1660# This tag requires that the tag GENERATE_LATEX is set to YES.
1661 1661
1662LATEX_HEADER = 1662LATEX_HEADER =
1663 1663
1664# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the 1664# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
1665# generated LaTeX document. The footer should contain everything after the last 1665# generated LaTeX document. The footer should contain everything after the last
@@ -1670,7 +1670,7 @@ LATEX_HEADER =
1670# Note: Only use a user-defined footer if you know what you are doing! 1670# Note: Only use a user-defined footer if you know what you are doing!
1671# This tag requires that the tag GENERATE_LATEX is set to YES. 1671# This tag requires that the tag GENERATE_LATEX is set to YES.
1672 1672
1673LATEX_FOOTER = 1673LATEX_FOOTER =
1674 1674
1675# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or 1675# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
1676# other source files which should be copied to the LATEX_OUTPUT output 1676# other source files which should be copied to the LATEX_OUTPUT output
@@ -1678,7 +1678,7 @@ LATEX_FOOTER =
1678# markers available. 1678# markers available.
1679# This tag requires that the tag GENERATE_LATEX is set to YES. 1679# This tag requires that the tag GENERATE_LATEX is set to YES.
1680 1680
1681LATEX_EXTRA_FILES = 1681LATEX_EXTRA_FILES =
1682 1682
1683# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is 1683# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
1684# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will 1684# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
@@ -1778,14 +1778,14 @@ RTF_HYPERLINKS = NO
1778# default style sheet that doxygen normally uses. 1778# default style sheet that doxygen normally uses.
1779# This tag requires that the tag GENERATE_RTF is set to YES. 1779# This tag requires that the tag GENERATE_RTF is set to YES.
1780 1780
1781RTF_STYLESHEET_FILE = 1781RTF_STYLESHEET_FILE =
1782 1782
1783# Set optional variables used in the generation of an RTF document. Syntax is 1783# Set optional variables used in the generation of an RTF document. Syntax is
1784# similar to doxygen's config file. A template extensions file can be generated 1784# similar to doxygen's config file. A template extensions file can be generated
1785# using doxygen -e rtf extensionFile. 1785# using doxygen -e rtf extensionFile.
1786# This tag requires that the tag GENERATE_RTF is set to YES. 1786# This tag requires that the tag GENERATE_RTF is set to YES.
1787 1787
1788RTF_EXTENSIONS_FILE = 1788RTF_EXTENSIONS_FILE =
1789 1789
1790#--------------------------------------------------------------------------- 1790#---------------------------------------------------------------------------
1791# Configuration options related to the man page output 1791# Configuration options related to the man page output
@@ -1820,7 +1820,7 @@ MAN_EXTENSION = .3
1820# MAN_EXTENSION with the initial . removed. 1820# MAN_EXTENSION with the initial . removed.
1821# This tag requires that the tag GENERATE_MAN is set to YES. 1821# This tag requires that the tag GENERATE_MAN is set to YES.
1822 1822
1823MAN_SUBDIR = 1823MAN_SUBDIR =
1824 1824
1825# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it 1825# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
1826# will generate one additional man file for each entity documented in the real 1826# will generate one additional man file for each entity documented in the real
@@ -1933,7 +1933,7 @@ PERLMOD_PRETTY = YES
1933# overwrite each other's variables. 1933# overwrite each other's variables.
1934# This tag requires that the tag GENERATE_PERLMOD is set to YES. 1934# This tag requires that the tag GENERATE_PERLMOD is set to YES.
1935 1935
1936PERLMOD_MAKEVAR_PREFIX = 1936PERLMOD_MAKEVAR_PREFIX =
1937 1937
1938#--------------------------------------------------------------------------- 1938#---------------------------------------------------------------------------
1939# Configuration options related to the preprocessor 1939# Configuration options related to the preprocessor
@@ -1974,7 +1974,7 @@ SEARCH_INCLUDES = YES
1974# preprocessor. 1974# preprocessor.
1975# This tag requires that the tag SEARCH_INCLUDES is set to YES. 1975# This tag requires that the tag SEARCH_INCLUDES is set to YES.
1976 1976
1977INCLUDE_PATH = 1977INCLUDE_PATH =
1978 1978
1979# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard 1979# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
1980# patterns (like *.h and *.hpp) to filter out the header-files in the 1980# patterns (like *.h and *.hpp) to filter out the header-files in the
@@ -1982,7 +1982,7 @@ INCLUDE_PATH =
1982# used. 1982# used.
1983# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. 1983# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1984 1984
1985INCLUDE_FILE_PATTERNS = 1985INCLUDE_FILE_PATTERNS =
1986 1986
1987# The PREDEFINED tag can be used to specify one or more macro names that are 1987# The PREDEFINED tag can be used to specify one or more macro names that are
1988# defined before the preprocessor is started (similar to the -D option of e.g. 1988# defined before the preprocessor is started (similar to the -D option of e.g.
@@ -1992,7 +1992,7 @@ INCLUDE_FILE_PATTERNS =
1992# recursively expanded use the := operator instead of the = operator. 1992# recursively expanded use the := operator instead of the = operator.
1993# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. 1993# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
1994 1994
1995PREDEFINED = 1995PREDEFINED =
1996 1996
1997# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this 1997# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
1998# tag can be used to specify a list of macro names that should be expanded. The 1998# tag can be used to specify a list of macro names that should be expanded. The
@@ -2001,7 +2001,7 @@ PREDEFINED =
2001# definition found in the source code. 2001# definition found in the source code.
2002# This tag requires that the tag ENABLE_PREPROCESSING is set to YES. 2002# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
2003 2003
2004EXPAND_AS_DEFINED = 2004EXPAND_AS_DEFINED =
2005 2005
2006# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will 2006# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
2007# remove all references to function-like macros that are alone on a line, have 2007# remove all references to function-like macros that are alone on a line, have
@@ -2030,13 +2030,13 @@ SKIP_FUNCTION_MACROS = YES
2030# the path). If a tag file is not located in the directory in which doxygen is 2030# the path). If a tag file is not located in the directory in which doxygen is
2031# run, you must also specify the path to the tagfile here. 2031# run, you must also specify the path to the tagfile here.
2032 2032
2033TAGFILES = 2033TAGFILES =
2034 2034
2035# When a file name is specified after GENERATE_TAGFILE, doxygen will create a 2035# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
2036# tag file that is based on the input files it reads. See section "Linking to 2036# tag file that is based on the input files it reads. See section "Linking to
2037# external documentation" for more information about the usage of tag files. 2037# external documentation" for more information about the usage of tag files.
2038 2038
2039GENERATE_TAGFILE = 2039GENERATE_TAGFILE =
2040 2040
2041# If the ALLEXTERNALS tag is set to YES all external class will be listed in the 2041# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
2042# class index. If set to NO only the inherited external classes will be listed. 2042# class index. If set to NO only the inherited external classes will be listed.
@@ -2084,14 +2084,14 @@ CLASS_DIAGRAMS = YES
2084# the mscgen tool resides. If left empty the tool is assumed to be found in the 2084# the mscgen tool resides. If left empty the tool is assumed to be found in the
2085# default search path. 2085# default search path.
2086 2086
2087MSCGEN_PATH = 2087MSCGEN_PATH =
2088 2088
2089# You can include diagrams made with dia in doxygen documentation. Doxygen will 2089# You can include diagrams made with dia in doxygen documentation. Doxygen will
2090# then run dia to produce the diagram and insert it in the documentation. The 2090# then run dia to produce the diagram and insert it in the documentation. The
2091# DIA_PATH tag allows you to specify the directory where the dia binary resides. 2091# DIA_PATH tag allows you to specify the directory where the dia binary resides.
2092# If left empty dia is assumed to be found in the default search path. 2092# If left empty dia is assumed to be found in the default search path.
2093 2093
2094DIA_PATH = 2094DIA_PATH =
2095 2095
2096# If set to YES, the inheritance and collaboration graphs will hide inheritance 2096# If set to YES, the inheritance and collaboration graphs will hide inheritance
2097# and usage relations if the target is undocumented or is not a class. 2097# and usage relations if the target is undocumented or is not a class.
@@ -2140,7 +2140,7 @@ DOT_FONTSIZE = 10
2140# the path where dot can find it using this tag. 2140# the path where dot can find it using this tag.
2141# This tag requires that the tag HAVE_DOT is set to YES. 2141# This tag requires that the tag HAVE_DOT is set to YES.
2142 2142
2143DOT_FONTPATH = 2143DOT_FONTPATH =
2144 2144
2145# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for 2145# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
2146# each documented class showing the direct and indirect inheritance relations. 2146# each documented class showing the direct and indirect inheritance relations.
@@ -2278,26 +2278,26 @@ INTERACTIVE_SVG = NO
2278# found. If left blank, it is assumed the dot tool can be found in the path. 2278# found. If left blank, it is assumed the dot tool can be found in the path.
2279# This tag requires that the tag HAVE_DOT is set to YES. 2279# This tag requires that the tag HAVE_DOT is set to YES.
2280 2280
2281DOT_PATH = 2281DOT_PATH =
2282 2282
2283# The DOTFILE_DIRS tag can be used to specify one or more directories that 2283# The DOTFILE_DIRS tag can be used to specify one or more directories that
2284# contain dot files that are included in the documentation (see the \dotfile 2284# contain dot files that are included in the documentation (see the \dotfile
2285# command). 2285# command).
2286# This tag requires that the tag HAVE_DOT is set to YES. 2286# This tag requires that the tag HAVE_DOT is set to YES.
2287 2287
2288DOTFILE_DIRS = 2288DOTFILE_DIRS =
2289 2289
2290# The MSCFILE_DIRS tag can be used to specify one or more directories that 2290# The MSCFILE_DIRS tag can be used to specify one or more directories that
2291# contain msc files that are included in the documentation (see the \mscfile 2291# contain msc files that are included in the documentation (see the \mscfile
2292# command). 2292# command).
2293 2293
2294MSCFILE_DIRS = 2294MSCFILE_DIRS =
2295 2295
2296# The DIAFILE_DIRS tag can be used to specify one or more directories that 2296# The DIAFILE_DIRS tag can be used to specify one or more directories that
2297# contain dia files that are included in the documentation (see the \diafile 2297# contain dia files that are included in the documentation (see the \diafile
2298# command). 2298# command).
2299 2299
2300DIAFILE_DIRS = 2300DIAFILE_DIRS =
2301 2301
2302# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the 2302# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
2303# path where java can find the plantuml.jar file. If left blank, it is assumed 2303# path where java can find the plantuml.jar file. If left blank, it is assumed
@@ -2306,7 +2306,7 @@ DIAFILE_DIRS =
2306# will not generate output for the diagram. 2306# will not generate output for the diagram.
2307# This tag requires that the tag HAVE_DOT is set to YES. 2307# This tag requires that the tag HAVE_DOT is set to YES.
2308 2308
2309PLANTUML_JAR_PATH = 2309PLANTUML_JAR_PATH =
2310 2310
2311# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes 2311# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
2312# that will be shown in the graph. If the number of nodes in a graph becomes 2312# that will be shown in the graph. If the number of nodes in a graph becomes
diff --git a/README.md b/README.md
index f420beb09..71d19784e 100644
--- a/README.md
+++ b/README.md
@@ -28,5 +28,5 @@ If you like, you can [donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cm
28* Infrastructure setup 28* Infrastructure setup
29* Eventually 3D displays to get proper 3D output working 29* Eventually 3D displays to get proper 3D output working
30* ... etc ... 30* ... etc ...
31 31
32We also more than gladly accept used 3DS consoles, preferrably ones with firmware 4.5 or lower! If you would like to give yours away, don't hesitate to join our IRC channel #citra on [Freenode](http://webchat.freenode.net/?channels=citra) and talk to neobrain or bunnei. Mind you, IRC is slow-paced, so it might be a while until people reply. If you're in a hurry you can just leave contact details in the channel or via private message and we'll get back to you. 32We also more than gladly accept used 3DS consoles, preferrably ones with firmware 4.5 or lower! If you would like to give yours away, don't hesitate to join our IRC channel #citra on [Freenode](http://webchat.freenode.net/?channels=citra) and talk to neobrain or bunnei. Mind you, IRC is slow-paced, so it might be a while until people reply. If you're in a hurry you can just leave contact details in the channel or via private message and we'll get back to you.
diff --git a/appveyor.yml b/appveyor.yml
index f2b656729..46362d1b4 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -35,11 +35,11 @@ after_build:
35 $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" 35 $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ",""
36 # Zip up the build folder 36 # Zip up the build folder
37 7z a $BUILD_NAME .\build\bin\release\* 37 7z a $BUILD_NAME .\build\bin\release\*
38 38
39 # Download winscp 39 # Download winscp
40 Invoke-WebRequest "http://hivelocity.dl.sourceforge.net/project/winscp/WinSCP/5.7/winscp570.zip" -OutFile "winscp570.zip" 40 Invoke-WebRequest "http://hivelocity.dl.sourceforge.net/project/winscp/WinSCP/5.7/winscp570.zip" -OutFile "winscp570.zip"
41 7z e -y winscp570.zip 41 7z e -y winscp570.zip
42 42
43 # Upload to server 43 # Upload to server
44 .\WinSCP.com /command ` 44 .\WinSCP.com /command `
45 "option batch abort" ` 45 "option batch abort" `
diff --git a/src/citra/resource.h b/src/citra/resource.h
index 0d42c8a8a..127896424 100644
--- a/src/citra/resource.h
+++ b/src/citra/resource.h
Binary files differ
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index efccdbec6..c05779380 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -89,15 +89,15 @@ if (Qt5_FOUND AND MSVC)
89 ) 89 )
90 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/") 90 set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/")
91 set(PLATFORMS ${DLL_DEST}platforms/) 91 set(PLATFORMS ${DLL_DEST}platforms/)
92 92
93 # windows commandline expects the / to be \ so switch them 93 # windows commandline expects the / to be \ so switch them
94 string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) 94 string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR})
95 string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) 95 string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR})
96 string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST}) 96 string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST})
97 string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS}) 97 string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS})
98 98
99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output 99 # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output
100 # cmake adds an extra check for command success which doesn't work too well with robocopy 100 # cmake adds an extra check for command success which doesn't work too well with robocopy
101 # so trick it into thinking the command was successful with the || cmd /c "exit /b 0" 101 # so trick it into thinking the command was successful with the || cmd /c "exit /b 0"
102 add_custom_command(TARGET citra-qt POST_BUILD 102 add_custom_command(TARGET citra-qt POST_BUILD
103 COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0" 103 COMMAND robocopy ${Qt5_DLL_DIR} ${DLL_DEST} ${Qt5_DLLS} /NJH /NJS /NDL /NFL /NC /NS /NP || cmd /c "exit /b 0"
diff --git a/src/citra_qt/bootmanager.cpp b/src/citra_qt/bootmanager.cpp
index 72b55e94d..3db09c65b 100644
--- a/src/citra_qt/bootmanager.cpp
+++ b/src/citra_qt/bootmanager.cpp
@@ -57,7 +57,7 @@ void EmuThread::run() {
57 Core::SingleStep(); 57 Core::SingleStep();
58 emit DebugModeEntered(); 58 emit DebugModeEntered();
59 yieldCurrentThread(); 59 yieldCurrentThread();
60 60
61 was_active = false; 61 was_active = false;
62 } else { 62 } else {
63 std::unique_lock<std::mutex> lock(running_mutex); 63 std::unique_lock<std::mutex> lock(running_mutex);
diff --git a/src/citra_qt/bootmanager.h b/src/citra_qt/bootmanager.h
index 16809eaae..475124319 100644
--- a/src/citra_qt/bootmanager.h
+++ b/src/citra_qt/bootmanager.h
@@ -80,7 +80,7 @@ signals:
80 * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns) 80 * @warning When connecting to this signal from other threads, make sure to specify either Qt::QueuedConnection (invoke slot within the destination object's message thread) or even Qt::BlockingQueuedConnection (additionally block source thread until slot returns)
81 */ 81 */
82 void DebugModeEntered(); 82 void DebugModeEntered();
83 83
84 /** 84 /**
85 * Emitted right before the CPU continues execution 85 * Emitted right before the CPU continues execution
86 * 86 *
diff --git a/src/citra_qt/debugger/callstack.cpp b/src/citra_qt/debugger/callstack.cpp
index 94e204717..6799ce844 100644
--- a/src/citra_qt/debugger/callstack.cpp
+++ b/src/citra_qt/debugger/callstack.cpp
@@ -39,7 +39,7 @@ void CallstackWidget::OnDebugModeEntered()
39 { 39 {
40 ret_addr = Memory::Read32(addr); 40 ret_addr = Memory::Read32(addr);
41 call_addr = ret_addr - 4; //get call address??? 41 call_addr = ret_addr - 4; //get call address???
42 42
43 if (Memory::GetPointer(call_addr) == nullptr) 43 if (Memory::GetPointer(call_addr) == nullptr)
44 break; 44 break;
45 45
diff --git a/src/citra_qt/main.cpp b/src/citra_qt/main.cpp
index f6010459a..8041816a0 100644
--- a/src/citra_qt/main.cpp
+++ b/src/citra_qt/main.cpp
@@ -127,7 +127,7 @@ GMainWindow::GMainWindow() : emu_thread(nullptr)
127 127
128 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); 128 ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer);
129 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); 129 SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked());
130 130
131 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); 131 ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool());
132 ToggleWindowMode(); 132 ToggleWindowMode();
133 133
diff --git a/src/citra_qt/main.ui b/src/citra_qt/main.ui
index 0942c28c8..9a809ee6c 100644
--- a/src/citra_qt/main.ui
+++ b/src/citra_qt/main.ui
@@ -24,7 +24,20 @@
24 <bool>true</bool> 24 <bool>true</bool>
25 </property> 25 </property>
26 <widget class="QWidget" name="centralwidget"> 26 <widget class="QWidget" name="centralwidget">
27 <layout class="QHBoxLayout" name="horizontalLayout"/> 27 <layout class="QHBoxLayout" name="horizontalLayout">
28 <property name="leftMargin">
29 <number>0</number>
30 </property>
31 <property name="topMargin">
32 <number>0</number>
33 </property>
34 <property name="rightMargin">
35 <number>0</number>
36 </property>
37 <property name="bottomMargin">
38 <number>0</number>
39 </property>
40 </layout>
28 </widget> 41 </widget>
29 <widget class="QMenuBar" name="menubar"> 42 <widget class="QMenuBar" name="menubar">
30 <property name="geometry"> 43 <property name="geometry">
@@ -92,7 +105,7 @@
92 </action> 105 </action>
93 <action name="action_Start"> 106 <action name="action_Start">
94 <property name="enabled"> 107 <property name="enabled">
95 <bool>false</bool> 108 <bool>false</bool>
96 </property> 109 </property>
97 <property name="text"> 110 <property name="text">
98 <string>&amp;Start</string> 111 <string>&amp;Start</string>
diff --git a/src/common/emu_window.cpp b/src/common/emu_window.cpp
index f5b6c7301..43facb85c 100644
--- a/src/common/emu_window.cpp
+++ b/src/common/emu_window.cpp
@@ -32,7 +32,7 @@ std::tuple<unsigned,unsigned> EmuWindow::ClipToTouchScreen(unsigned new_x, unsig
32 32
33 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); 33 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left);
34 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); 34 new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1);
35 35
36 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); 36 new_y = std::max(new_y, framebuffer_layout.bottom_screen.top);
37 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); 37 new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1);
38 38
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 7cdd1484f..24648ea33 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -16,7 +16,7 @@
16 #include <io.h> 16 #include <io.h>
17 #include <direct.h> // getcwd 17 #include <direct.h> // getcwd
18 #include <tchar.h> 18 #include <tchar.h>
19 19
20 // 64 bit offsets for windows 20 // 64 bit offsets for windows
21 #define fseeko _fseeki64 21 #define fseeko _fseeki64
22 #define ftello _ftelli64 22 #define ftello _ftelli64
diff --git a/src/common/swap.h b/src/common/swap.h
index 7e37655bf..588cebc70 100644
--- a/src/common/swap.h
+++ b/src/common/swap.h
@@ -135,7 +135,7 @@ template <>
135inline void swap<8>(u8* data) { 135inline void swap<8>(u8* data) {
136 *reinterpret_cast<u64*>(data) = swap64(data); 136 *reinterpret_cast<u64*>(data) = swap64(data);
137} 137}
138 138
139} // Namespace Common 139} // Namespace Common
140 140
141 141
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 42b4be938..bbc285168 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -36,6 +36,7 @@ set(SRCS
36 hle/kernel/shared_memory.cpp 36 hle/kernel/shared_memory.cpp
37 hle/kernel/thread.cpp 37 hle/kernel/thread.cpp
38 hle/kernel/timer.cpp 38 hle/kernel/timer.cpp
39 hle/kernel/vm_manager.cpp
39 hle/service/ac_u.cpp 40 hle/service/ac_u.cpp
40 hle/service/act_u.cpp 41 hle/service/act_u.cpp
41 hle/service/am_app.cpp 42 hle/service/am_app.cpp
@@ -147,6 +148,7 @@ set(HEADERS
147 hle/kernel/shared_memory.h 148 hle/kernel/shared_memory.h
148 hle/kernel/thread.h 149 hle/kernel/thread.h
149 hle/kernel/timer.h 150 hle/kernel/timer.h
151 hle/kernel/vm_manager.h
150 hle/result.h 152 hle/result.h
151 hle/service/ac_u.h 153 hle/service/ac_u.h
152 hle/service/act_u.h 154 hle/service/act_u.h
diff --git a/src/core/arm/disassembler/arm_disasm.cpp b/src/core/arm/disassembler/arm_disasm.cpp
index 913dc1454..f6d44d85a 100644
--- a/src/core/arm/disassembler/arm_disasm.cpp
+++ b/src/core/arm/disassembler/arm_disasm.cpp
@@ -813,7 +813,7 @@ Opcode ARM_Disasm::Decode11(uint32_t insn) {
813 // SWI 813 // SWI
814 return OP_SWI; 814 return OP_SWI;
815 } 815 }
816 816
817 uint8_t bit4 = (insn >> 4) & 0x1; 817 uint8_t bit4 = (insn >> 4) & 0x1;
818 uint8_t cpnum = (insn >> 8) & 0xf; 818 uint8_t cpnum = (insn >> 8) & 0xf;
819 819
diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
index b5d1b43cd..b00eb49a9 100644
--- a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp
@@ -134,7 +134,7 @@ static unsigned int DPO(Immediate)(ARMul_State* cpu, unsigned int sht_oper) {
134 unsigned int immed_8 = BITS(sht_oper, 0, 7); 134 unsigned int immed_8 = BITS(sht_oper, 0, 7);
135 unsigned int rotate_imm = BITS(sht_oper, 8, 11); 135 unsigned int rotate_imm = BITS(sht_oper, 8, 11);
136 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2); 136 unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2);
137 if (rotate_imm == 0) 137 if (rotate_imm == 0)
138 cpu->shifter_carry_out = cpu->CFlag; 138 cpu->shifter_carry_out = cpu->CFlag;
139 else 139 else
140 cpu->shifter_carry_out = BIT(shifter_operand, 31); 140 cpu->shifter_carry_out = BIT(shifter_operand, 31);
@@ -521,7 +521,7 @@ static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned
521 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; 521 addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8;
522 else 522 else
523 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; 523 addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8;
524 524
525 virt_addr = addr; 525 virt_addr = addr;
526} 526}
527 527
@@ -550,7 +550,7 @@ static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, unsig
550 550
551 if (U_BIT) 551 if (U_BIT)
552 addr = rn + offset_8; 552 addr = rn + offset_8;
553 else 553 else
554 addr = rn - offset_8; 554 addr = rn - offset_8;
555 555
556 virt_addr = addr; 556 virt_addr = addr;
@@ -1306,8 +1306,8 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index)
1306 inst_cream->Rd = BITS(inst, 12, 15); 1306 inst_cream->Rd = BITS(inst, 12, 15);
1307 inst_cream->shifter_operand = BITS(inst, 0, 11); 1307 inst_cream->shifter_operand = BITS(inst, 0, 11);
1308 inst_cream->shtop_func = get_shtop(inst); 1308 inst_cream->shtop_func = get_shtop(inst);
1309 1309
1310 if (inst_cream->Rd == 15) 1310 if (inst_cream->Rd == 15)
1311 inst_base->br = INDIRECT_BRANCH; 1311 inst_base->br = INDIRECT_BRANCH;
1312 1312
1313 return inst_base; 1313 return inst_base;
@@ -1350,7 +1350,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index)
1350 inst_cream->shifter_operand = BITS(inst, 0, 11); 1350 inst_cream->shifter_operand = BITS(inst, 0, 11);
1351 inst_cream->shtop_func = get_shtop(inst); 1351 inst_cream->shtop_func = get_shtop(inst);
1352 1352
1353 if (inst_cream->Rd == 15) 1353 if (inst_cream->Rd == 15)
1354 inst_base->br = INDIRECT_BRANCH; 1354 inst_base->br = INDIRECT_BRANCH;
1355 return inst_base; 1355 return inst_base;
1356} 1356}
@@ -3269,7 +3269,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index)
3269#define VFP_INTERPRETER_STRUCT 3269#define VFP_INTERPRETER_STRUCT
3270#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3270#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3271#undef VFP_INTERPRETER_STRUCT 3271#undef VFP_INTERPRETER_STRUCT
3272 3272
3273#define VFP_INTERPRETER_TRANS 3273#define VFP_INTERPRETER_TRANS
3274#include "core/arm/skyeye_common/vfp/vfpinstr.cpp" 3274#include "core/arm/skyeye_common/vfp/vfpinstr.cpp"
3275#undef VFP_INTERPRETER_TRANS 3275#undef VFP_INTERPRETER_TRANS
@@ -3478,9 +3478,9 @@ const transop_fp_t arm_instruction_trans[] = {
3478 INTERPRETER_TRANSLATE(bbl), 3478 INTERPRETER_TRANSLATE(bbl),
3479 3479
3480 // All the thumb instructions should be placed the end of table 3480 // All the thumb instructions should be placed the end of table
3481 INTERPRETER_TRANSLATE(b_2_thumb), 3481 INTERPRETER_TRANSLATE(b_2_thumb),
3482 INTERPRETER_TRANSLATE(b_cond_thumb), 3482 INTERPRETER_TRANSLATE(b_cond_thumb),
3483 INTERPRETER_TRANSLATE(bl_1_thumb), 3483 INTERPRETER_TRANSLATE(bl_1_thumb),
3484 INTERPRETER_TRANSLATE(bl_2_thumb), 3484 INTERPRETER_TRANSLATE(bl_2_thumb),
3485 INTERPRETER_TRANSLATE(blx_1_thumb) 3485 INTERPRETER_TRANSLATE(blx_1_thumb)
3486}; 3486};
@@ -4338,7 +4338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4338 } 4338 }
4339 } 4339 }
4340 if (BIT(inst, 13)) { 4340 if (BIT(inst, 13)) {
4341 if (cpu->Mode == USER32MODE) 4341 if (cpu->Mode == USER32MODE)
4342 cpu->Reg[13] = ReadMemory32(cpu, addr); 4342 cpu->Reg[13] = ReadMemory32(cpu, addr);
4343 else 4343 else
4344 cpu->Reg_usr[0] = ReadMemory32(cpu, addr); 4344 cpu->Reg_usr[0] = ReadMemory32(cpu, addr);
@@ -4346,7 +4346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
4346 addr += 4; 4346 addr += 4;
4347 } 4347 }
4348 if (BIT(inst, 14)) { 4348 if (BIT(inst, 14)) {
4349 if (cpu->Mode == USER32MODE) 4349 if (cpu->Mode == USER32MODE)
4350 cpu->Reg[14] = ReadMemory32(cpu, addr); 4350 cpu->Reg[14] = ReadMemory32(cpu, addr);
4351 else 4351 else
4352 cpu->Reg_usr[1] = ReadMemory32(cpu, addr); 4352 cpu->Reg_usr[1] = ReadMemory32(cpu, addr);
@@ -5148,7 +5148,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5148 REV16_INST: 5148 REV16_INST:
5149 REVSH_INST: 5149 REVSH_INST:
5150 { 5150 {
5151 5151
5152 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { 5152 if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) {
5153 rev_inst* const inst_cream = (rev_inst*)inst_base->component; 5153 rev_inst* const inst_cream = (rev_inst*)inst_base->component;
5154 5154
@@ -5721,7 +5721,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
5721 5721
5722 if (do_swap) 5722 if (do_swap)
5723 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); 5723 rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16));
5724 5724
5725 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); 5725 const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF);
5726 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); 5726 const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF);
5727 s64 result; 5727 s64 result;
@@ -6583,7 +6583,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6583 { 6583 {
6584 u32 lo_val = 0; 6584 u32 lo_val = 0;
6585 u32 hi_val = 0; 6585 u32 hi_val = 0;
6586 6586
6587 // UHADD16 6587 // UHADD16
6588 if (op2 == 0x00) { 6588 if (op2 == 0x00) {
6589 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); 6589 lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF);
@@ -6772,7 +6772,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) {
6772 6772
6773 u16 lo_val = 0; 6773 u16 lo_val = 0;
6774 u16 hi_val = 0; 6774 u16 hi_val = 0;
6775 6775
6776 // UQADD16 6776 // UQADD16
6777 if (op2 == 0x00) { 6777 if (op2 == 0x00) {
6778 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF); 6778 lo_val = ARMul_UnsignedSaturatedAdd16(rn_val & 0xFFFF, rm_val & 0xFFFF);
diff --git a/src/core/arm/dyncom/arm_dyncom_thumb.cpp b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
index cdaf21450..2fc8170be 100644
--- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp
+++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp
@@ -184,7 +184,7 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) {
184 case 9: // LDR Rd,[PC,#imm8] 184 case 9: // LDR Rd,[PC,#imm8]
185 *ainstr = 0xE59F0000 // base 185 *ainstr = 0xE59F0000 // base
186 | ((tinstr & 0x0700) << (12 - 8)) // Rd 186 | ((tinstr & 0x0700) << (12 - 8)) // Rd
187 |((tinstr & 0x00FF) << (2 - 0)); // off8 187 |((tinstr & 0x00FF) << (2 - 0)); // off8
188 break; 188 break;
189 189
190 case 10: 190 case 10:
diff --git a/src/core/arm/interpreter/armsupp.cpp b/src/core/arm/interpreter/armsupp.cpp
index 1b078dc71..83f7f3e2c 100644
--- a/src/core/arm/interpreter/armsupp.cpp
+++ b/src/core/arm/interpreter/armsupp.cpp
@@ -628,7 +628,7 @@ void WriteCP15Register(ARMul_State* cpu, u32 value, u32 crn, u32 opcode_1, u32 c
628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; 628 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value;
629 else if (opcode_2 == 5) 629 else if (opcode_2 == 5)
630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; 630 cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value;
631 631
632 } 632 }
633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) 633 else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2)
634 { 634 {
diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h
index 08ece69b6..d2c901100 100644
--- a/src/core/arm/skyeye_common/armdefs.h
+++ b/src/core/arm/skyeye_common/armdefs.h
@@ -1,16 +1,16 @@
1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. 1/* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator.
2 Copyright (C) 1994 Advanced RISC Machines Ltd. 2 Copyright (C) 1994 Advanced RISC Machines Ltd.
3 3
4 This program is free software; you can redistribute it and/or modify 4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by 5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or 6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version. 7 (at your option) any later version.
8 8
9 This program is distributed in the hope that it will be useful, 9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details. 12 GNU General Public License for more details.
13 13
14 You should have received a copy of the GNU General Public License 14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software 15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
diff --git a/src/core/arm/skyeye_common/vfp/vfp_helper.h b/src/core/arm/skyeye_common/vfp/vfp_helper.h
index ccc0212ab..2007d6dc4 100644
--- a/src/core/arm/skyeye_common/vfp/vfp_helper.h
+++ b/src/core/arm/skyeye_common/vfp/vfp_helper.h
@@ -18,10 +18,10 @@
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19*/ 19*/
20 20
21/* 21/*
22 * The following code is derivative from Linux Android kernel vfp 22 * The following code is derivative from Linux Android kernel vfp
23 * floating point support. 23 * floating point support.
24 * 24 *
25 * Copyright (C) 2004 ARM Limited. 25 * Copyright (C) 2004 ARM Limited.
26 * Written by Deep Blue Solutions Limited. 26 * Written by Deep Blue Solutions Limited.
27 * 27 *
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp
index f70c84c3d..e53c2e606 100644
--- a/src/core/core_timing.cpp
+++ b/src/core/core_timing.cpp
@@ -549,7 +549,7 @@ std::string GetScheduledEventsSummary() {
549 const char* name = event_types[event->type].name; 549 const char* name = event_types[event->type].name;
550 if (!name) 550 if (!name)
551 name = "[unknown]"; 551 name = "[unknown]";
552 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, 552 text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time,
553 (u32)(event->userdata >> 32), (u32)(event->userdata)); 553 (u32)(event->userdata >> 32), (u32)(event->userdata));
554 event = event->next; 554 event = event->next;
555 } 555 }
diff --git a/src/core/core_timing.h b/src/core/core_timing.h
index 01519608d..64f5b06d9 100644
--- a/src/core/core_timing.h
+++ b/src/core/core_timing.h
@@ -87,7 +87,7 @@ void UnregisterAllEvents();
87/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, 87/// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk,
88/// when we implement state saves. 88/// when we implement state saves.
89/** 89/**
90 * Schedules an event to run after the specified number of cycles, 90 * Schedules an event to run after the specified number of cycles,
91 * with an optional parameter to be passed to the callback handler. 91 * with an optional parameter to be passed to the callback handler.
92 * This must be run ONLY from within the cpu thread. 92 * This must be run ONLY from within the cpu thread.
93 * @param cycles_into_future The number of cycles after which this event will be fired 93 * @param cycles_into_future The number of cycles after which this event will be fired
diff --git a/src/core/file_sys/archive_extsavedata.cpp b/src/core/file_sys/archive_extsavedata.cpp
index 38d498d0e..975aafb35 100644
--- a/src/core/file_sys/archive_extsavedata.cpp
+++ b/src/core/file_sys/archive_extsavedata.cpp
@@ -30,8 +30,8 @@ std::string GetExtSaveDataPath(const std::string& mount_point, const Path& path)
30std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { 30std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) {
31 if (shared) 31 if (shared)
32 return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str()); 32 return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str());
33 33
34 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), 34 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(),
35 SYSTEM_ID.c_str(), SDCARD_ID.c_str()); 35 SYSTEM_ID.c_str(), SDCARD_ID.c_str());
36} 36}
37 37
diff --git a/src/core/file_sys/archive_extsavedata.h b/src/core/file_sys/archive_extsavedata.h
index c77c04e44..ef0b27bde 100644
--- a/src/core/file_sys/archive_extsavedata.h
+++ b/src/core/file_sys/archive_extsavedata.h
@@ -35,14 +35,14 @@ public:
35private: 35private:
36 /** 36 /**
37 * This holds the full directory path for this archive, it is only set after a successful call 37 * This holds the full directory path for this archive, it is only set after a successful call
38 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. 38 * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>.
39 * See GetExtSaveDataPath for the code that extracts this data from an archive path. 39 * See GetExtSaveDataPath for the code that extracts this data from an archive path.
40 */ 40 */
41 std::string mount_point; 41 std::string mount_point;
42}; 42};
43 43
44/** 44/**
45 * Constructs a path to the concrete ExtData archive in the host filesystem based on the 45 * Constructs a path to the concrete ExtData archive in the host filesystem based on the
46 * input Path and base mount point. 46 * input Path and base mount point.
47 * @param mount_point The base mount point of the ExtSaveData archives. 47 * @param mount_point The base mount point of the ExtSaveData archives.
48 * @param path The path that identifies the requested concrete ExtSaveData archive. 48 * @param path The path that identifies the requested concrete ExtSaveData archive.
diff --git a/src/core/file_sys/archive_savedata.cpp b/src/core/file_sys/archive_savedata.cpp
index 8dff51966..a92309377 100644
--- a/src/core/file_sys/archive_savedata.cpp
+++ b/src/core/file_sys/archive_savedata.cpp
@@ -21,7 +21,7 @@
21namespace FileSys { 21namespace FileSys {
22 22
23static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { 23static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) {
24 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), 24 return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(),
25 SYSTEM_ID.c_str(), SDCARD_ID.c_str()); 25 SYSTEM_ID.c_str(), SDCARD_ID.c_str());
26} 26}
27 27
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h
index 201ec0db9..1b8249c74 100644
--- a/src/core/hle/kernel/resource_limit.h
+++ b/src/core/hle/kernel/resource_limit.h
@@ -81,13 +81,13 @@ public:
81 s32 max_timers = 0; 81 s32 max_timers = 0;
82 s32 max_shared_mems = 0; 82 s32 max_shared_mems = 0;
83 s32 max_address_arbiters = 0; 83 s32 max_address_arbiters = 0;
84 84
85 /// Max CPU time that the processes in this category can utilize 85 /// Max CPU time that the processes in this category can utilize
86 s32 max_cpu_time = 0; 86 s32 max_cpu_time = 0;
87 87
88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that 88 // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that
89 // APPLICATION resource limits should not be affected by the objects created by service modules. 89 // APPLICATION resource limits should not be affected by the objects created by service modules.
90 // Currently we have no way of distinguishing if a Create was called by the running application, 90 // Currently we have no way of distinguishing if a Create was called by the running application,
91 // or by a service module. Approach this once we have separated the service modules into their own processes 91 // or by a service module. Approach this once we have separated the service modules into their own processes
92 92
93 /// Current memory that the processes in this category are using 93 /// Current memory that the processes in this category are using
diff --git a/src/core/hle/kernel/semaphore.cpp b/src/core/hle/kernel/semaphore.cpp
index dbb4c9b7f..96d61ed3a 100644
--- a/src/core/hle/kernel/semaphore.cpp
+++ b/src/core/hle/kernel/semaphore.cpp
@@ -42,7 +42,7 @@ void Semaphore::Acquire() {
42 42
43ResultVal<s32> Semaphore::Release(s32 release_count) { 43ResultVal<s32> Semaphore::Release(s32 release_count) {
44 if (max_count - available_count < release_count) 44 if (max_count - available_count < release_count)
45 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, 45 return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel,
46 ErrorSummary::InvalidArgument, ErrorLevel::Permanent); 46 ErrorSummary::InvalidArgument, ErrorLevel::Permanent);
47 47
48 s32 previous_count = available_count; 48 s32 previous_count = available_count;
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 690d33b55..22c795ad4 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -100,7 +100,7 @@ void Thread::Stop() {
100 } 100 }
101 101
102 status = THREADSTATUS_DEAD; 102 status = THREADSTATUS_DEAD;
103 103
104 WakeupAllWaitingThreads(); 104 WakeupAllWaitingThreads();
105 105
106 // Clean up any dangling references in objects that this thread was waiting for 106 // Clean up any dangling references in objects that this thread was waiting for
@@ -169,7 +169,7 @@ static void PriorityBoostStarvedThreads() {
169 } 169 }
170} 170}
171 171
172/** 172/**
173 * Switches the CPU's active thread context to that of the specified thread 173 * Switches the CPU's active thread context to that of the specified thread
174 * @param new_thread The thread to switch to 174 * @param new_thread The thread to switch to
175 */ 175 */
@@ -353,7 +353,7 @@ void Thread::ResumeFromWait() {
353 GetObjectId()); 353 GetObjectId());
354 return; 354 return;
355 } 355 }
356 356
357 ready_queue.push_back(current_priority, this); 357 ready_queue.push_back(current_priority, this);
358 status = THREADSTATUS_READY; 358 status = THREADSTATUS_READY;
359} 359}
@@ -504,7 +504,7 @@ void Reschedule() {
504 } else if (next) { 504 } else if (next) {
505 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); 505 LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId());
506 } 506 }
507 507
508 SwitchContext(next); 508 SwitchContext(next);
509} 509}
510 510
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h
index 389928178..2c65419c3 100644
--- a/src/core/hle/kernel/thread.h
+++ b/src/core/hle/kernel/thread.h
@@ -94,7 +94,7 @@ public:
94 * @return The thread's ID 94 * @return The thread's ID
95 */ 95 */
96 u32 GetThreadId() const { return thread_id; } 96 u32 GetThreadId() const { return thread_id; }
97 97
98 /** 98 /**
99 * Release an acquired wait object 99 * Release an acquired wait object
100 * @param wait_object WaitObject to release 100 * @param wait_object WaitObject to release
diff --git a/src/core/hle/kernel/timer.cpp b/src/core/hle/kernel/timer.cpp
index 25d066bf1..8aa4110a6 100644
--- a/src/core/hle/kernel/timer.cpp
+++ b/src/core/hle/kernel/timer.cpp
@@ -88,7 +88,7 @@ static void TimerCallback(u64 timer_handle, int cycles_late) {
88 if (timer->interval_delay != 0) { 88 if (timer->interval_delay != 0) {
89 // Reschedule the timer with the interval delay 89 // Reschedule the timer with the interval delay
90 u64 interval_microseconds = timer->interval_delay / 1000; 90 u64 interval_microseconds = timer->interval_delay / 1000;
91 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, 91 CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late,
92 timer_callback_event_type, timer_handle); 92 timer_callback_event_type, timer_handle);
93 } 93 }
94} 94}
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp
new file mode 100644
index 000000000..b2dd21542
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.cpp
@@ -0,0 +1,245 @@
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 "common/assert.h"
6
7#include "core/hle/kernel/vm_manager.h"
8#include "core/memory_setup.h"
9
10namespace Kernel {
11
12bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
13 ASSERT(base + size == next.base);
14 if (permissions != next.permissions ||
15 meminfo_state != next.meminfo_state ||
16 type != next.type) {
17 return false;
18 }
19 if (type == VMAType::AllocatedMemoryBlock &&
20 (backing_block != next.backing_block || offset + size != next.offset)) {
21 return false;
22 }
23 if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
24 return false;
25 }
26 if (type == VMAType::MMIO && paddr + size != next.paddr) {
27 return false;
28 }
29 return true;
30}
31
32VMManager::VMManager() {
33 Reset();
34}
35
36void VMManager::Reset() {
37 vma_map.clear();
38
39 // Initialize the map with a single free region covering the entire managed space.
40 VirtualMemoryArea initial_vma;
41 initial_vma.size = MAX_ADDRESS;
42 vma_map.emplace(initial_vma.base, initial_vma);
43
44 UpdatePageTableForVMA(initial_vma);
45}
46
47VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
48 return std::prev(vma_map.upper_bound(target));
49}
50
51ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target,
52 std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) {
53 ASSERT(block != nullptr);
54 ASSERT(offset + size <= block->size());
55
56 // This is the appropriately sized VMA that will turn into our allocation.
57 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
58 VirtualMemoryArea& final_vma = vma_handle->second;
59 ASSERT(final_vma.size == size);
60
61 final_vma.type = VMAType::AllocatedMemoryBlock;
62 final_vma.permissions = VMAPermission::ReadWrite;
63 final_vma.meminfo_state = state;
64 final_vma.backing_block = block;
65 final_vma.offset = offset;
66 UpdatePageTableForVMA(final_vma);
67
68 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
69}
70
71ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) {
72 ASSERT(memory != nullptr);
73
74 // This is the appropriately sized VMA that will turn into our allocation.
75 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
76 VirtualMemoryArea& final_vma = vma_handle->second;
77 ASSERT(final_vma.size == size);
78
79 final_vma.type = VMAType::BackingMemory;
80 final_vma.permissions = VMAPermission::ReadWrite;
81 final_vma.meminfo_state = state;
82 final_vma.backing_memory = memory;
83 UpdatePageTableForVMA(final_vma);
84
85 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
86}
87
88ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) {
89 // This is the appropriately sized VMA that will turn into our allocation.
90 CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
91 VirtualMemoryArea& final_vma = vma_handle->second;
92 ASSERT(final_vma.size == size);
93
94 final_vma.type = VMAType::MMIO;
95 final_vma.permissions = VMAPermission::ReadWrite;
96 final_vma.meminfo_state = state;
97 final_vma.paddr = paddr;
98 UpdatePageTableForVMA(final_vma);
99
100 return MakeResult<VMAHandle>(MergeAdjacent(vma_handle));
101}
102
103void VMManager::Unmap(VMAHandle vma_handle) {
104 VMAIter iter = StripIterConstness(vma_handle);
105
106 VirtualMemoryArea& vma = iter->second;
107 vma.type = VMAType::Free;
108 vma.permissions = VMAPermission::None;
109 vma.meminfo_state = MemoryState::Free;
110
111 vma.backing_block = nullptr;
112 vma.offset = 0;
113 vma.backing_memory = nullptr;
114 vma.paddr = 0;
115
116 UpdatePageTableForVMA(vma);
117
118 MergeAdjacent(iter);
119}
120
121void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) {
122 VMAIter iter = StripIterConstness(vma_handle);
123
124 VirtualMemoryArea& vma = iter->second;
125 vma.permissions = new_perms;
126 UpdatePageTableForVMA(vma);
127
128 MergeAdjacent(iter);
129}
130
131VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) {
132 // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given
133 // non-const access to its container.
134 return vma_map.erase(iter, iter); // Erases an empty range of elements
135}
136
137ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) {
138 ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size);
139 ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base);
140
141 VMAIter vma_handle = StripIterConstness(FindVMA(base));
142 if (vma_handle == vma_map.end()) {
143 // Target address is outside the range managed by the kernel
144 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
145 ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5
146 }
147
148 VirtualMemoryArea& vma = vma_handle->second;
149 if (vma.type != VMAType::Free) {
150 // Region is already allocated
151 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
152 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
153 }
154
155 u32 start_in_vma = base - vma.base;
156 u32 end_in_vma = start_in_vma + size;
157
158 if (end_in_vma > vma.size) {
159 // Requested allocation doesn't fit inside VMA
160 return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS,
161 ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5
162 }
163
164 if (end_in_vma != vma.size) {
165 // Split VMA at the end of the allocated region
166 SplitVMA(vma_handle, end_in_vma);
167 }
168 if (start_in_vma != 0) {
169 // Split VMA at the start of the allocated region
170 vma_handle = SplitVMA(vma_handle, start_in_vma);
171 }
172
173 return MakeResult<VMAIter>(vma_handle);
174}
175
176VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) {
177 VirtualMemoryArea& old_vma = vma_handle->second;
178 VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA
179
180 // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably
181 // a bug. This restriction might be removed later.
182 ASSERT(offset_in_vma < old_vma.size);
183 ASSERT(offset_in_vma > 0);
184
185 old_vma.size = offset_in_vma;
186 new_vma.base += offset_in_vma;
187 new_vma.size -= offset_in_vma;
188
189 switch (new_vma.type) {
190 case VMAType::Free:
191 break;
192 case VMAType::AllocatedMemoryBlock:
193 new_vma.offset += offset_in_vma;
194 break;
195 case VMAType::BackingMemory:
196 new_vma.backing_memory += offset_in_vma;
197 break;
198 case VMAType::MMIO:
199 new_vma.paddr += offset_in_vma;
200 break;
201 }
202
203 ASSERT(old_vma.CanBeMergedWith(new_vma));
204
205 return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma);
206}
207
208VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
209 VMAIter next_vma = std::next(iter);
210 if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) {
211 iter->second.size += next_vma->second.size;
212 vma_map.erase(next_vma);
213 }
214
215 if (iter != vma_map.begin()) {
216 VMAIter prev_vma = std::prev(iter);
217 if (prev_vma->second.CanBeMergedWith(iter->second)) {
218 prev_vma->second.size += iter->second.size;
219 vma_map.erase(iter);
220 iter = prev_vma;
221 }
222 }
223
224 return iter;
225}
226
227void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
228 switch (vma.type) {
229 case VMAType::Free:
230 Memory::UnmapRegion(vma.base, vma.size);
231 break;
232 case VMAType::AllocatedMemoryBlock:
233 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset);
234 break;
235 case VMAType::BackingMemory:
236 Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory);
237 break;
238 case VMAType::MMIO:
239 // TODO(yuriks): Add support for MMIO handlers.
240 Memory::MapIoRegion(vma.base, vma.size);
241 break;
242 }
243}
244
245}
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h
new file mode 100644
index 000000000..22b724603
--- /dev/null
+++ b/src/core/hle/kernel/vm_manager.h
@@ -0,0 +1,200 @@
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 <map>
8#include <memory>
9#include <string>
10#include <vector>
11
12#include "common/common_types.h"
13
14#include "core/hle/result.h"
15
16namespace Kernel {
17
18enum class VMAType : u8 {
19 /// VMA represents an unmapped region of the address space.
20 Free,
21 /// VMA is backed by a ref-counted allocate memory block.
22 AllocatedMemoryBlock,
23 /// VMA is backed by a raw, unmanaged pointer.
24 BackingMemory,
25 /// VMA is mapped to MMIO registers at a fixed PAddr.
26 MMIO,
27 // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP
28};
29
30/// Permissions for mapped memory blocks
31enum class VMAPermission : u8 {
32 None = 0,
33 Read = 1,
34 Write = 2,
35 Execute = 4,
36
37 ReadWrite = Read | Write,
38 ReadExecute = Read | Execute,
39 WriteExecute = Write | Execute,
40 ReadWriteExecute = Read | Write | Execute,
41};
42
43/// Set of values returned in MemoryInfo.state by svcQueryMemory.
44enum class MemoryState : u8 {
45 Free = 0,
46 Reserved = 1,
47 IO = 2,
48 Static = 3,
49 Code = 4,
50 Private = 5,
51 Shared = 6,
52 Continuous = 7,
53 Aliased = 8,
54 Alias = 9,
55 AliasCode = 10,
56 Locked = 11,
57};
58
59/**
60 * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space
61 * with homogeneous attributes across its extents. In this particular implementation each VMA is
62 * also backed by a single host memory allocation.
63 */
64struct VirtualMemoryArea {
65 /// Virtual base address of the region.
66 VAddr base = 0;
67 /// Size of the region.
68 u32 size = 0;
69
70 VMAType type = VMAType::Free;
71 VMAPermission permissions = VMAPermission::None;
72 /// Tag returned by svcQueryMemory. Not otherwise used.
73 MemoryState meminfo_state = MemoryState::Free;
74
75 // Settings for type = AllocatedMemoryBlock
76 /// Memory block backing this VMA.
77 std::shared_ptr<std::vector<u8>> backing_block = nullptr;
78 /// Offset into the backing_memory the mapping starts from.
79 u32 offset = 0;
80
81 // Settings for type = BackingMemory
82 /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
83 u8* backing_memory = nullptr;
84
85 // Settings for type = MMIO
86 /// Physical address of the register area this VMA maps to.
87 PAddr paddr = 0;
88
89 /// Tests if this area can be merged to the right with `next`.
90 bool CanBeMergedWith(const VirtualMemoryArea& next) const;
91};
92
93/**
94 * Manages a process' virtual addressing space. This class maintains a list of allocated and free
95 * regions in the address space, along with their attributes, and allows kernel clients to
96 * manipulate it, adjusting the page table to match.
97 *
98 * This is similar in idea and purpose to the VM manager present in operating system kernels, with
99 * the main difference being that it doesn't have to support swapping or memory mapping of files.
100 * The implementation is also simplified by not having to allocate page frames. See these articles
101 * about the Linux kernel for an explantion of the concept and implementation:
102 * - 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/
104 */
105class VMManager {
106 // TODO(yuriks): Make page tables switchable to support multiple VMManagers
107public:
108 /**
109 * The maximum amount of address space managed by the kernel. Addresses above this are never used.
110 * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000.
111 */
112 static const u32 MAX_ADDRESS = 0x40000000;
113
114 /**
115 * A map covering the entirety of the managed address space, keyed by the `base` field of each
116 * VMA. It must always be modified by splitting or merging VMAs, so that the invariant
117 * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be
118 * merged when possible so that no two similar and adjacent regions exist that have not been
119 * merged.
120 */
121 std::map<VAddr, VirtualMemoryArea> vma_map;
122 using VMAHandle = decltype(vma_map)::const_iterator;
123
124 VMManager();
125
126 /// Clears the address space map, re-initializing with a single free area.
127 void Reset();
128
129 /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
130 VMAHandle FindVMA(VAddr target) const;
131
132 // TODO(yuriks): Should these functions actually return the handle?
133
134 /**
135 * Maps part of a ref-counted block of memory at a given address.
136 *
137 * @param target The guest address to start the mapping at.
138 * @param block The block to be mapped.
139 * @param offset Offset into `block` to map from.
140 * @param size Size of the mapping.
141 * @param state MemoryState tag to attach to the VMA.
142 */
143 ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block,
144 u32 offset, u32 size, MemoryState state);
145
146 /**
147 * Maps an unmanaged host memory pointer at a given address.
148 *
149 * @param target The guest address to start the mapping at.
150 * @param memory The memory to be mapped.
151 * @param size Size of the mapping.
152 * @param state MemoryState tag to attach to the VMA.
153 */
154 ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
155
156 /**
157 * Maps a memory-mapped IO region at a given address.
158 *
159 * @param target The guest address to start the mapping at.
160 * @param paddr The physical address where the registers are present.
161 * @param size Size of the mapping.
162 * @param state MemoryState tag to attach to the VMA.
163 */
164 ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state);
165
166 /// Unmaps the given VMA.
167 void Unmap(VMAHandle vma);
168
169 /// Changes the permissions of the given VMA.
170 void Reprotect(VMAHandle vma, VMAPermission new_perms);
171
172private:
173 using VMAIter = decltype(vma_map)::iterator;
174
175 /// Converts a VMAHandle to a mutable VMAIter.
176 VMAIter StripIterConstness(const VMAHandle& iter);
177
178 /**
179 * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing
180 * the appropriate error checking.
181 */
182 ResultVal<VMAIter> CarveVMA(VAddr base, u32 size);
183
184 /**
185 * Splits a VMA in two, at the specified offset.
186 * @returns the right side of the split, with the original iterator becoming the left side.
187 */
188 VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma);
189
190 /**
191 * Checks for and merges the specified VMA with adjacent ones if possible.
192 * @returns the merged VMA or the original if no merging was possible.
193 */
194 VMAIter MergeAdjacent(VMAIter vma);
195
196 /// Updates the pages corresponding to this VMA so they match the VMA's attributes.
197 void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
198};
199
200}
diff --git a/src/core/hle/service/apt/apt.cpp b/src/core/hle/service/apt/apt.cpp
index 3fd4cfb08..5d14f393d 100644
--- a/src/core/hle/service/apt/apt.cpp
+++ b/src/core/hle/service/apt/apt.cpp
@@ -151,7 +151,7 @@ void SendParameter(Service::Interface* self) {
151 u32 handle = cmd_buff[6]; 151 u32 handle = cmd_buff[6];
152 u32 size = cmd_buff[7]; 152 u32 size = cmd_buff[7];
153 u32 in_param_buffer_ptr = cmd_buff[8]; 153 u32 in_param_buffer_ptr = cmd_buff[8];
154 154
155 cmd_buff[1] = RESULT_SUCCESS.raw; // No error 155 cmd_buff[1] = RESULT_SUCCESS.raw; // No error
156 156
157 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X," 157 LOG_WARNING(Service_APT, "(STUBBED) called src_app_id=0x%08X, dst_app_id=0x%08X, signal_type=0x%08X,"
@@ -283,7 +283,7 @@ void Init() {
283 AddService(new APT_A_Interface); 283 AddService(new APT_A_Interface);
284 AddService(new APT_S_Interface); 284 AddService(new APT_S_Interface);
285 AddService(new APT_U_Interface); 285 AddService(new APT_U_Interface);
286 286
287 // Load the shared system font (if available). 287 // Load the shared system font (if available).
288 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header 288 // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header
289 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided 289 // generated by the APT:U service. The best way to get is by dumping it from RAM. We've provided
diff --git a/src/core/hle/service/apt/apt.h b/src/core/hle/service/apt/apt.h
index e7fa39325..a03e1712a 100644
--- a/src/core/hle/service/apt/apt.h
+++ b/src/core/hle/service/apt/apt.h
@@ -63,7 +63,7 @@ void Initialize(Service::Interface* self);
63 * 4 : Handle to shared font memory 63 * 4 : Handle to shared font memory
64 */ 64 */
65void GetSharedFont(Service::Interface* self); 65void GetSharedFont(Service::Interface* self);
66 66
67/** 67/**
68 * APT::NotifyToWait service function 68 * APT::NotifyToWait service function
69 * Inputs: 69 * Inputs:
@@ -88,7 +88,7 @@ void Enable(Service::Interface* self);
88 * 4 : Home Menu AppId 88 * 4 : Home Menu AppId
89 * 5 : AppID of currently active app 89 * 5 : AppID of currently active app
90 */ 90 */
91void GetAppletManInfo(Service::Interface* self); 91void GetAppletManInfo(Service::Interface* self);
92 92
93/** 93/**
94 * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. 94 * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet.
@@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self);
100 * Outputs: 100 * Outputs:
101 * 0 : Return header 101 * 0 : Return header
102 * 1 : Result of function, 0 on success, otherwise error code 102 * 1 : Result of function, 0 on success, otherwise error code
103 * 2 : Output, 0 = not registered, 1 = registered. 103 * 2 : Output, 0 = not registered, 1 = registered.
104 */ 104 */
105void IsRegistered(Service::Interface* self); 105void IsRegistered(Service::Interface* self);
106 106
107void InquireNotification(Service::Interface* self); 107void InquireNotification(Service::Interface* self);
108 108
109/** 109/**
110 * APT::SendParameter service function. This sets the parameter data state. 110 * APT::SendParameter service function. This sets the parameter data state.
111 * Inputs: 111 * Inputs:
112 * 1 : Source AppID 112 * 1 : Source AppID
113 * 2 : Destination AppID 113 * 2 : Destination AppID
diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h
index 71f1e7464..6fb51d57d 100644
--- a/src/core/hle/service/boss_p.h
+++ b/src/core/hle/service/boss_p.h
@@ -14,7 +14,7 @@ namespace BOSS_P {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 17
18 std::string GetPortName() const override { 18 std::string GetPortName() const override {
19 return "boss:P"; 19 return "boss:P";
20 } 20 }
diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h
index 2668f2dfd..89e77fe47 100644
--- a/src/core/hle/service/boss_u.h
+++ b/src/core/hle/service/boss_u.h
@@ -14,7 +14,7 @@ namespace BOSS_U {
14class Interface : public Service::Interface { 14class Interface : public Service::Interface {
15public: 15public:
16 Interface(); 16 Interface();
17 17
18 std::string GetPortName() const override { 18 std::string GetPortName() const override {
19 return "boss:U"; 19 return "boss:U";
20 } 20 }
diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp
index fcfd87715..ecda0dbdf 100644
--- a/src/core/hle/service/cam_u.cpp
+++ b/src/core/hle/service/cam_u.cpp
@@ -19,5 +19,5 @@ namespace CAM_U {
19Interface::Interface() { 19Interface::Interface() {
20 //Register(FunctionTable); 20 //Register(FunctionTable);
21} 21}
22 22
23} // namespace 23} // namespace
diff --git a/src/core/hle/service/cfg/cfg.cpp b/src/core/hle/service/cfg/cfg.cpp
index d42682883..62ad90fdc 100644
--- a/src/core/hle/service/cfg/cfg.cpp
+++ b/src/core/hle/service/cfg/cfg.cpp
@@ -315,11 +315,11 @@ void Init() {
315 AddService(new CFG_I_Interface); 315 AddService(new CFG_I_Interface);
316 AddService(new CFG_S_Interface); 316 AddService(new CFG_S_Interface);
317 AddService(new CFG_U_Interface); 317 AddService(new CFG_U_Interface);
318 318
319 // Open the SystemSaveData archive 0x00010017 319 // Open the SystemSaveData archive 0x00010017
320 FileSys::Path archive_path(cfg_system_savedata_id); 320 FileSys::Path archive_path(cfg_system_savedata_id);
321 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); 321 auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path);
322 322
323 // If the archive didn't exist, create the files inside 323 // If the archive didn't exist, create the files inside
324 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { 324 if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) {
325 // Format the archive to create the directories 325 // Format the archive to create the directories
diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp
index 6d4a9c7c9..7cab68024 100644
--- a/src/core/hle/service/fs/archive.cpp
+++ b/src/core/hle/service/fs/archive.cpp
@@ -254,7 +254,7 @@ ResultVal<ArchiveHandle> OpenArchive(ArchiveIdCode id_code, FileSys::Path& archi
254 254
255 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); 255 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path));
256 256
257 // This should never even happen in the first place with 64-bit handles, 257 // This should never even happen in the first place with 64-bit handles,
258 while (handle_map.count(next_handle) != 0) { 258 while (handle_map.count(next_handle) != 0) {
259 ++next_handle; 259 ++next_handle;
260 } 260 }
@@ -488,7 +488,7 @@ void ArchiveInit() {
488 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC); 488 RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC);
489 else 489 else
490 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); 490 LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str());
491 491
492 // Create the SaveData archive 492 // Create the SaveData archive
493 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory); 493 auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory);
494 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); 494 RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData);
@@ -503,7 +503,7 @@ void ArchiveInit() {
503 if (sharedextsavedata_factory->Initialize()) 503 if (sharedextsavedata_factory->Initialize())
504 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); 504 RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData);
505 else 505 else
506 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", 506 LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s",
507 sharedextsavedata_factory->GetMountPoint().c_str()); 507 sharedextsavedata_factory->GetMountPoint().c_str());
508 508
509 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive 509 // Create the SaveDataCheck archive, basically a small variation of the RomFS archive
diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp
index b25c8941d..32db773bb 100644
--- a/src/core/hle/service/fs/fs_user.cpp
+++ b/src/core/hle/service/fs/fs_user.cpp
@@ -434,7 +434,7 @@ static void IsSdmcWriteable(Service::Interface* self) {
434} 434}
435 435
436/** 436/**
437 * FS_User::FormatSaveData service function, 437 * FS_User::FormatSaveData service function,
438 * formats the SaveData specified by the input path. 438 * formats the SaveData specified by the input path.
439 * Inputs: 439 * Inputs:
440 * 0 : 0x084C0242 440 * 0 : 0x084C0242
@@ -520,7 +520,7 @@ static void CreateExtSaveData(Service::Interface* self) {
520 LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " 520 LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X "
521 "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " 521 "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X "
522 "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, 522 "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low,
523 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9], 523 cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9],
524 cmd_buff[10], cmd_buff[11]); 524 cmd_buff[10], cmd_buff[11]);
525 525
526 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; 526 cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw;
@@ -544,7 +544,7 @@ static void DeleteExtSaveData(Service::Interface* self) {
544 u32 save_high = cmd_buff[3]; 544 u32 save_high = cmd_buff[3];
545 u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is 545 u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is
546 546
547 LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", 547 LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X",
548 save_low, save_high, cmd_buff[1] & 0xFF, unknown); 548 save_low, save_high, cmd_buff[1] & 0xFF, unknown);
549 549
550 cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw; 550 cmd_buff[1] = DeleteExtSaveData(media_type, save_high, save_low).raw;
diff --git a/src/core/hle/service/gsp_gpu.cpp b/src/core/hle/service/gsp_gpu.cpp
index 4af168bfc..4b0b4229d 100644
--- a/src/core/hle/service/gsp_gpu.cpp
+++ b/src/core/hle/service/gsp_gpu.cpp
@@ -167,7 +167,7 @@ static void WriteHWRegsWithMask(Service::Interface* self) {
167 u32* cmd_buff = Kernel::GetCommandBuffer(); 167 u32* cmd_buff = Kernel::GetCommandBuffer();
168 u32 reg_addr = cmd_buff[1]; 168 u32 reg_addr = cmd_buff[1];
169 u32 size = cmd_buff[2]; 169 u32 size = cmd_buff[2];
170 170
171 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); 171 u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]);
172 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); 172 u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]);
173 173
@@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) {
208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); 208 PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left);
209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); 209 PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right);
210 if (info.active_fb == 0) { 210 if (info.active_fb == 0) {
211 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, 211 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4,
212 &phys_address_left); 212 &phys_address_left);
213 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, 213 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4,
214 &phys_address_right); 214 &phys_address_right);
215 } else { 215 } else {
216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, 216 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4,
217 &phys_address_left); 217 &phys_address_left);
218 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, 218 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4,
219 &phys_address_right); 219 &phys_address_right);
220 } 220 }
221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, 221 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4,
222 &info.stride); 222 &info.stride);
223 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, 223 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4,
224 &info.format); 224 &info.format);
225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, 225 WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4,
226 &info.shown_fb); 226 &info.shown_fb);
227} 227}
228 228
@@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
374 { 374 {
375 auto& params = command.set_command_list_last; 375 auto& params = command.set_command_list_last;
376 376
377 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), 377 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)),
378 Memory::VirtualToPhysicalAddress(params.address) >> 3); 378 Memory::VirtualToPhysicalAddress(params.address) >> 3);
379 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size); 379 WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size);
380 380
@@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) {
470 470
471 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD 471 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD
472 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD 472 LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD
473 473
474 cmd_buff[1] = RESULT_SUCCESS.raw; 474 cmd_buff[1] = RESULT_SUCCESS.raw;
475} 475}
476 476
@@ -516,8 +516,8 @@ static void TriggerCmdReqQueue(Service::Interface* self) {
516 */ 516 */
517static void ImportDisplayCaptureInfo(Service::Interface* self) { 517static void ImportDisplayCaptureInfo(Service::Interface* self) {
518 u32* cmd_buff = Kernel::GetCommandBuffer(); 518 u32* cmd_buff = Kernel::GetCommandBuffer();
519 519
520 // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0, 520 // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0,
521 // because we only support a single running application at a time. 521 // because we only support a single running application at a time.
522 // This should always return the framebuffer data that is currently displayed on the screen. 522 // This should always return the framebuffer data that is currently displayed on the screen.
523 523
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index feac53816..c7c1bb5ab 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -106,7 +106,7 @@ void Update() {
106 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; 106 mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks;
107 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); 107 mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks();
108 } 108 }
109 109
110 // Signal both handles when there's an update to Pad or touch 110 // Signal both handles when there's an update to Pad or touch
111 event_pad_or_touch_1->Signal(); 111 event_pad_or_touch_1->Signal();
112 event_pad_or_touch_2->Signal(); 112 event_pad_or_touch_2->Signal();
diff --git a/src/core/hle/service/hid/hid_spvr.cpp b/src/core/hle/service/hid/hid_spvr.cpp
index 02db12efd..532931ae0 100644
--- a/src/core/hle/service/hid/hid_spvr.cpp
+++ b/src/core/hle/service/hid/hid_spvr.cpp
@@ -25,6 +25,6 @@ const Interface::FunctionInfo FunctionTable[] = {
25HID_SPVR_Interface::HID_SPVR_Interface() { 25HID_SPVR_Interface::HID_SPVR_Interface() {
26 Register(FunctionTable); 26 Register(FunctionTable);
27} 27}
28 28
29} // namespace HID 29} // namespace HID
30} // namespace Service 30} // namespace Service
diff --git a/src/core/hle/service/hid/hid_user.h b/src/core/hle/service/hid/hid_user.h
index 0eeec2c25..baf7fed79 100644
--- a/src/core/hle/service/hid/hid_user.h
+++ b/src/core/hle/service/hid/hid_user.h
@@ -11,7 +11,7 @@
11 11
12namespace Service { 12namespace Service {
13namespace HID { 13namespace HID {
14 14
15/** 15/**
16 * HID service interface. 16 * HID service interface.
17 */ 17 */
diff --git a/src/core/hle/service/ptm/ptm.h b/src/core/hle/service/ptm/ptm.h
index 493e6a11f..b690003cb 100644
--- a/src/core/hle/service/ptm/ptm.h
+++ b/src/core/hle/service/ptm/ptm.h
@@ -20,15 +20,15 @@ enum class ChargeLevels : u32 {
20 CompletelyFull = 5, 20 CompletelyFull = 5,
21}; 21};
22 22
23/** 23/**
24 * Represents the gamecoin file structure in the SharedExtData archive 24 * Represents the gamecoin file structure in the SharedExtData archive
25 * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) 25 * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat)
26 */ 26 */
27struct GameCoin { 27struct GameCoin {
28 u32 magic; ///< Magic number: 0x4F00 28 u32 magic; ///< Magic number: 0x4F00
29 u16 total_coins; ///< Total Play Coins 29 u16 total_coins; ///< Total Play Coins
30 u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. 30 u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below.
31 u32 step_count; ///< Total step count at the time a new Play Coin was obtained. 31 u32 step_count; ///< Total step count at the time a new Play Coin was obtained.
32 u32 last_step_count; ///< Step count for the day the last Play Coin was obtained 32 u32 last_step_count; ///< Step count for the day the last Play Coin was obtained
33 u16 year; 33 u16 year;
34 u8 month; 34 u8 month;
diff --git a/src/core/hle/service/ptm/ptm_play.cpp b/src/core/hle/service/ptm/ptm_play.cpp
index 48e68a3d8..7bb990193 100644
--- a/src/core/hle/service/ptm/ptm_play.cpp
+++ b/src/core/hle/service/ptm/ptm_play.cpp
@@ -18,6 +18,6 @@ const Interface::FunctionInfo FunctionTable[] = {
18PTM_Play_Interface::PTM_Play_Interface() { 18PTM_Play_Interface::PTM_Play_Interface() {
19 Register(FunctionTable); 19 Register(FunctionTable);
20} 20}
21 21
22} // namespace PTM 22} // namespace PTM
23} // namespace Service \ No newline at end of file 23} // namespace Service \ No newline at end of file
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 64185c62e..dc667500c 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -52,7 +52,7 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_por
52std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; 52std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services;
53 53
54/** 54/**
55 * Creates a function string for logging, complete with the name (or header code, depending 55 * Creates a function string for logging, complete with the name (or header code, depending
56 * on what's passed in) the port name, and all the cmd_buff arguments. 56 * on what's passed in) the port name, and all the cmd_buff arguments.
57 */ 57 */
58static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { 58static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) {
diff --git a/src/core/hle/service/soc_u.cpp b/src/core/hle/service/soc_u.cpp
index 39b8d65fd..1e0f5df9b 100644
--- a/src/core/hle/service/soc_u.cpp
+++ b/src/core/hle/service/soc_u.cpp
@@ -139,7 +139,7 @@ static int TranslateError(int error) {
139 auto found = error_map.find(error); 139 auto found = error_map.find(error);
140 if (found != error_map.end()) 140 if (found != error_map.end())
141 return -found->second; 141 return -found->second;
142 142
143 return error; 143 return error;
144} 144}
145 145
@@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) {
346 sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); 346 sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr);
347 347
348 int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); 348 int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len));
349 349
350 int result = 0; 350 int result = 0;
351 if (res != 0) 351 if (res != 0)
352 result = TranslateError(GET_ERRNO); 352 result = TranslateError(GET_ERRNO);
@@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) {
360 u32 socket_handle = cmd_buffer[1]; 360 u32 socket_handle = cmd_buffer[1];
361 u32 ctr_cmd = cmd_buffer[2]; 361 u32 ctr_cmd = cmd_buffer[2];
362 u32 ctr_arg = cmd_buffer[3]; 362 u32 ctr_arg = cmd_buffer[3];
363 363
364 int result = 0; 364 int result = 0;
365 u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX) 365 u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX)
366 SCOPE_EXIT({ 366 SCOPE_EXIT({
367 cmd_buffer[1] = result; 367 cmd_buffer[1] = result;
368 cmd_buffer[2] = posix_ret; 368 cmd_buffer[2] = posix_ret;
369 }); 369 });
370 370
371 if (ctr_cmd == 3) { // F_GETFL 371 if (ctr_cmd == 3) { // F_GETFL
372#if EMU_PLATFORM == PLATFORM_WINDOWS 372#if EMU_PLATFORM == PLATFORM_WINDOWS
373 posix_ret = 0; 373 posix_ret = 0;
@@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) {
404 posix_ret = -1; 404 posix_ret = -1;
405 return; 405 return;
406 } 406 }
407 407
408 flags &= ~O_NONBLOCK; 408 flags &= ~O_NONBLOCK;
409 if (ctr_arg & 4) // O_NONBLOCK 409 if (ctr_arg & 4) // O_NONBLOCK
410 flags |= O_NONBLOCK; 410 flags |= O_NONBLOCK;
411 411
412 int ret = ::fcntl(socket_handle, F_SETFL, flags); 412 int ret = ::fcntl(socket_handle, F_SETFL, flags);
413 if (ret == SOCKET_ERROR_VALUE) { 413 if (ret == SOCKET_ERROR_VALUE) {
414 result = TranslateError(GET_ERRNO); 414 result = TranslateError(GET_ERRNO);
@@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) {
439} 439}
440 440
441static void Accept(Service::Interface* self) { 441static void Accept(Service::Interface* self) {
442 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 442 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
443 // preventing graceful shutdown when closing the emulator, this can be fixed by always 443 // preventing graceful shutdown when closing the emulator, this can be fixed by always
444 // performing nonblocking operations and spinlock until the data is available 444 // performing nonblocking operations and spinlock until the data is available
445 u32* cmd_buffer = Kernel::GetCommandBuffer(); 445 u32* cmd_buffer = Kernel::GetCommandBuffer();
446 u32 socket_handle = cmd_buffer[1]; 446 u32 socket_handle = cmd_buffer[1];
@@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) {
448 sockaddr addr; 448 sockaddr addr;
449 socklen_t addr_len = sizeof(addr); 449 socklen_t addr_len = sizeof(addr);
450 u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len)); 450 u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len));
451 451
452 if ((s32)ret != SOCKET_ERROR_VALUE) 452 if ((s32)ret != SOCKET_ERROR_VALUE)
453 open_sockets[ret] = { ret, true }; 453 open_sockets[ret] = { ret, true };
454 454
@@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) {
525} 525}
526 526
527static void RecvFrom(Service::Interface* self) { 527static void RecvFrom(Service::Interface* self) {
528 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 528 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
529 // preventing graceful shutdown when closing the emulator, this can be fixed by always 529 // preventing graceful shutdown when closing the emulator, this can be fixed by always
530 // performing nonblocking operations and spinlock until the data is available 530 // performing nonblocking operations and spinlock until the data is available
531 u32* cmd_buffer = Kernel::GetCommandBuffer(); 531 u32* cmd_buffer = Kernel::GetCommandBuffer();
532 u32 socket_handle = cmd_buffer[1]; 532 u32 socket_handle = cmd_buffer[1];
@@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) {
568 pollfd* platform_pollfd = new pollfd[nfds]; 568 pollfd* platform_pollfd = new pollfd[nfds];
569 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) 569 for (unsigned current_fds = 0; current_fds < nfds; ++current_fds)
570 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]); 570 platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]);
571 571
572 int ret = ::poll(platform_pollfd, nfds, timeout); 572 int ret = ::poll(platform_pollfd, nfds, timeout);
573 573
574 // Now update the output pollfd structure 574 // Now update the output pollfd structure
@@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) {
630 socklen_t len = cmd_buffer[2]; 630 socklen_t len = cmd_buffer[2];
631 631
632 CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); 632 CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2]));
633 633
634 sockaddr dest_addr; 634 sockaddr dest_addr;
635 socklen_t dest_addr_len = sizeof(dest_addr); 635 socklen_t dest_addr_len = sizeof(dest_addr);
636 int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); 636 int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len);
@@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) {
651} 651}
652 652
653static void Connect(Service::Interface* self) { 653static void Connect(Service::Interface* self) {
654 // TODO(Subv): Calling this function on a blocking socket will block the emu thread, 654 // TODO(Subv): Calling this function on a blocking socket will block the emu thread,
655 // preventing graceful shutdown when closing the emulator, this can be fixed by always 655 // preventing graceful shutdown when closing the emulator, this can be fixed by always
656 // performing nonblocking operations and spinlock until the data is available 656 // performing nonblocking operations and spinlock until the data is available
657 u32* cmd_buffer = Kernel::GetCommandBuffer(); 657 u32* cmd_buffer = Kernel::GetCommandBuffer();
658 u32 socket_handle = cmd_buffer[1]; 658 u32 socket_handle = cmd_buffer[1];
diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp
index ca3ff3328..d1555c753 100644
--- a/src/core/hle/svc.cpp
+++ b/src/core/hle/svc.cpp
@@ -228,7 +228,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou
228 // Actually wait the current thread on each object if we decided to wait... 228 // Actually wait the current thread on each object if we decided to wait...
229 std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; 229 std::vector<SharedPtr<Kernel::WaitObject>> wait_objects;
230 wait_objects.reserve(handle_count); 230 wait_objects.reserve(handle_count);
231 231
232 for (int i = 0; i < handle_count; ++i) { 232 for (int i = 0; i < handle_count; ++i) {
233 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); 233 auto object = Kernel::g_handle_table.GetWaitObject(handles[i]);
234 object->AddWaitingThread(Kernel::GetCurrentThread()); 234 object->AddWaitingThread(Kernel::GetCurrentThread());
@@ -475,7 +475,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
475 return ERR_INVALID_HANDLE; 475 return ERR_INVALID_HANDLE;
476 476
477 const SharedPtr<Kernel::Process> process = thread->owner_process; 477 const SharedPtr<Kernel::Process> process = thread->owner_process;
478 478
479 ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); 479 ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle);
480 480
481 *process_id = process->process_id; 481 *process_id = process->process_id;
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index 99cfdaafc..789d3dda4 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -140,7 +140,7 @@ inline void Write(u32 addr, const T data) {
140 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions 140 // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions
141 // TODO(Subv): Verify if raw copies perform scaling 141 // TODO(Subv): Verify if raw copies perform scaling
142 memcpy(dst_pointer, src_pointer, output_size); 142 memcpy(dst_pointer, src_pointer, output_size);
143 143
144 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy", 144 LOG_TRACE(HW_GPU, "DisplayTriggerTransfer: 0x%08x bytes from 0x%08x(%ux%u)-> 0x%08x(%ux%u), output format: %x, flags 0x%08X, Raw copy",
145 output_size, 145 output_size,
146 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(), 146 config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(),
@@ -159,14 +159,14 @@ inline void Write(u32 addr, const T data) {
159 for (u32 x = 0; x < output_width; ++x) { 159 for (u32 x = 0; x < output_width; ++x) {
160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; 160 Math::Vec4<u8> src_color = { 0, 0, 0, 0 };
161 161
162 // Calculate the [x,y] position of the input image 162 // Calculate the [x,y] position of the input image
163 // based on the current output position and the scale 163 // based on the current output position and the scale
164 u32 input_x = x * horizontal_scale; 164 u32 input_x = x * horizontal_scale;
165 u32 input_y = y * vertical_scale; 165 u32 input_y = y * vertical_scale;
166 166
167 if (config.flip_vertically) { 167 if (config.flip_vertically) {
168 // Flip the y value of the output data, 168 // Flip the y value of the output data,
169 // we do this after calculating the [x,y] position of the input image 169 // we do this after calculating the [x,y] position of the input image
170 // to account for the scaling options. 170 // to account for the scaling options.
171 y = output_height - y - 1; 171 y = output_height - y - 1;
172 } 172 }
@@ -302,7 +302,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) {
302 // - If frameskip == 0 (disabled), always swap buffers 302 // - If frameskip == 0 (disabled), always swap buffers
303 // - If frameskip == 1, swap buffers every other frame (starting from the first frame) 303 // - If frameskip == 1, swap buffers every other frame (starting from the first frame)
304 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame) 304 // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame)
305 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || 305 if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) ||
306 Settings::values.frame_skip == 0) { 306 Settings::values.frame_skip == 0) {
307 VideoCore::g_renderer->SwapBuffers(); 307 VideoCore::g_renderer->SwapBuffers();
308 } 308 }
diff --git a/src/core/hw/lcd.cpp b/src/core/hw/lcd.cpp
index 09134c95b..963c8d981 100644
--- a/src/core/hw/lcd.cpp
+++ b/src/core/hw/lcd.cpp
@@ -66,5 +66,5 @@ void Init() {
66void Shutdown() { 66void Shutdown() {
67 LOG_DEBUG(HW_LCD, "shutdown OK"); 67 LOG_DEBUG(HW_LCD, "shutdown OK");
68} 68}
69 69
70} // namespace 70} // namespace
diff --git a/src/core/hw/lcd.h b/src/core/hw/lcd.h
index fb14c3b21..8631eb201 100644
--- a/src/core/hw/lcd.h
+++ b/src/core/hw/lcd.h
@@ -85,5 +85,5 @@ void Init();
85 85
86/// Shutdown hardware 86/// Shutdown hardware
87void Shutdown(); 87void Shutdown();
88 88
89} // namespace 89} // namespace
diff --git a/src/core/loader/3dsx.cpp b/src/core/loader/3dsx.cpp
index ad5e929ce..14aeebebb 100644
--- a/src/core/loader/3dsx.cpp
+++ b/src/core/loader/3dsx.cpp
@@ -234,7 +234,7 @@ ResultStatus AppLoader_THREEDSX::Load() {
234 Kernel::g_current_process = Kernel::Process::Create(filename, 0); 234 Kernel::g_current_process = Kernel::Process::Create(filename, 0);
235 Kernel::g_current_process->svc_access_mask.set(); 235 Kernel::g_current_process->svc_access_mask.set();
236 Kernel::g_current_process->address_mappings = default_address_mappings; 236 Kernel::g_current_process->address_mappings = default_address_mappings;
237 237
238 // Attach the default resource limit (APPLICATION) to the process 238 // Attach the default resource limit (APPLICATION) to the process
239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 239 Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION);
240 240
diff --git a/src/core/mem_map.cpp b/src/core/mem_map.cpp
index 5ecec9566..bf814b945 100644
--- a/src/core/mem_map.cpp
+++ b/src/core/mem_map.cpp
@@ -8,6 +8,10 @@
8#include "common/logging/log.h" 8#include "common/logging/log.h"
9 9
10#include "core/hle/config_mem.h" 10#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/result.h"
11#include "core/hle/shared_page.h" 15#include "core/hle/shared_page.h"
12#include "core/mem_map.h" 16#include "core/mem_map.h"
13#include "core/memory.h" 17#include "core/memory.h"
@@ -17,31 +21,23 @@
17 21
18namespace Memory { 22namespace Memory {
19 23
20u8* g_exefs_code; ///< ExeFS:/.code is loaded here
21u8* g_heap; ///< Application heap (main memory)
22u8* g_shared_mem; ///< Shared memory
23u8* g_heap_linear; ///< Linear heap
24u8* g_vram; ///< Video memory (VRAM) pointer
25u8* g_dsp_mem; ///< DSP memory
26u8* g_tls_mem; ///< TLS memory
27
28namespace { 24namespace {
29 25
30struct MemoryArea { 26struct MemoryArea {
31 u8** ptr;
32 u32 base; 27 u32 base;
33 u32 size; 28 u32 size;
29 const char* name;
34}; 30};
35 31
36// We don't declare the IO regions in here since its handled by other means. 32// We don't declare the IO regions in here since its handled by other means.
37static MemoryArea memory_areas[] = { 33static MemoryArea memory_areas[] = {
38 {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE}, 34 {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here
39 {&g_heap, HEAP_VADDR, HEAP_SIZE }, 35 {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory)
40 {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE }, 36 {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory
41 {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE }, 37 {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory)
42 {&g_vram, VRAM_VADDR, VRAM_SIZE }, 38 {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM)
43 {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE }, 39 {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory
44 {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE }, 40 {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory
45}; 41};
46 42
47/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock 43/// Represents a block of memory mapped by ControlMemory/MapMemoryBlock
@@ -135,27 +131,34 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) {
135 return addr | 0x80000000; 131 return addr | 0x80000000;
136} 132}
137 133
134// TODO(yuriks): Move this into Process
135static Kernel::VMManager address_space;
136
138void Init() { 137void Init() {
138 using namespace Kernel;
139
139 InitMemoryMap(); 140 InitMemoryMap();
140 141
141 for (MemoryArea& area : memory_areas) { 142 for (MemoryArea& area : memory_areas) {
142 *area.ptr = new u8[area.size]; 143 auto block = std::make_shared<std::vector<u8>>(area.size);
143 MapMemoryRegion(area.base, area.size, *area.ptr); 144 address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap();
144 } 145 }
145 MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem);
146 MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page);
147 146
148 LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap); 147 auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR,
148 (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom();
149 address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
150
151 auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR,
152 (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom();
153 address_space.Reprotect(shared_page_vma, VMAPermission::Read);
154
155 LOG_DEBUG(HW_Memory, "initialized OK");
149} 156}
150 157
151void Shutdown() { 158void Shutdown() {
152 heap_map.clear(); 159 heap_map.clear();
153 heap_linear_map.clear(); 160 heap_linear_map.clear();
154 161 address_space.Reset();
155 for (MemoryArea& area : memory_areas) {
156 delete[] *area.ptr;
157 *area.ptr = nullptr;
158 }
159 162
160 LOG_DEBUG(HW_Memory, "shutdown OK"); 163 LOG_DEBUG(HW_Memory, "shutdown OK");
161} 164}
diff --git a/src/core/mem_map.h b/src/core/mem_map.h
index 945815cd6..ba50914a8 100644
--- a/src/core/mem_map.h
+++ b/src/core/mem_map.h
@@ -8,14 +8,6 @@
8 8
9namespace Memory { 9namespace Memory {
10 10
11extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here
12extern u8* g_heap; ///< Application heap (main memory)
13extern u8* g_shared_mem; ///< Shared memory
14extern u8* g_heap_linear; ///< Linear heap (main memory)
15extern u8* g_vram; ///< Video memory (VRAM)
16extern u8* g_dsp_mem; ///< DSP memory
17extern u8* g_tls_mem; ///< TLS memory
18
19void Init(); 11void Init();
20void Shutdown(); 12void Shutdown();
21 13
diff --git a/src/core/memory.cpp b/src/core/memory.cpp
index 5d8069acd..28844a915 100644
--- a/src/core/memory.cpp
+++ b/src/core/memory.cpp
@@ -14,12 +14,10 @@
14#include "core/hw/hw.h" 14#include "core/hw/hw.h"
15#include "core/mem_map.h" 15#include "core/mem_map.h"
16#include "core/memory.h" 16#include "core/memory.h"
17#include "core/memory_setup.h"
17 18
18namespace Memory { 19namespace Memory {
19 20
20const u32 PAGE_MASK = PAGE_SIZE - 1;
21const int PAGE_BITS = 12;
22
23enum class PageType { 21enum class PageType {
24 /// Page is unmapped and should cause an access error. 22 /// Page is unmapped and should cause an access error.
25 Unmapped, 23 Unmapped,
@@ -64,7 +62,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) {
64 while (base != end) { 62 while (base != end) {
65 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); 63 ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base);
66 64
67 if (current_page_table->attributes[base] != PageType::Unmapped) { 65 if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) {
68 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); 66 LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE);
69 } 67 }
70 current_page_table->attributes[base] = type; 68 current_page_table->attributes[base] = type;
@@ -92,6 +90,12 @@ void MapIoRegion(VAddr base, u32 size) {
92 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); 90 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special);
93} 91}
94 92
93void UnmapRegion(VAddr base, u32 size) {
94 ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size);
95 ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base);
96 MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
97}
98
95template <typename T> 99template <typename T>
96T Read(const VAddr vaddr) { 100T Read(const VAddr vaddr) {
97 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS]; 101 const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
diff --git a/src/core/memory.h b/src/core/memory.h
index 2d225801b..0b8ff9ec4 100644
--- a/src/core/memory.h
+++ b/src/core/memory.h
@@ -97,7 +97,7 @@ enum : VAddr {
97 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, 97 SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE,
98 98
99 // TODO(yuriks): The size of this area is dynamic, the kernel grows 99 // TODO(yuriks): The size of this area is dynamic, the kernel grows
100 // it as more and more threads are created. For now we'll just use a 100 // it as more and more threads are created. For now we'll just use a
101 // hardcoded value. 101 // hardcoded value.
102 /// Area where TLS (Thread-Local Storage) buffers are allocated. 102 /// Area where TLS (Thread-Local Storage) buffers are allocated.
103 TLS_AREA_VADDR = 0x1FF82000, 103 TLS_AREA_VADDR = 0x1FF82000,
diff --git a/src/core/memory_setup.h b/src/core/memory_setup.h
index 46263495f..361bfc816 100644
--- a/src/core/memory_setup.h
+++ b/src/core/memory_setup.h
@@ -6,8 +6,13 @@
6 6
7#include "common/common_types.h" 7#include "common/common_types.h"
8 8
9#include "core/memory.h"
10
9namespace Memory { 11namespace Memory {
10 12
13const u32 PAGE_MASK = PAGE_SIZE - 1;
14const int PAGE_BITS = 12;
15
11void InitMemoryMap(); 16void InitMemoryMap();
12 17
13/** 18/**
@@ -26,4 +31,6 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target);
26 */ 31 */
27void MapIoRegion(VAddr base, u32 size); 32void MapIoRegion(VAddr base, u32 size);
28 33
34void UnmapRegion(VAddr base, u32 size);
35
29} 36}
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp
index 100d8c7c1..b46fadd9f 100644
--- a/src/video_core/command_processor.cpp
+++ b/src/video_core/command_processor.cpp
@@ -56,7 +56,17 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
56 // Trigger IRQ 56 // Trigger IRQ
57 case PICA_REG_INDEX(trigger_irq): 57 case PICA_REG_INDEX(trigger_irq):
58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); 58 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D);
59 return; 59 break;
60
61 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c):
62 case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d):
63 {
64 unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]);
65 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;
67 g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32);
68 break;
69 }
60 70
61 // It seems like these trigger vertex rendering 71 // It seems like these trigger vertex rendering
62 case PICA_REG_INDEX(trigger_draw): 72 case PICA_REG_INDEX(trigger_draw):
@@ -136,7 +146,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
136 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), 146 input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(),
137 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32()); 147 input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32());
138 } 148 }
139 149
140 // Load per-vertex data from the loader arrays 150 // Load per-vertex data from the loader arrays
141 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 151 for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
142 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]); 152 const u8* srcdata = Memory::GetPhysicalPointer(vertex_attribute_sources[i] + vertex_attribute_strides[i] * vertex + comp * vertex_attribute_element_size[i]);
@@ -193,7 +203,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
193 const Pica::VertexShader::OutputVertex& v2) { 203 const Pica::VertexShader::OutputVertex& v2) {
194 VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); 204 VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2);
195 }; 205 };
196 206
197 primitive_assembler.SubmitVertex(output, AddHWTriangle); 207 primitive_assembler.SubmitVertex(output, AddHWTriangle);
198 } else { 208 } else {
199 // Send to triangle clipper 209 // Send to triangle clipper
@@ -282,7 +292,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
282 } 292 }
283 break; 293 break;
284 } 294 }
285 295
286 // Load default vertex input attributes 296 // Load default vertex input attributes
287 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): 297 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233):
288 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234): 298 case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[1], 0x234):
@@ -306,7 +316,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
306 } 316 }
307 317
308 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; 318 Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index];
309 319
310 // NOTE: The destination component order indeed is "backwards" 320 // NOTE: The destination component order indeed is "backwards"
311 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); 321 attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8);
312 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF)); 322 attribute.z = float24::FromRawFloat24(((default_attr_write_buffer[0] & 0xFF) << 16) | ((default_attr_write_buffer[1] >> 16) & 0xFFFF));
@@ -363,38 +373,34 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) {
363 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); 373 g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id));
364} 374}
365 375
366static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) {
367 const CommandHeader& header = *(const CommandHeader*)(&first_command_word[1]);
368
369 u32* read_pointer = (u32*)first_command_word;
370
371 const u32 write_mask = ((header.parameter_mask & 0x1) ? (0xFFu << 0) : 0u) |
372 ((header.parameter_mask & 0x2) ? (0xFFu << 8) : 0u) |
373 ((header.parameter_mask & 0x4) ? (0xFFu << 16) : 0u) |
374 ((header.parameter_mask & 0x8) ? (0xFFu << 24) : 0u);
375
376 WritePicaReg(header.cmd_id, *read_pointer, write_mask);
377 read_pointer += 2;
378
379 for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) {
380 u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0);
381 WritePicaReg(cmd, *read_pointer, write_mask);
382 ++read_pointer;
383 }
384
385 // align read pointer to 8 bytes
386 if ((first_command_word - read_pointer) % 2)
387 ++read_pointer;
388
389 return read_pointer - first_command_word;
390}
391
392void ProcessCommandList(const u32* list, u32 size) { 376void ProcessCommandList(const u32* list, u32 size) {
393 u32* read_pointer = (u32*)list; 377 g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list;
394 u32 list_length = size / sizeof(u32); 378 g_state.cmd_list.length = size / sizeof(u32);
395 379
396 while (read_pointer < list + list_length) { 380 while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) {
397 read_pointer += ExecuteCommandBlock(read_pointer); 381 // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF
382 static const u32 expand_bits_to_bytes[] = {
383 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff,
384 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff,
385 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff,
386 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff
387 };
388
389 // Align read pointer to 8 bytes
390 if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0)
391 ++g_state.cmd_list.current_ptr;
392
393 u32 value = *g_state.cmd_list.current_ptr++;
394 const CommandHeader header = { *g_state.cmd_list.current_ptr++ };
395 const u32 write_mask = expand_bits_to_bytes[header.parameter_mask];
396 u32 cmd = header.cmd_id;
397
398 WritePicaReg(cmd, value, write_mask);
399
400 for (unsigned i = 0; i < header.extra_data_length; ++i) {
401 u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0);
402 WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask);
403 }
398 } 404 }
399} 405}
400 406
diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp
index 7987b922c..b92cd1a7e 100644
--- a/src/video_core/debug_utils/debug_utils.cpp
+++ b/src/video_core/debug_utils/debug_utils.cpp
@@ -319,7 +319,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture
319 // TODO(neobrain): Fix code design to unify vertical block offsets! 319 // TODO(neobrain): Fix code design to unify vertical block offsets!
320 source += coarse_y * info.stride; 320 source += coarse_y * info.stride;
321 } 321 }
322 322
323 // TODO: Assert that width/height are multiples of block dimensions 323 // TODO: Assert that width/height are multiples of block dimensions
324 324
325 switch (info.format) { 325 switch (info.format) {
diff --git a/src/video_core/math.h b/src/video_core/math.h
index f9a822658..4928c9bf2 100644
--- a/src/video_core/math.h
+++ b/src/video_core/math.h
@@ -461,7 +461,7 @@ public:
461 // e.g. Vec2 uv() { return Vec2(x,y); } 461 // e.g. Vec2 uv() { return Vec2(x,y); }
462 462
463 // _DEFINE_SWIZZLER2 defines a single such function 463 // _DEFINE_SWIZZLER2 defines a single such function
464 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) 464 // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r)
465 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) 465 // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx)
466#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } 466#define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); }
467#define DEFINE_SWIZZLER2_COMP1(a, a2) \ 467#define DEFINE_SWIZZLER2_COMP1(a, a2) \
diff --git a/src/video_core/pica.h b/src/video_core/pica.h
index b67dce1a9..8ad47a928 100644
--- a/src/video_core/pica.h
+++ b/src/video_core/pica.h
@@ -16,7 +16,7 @@
16#include "common/common_types.h" 16#include "common/common_types.h"
17#include "common/logging/log.h" 17#include "common/logging/log.h"
18 18
19#include "math.h" 19#include "math.h"
20 20
21namespace Pica { 21namespace Pica {
22 22
@@ -162,6 +162,25 @@ struct Regs {
162 ETC1A4 = 13, // compressed 162 ETC1A4 = 13, // compressed
163 }; 163 };
164 164
165 enum class LogicOp : u32 {
166 Clear = 0,
167 And = 1,
168 AndReverse = 2,
169 Copy = 3,
170 Set = 4,
171 CopyInverted = 5,
172 NoOp = 6,
173 Invert = 7,
174 Nand = 8,
175 Or = 9,
176 Nor = 10,
177 Xor = 11,
178 Equiv = 12,
179 AndInverted = 13,
180 OrReverse = 14,
181 OrInverted = 15,
182 };
183
165 static unsigned NibblesPerPixel(TextureFormat format) { 184 static unsigned NibblesPerPixel(TextureFormat format) {
166 switch (format) { 185 switch (format) {
167 case TextureFormat::RGBA8: 186 case TextureFormat::RGBA8:
@@ -221,6 +240,7 @@ struct Regs {
221 enum class Source : u32 { 240 enum class Source : u32 {
222 PrimaryColor = 0x0, 241 PrimaryColor = 0x0,
223 PrimaryFragmentColor = 0x1, 242 PrimaryFragmentColor = 0x1,
243 SecondaryFragmentColor = 0x2,
224 244
225 Texture0 = 0x3, 245 Texture0 = 0x3,
226 Texture1 = 0x4, 246 Texture1 = 0x4,
@@ -337,7 +357,7 @@ struct Regs {
337 return (stage_index < 4) && (update_mask_a & (1 << stage_index)); 357 return (stage_index < 4) && (update_mask_a & (1 << stage_index));
338 } 358 }
339 } tev_combiner_buffer_input; 359 } tev_combiner_buffer_input;
340 360
341 INSERT_PADDING_WORDS(0xf); 361 INSERT_PADDING_WORDS(0xf);
342 TevStageConfig tev_stage4; 362 TevStageConfig tev_stage4;
343 INSERT_PADDING_WORDS(0x3); 363 INSERT_PADDING_WORDS(0x3);
@@ -413,12 +433,8 @@ struct Regs {
413 } alpha_blending; 433 } alpha_blending;
414 434
415 union { 435 union {
416 enum Op { 436 BitField<0, 4, LogicOp> logic_op;
417 Set = 4, 437 };
418 };
419
420 BitField<0, 4, Op> op;
421 } logic_op;
422 438
423 union { 439 union {
424 BitField< 0, 8, u32> r; 440 BitField< 0, 8, u32> r;
@@ -703,12 +719,38 @@ struct Regs {
703 struct { 719 struct {
704 // Index of the current default attribute 720 // Index of the current default attribute
705 u32 index; 721 u32 index;
706 722
707 // Writing to these registers sets the "current" default attribute. 723 // Writing to these registers sets the "current" default attribute.
708 u32 set_value[3]; 724 u32 set_value[3];
709 } vs_default_attributes_setup; 725 } vs_default_attributes_setup;
710 726
711 INSERT_PADDING_WORDS(0x28); 727 INSERT_PADDING_WORDS(0x2);
728
729 struct {
730 // There are two channels that can be used to configure the next command buffer, which
731 // can be then executed by writing to the "trigger" registers. There are two reasons why a
732 // game might use this feature:
733 // 1) With this, an arbitrary number of additional command buffers may be executed in
734 // sequence without requiring any intervention of the CPU after the initial one is
735 // kicked off.
736 // 2) Games can configure these registers to provide a command list subroutine mechanism.
737
738 BitField< 0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer
739 BitField< 0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer
740 u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to
741
742 unsigned GetSize(unsigned index) const {
743 ASSERT(index < 2);
744 return 8 * size[index];
745 }
746
747 PAddr GetPhysicalAddress(unsigned index) const {
748 ASSERT(index < 2);
749 return (PAddr)(8 * addr[index]);
750 }
751 } command_buffer;
752
753 INSERT_PADDING_WORDS(0x20);
712 754
713 enum class TriangleTopology : u32 { 755 enum class TriangleTopology : u32 {
714 List = 0, 756 List = 0,
@@ -861,6 +903,7 @@ struct Regs {
861 ADD_FIELD(trigger_draw); 903 ADD_FIELD(trigger_draw);
862 ADD_FIELD(trigger_draw_indexed); 904 ADD_FIELD(trigger_draw_indexed);
863 ADD_FIELD(vs_default_attributes_setup); 905 ADD_FIELD(vs_default_attributes_setup);
906 ADD_FIELD(command_buffer);
864 ADD_FIELD(triangle_topology); 907 ADD_FIELD(triangle_topology);
865 ADD_FIELD(vs_bool_uniforms); 908 ADD_FIELD(vs_bool_uniforms);
866 ADD_FIELD(vs_int_uniforms); 909 ADD_FIELD(vs_int_uniforms);
@@ -938,6 +981,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228);
938ASSERT_REG_POSITION(trigger_draw, 0x22e); 981ASSERT_REG_POSITION(trigger_draw, 0x22e);
939ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); 982ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f);
940ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); 983ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232);
984ASSERT_REG_POSITION(command_buffer, 0x238);
941ASSERT_REG_POSITION(triangle_topology, 0x25e); 985ASSERT_REG_POSITION(triangle_topology, 0x25e);
942ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); 986ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0);
943ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); 987ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1);
@@ -1053,21 +1097,12 @@ private:
1053 float value; 1097 float value;
1054}; 1098};
1055 1099
1056union CommandHeader {
1057 CommandHeader(u32 h) : hex(h) {}
1058
1059 u32 hex;
1060
1061 BitField< 0, 16, u32> cmd_id;
1062 BitField<16, 4, u32> parameter_mask;
1063 BitField<20, 11, u32> extra_data_length;
1064 BitField<31, 1, u32> group_commands;
1065};
1066
1067/// Struct used to describe current Pica state 1100/// Struct used to describe current Pica state
1068struct State { 1101struct State {
1102 /// Pica registers
1069 Regs regs; 1103 Regs regs;
1070 1104
1105 /// Vertex shader memory
1071 struct { 1106 struct {
1072 struct { 1107 struct {
1073 Math::Vec4<float24> f[96]; 1108 Math::Vec4<float24> f[96];
@@ -1080,6 +1115,13 @@ struct State {
1080 std::array<u32, 1024> program_code; 1115 std::array<u32, 1024> program_code;
1081 std::array<u32, 1024> swizzle_data; 1116 std::array<u32, 1024> swizzle_data;
1082 } vs; 1117 } vs;
1118
1119 /// Current Pica command list
1120 struct {
1121 const u32* head_ptr;
1122 const u32* current_ptr;
1123 u32 length;
1124 } cmd_list;
1083}; 1125};
1084 1126
1085/// Initialize Pica state 1127/// Initialize Pica state
diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp
index 767ff4205..113b573f8 100644
--- a/src/video_core/rasterizer.cpp
+++ b/src/video_core/rasterizer.cpp
@@ -104,7 +104,7 @@ static u32 GetDepth(int x, int y) {
104 u8* depth_buffer = Memory::GetPhysicalPointer(addr); 104 u8* depth_buffer = Memory::GetPhysicalPointer(addr);
105 105
106 y = framebuffer.height - y; 106 y = framebuffer.height - y;
107 107
108 const u32 coarse_y = y & ~7; 108 const u32 coarse_y = y & ~7;
109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); 109 u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format);
110 u32 stride = framebuffer.width * bytes_per_pixel; 110 u32 stride = framebuffer.width * bytes_per_pixel;
@@ -402,11 +402,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
402 402
403 auto GetSource = [&](Source source) -> Math::Vec4<u8> { 403 auto GetSource = [&](Source source) -> Math::Vec4<u8> {
404 switch (source) { 404 switch (source) {
405 // TODO: What's the difference between these two?
406 case Source::PrimaryColor: 405 case Source::PrimaryColor:
406
407 // HACK: Until we implement fragment lighting, use primary_color
407 case Source::PrimaryFragmentColor: 408 case Source::PrimaryFragmentColor:
408 return primary_color; 409 return primary_color;
409 410
411 // HACK: Until we implement fragment lighting, use zero
412 case Source::SecondaryFragmentColor:
413 return {0, 0, 0, 0};
414
410 case Source::Texture0: 415 case Source::Texture0:
411 return texture_color[0]; 416 return texture_color[0];
412 417
@@ -570,6 +575,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
570 case Operation::Add: 575 case Operation::Add:
571 return std::min(255, input[0] + input[1]); 576 return std::min(255, input[0] + input[1]);
572 577
578 case Operation::AddSigned:
579 {
580 // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct
581 auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128;
582 return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255));
583 }
584
573 case Operation::Lerp: 585 case Operation::Lerp:
574 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255; 586 return (input[0] * input[2] + input[1] * (255 - input[2])) / 255;
575 587
@@ -808,10 +820,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
808 } 820 }
809 }; 821 };
810 822
811 using BlendEquation = Regs::BlendEquation;
812 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, 823 static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor,
813 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, 824 const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor,
814 BlendEquation equation) { 825 Regs::BlendEquation equation) {
815 Math::Vec4<int> result; 826 Math::Vec4<int> result;
816 827
817 auto src_result = (src * srcfactor).Cast<int>(); 828 auto src_result = (src * srcfactor).Cast<int>();
@@ -866,8 +877,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0,
866 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); 877 blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb);
867 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); 878 blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a();
868 } else { 879 } else {
869 LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); 880 static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 {
870 UNIMPLEMENTED(); 881 switch (op) {
882 case Regs::LogicOp::Clear:
883 return 0;
884
885 case Regs::LogicOp::And:
886 return src & dest;
887
888 case Regs::LogicOp::AndReverse:
889 return src & ~dest;
890
891 case Regs::LogicOp::Copy:
892 return src;
893
894 case Regs::LogicOp::Set:
895 return 255;
896
897 case Regs::LogicOp::CopyInverted:
898 return ~src;
899
900 case Regs::LogicOp::NoOp:
901 return dest;
902
903 case Regs::LogicOp::Invert:
904 return ~dest;
905
906 case Regs::LogicOp::Nand:
907 return ~(src & dest);
908
909 case Regs::LogicOp::Or:
910 return src | dest;
911
912 case Regs::LogicOp::Nor:
913 return ~(src | dest);
914
915 case Regs::LogicOp::Xor:
916 return src ^ dest;
917
918 case Regs::LogicOp::Equiv:
919 return ~(src ^ dest);
920
921 case Regs::LogicOp::AndInverted:
922 return ~src & dest;
923
924 case Regs::LogicOp::OrReverse:
925 return src | ~dest;
926
927 case Regs::LogicOp::OrInverted:
928 return ~src | dest;
929 }
930 };
931
932 blend_output = Math::MakeVec(
933 LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op),
934 LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op),
935 LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op),
936 LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op));
871 } 937 }
872 938
873 const Math::Vec4<u8> result = { 939 const Math::Vec4<u8> result = {
diff --git a/src/video_core/renderer_opengl/generated/gl_3_2_core.c b/src/video_core/renderer_opengl/generated/gl_3_2_core.c
index ef29972d7..95fd29c0a 100644
--- a/src/video_core/renderer_opengl/generated/gl_3_2_core.c
+++ b/src/video_core/renderer_opengl/generated/gl_3_2_core.c
@@ -62,9 +62,9 @@ static int TestPointer(const PROC pTest)
62 ptrdiff_t iTest; 62 ptrdiff_t iTest;
63 if(!pTest) return 0; 63 if(!pTest) return 0;
64 iTest = (ptrdiff_t)pTest; 64 iTest = (ptrdiff_t)pTest;
65 65
66 if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0; 66 if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0;
67 67
68 return 1; 68 return 1;
69} 69}
70 70
@@ -79,7 +79,7 @@ static PROC WinGetProcAddress(const char *name)
79 glMod = GetModuleHandleA("OpenGL32.dll"); 79 glMod = GetModuleHandleA("OpenGL32.dll");
80 return (PROC)GetProcAddress(glMod, (LPCSTR)name); 80 return (PROC)GetProcAddress(glMod, (LPCSTR)name);
81} 81}
82 82
83#define IntGetProcAddress(name) WinGetProcAddress(name) 83#define IntGetProcAddress(name) WinGetProcAddress(name)
84#else 84#else
85 #if defined(__APPLE__) 85 #if defined(__APPLE__)
@@ -1083,7 +1083,7 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName)
1083 if(strcmp(extensionName, currLoc->extensionName) == 0) 1083 if(strcmp(extensionName, currLoc->extensionName) == 0)
1084 return currLoc; 1084 return currLoc;
1085 } 1085 }
1086 1086
1087 return NULL; 1087 return NULL;
1088} 1088}
1089 1089
@@ -1135,15 +1135,15 @@ int ogl_LoadFunctions()
1135{ 1135{
1136 int numFailed = 0; 1136 int numFailed = 0;
1137 ClearExtensionVars(); 1137 ClearExtensionVars();
1138 1138
1139 _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv"); 1139 _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv");
1140 if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED; 1140 if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED;
1141 _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi"); 1141 _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi");
1142 if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED; 1142 if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED;
1143 1143
1144 ProcExtsFromExtList(); 1144 ProcExtsFromExtList();
1145 numFailed = Load_Version_3_2(); 1145 numFailed = Load_Version_3_2();
1146 1146
1147 if(numFailed == 0) 1147 if(numFailed == 0)
1148 return ogl_LOAD_SUCCEEDED; 1148 return ogl_LOAD_SUCCEEDED;
1149 else 1149 else
@@ -1177,7 +1177,7 @@ int ogl_IsVersionGEQ(int majorVersion, int minorVersion)
1177{ 1177{
1178 if(g_major_version == 0) 1178 if(g_major_version == 0)
1179 GetGLVersion(); 1179 GetGLVersion();
1180 1180
1181 if(majorVersion > g_major_version) return 1; 1181 if(majorVersion > g_major_version) return 1;
1182 if(majorVersion < g_major_version) return 0; 1182 if(majorVersion < g_major_version) return 0;
1183 if(minorVersion >= g_minor_version) return 1; 1183 if(minorVersion >= g_minor_version) return 1;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 4b7d099a5..b51f8efdf 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -135,6 +135,7 @@ void RasterizerOpenGL::Reset() {
135 SyncBlendFuncs(); 135 SyncBlendFuncs();
136 SyncBlendColor(); 136 SyncBlendColor();
137 SyncAlphaTest(); 137 SyncAlphaTest();
138 SyncLogicOp();
138 SyncStencilTest(); 139 SyncStencilTest();
139 SyncDepthTest(); 140 SyncDepthTest();
140 141
@@ -249,6 +250,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
249 SyncDepthTest(); 250 SyncDepthTest();
250 break; 251 break;
251 252
253 // Logic op
254 case PICA_REG_INDEX(output_merger.logic_op):
255 SyncLogicOp();
256 break;
257
252 // TEV stage 0 258 // TEV stage 0
253 case PICA_REG_INDEX(tev_stage0.color_source1): 259 case PICA_REG_INDEX(tev_stage0.color_source1):
254 SyncTevSources(0, regs.tev_stage0); 260 SyncTevSources(0, regs.tev_stage0);
@@ -350,7 +356,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) {
350 case PICA_REG_INDEX(tev_stage5.color_scale): 356 case PICA_REG_INDEX(tev_stage5.color_scale):
351 SyncTevMultipliers(5, regs.tev_stage5); 357 SyncTevMultipliers(5, regs.tev_stage5);
352 break; 358 break;
353 359
354 // TEV combiner buffer color 360 // TEV combiner buffer color
355 case PICA_REG_INDEX(tev_combiner_buffer_color): 361 case PICA_REG_INDEX(tev_combiner_buffer_color):
356 SyncCombinerColor(); 362 SyncCombinerColor();
@@ -633,6 +639,10 @@ void RasterizerOpenGL::SyncAlphaTest() {
633 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); 639 glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f);
634} 640}
635 641
642void RasterizerOpenGL::SyncLogicOp() {
643 state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op);
644}
645
636void RasterizerOpenGL::SyncStencilTest() { 646void RasterizerOpenGL::SyncStencilTest() {
637 // TODO: Implement stencil test, mask, and op 647 // TODO: Implement stencil test, mask, and op
638} 648}
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 9896f8d04..d7d422b1f 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -125,6 +125,9 @@ private:
125 /// Syncs the alpha test states to match the PICA register 125 /// Syncs the alpha test states to match the PICA register
126 void SyncAlphaTest(); 126 void SyncAlphaTest();
127 127
128 /// Syncs the logic op states to match the PICA register
129 void SyncLogicOp();
130
128 /// Syncs the stencil test states to match the PICA register 131 /// Syncs the stencil test states to match the PICA register
129 void SyncStencilTest(); 132 void SyncStencilTest();
130 133
diff --git a/src/video_core/renderer_opengl/gl_shaders.h b/src/video_core/renderer_opengl/gl_shaders.h
index 8f0941230..a8cb2f595 100644
--- a/src/video_core/renderer_opengl/gl_shaders.h
+++ b/src/video_core/renderer_opengl/gl_shaders.h
@@ -69,15 +69,16 @@ const char g_fragment_shader_hw[] = R"(
69#define NUM_VTX_ATTR 7 69#define NUM_VTX_ATTR 7
70#define NUM_TEV_STAGES 6 70#define NUM_TEV_STAGES 6
71 71
72#define SOURCE_PRIMARYCOLOR 0x0 72#define SOURCE_PRIMARYCOLOR 0x0
73#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 73#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1
74#define SOURCE_TEXTURE0 0x3 74#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2
75#define SOURCE_TEXTURE1 0x4 75#define SOURCE_TEXTURE0 0x3
76#define SOURCE_TEXTURE2 0x5 76#define SOURCE_TEXTURE1 0x4
77#define SOURCE_TEXTURE3 0x6 77#define SOURCE_TEXTURE2 0x5
78#define SOURCE_PREVIOUSBUFFER 0xd 78#define SOURCE_TEXTURE3 0x6
79#define SOURCE_CONSTANT 0xe 79#define SOURCE_PREVIOUSBUFFER 0xd
80#define SOURCE_PREVIOUS 0xf 80#define SOURCE_CONSTANT 0xe
81#define SOURCE_PREVIOUS 0xf
81 82
82#define COLORMODIFIER_SOURCECOLOR 0x0 83#define COLORMODIFIER_SOURCECOLOR 0x0
83#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 84#define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1
@@ -151,8 +152,11 @@ vec4 GetSource(int source) {
151 if (source == SOURCE_PRIMARYCOLOR) { 152 if (source == SOURCE_PRIMARYCOLOR) {
152 return o[2]; 153 return o[2];
153 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { 154 } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) {
154 // HACK: Uses color value, but should really use fragment lighting output 155 // HACK: Until we implement fragment lighting, use primary_color
155 return o[2]; 156 return o[2];
157 } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) {
158 // HACK: Until we implement fragment lighting, use zero
159 return vec4(0.0, 0.0, 0.0, 0.0);
156 } else if (source == SOURCE_TEXTURE0) { 160 } else if (source == SOURCE_TEXTURE0) {
157 return texture(tex[0], o[3].xy); 161 return texture(tex[0], o[3].xy);
158 } else if (source == SOURCE_TEXTURE1) { 162 } else if (source == SOURCE_TEXTURE1) {
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp
index 1afa58c99..9c5f38f94 100644
--- a/src/video_core/renderer_opengl/gl_state.cpp
+++ b/src/video_core/renderer_opengl/gl_state.cpp
@@ -32,6 +32,8 @@ OpenGLState::OpenGLState() {
32 blend.color.blue = 0.0f; 32 blend.color.blue = 0.0f;
33 blend.color.alpha = 0.0f; 33 blend.color.alpha = 0.0f;
34 34
35 logic_op = GL_COPY;
36
35 for (auto& texture_unit : texture_units) { 37 for (auto& texture_unit : texture_units) {
36 texture_unit.enabled_2d = false; 38 texture_unit.enabled_2d = false;
37 texture_unit.texture_2d = 0; 39 texture_unit.texture_2d = 0;
@@ -82,7 +84,7 @@ void OpenGLState::Apply() {
82 } else { 84 } else {
83 glDisable(GL_STENCIL_TEST); 85 glDisable(GL_STENCIL_TEST);
84 } 86 }
85 } 87 }
86 88
87 if (stencil.test_func != cur_state.stencil.test_func || 89 if (stencil.test_func != cur_state.stencil.test_func ||
88 stencil.test_ref != cur_state.stencil.test_ref || 90 stencil.test_ref != cur_state.stencil.test_ref ||
@@ -99,8 +101,13 @@ void OpenGLState::Apply() {
99 if (blend.enabled != cur_state.blend.enabled) { 101 if (blend.enabled != cur_state.blend.enabled) {
100 if (blend.enabled) { 102 if (blend.enabled) {
101 glEnable(GL_BLEND); 103 glEnable(GL_BLEND);
104
105 cur_state.logic_op = GL_COPY;
106 glLogicOp(cur_state.logic_op);
107 glDisable(GL_COLOR_LOGIC_OP);
102 } else { 108 } else {
103 glDisable(GL_BLEND); 109 glDisable(GL_BLEND);
110 glEnable(GL_COLOR_LOGIC_OP);
104 } 111 }
105 } 112 }
106 113
@@ -118,6 +125,10 @@ void OpenGLState::Apply() {
118 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); 125 glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func);
119 } 126 }
120 127
128 if (logic_op != cur_state.logic_op) {
129 glLogicOp(logic_op);
130 }
131
121 // Textures 132 // Textures
122 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) { 133 for (unsigned texture_index = 0; texture_index < ARRAY_SIZE(texture_units); ++texture_index) {
123 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) { 134 if (texture_units[texture_index].enabled_2d != cur_state.texture_units[texture_index].enabled_2d) {
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h
index 281b7cad5..6b97721d6 100644
--- a/src/video_core/renderer_opengl/gl_state.h
+++ b/src/video_core/renderer_opengl/gl_state.h
@@ -42,6 +42,8 @@ public:
42 } color; // GL_BLEND_COLOR 42 } color; // GL_BLEND_COLOR
43 } blend; 43 } blend;
44 44
45 GLenum logic_op; // GL_LOGIC_OP_MODE
46
45 // 3 texture units - one for each that is used in PICA fragment shader emulation 47 // 3 texture units - one for each that is used in PICA fragment shader emulation
46 struct { 48 struct {
47 bool enabled_2d; // GL_TEXTURE_2D 49 bool enabled_2d; // GL_TEXTURE_2D
@@ -61,7 +63,7 @@ public:
61 static const OpenGLState& GetCurState() { 63 static const OpenGLState& GetCurState() {
62 return cur_state; 64 return cur_state;
63 } 65 }
64 66
65 /// Apply this state as the current OpenGL state 67 /// Apply this state as the current OpenGL state
66 void Apply(); 68 void Apply();
67 69
diff --git a/src/video_core/renderer_opengl/pica_to_gl.h b/src/video_core/renderer_opengl/pica_to_gl.h
index f8763e71b..e566f9f7a 100644
--- a/src/video_core/renderer_opengl/pica_to_gl.h
+++ b/src/video_core/renderer_opengl/pica_to_gl.h
@@ -71,6 +71,37 @@ inline GLenum BlendFunc(Pica::Regs::BlendFactor factor) {
71 return blend_func_table[(unsigned)factor]; 71 return blend_func_table[(unsigned)factor];
72} 72}
73 73
74inline GLenum LogicOp(Pica::Regs::LogicOp op) {
75 static const GLenum logic_op_table[] = {
76 GL_CLEAR, // Clear
77 GL_AND, // And
78 GL_AND_REVERSE, // AndReverse
79 GL_COPY, // Copy
80 GL_SET, // Set
81 GL_COPY_INVERTED, // CopyInverted
82 GL_NOOP, // NoOp
83 GL_INVERT, // Invert
84 GL_NAND, // Nand
85 GL_OR, // Or
86 GL_NOR, // Nor
87 GL_XOR, // Xor
88 GL_EQUIV, // Equiv
89 GL_AND_INVERTED, // AndInverted
90 GL_OR_REVERSE, // OrReverse
91 GL_OR_INVERTED, // OrInverted
92 };
93
94 // Range check table for input
95 if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) {
96 LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op);
97 UNREACHABLE();
98
99 return GL_COPY;
100 }
101
102 return logic_op_table[(unsigned)op];
103}
104
74inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { 105inline GLenum CompareFunc(Pica::Regs::CompareFunc func) {
75 static const GLenum compare_func_table[] = { 106 static const GLenum compare_func_table[] = {
76 GL_NEVER, // CompareFunc::Never 107 GL_NEVER, // CompareFunc::Never
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp
index 16cf92e20..382aeaa05 100644
--- a/src/video_core/renderer_opengl/renderer_opengl.cpp
+++ b/src/video_core/renderer_opengl/renderer_opengl.cpp
@@ -157,7 +157,7 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig&
157 state.texture_units[0].enabled_2d = true; 157 state.texture_units[0].enabled_2d = true;
158 state.texture_units[0].texture_2d = texture.handle; 158 state.texture_units[0].texture_2d = texture.handle;
159 state.Apply(); 159 state.Apply();
160 160
161 glActiveTexture(GL_TEXTURE0); 161 glActiveTexture(GL_TEXTURE0);
162 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); 162 glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride);
163 163
diff --git a/src/video_core/vertex_shader.cpp b/src/video_core/vertex_shader.cpp
index 7d68998f1..87006a832 100644
--- a/src/video_core/vertex_shader.cpp
+++ b/src/video_core/vertex_shader.cpp
@@ -119,17 +119,13 @@ static void ProcessShaderCode(VertexShaderState& state) {
119 switch (instr.opcode.Value().GetInfo().type) { 119 switch (instr.opcode.Value().GetInfo().type) {
120 case OpCode::Type::Arithmetic: 120 case OpCode::Type::Arithmetic:
121 { 121 {
122 bool is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); 122 const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed));
123 // TODO: We don't really support this properly: For instance, the address register
124 // offset needs to be applied to SRC2 instead, etc.
125 // For now, we just abort in this situation.
126 ASSERT_MSG(!is_inverted, "Bad condition...");
127 123
128 const int address_offset = (instr.common.address_register_index == 0) 124 const int address_offset = (instr.common.address_register_index == 0)
129 ? 0 : state.address_registers[instr.common.address_register_index - 1]; 125 ? 0 : state.address_registers[instr.common.address_register_index - 1];
130 126
131 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + address_offset); 127 const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + (!is_inverted * address_offset));
132 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted)); 128 const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted) + ( is_inverted * address_offset));
133 129
134 const bool negate_src1 = ((bool)swizzle.negate_src1 != false); 130 const bool negate_src1 = ((bool)swizzle.negate_src1 != false);
135 const bool negate_src2 = ((bool)swizzle.negate_src2 != false); 131 const bool negate_src2 = ((bool)swizzle.negate_src2 != false);
@@ -208,6 +204,15 @@ static void ProcessShaderCode(VertexShaderState& state) {
208 } 204 }
209 break; 205 break;
210 206
207 case OpCode::Id::MIN:
208 for (int i = 0; i < 4; ++i) {
209 if (!swizzle.DestComponentEnabled(i))
210 continue;
211
212 dest[i] = std::min(src1[i], src2[i]);
213 }
214 break;
215
211 case OpCode::Id::DP3: 216 case OpCode::Id::DP3:
212 case OpCode::Id::DP4: 217 case OpCode::Id::DP4:
213 { 218 {
@@ -279,6 +284,16 @@ static void ProcessShaderCode(VertexShaderState& state) {
279 break; 284 break;
280 } 285 }
281 286
287 case OpCode::Id::SLT:
288 case OpCode::Id::SLTI:
289 for (int i = 0; i < 4; ++i) {
290 if (!swizzle.DestComponentEnabled(i))
291 continue;
292
293 dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f) : float24::FromFloat32(0.0f);
294 }
295 break;
296
282 case OpCode::Id::CMP: 297 case OpCode::Id::CMP:
283 for (int i = 0; i < 2; ++i) { 298 for (int i = 0; i < 2; ++i) {
284 // TODO: Can you restrict to one compare via dest masking? 299 // TODO: Can you restrict to one compare via dest masking?
@@ -330,7 +345,7 @@ static void ProcessShaderCode(VertexShaderState& state) {
330 345
331 case OpCode::Type::MultiplyAdd: 346 case OpCode::Type::MultiplyAdd:
332 { 347 {
333 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) || 348 if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) ||
334 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) { 349 (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) {
335 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id]; 350 const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id];
336 351
@@ -547,7 +562,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) {
547 const auto& attribute_register_map = regs.vs_input_register_map; 562 const auto& attribute_register_map = regs.vs_input_register_map;
548 float24 dummy_register; 563 float24 dummy_register;
549 boost::fill(state.input_register_table, &dummy_register); 564 boost::fill(state.input_register_table, &dummy_register);
550 565
551 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x; 566 if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x;
552 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x; 567 if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x;
553 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x; 568 if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x;