diff options
210 files changed, 4512 insertions, 1964 deletions
diff --git a/.travis-build.sh b/.travis-build.sh index 21582c689..422e13220 100755 --- a/.travis-build.sh +++ b/.travis-build.sh @@ -3,14 +3,20 @@ set -e set -x +if grep -r '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis* dist/*.desktop \ + dist/*.svg dist/*.xml; then + echo Trailing whitespace found, aborting + exit 1 +fi + #if OS is linux or is not set if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then mkdir build && cd build - cmake -DUSE_QT5=OFF .. + cmake -DUSE_QT5=OFF .. make -j4 elif [ "$TRAVIS_OS_NAME" = "osx" ]; then export Qt5_DIR=$(brew --prefix)/opt/qt5 mkdir build && cd build cmake .. -GXcode - xcodebuild -configuration Release + xcodebuild -configuration Release | xcpretty -c && exit ${PIPESTATUS[0]} fi diff --git a/.travis-deps.sh b/.travis-deps.sh index f8074fb91..b9561bb66 100755 --- a/.travis-deps.sh +++ b/.travis-deps.sh @@ -26,4 +26,5 @@ if [ "$TRAVIS_OS_NAME" = "linux" -o -z "$TRAVIS_OS_NAME" ]; then elif [ "$TRAVIS_OS_NAME" = "osx" ]; then brew tap homebrew/versions brew install qt5 glfw3 pkgconfig + gem install xcpretty fi 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 REV_NAME="citra-${GITDATE}-${GITREV}-linux-amd64" UPLOAD_DIR="/citra/nightly/linux-amd64" mkdir "$REV_NAME" - + sudo apt-get -qq install lftp cp build/src/citra/citra "$REV_NAME" cp build/src/citra_qt/citra-qt "$REV_NAME" @@ -14,7 +14,7 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then REV_NAME="citra-${GITDATE}-${GITREV}-osx-amd64" UPLOAD_DIR="/citra/nightly/osx-amd64" mkdir "$REV_NAME" - + brew install lftp cp build/src/citra/Release/citra "$REV_NAME" cp -r build/src/citra_qt/Release/citra-qt.app "$REV_NAME" @@ -22,7 +22,7 @@ if [ "$TRAVIS_BRANCH" = "master" ]; then # move qt libs into app bundle for deployment $(brew --prefix)/opt/qt5/bin/macdeployqt "${REV_NAME}/citra-qt.app" fi - + ARCHIVE_NAME="${REV_NAME}.tar.xz" tar -cJvf "$ARCHIVE_NAME" "$REV_NAME" 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 env: global: - - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" + - secure: "AXHFIafTmbGDsHD3mUVj5a4I397DQjti/WoqAJGUp2PglxTcc04BwxZ9Z+xLuf5N2Hs5r9ojAJLT8OGxJCLBDXzneQTNSqXbFuYSLbqrEAiIRlA9eRIotWCg+wYcO+5e8MKX+cHVKwiIWasUB21AtCdq6msh6Y3pUshZp212VPg=" before_install: - sh .travis-deps.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index d958dfc35..6805ebed8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -45,7 +45,7 @@ else() set(CMAKE_CXX_FLAGS_RELEASE "${optimization_flags} /MP /MD" CACHE STRING "" FORCE) set(CMAKE_C_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) set(CMAKE_CXX_FLAGS_RELWITHDEBINFO "${optimization_flags} /MP /MD /Zi /Zo" CACHE STRING "" FORCE) - + set(CMAKE_EXE_LINKER_FLAGS_DEBUG "/DEBUG" CACHE STRING "" FORCE) set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "/DEBUG" CACHE STRING "" FORCE) endif() @@ -114,7 +114,7 @@ if (ENABLE_GLFW) set(TMP_TOOLSET "mingw-${TMP_ARCH}") endif() - set(GLFW_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/glfw-3.0.4.bin") + set(GLFW_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/externals/glfw-3.1.1.bin") set(GLFW_INCLUDE_DIRS "${GLFW_PREFIX}/include" CACHE PATH "Path to GLFW3 headers") set(GLFW_LIBRARY_DIRS "${GLFW_PREFIX}/lib-${TMP_TOOLSET}" CACHE PATH "Path to GLFW3 libraries") @@ -137,7 +137,7 @@ IF (APPLE) FIND_LIBRARY(IOKIT_LIBRARY IOKit) # GLFW dependency FIND_LIBRARY(COREVIDEO_LIBRARY CoreVideo) # GLFW dependency set(PLATFORM_LIBRARIES iconv ${COCOA_LIBRARY} ${IOKIT_LIBRARY} ${COREVIDEO_LIBRARY}) - + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -stdlib=libc++") ELSEIF(MINGW) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c8c8e3884..906a4bc7d 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -10,16 +10,16 @@ Citra is a brand new project, so we have a great opportunity to keep things clea ### Naming Rules * Functions - * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) + * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore) * Variables * lower_case_underscored * Prefix "g_" if global * Classes - * CamelCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) + * PascalCase, "_" may also be used for clarity (e.g. OGL_VideoInterface) * Files/Folders * lower_case_underscored * Namespaces - * CamelCase, "_" may also be used for clarity (e.g. ARM_InitCore) + * PascalCase, "_" may also be used for clarity (e.g. ARM_InitCore) ### Indentation/Whitespace Style Follow the indentation/whitespace style shown below. Do not use tabs, use 4-spaces instead. @@ -38,7 +38,7 @@ PROJECT_NAME = Citra # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -51,7 +51,7 @@ PROJECT_BRIEF = "Nintendo 3DS emulator/debugger" # and the maximum width should not exceed 200 pixels. Doxygen will copy the logo # to the output directory. -PROJECT_LOGO = doc-icon.png +PROJECT_LOGO = dist/doc-icon.png # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is @@ -162,7 +162,7 @@ FULL_PATH_NAMES = YES # will be relative from the directory where doxygen is started. # This tag requires that the tag FULL_PATH_NAMES is set to YES. -STRIP_FROM_PATH = +STRIP_FROM_PATH = # The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the # path mentioned in the documentation of a class, which tells the reader which @@ -171,7 +171,7 @@ STRIP_FROM_PATH = # specify the list of include paths that are normally passed to the compiler # using the -I flag. -STRIP_FROM_INC_PATH = +STRIP_FROM_INC_PATH = # If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but # less readable) file names. This can be useful is your file systems doesn't @@ -238,13 +238,13 @@ TAB_SIZE = 4 # "Side Effects:". You can put \n's in the value part of an alias to insert # newlines. -ALIASES = +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" # will allow you to use the command class in the itcl::class meaning. -TCL_SUBST = +TCL_SUBST = # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For @@ -291,7 +291,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable @@ -627,7 +627,7 @@ GENERATE_DEPRECATEDLIST= YES # sections, marked by \if <section_label> ... \endif and \cond <section_label> # ... \endcond blocks. -ENABLED_SECTIONS = +ENABLED_SECTIONS = # The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the # initial value of a variable or macro / define can have for it to appear in the @@ -669,7 +669,7 @@ SHOW_NAMESPACES = YES # by doxygen. Whatever the program writes to standard output is used as the file # version. For an example see the documentation. -FILE_VERSION_FILTER = +FILE_VERSION_FILTER = # The LAYOUT_FILE tag can be used to specify a layout file which will be parsed # by doxygen. The layout file controls the global structure of the generated @@ -682,7 +682,7 @@ FILE_VERSION_FILTER = # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE # tag is left empty. -LAYOUT_FILE = +LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib @@ -692,7 +692,7 @@ LAYOUT_FILE = # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. -CITE_BIB_FILES = +CITE_BIB_FILES = #--------------------------------------------------------------------------- # Configuration options related to warning and progress messages @@ -751,7 +751,7 @@ WARN_FORMAT = "$file:$line: $text" # messages should be written. If left blank the output is written to standard # error (stderr). -WARN_LOGFILE = +WARN_LOGFILE = #--------------------------------------------------------------------------- # Configuration options related to the input files @@ -807,7 +807,7 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -823,7 +823,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -834,13 +834,13 @@ EXCLUDE_PATTERNS = # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include # command). -EXAMPLE_PATH = +EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and @@ -860,7 +860,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = +IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -877,7 +877,7 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. -INPUT_FILTER = +INPUT_FILTER = # The FILTER_PATTERNS tag can be used to specify filters on a per file pattern # basis. Doxygen will compare the file name with each pattern and apply the @@ -886,7 +886,7 @@ INPUT_FILTER = # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. -FILTER_PATTERNS = +FILTER_PATTERNS = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER ) will also be used to filter the input files that are used for @@ -901,14 +901,14 @@ FILTER_SOURCE_FILES = NO # *.ext= (so without naming a filter). # This tag requires that the tag FILTER_SOURCE_FILES is set to YES. -FILTER_SOURCE_PATTERNS = +FILTER_SOURCE_PATTERNS = # If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that # is part of the input, its contents will be placed on the main page # (index.html). This can be useful if you have a project on for instance GitHub # and want to reuse the introduction page also for the doxygen output. -USE_MDFILE_AS_MAINPAGE = +USE_MDFILE_AS_MAINPAGE = #--------------------------------------------------------------------------- # Configuration options related to source browsing @@ -1013,7 +1013,7 @@ CLANG_ASSISTED_PARSING = NO # specified with INPUT and INCLUDE_PATH. # This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. -CLANG_OPTIONS = +CLANG_OPTIONS = #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index @@ -1039,7 +1039,7 @@ COLS_IN_ALPHA_INDEX = 5 # while generating the index headers. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. -IGNORE_PREFIX = +IGNORE_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the HTML output @@ -1083,7 +1083,7 @@ HTML_FILE_EXTENSION = .html # of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_HEADER = +HTML_HEADER = # The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each # generated HTML page. If the tag is left blank doxygen will generate a standard @@ -1093,7 +1093,7 @@ HTML_HEADER = # that doxygen normally uses. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_FOOTER = +HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user-defined cascading style # sheet that is used by each HTML page. It can be used to fine-tune the look of @@ -1105,7 +1105,7 @@ HTML_FOOTER = # obsolete. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_STYLESHEET = +HTML_STYLESHEET = # The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined # cascading style sheets that are included after the standard style sheets @@ -1118,7 +1118,7 @@ HTML_STYLESHEET = # list). For an example see the documentation. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_STYLESHEET = +HTML_EXTRA_STYLESHEET = # The HTML_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the HTML output directory. Note @@ -1128,7 +1128,7 @@ HTML_EXTRA_STYLESHEET = # files will be copied as-is; there are no commands or markers available. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_EXTRA_FILES = +HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the stylesheet and background images according to @@ -1256,7 +1256,7 @@ GENERATE_HTMLHELP = NO # written to the html output directory. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_FILE = +CHM_FILE = # The HHC_LOCATION tag can be used to specify the location (absolute path # including file name) of the HTML help compiler ( hhc.exe). If non-empty @@ -1264,7 +1264,7 @@ CHM_FILE = # The file has to be specified with full path. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -HHC_LOCATION = +HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated ( # YES) or that it should be included in the master .chm file ( NO). @@ -1277,7 +1277,7 @@ GENERATE_CHI = NO # and project file content. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. -CHM_INDEX_ENCODING = +CHM_INDEX_ENCODING = # The BINARY_TOC flag controls whether a binary table of contents is generated ( # YES) or a normal table of contents ( NO) in the .chm file. Furthermore it @@ -1308,7 +1308,7 @@ GENERATE_QHP = NO # the HTML output folder. # This tag requires that the tag GENERATE_QHP is set to YES. -QCH_FILE = +QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace @@ -1333,7 +1333,7 @@ QHP_VIRTUAL_FOLDER = doc # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_NAME = +QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom @@ -1341,21 +1341,21 @@ QHP_CUST_FILTER_NAME = # filters). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_CUST_FILTER_ATTRS = +QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: # http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. -QHP_SECT_FILTER_ATTRS = +QHP_SECT_FILTER_ATTRS = # The QHG_LOCATION tag can be used to specify the location of Qt's # qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the # generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. -QHG_LOCATION = +QHG_LOCATION = # If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be # 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 # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_EXTENSIONS = +MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site @@ -1496,7 +1496,7 @@ MATHJAX_EXTENSIONS = # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_CODEFILE = +MATHJAX_CODEFILE = # When the SEARCHENGINE tag is enabled doxygen will generate a search box for # the HTML output. The underlying search engine uses javascript and DHTML and @@ -1556,7 +1556,7 @@ EXTERNAL_SEARCH = NO # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. -SEARCHENGINE_URL = +SEARCHENGINE_URL = # When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed # search data is written to a file for indexing by an external tool. With the @@ -1572,7 +1572,7 @@ SEARCHDATA_FILE = searchdata.xml # projects and redirect the results back to the right project. # This tag requires that the tag SEARCHENGINE is set to YES. -EXTERNAL_SEARCH_ID = +EXTERNAL_SEARCH_ID = # The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen # projects other than the one defined by this configuration file, but that are @@ -1582,7 +1582,7 @@ EXTERNAL_SEARCH_ID = # EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ... # This tag requires that the tag SEARCHENGINE is set to YES. -EXTRA_SEARCH_MAPPINGS = +EXTRA_SEARCH_MAPPINGS = #--------------------------------------------------------------------------- # Configuration options related to the LaTeX output @@ -1643,7 +1643,7 @@ PAPER_TYPE = a4 # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. -EXTRA_PACKAGES = +EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for the # generated LaTeX document. The header should contain everything until the first @@ -1659,7 +1659,7 @@ EXTRA_PACKAGES = # HTML_HEADER. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_HEADER = +LATEX_HEADER = # The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the # generated LaTeX document. The footer should contain everything after the last @@ -1670,7 +1670,7 @@ LATEX_HEADER = # Note: Only use a user-defined footer if you know what you are doing! # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_FOOTER = +LATEX_FOOTER = # The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or # other source files which should be copied to the LATEX_OUTPUT output @@ -1678,7 +1678,7 @@ LATEX_FOOTER = # markers available. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_EXTRA_FILES = +LATEX_EXTRA_FILES = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is # prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will @@ -1778,14 +1778,14 @@ RTF_HYPERLINKS = NO # default style sheet that doxygen normally uses. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_STYLESHEET_FILE = +RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is # similar to doxygen's config file. A template extensions file can be generated # using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. -RTF_EXTENSIONS_FILE = +RTF_EXTENSIONS_FILE = #--------------------------------------------------------------------------- # Configuration options related to the man page output @@ -1820,7 +1820,7 @@ MAN_EXTENSION = .3 # MAN_EXTENSION with the initial . removed. # This tag requires that the tag GENERATE_MAN is set to YES. -MAN_SUBDIR = +MAN_SUBDIR = # If the MAN_LINKS tag is set to YES and doxygen generates man output, then it # will generate one additional man file for each entity documented in the real @@ -1933,7 +1933,7 @@ PERLMOD_PRETTY = YES # overwrite each other's variables. # This tag requires that the tag GENERATE_PERLMOD is set to YES. -PERLMOD_MAKEVAR_PREFIX = +PERLMOD_MAKEVAR_PREFIX = #--------------------------------------------------------------------------- # Configuration options related to the preprocessor @@ -1974,7 +1974,7 @@ SEARCH_INCLUDES = YES # preprocessor. # This tag requires that the tag SEARCH_INCLUDES is set to YES. -INCLUDE_PATH = +INCLUDE_PATH = # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the @@ -1982,7 +1982,7 @@ INCLUDE_PATH = # used. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -INCLUDE_FILE_PATTERNS = +INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that are # defined before the preprocessor is started (similar to the -D option of e.g. @@ -1992,7 +1992,7 @@ INCLUDE_FILE_PATTERNS = # recursively expanded use the := operator instead of the = operator. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -PREDEFINED = +PREDEFINED = # If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this # tag can be used to specify a list of macro names that should be expanded. The @@ -2001,7 +2001,7 @@ PREDEFINED = # definition found in the source code. # This tag requires that the tag ENABLE_PREPROCESSING is set to YES. -EXPAND_AS_DEFINED = +EXPAND_AS_DEFINED = # If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will # remove all references to function-like macros that are alone on a line, have @@ -2030,13 +2030,13 @@ SKIP_FUNCTION_MACROS = YES # the path). If a tag file is not located in the directory in which doxygen is # run, you must also specify the path to the tagfile here. -TAGFILES = +TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create a # tag file that is based on the input files it reads. See section "Linking to # external documentation" for more information about the usage of tag files. -GENERATE_TAGFILE = +GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external class will be listed in the # class index. If set to NO only the inherited external classes will be listed. @@ -2084,14 +2084,14 @@ CLASS_DIAGRAMS = YES # the mscgen tool resides. If left empty the tool is assumed to be found in the # default search path. -MSCGEN_PATH = +MSCGEN_PATH = # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. # If left empty dia is assumed to be found in the default search path. -DIA_PATH = +DIA_PATH = # If set to YES, the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. @@ -2140,7 +2140,7 @@ DOT_FONTSIZE = 10 # the path where dot can find it using this tag. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTPATH = +DOT_FONTPATH = # If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for # each documented class showing the direct and indirect inheritance relations. @@ -2278,26 +2278,26 @@ INTERACTIVE_SVG = NO # found. If left blank, it is assumed the dot tool can be found in the path. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_PATH = +DOT_PATH = # The DOTFILE_DIRS tag can be used to specify one or more directories that # contain dot files that are included in the documentation (see the \dotfile # command). # This tag requires that the tag HAVE_DOT is set to YES. -DOTFILE_DIRS = +DOTFILE_DIRS = # The MSCFILE_DIRS tag can be used to specify one or more directories that # contain msc files that are included in the documentation (see the \mscfile # command). -MSCFILE_DIRS = +MSCFILE_DIRS = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile # command). -DIAFILE_DIRS = +DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the # path where java can find the plantuml.jar file. If left blank, it is assumed @@ -2306,7 +2306,7 @@ DIAFILE_DIRS = # will not generate output for the diagram. # This tag requires that the tag HAVE_DOT is set to YES. -PLANTUML_JAR_PATH = +PLANTUML_JAR_PATH = # The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes # that will be shown in the graph. If the number of nodes in a graph becomes @@ -28,5 +28,5 @@ If you like, you can [donate by PayPal](https://www.paypal.com/cgi-bin/webscr?cm * Infrastructure setup * Eventually 3D displays to get proper 3D output working * ... etc ... - + We 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..aef2d6f73 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -33,18 +33,22 @@ after_build: $GITREV = $(git show -s --format='%h') # Where are these spaces coming from? Regardless, let's remove them $BUILD_NAME = "citra-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" + $BUILD_NAME_NOQT = "citra-noqt-${GITDATE}-${GITREV}-windows-amd64.7z" -replace " ","" # Zip up the build folder 7z a $BUILD_NAME .\build\bin\release\* - + # Do a second archive with only the binaries + 7z a $BUILD_NAME_NOQT .\build\bin\release\*.exe + # Download winscp - Invoke-WebRequest "http://hivelocity.dl.sourceforge.net/project/winscp/WinSCP/5.7/winscp570.zip" -OutFile "winscp570.zip" - 7z e -y winscp570.zip - + Invoke-WebRequest "http://iweb.dl.sourceforge.net/project/winscp/WinSCP/5.7.3/winscp573.zip" -OutFile "winscp573.zip" + 7z e -y winscp573.zip + # Upload to server .\WinSCP.com /command ` "option batch abort" ` "option confirm off" ` "open sftp://citra-builds:${env:BUILD_PASSWORD}@builds.citra-emu.org -hostkey=*" ` "put $BUILD_NAME /citra/nightly/windows-amd64/" ` + "put $BUILD_NAME_NOQT /citra/nightly/windows-noqt-amd64/" ` "exit" } diff --git a/src/assets/citra.ico b/dist/citra.ico Binary files differindex 4fef651e2..4fef651e2 100644 --- a/src/assets/citra.ico +++ b/dist/citra.ico diff --git a/doc-icon.png b/dist/doc-icon.png Binary files differindex 420b1546f..420b1546f 100644 --- a/doc-icon.png +++ b/dist/doc-icon.png diff --git a/externals/glfw-3.0.4.bin/include/GLFW/glfw3native.h b/externals/glfw-3.0.4.bin/include/GLFW/glfw3native.h deleted file mode 100644 index d570f5876..000000000 --- a/externals/glfw-3.0.4.bin/include/GLFW/glfw3native.h +++ /dev/null @@ -1,180 +0,0 @@ -/************************************************************************* - * GLFW 3.0 - www.glfw.org - * A library for OpenGL, window and input - *------------------------------------------------------------------------ - * Copyright (c) 2002-2006 Marcus Geelnard - * Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org> - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any damages - * arising from the use of this software. - * - * Permission is granted to anyone to use this software for any purpose, - * including commercial applications, and to alter it and redistribute it - * freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you must not - * claim that you wrote the original software. If you use this software - * in a product, an acknowledgment in the product documentation would - * be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and must not - * be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - * - *************************************************************************/ - -#ifndef _glfw3_native_h_ -#define _glfw3_native_h_ - -#ifdef __cplusplus -extern "C" { -#endif - - -/************************************************************************* - * Doxygen documentation - *************************************************************************/ - -/*! @defgroup native Native access - * - * **By using the native API, you assert that you know what you're doing and - * how to fix problems caused by using it. If you don't, you shouldn't be - * using it.** - * - * Before the inclusion of @ref glfw3native.h, you must define exactly one - * window API macro and exactly one context API macro. Failure to do this - * will cause a compile-time error. - * - * The available window API macros are: - * * `GLFW_EXPOSE_NATIVE_WIN32` - * * `GLFW_EXPOSE_NATIVE_COCOA` - * * `GLFW_EXPOSE_NATIVE_X11` - * - * The available context API macros are: - * * `GLFW_EXPOSE_NATIVE_WGL` - * * `GLFW_EXPOSE_NATIVE_NSGL` - * * `GLFW_EXPOSE_NATIVE_GLX` - * * `GLFW_EXPOSE_NATIVE_EGL` - * - * These macros select which of the native access functions that are declared - * and which platform-specific headers to include. It is then up your (by - * definition platform-specific) code to handle which of these should be - * defined. - */ - - -/************************************************************************* - * System headers and types - *************************************************************************/ - -#if defined(GLFW_EXPOSE_NATIVE_WIN32) - #include <windows.h> -#elif defined(GLFW_EXPOSE_NATIVE_COCOA) - #if defined(__OBJC__) - #import <Cocoa/Cocoa.h> - #else - typedef void* id; - #endif -#elif defined(GLFW_EXPOSE_NATIVE_X11) - #include <X11/Xlib.h> -#else - #error "No window API specified" -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WGL) - /* WGL is declared by windows.h */ -#elif defined(GLFW_EXPOSE_NATIVE_NSGL) - /* NSGL is declared by Cocoa.h */ -#elif defined(GLFW_EXPOSE_NATIVE_GLX) - #include <GL/glx.h> -#elif defined(GLFW_EXPOSE_NATIVE_EGL) - #include <EGL/egl.h> -#else - #error "No context API specified" -#endif - - -/************************************************************************* - * Functions - *************************************************************************/ - -#if defined(GLFW_EXPOSE_NATIVE_WIN32) -/*! @brief Returns the `HWND` of the specified window. - * @return The `HWND` of the specified window. - * @ingroup native - */ -GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_WGL) -/*! @brief Returns the `HGLRC` of the specified window. - * @return The `HGLRC` of the specified window. - * @ingroup native - */ -GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_COCOA) -/*! @brief Returns the `NSWindow` of the specified window. - * @return The `NSWindow` of the specified window. - * @ingroup native - */ -GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_NSGL) -/*! @brief Returns the `NSOpenGLContext` of the specified window. - * @return The `NSOpenGLContext` of the specified window. - * @ingroup native - */ -GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_X11) -/*! @brief Returns the `Display` used by GLFW. - * @return The `Display` used by GLFW. - * @ingroup native - */ -GLFWAPI Display* glfwGetX11Display(void); -/*! @brief Returns the `Window` of the specified window. - * @return The `Window` of the specified window. - * @ingroup native - */ -GLFWAPI Window glfwGetX11Window(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_GLX) -/*! @brief Returns the `GLXContext` of the specified window. - * @return The `GLXContext` of the specified window. - * @ingroup native - */ -GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); -#endif - -#if defined(GLFW_EXPOSE_NATIVE_EGL) -/*! @brief Returns the `EGLDisplay` used by GLFW. - * @return The `EGLDisplay` used by GLFW. - * @ingroup native - */ -GLFWAPI EGLDisplay glfwGetEGLDisplay(void); -/*! @brief Returns the `EGLContext` of the specified window. - * @return The `EGLContext` of the specified window. - * @ingroup native - */ -GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); -/*! @brief Returns the `EGLSurface` of the specified window. - * @return The `EGLSurface` of the specified window. - * @ingroup native - */ -GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); -#endif - -#ifdef __cplusplus -} -#endif - -#endif /* _glfw3_native_h_ */ - diff --git a/externals/glfw-3.0.4.bin/lib-mingw-i686/glfw3.dll b/externals/glfw-3.0.4.bin/lib-mingw-i686/glfw3.dll Binary files differdeleted file mode 100644 index 5941d1a0a..000000000 --- a/externals/glfw-3.0.4.bin/lib-mingw-i686/glfw3.dll +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-mingw-i686/libglfw3.a b/externals/glfw-3.0.4.bin/lib-mingw-i686/libglfw3.a Binary files differdeleted file mode 100644 index 7138ee9b5..000000000 --- a/externals/glfw-3.0.4.bin/lib-mingw-i686/libglfw3.a +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-mingw-x86_64/glfw3.dll b/externals/glfw-3.0.4.bin/lib-mingw-x86_64/glfw3.dll Binary files differdeleted file mode 100644 index 49cf94a80..000000000 --- a/externals/glfw-3.0.4.bin/lib-mingw-x86_64/glfw3.dll +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-mingw-x86_64/libglfw3.a b/externals/glfw-3.0.4.bin/lib-mingw-x86_64/libglfw3.a Binary files differdeleted file mode 100644 index d1ca9a42a..000000000 --- a/externals/glfw-3.0.4.bin/lib-mingw-x86_64/libglfw3.a +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3.dll b/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3.dll Binary files differdeleted file mode 100644 index d66c5dd89..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3.dll +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3.lib b/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3.lib Binary files differdeleted file mode 100644 index 2f972ab1a..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3dll.lib b/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3dll.lib Binary files differdeleted file mode 100644 index 365cdbafb..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v110-Win32/glfw3dll.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3.dll b/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3.dll Binary files differdeleted file mode 100644 index 44e6d49e4..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3.dll +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3.lib b/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3.lib Binary files differdeleted file mode 100644 index 77757999e..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3dll.lib b/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3dll.lib Binary files differdeleted file mode 100644 index 20b548406..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v110-x64/glfw3dll.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3.dll b/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3.dll Binary files differdeleted file mode 100644 index e15fc43b4..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3.dll +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3.lib b/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3.lib Binary files differdeleted file mode 100644 index 071a0ab84..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3dll.lib b/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3dll.lib Binary files differdeleted file mode 100644 index d0c5ff5e1..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v120-Win32/glfw3dll.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3.dll b/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3.dll Binary files differdeleted file mode 100644 index 9da042a6b..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3.dll +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3.lib b/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3.lib Binary files differdeleted file mode 100644 index e2b495ff5..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3dll.lib b/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3dll.lib Binary files differdeleted file mode 100644 index 3d6e86418..000000000 --- a/externals/glfw-3.0.4.bin/lib-msvc_v120-x64/glfw3dll.lib +++ /dev/null diff --git a/externals/glfw-3.0.4.bin/COPYING.txt b/externals/glfw-3.1.1.bin/COPYING.txt index b30c70158..b30c70158 100644 --- a/externals/glfw-3.0.4.bin/COPYING.txt +++ b/externals/glfw-3.1.1.bin/COPYING.txt diff --git a/externals/glfw-3.0.4.bin/include/GLFW/glfw3.h b/externals/glfw-3.1.1.bin/include/GLFW/glfw3.h index 0f97738c7..009fa755f 100644 --- a/externals/glfw-3.0.4.bin/include/GLFW/glfw3.h +++ b/externals/glfw-3.1.1.bin/include/GLFW/glfw3.h @@ -1,5 +1,5 @@ /************************************************************************* - * GLFW 3.0 - www.glfw.org + * GLFW 3.1 - www.glfw.org * A library for OpenGL, window and input *------------------------------------------------------------------------ * Copyright (c) 2002-2006 Marcus Geelnard @@ -38,23 +38,27 @@ extern "C" { * Doxygen documentation *************************************************************************/ -/*! @defgroup clipboard Clipboard support - */ /*! @defgroup context Context handling + * + * This is the reference documentation for context related functions. For more + * information, see the @ref context. */ -/*! @defgroup error Error handling - */ -/*! @defgroup init Initialization and version information +/*! @defgroup init Initialization, version and errors + * + * This is the reference documentation for initialization and termination of + * the library, version management and error handling. For more information, + * see the @ref intro. */ /*! @defgroup input Input handling + * + * This is the reference documentation for input related functions and types. + * For more information, see the @ref input. */ /*! @defgroup monitor Monitor handling * * This is the reference documentation for monitor related functions and types. * For more information, see the @ref monitor. */ -/*! @defgroup time Time input - */ /*! @defgroup window Window handling * * This is the reference documentation for window related functions and types, @@ -64,28 +68,17 @@ extern "C" { /************************************************************************* - * Global definitions + * Compiler- and platform-specific preprocessor work *************************************************************************/ -/* ------------------- BEGIN SYSTEM/COMPILER SPECIFIC -------------------- */ - -/* Please report any problems that you find with your compiler, which may - * be solved in this section! There are several compilers that I have not - * been able to test this file with yet. - * - * First: If we are we on Windows, we want a single define for it (_WIN32) - * (Note: For Cygwin the compiler flag -mwin32 should be used, but to - * make sure that things run smoothly for Cygwin users, we add __CYGWIN__ - * to the list of "valid Win32 identifiers", which removes the need for - * -mwin32) +/* If we are we on Windows, we want a single define for it. */ -#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__CYGWIN__)) +#if !defined(_WIN32) && (defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)) #define _WIN32 #endif /* _WIN32 */ -/* In order for extension support to be portable, we need to define an - * OpenGL function call method. We use the keyword APIENTRY, which is - * defined for Win32. (Note: Windows also needs this for <GL/gl.h>) +/* It is customary to use APIENTRY for OpenGL function pointer declarations on + * all platforms. Additionally, the Windows OpenGL header needs APIENTRY. */ #ifndef APIENTRY #ifdef _WIN32 @@ -95,44 +88,23 @@ extern "C" { #endif #endif /* APIENTRY */ -/* The following three defines are here solely to make some Windows-based - * <GL/gl.h> files happy. Theoretically we could include <windows.h>, but - * it has the major drawback of severely polluting our namespace. +/* Some Windows OpenGL headers need this. */ - -/* Under Windows, we need WINGDIAPI defined */ #if !defined(WINGDIAPI) && defined(_WIN32) - #if defined(_MSC_VER) || defined(__BORLANDC__) || defined(__POCC__) - /* Microsoft Visual C++, Borland C++ Builder and Pelles C */ - #define WINGDIAPI __declspec(dllimport) - #elif defined(__LCC__) - /* LCC-Win32 */ - #define WINGDIAPI __stdcall - #else - /* Others (e.g. MinGW, Cygwin) */ - #define WINGDIAPI extern - #endif + #define WINGDIAPI __declspec(dllimport) #define GLFW_WINGDIAPI_DEFINED #endif /* WINGDIAPI */ -/* Some <GL/glu.h> files also need CALLBACK defined */ +/* Some Windows GLU headers need this. + */ #if !defined(CALLBACK) && defined(_WIN32) - #if defined(_MSC_VER) - /* Microsoft Visual C++ */ - #if (defined(_M_MRX000) || defined(_M_IX86) || defined(_M_ALPHA) || defined(_M_PPC)) && !defined(MIDL_PASS) - #define CALLBACK __stdcall - #else - #define CALLBACK - #endif - #else - /* Other Windows compilers */ - #define CALLBACK __stdcall - #endif + #define CALLBACK __stdcall #define GLFW_CALLBACK_DEFINED #endif /* CALLBACK */ -/* Most GL/glu.h variants on Windows need wchar_t - * OpenGL/gl.h blocks the definition of ptrdiff_t by glext.h on OS X */ +/* Most Windows GLU headers need wchar_t. + * The OS X OpenGL header blocks the definition of ptrdiff_t by glext.h. + */ #if !defined(GLFW_INCLUDE_NONE) #include <stddef.h> #endif @@ -140,67 +112,79 @@ extern "C" { /* Include the chosen client API headers. */ #if defined(__APPLE_CC__) - #if defined(GLFW_INCLUDE_GLCOREARB) - #include <OpenGL/gl3.h> - #elif !defined(GLFW_INCLUDE_NONE) - #define GL_GLEXT_LEGACY - #include <OpenGL/gl.h> + #if defined(GLFW_INCLUDE_GLCOREARB) + #include <OpenGL/gl3.h> + #if defined(GLFW_INCLUDE_GLEXT) + #include <OpenGL/gl3ext.h> #endif - #if defined(GLFW_INCLUDE_GLU) - #include <OpenGL/glu.h> + #elif !defined(GLFW_INCLUDE_NONE) + #if !defined(GLFW_INCLUDE_GLEXT) + #define GL_GLEXT_LEGACY #endif + #include <OpenGL/gl.h> + #endif + #if defined(GLFW_INCLUDE_GLU) + #include <OpenGL/glu.h> + #endif #else - #if defined(GLFW_INCLUDE_GLCOREARB) - #include <GL/glcorearb.h> - #elif defined(GLFW_INCLUDE_ES1) - #include <GLES/gl.h> - #elif defined(GLFW_INCLUDE_ES2) - #include <GLES2/gl2.h> - #elif defined(GLFW_INCLUDE_ES3) - #include <GLES3/gl3.h> - #elif !defined(GLFW_INCLUDE_NONE) - #include <GL/gl.h> + #if defined(GLFW_INCLUDE_GLCOREARB) + #include <GL/glcorearb.h> + #elif defined(GLFW_INCLUDE_ES1) + #include <GLES/gl.h> + #if defined(GLFW_INCLUDE_GLEXT) + #include <GLES/glext.h> + #endif + #elif defined(GLFW_INCLUDE_ES2) + #include <GLES2/gl2.h> + #if defined(GLFW_INCLUDE_GLEXT) + #include <GLES2/gl2ext.h> #endif - #if defined(GLFW_INCLUDE_GLU) - #include <GL/glu.h> + #elif defined(GLFW_INCLUDE_ES3) + #include <GLES3/gl3.h> + #if defined(GLFW_INCLUDE_GLEXT) + #include <GLES3/gl2ext.h> #endif + #elif defined(GLFW_INCLUDE_ES31) + #include <GLES3/gl31.h> + #if defined(GLFW_INCLUDE_GLEXT) + #include <GLES3/gl2ext.h> + #endif + #elif !defined(GLFW_INCLUDE_NONE) + #include <GL/gl.h> + #if defined(GLFW_INCLUDE_GLEXT) + #include <GL/glext.h> + #endif + #endif + #if defined(GLFW_INCLUDE_GLU) + #include <GL/glu.h> + #endif #endif #if defined(GLFW_DLL) && defined(_GLFW_BUILD_DLL) - /* GLFW_DLL is defined by users of GLFW when compiling programs that will link - * to the DLL version of the GLFW library. _GLFW_BUILD_DLL is defined by the - * GLFW configuration header when compiling the DLL version of the library. + /* GLFW_DLL must be defined by applications that are linking against the DLL + * version of the GLFW library. _GLFW_BUILD_DLL is defined by the GLFW + * configuration header when compiling the DLL version of the library. */ - #error "You must not have both GLFW_DLL and _GLFW_BUILD_DLL defined" + #error "You may not have both GLFW_DLL and _GLFW_BUILD_DLL defined" #endif +/* GLFWAPI is used to declare public API functions for export + * from the DLL / shared library / dynamic library. + */ #if defined(_WIN32) && defined(_GLFW_BUILD_DLL) - - /* We are building a Win32 DLL */ + /* We are building GLFW as a Win32 DLL */ #define GLFWAPI __declspec(dllexport) - #elif defined(_WIN32) && defined(GLFW_DLL) - - /* We are calling a Win32 DLL */ - #if defined(__LCC__) - #define GLFWAPI extern - #else - #define GLFWAPI __declspec(dllimport) - #endif - + /* We are calling GLFW as a Win32 DLL */ + #define GLFWAPI __declspec(dllimport) #elif defined(__GNUC__) && defined(_GLFW_BUILD_DLL) - + /* We are building GLFW as a shared / dynamic library */ #define GLFWAPI __attribute__((visibility("default"))) - #else - - /* We are either building/calling a static lib or we are non-win32 */ + /* We are building or calling GLFW as a static library */ #define GLFWAPI - #endif -/* -------------------- END SYSTEM/COMPILER SPECIFIC --------------------- */ - /************************************************************************* * GLFW API tokens @@ -220,27 +204,36 @@ extern "C" { * backward-compatible. * @ingroup init */ -#define GLFW_VERSION_MINOR 0 +#define GLFW_VERSION_MINOR 1 /*! @brief The revision number of the GLFW library. * * This is incremented when a bug fix release is made that does not contain any * API changes. * @ingroup init */ -#define GLFW_VERSION_REVISION 4 +#define GLFW_VERSION_REVISION 1 /*! @} */ /*! @name Key and button actions * @{ */ -/*! @brief The key or button was released. +/*! @brief The key or mouse button was released. + * + * The key or mouse button was released. + * * @ingroup input */ #define GLFW_RELEASE 0 -/*! @brief The key or button was pressed. +/*! @brief The key or mouse button was pressed. + * + * The key or mouse button was pressed. + * * @ingroup input */ #define GLFW_PRESS 1 /*! @brief The key was held down until it repeated. + * + * The key was held down until it repeated. + * * @ingroup input */ #define GLFW_REPEAT 2 @@ -248,20 +241,22 @@ extern "C" { /*! @defgroup keys Keyboard keys * - * These key codes are inspired by the *USB HID Usage Tables v1.12* (p. 53-60), - * but re-arranged to map to 7-bit ASCII for printable keys (function keys are - * put in the 256+ range). - * - * The naming of the key codes follow these rules: - * - The US keyboard layout is used - * - Names of printable alpha-numeric characters are used (e.g. "A", "R", - * "3", etc.) - * - For non-alphanumeric characters, Unicode:ish names are used (e.g. - * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not - * correspond to the Unicode standard (usually for brevity) - * - Keys that lack a clear US mapping are named "WORLD_x" - * - For non-printable keys, custom names are used (e.g. "F4", - * "BACKSPACE", etc.) + * See [key input](@ref input_key) for how these are used. + * + * These key codes are inspired by the _USB HID Usage Tables v1.12_ (p. 53-60), + * but re-arranged to map to 7-bit ASCII for printable keys (function keys are + * put in the 256+ range). + * + * The naming of the key codes follow these rules: + * - The US keyboard layout is used + * - Names of printable alpha-numeric characters are used (e.g. "A", "R", + * "3", etc.) + * - For non-alphanumeric characters, Unicode:ish names are used (e.g. + * "COMMA", "LEFT_SQUARE_BRACKET", etc.). Note that some names do not + * correspond to the Unicode standard (usually for brevity) + * - Keys that lack a clear US mapping are named "WORLD_x" + * - For non-printable keys, custom names are used (e.g. "F4", + * "BACKSPACE", etc.) * * @ingroup input * @{ @@ -398,6 +393,9 @@ extern "C" { /*! @} */ /*! @defgroup mods Modifier key flags + * + * See [key input](@ref input_key) for how these are used. + * * @ingroup input * @{ */ @@ -417,6 +415,9 @@ extern "C" { /*! @} */ /*! @defgroup buttons Mouse buttons + * + * See [mouse button input](@ref input_mouse_button) for how these are used. + * * @ingroup input * @{ */ #define GLFW_MOUSE_BUTTON_1 0 @@ -434,6 +435,9 @@ extern "C" { /*! @} */ /*! @defgroup joysticks Joysticks + * + * See [joystick input](@ref joystick) for how these are used. + * * @ingroup input * @{ */ #define GLFW_JOYSTICK_1 0 @@ -456,36 +460,131 @@ extern "C" { /*! @} */ /*! @defgroup errors Error codes - * @ingroup error + * + * See [error handling](@ref error_handling) for how these are used. + * + * @ingroup init * @{ */ /*! @brief GLFW has not been initialized. + * + * This occurs if a GLFW function was called that may not be called unless the + * library is [initialized](@ref intro_init). + * + * @par Analysis + * Application programmer error. Initialize GLFW before calling any function + * that requires initialization. */ #define GLFW_NOT_INITIALIZED 0x00010001 /*! @brief No context is current for this thread. + * + * This occurs if a GLFW function was called that needs and operates on the + * current OpenGL or OpenGL ES context but no context is current on the calling + * thread. One such function is @ref glfwSwapInterval. + * + * @par Analysis + * Application programmer error. Ensure a context is current before calling + * functions that require a current context. */ #define GLFW_NO_CURRENT_CONTEXT 0x00010002 -/*! @brief One of the enum parameters for the function was given an invalid - * enum. +/*! @brief One of the arguments to the function was an invalid enum value. + * + * One of the arguments to the function was an invalid enum value, for example + * requesting [GLFW_RED_BITS](@ref window_hints_fb) with @ref + * glfwGetWindowAttrib. + * + * @par Analysis + * Application programmer error. Fix the offending call. */ #define GLFW_INVALID_ENUM 0x00010003 -/*! @brief One of the parameters for the function was given an invalid value. +/*! @brief One of the arguments to the function was an invalid value. + * + * One of the arguments to the function was an invalid value, for example + * requesting a non-existent OpenGL or OpenGL ES version like 2.7. + * + * Requesting a valid but unavailable OpenGL or OpenGL ES version will instead + * result in a @ref GLFW_VERSION_UNAVAILABLE error. + * + * @par Analysis + * Application programmer error. Fix the offending call. */ #define GLFW_INVALID_VALUE 0x00010004 /*! @brief A memory allocation failed. + * + * A memory allocation failed. + * + * @par Analysis + * A bug in GLFW or the underlying operating system. Report the bug to our + * [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_OUT_OF_MEMORY 0x00010005 /*! @brief GLFW could not find support for the requested client API on the * system. + * + * GLFW could not find support for the requested client API on the system. If + * emitted by functions other than @ref glfwCreateWindow, no supported client + * API was found. + * + * @par Analysis + * The installed graphics driver does not support the requested client API, or + * does not support it via the chosen context creation backend. Below are + * a few examples. + * + * @par + * Some pre-installed Windows graphics drivers do not support OpenGL. AMD only + * supports OpenGL ES via EGL, while Nvidia and Intel only supports it via + * a WGL or GLX extension. OS X does not provide OpenGL ES at all. The Mesa + * EGL, OpenGL and OpenGL ES libraries do not interface with the Nvidia binary + * driver. */ #define GLFW_API_UNAVAILABLE 0x00010006 -/*! @brief The requested client API version is not available. +/*! @brief The requested OpenGL or OpenGL ES version is not available. + * + * The requested OpenGL or OpenGL ES version (including any requested context + * or framebuffer hints) is not available on this machine. + * + * @par Analysis + * The machine does not support your requirements. If your application is + * sufficiently flexible, downgrade your requirements and try again. + * Otherwise, inform the user that their machine does not match your + * requirements. + * + * @par + * Future invalid OpenGL and OpenGL ES versions, for example OpenGL 4.8 if 5.0 + * comes out before the 4.x series gets that far, also fail with this error and + * not @ref GLFW_INVALID_VALUE, because GLFW cannot know what future versions + * will exist. */ #define GLFW_VERSION_UNAVAILABLE 0x00010007 /*! @brief A platform-specific error occurred that does not match any of the * more specific categories. + * + * A platform-specific error occurred that does not match any of the more + * specific categories. + * + * @par Analysis + * A bug or configuration error in GLFW, the underlying operating system or + * its drivers, or a lack of required resources. Report the issue to our + * [issue tracker](https://github.com/glfw/glfw/issues). */ #define GLFW_PLATFORM_ERROR 0x00010008 -/*! @brief The clipboard did not contain data in the requested format. +/*! @brief The requested format is not supported or available. + * + * If emitted during window creation, the requested pixel format is not + * supported. + * + * If emitted when querying the clipboard, the contents of the clipboard could + * not be converted to the requested format. + * + * @par Analysis + * If emitted during window creation, one or more + * [hard constraints](@ref window_hints_hard) did not match any of the + * available pixel formats. If your application is sufficiently flexible, + * downgrade your requirements and try again. Otherwise, inform the user that + * their machine does not match your requirements. + * + * @par + * If emitted when querying the clipboard, ignore the error or report it to + * the user, as appropriate. */ #define GLFW_FORMAT_UNAVAILABLE 0x00010009 /*! @} */ @@ -495,6 +594,8 @@ extern "C" { #define GLFW_RESIZABLE 0x00020003 #define GLFW_VISIBLE 0x00020004 #define GLFW_DECORATED 0x00020005 +#define GLFW_AUTO_ICONIFY 0x00020006 +#define GLFW_FLOATING 0x00020007 #define GLFW_RED_BITS 0x00021001 #define GLFW_GREEN_BITS 0x00021002 @@ -511,6 +612,7 @@ extern "C" { #define GLFW_SAMPLES 0x0002100D #define GLFW_SRGB_CAPABLE 0x0002100E #define GLFW_REFRESH_RATE 0x0002100F +#define GLFW_DOUBLEBUFFER 0x00021010 #define GLFW_CLIENT_API 0x00022001 #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002 @@ -520,6 +622,7 @@ extern "C" { #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006 #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007 #define GLFW_OPENGL_PROFILE 0x00022008 +#define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009 #define GLFW_OPENGL_API 0x00030001 #define GLFW_OPENGL_ES_API 0x00030002 @@ -540,9 +643,54 @@ extern "C" { #define GLFW_CURSOR_HIDDEN 0x00034002 #define GLFW_CURSOR_DISABLED 0x00034003 +#define GLFW_ANY_RELEASE_BEHAVIOR 0 +#define GLFW_RELEASE_BEHAVIOR_FLUSH 0x00035001 +#define GLFW_RELEASE_BEHAVIOR_NONE 0x00035002 + +/*! @defgroup shapes Standard cursor shapes + * + * See [standard cursor creation](@ref cursor_standard) for how these are used. + * + * @ingroup input + * @{ */ + +/*! @brief The regular arrow cursor shape. + * + * The regular arrow cursor. + */ +#define GLFW_ARROW_CURSOR 0x00036001 +/*! @brief The text input I-beam cursor shape. + * + * The text input I-beam cursor shape. + */ +#define GLFW_IBEAM_CURSOR 0x00036002 +/*! @brief The crosshair shape. + * + * The crosshair shape. + */ +#define GLFW_CROSSHAIR_CURSOR 0x00036003 +/*! @brief The hand shape. + * + * The hand shape. + */ +#define GLFW_HAND_CURSOR 0x00036004 +/*! @brief The horizontal resize arrow shape. + * + * The horizontal resize arrow shape. + */ +#define GLFW_HRESIZE_CURSOR 0x00036005 +/*! @brief The vertical resize arrow shape. + * + * The vertical resize arrow shape. + */ +#define GLFW_VRESIZE_CURSOR 0x00036006 +/*! @} */ + #define GLFW_CONNECTED 0x00040001 #define GLFW_DISCONNECTED 0x00040002 +#define GLFW_DONT_CARE -1 + /************************************************************************* * GLFW API types @@ -573,6 +721,14 @@ typedef struct GLFWmonitor GLFWmonitor; */ typedef struct GLFWwindow GLFWwindow; +/*! @brief Opaque cursor object. + * + * Opaque cursor object. + * + * @ingroup cursor + */ +typedef struct GLFWcursor GLFWcursor; + /*! @brief The function signature for error callbacks. * * This is the function signature for error callback functions. @@ -582,7 +738,7 @@ typedef struct GLFWwindow GLFWwindow; * * @sa glfwSetErrorCallback * - * @ingroup error + * @ingroup init */ typedef void (* GLFWerrorfun)(int,const char*); @@ -590,7 +746,7 @@ typedef void (* GLFWerrorfun)(int,const char*); * * This is the function signature for window position callback functions. * - * @param[in] window The window that the user moved. + * @param[in] window The window that was moved. * @param[in] xpos The new x-coordinate, in screen coordinates, of the * upper-left corner of the client area of the window. * @param[in] ypos The new y-coordinate, in screen coordinates, of the @@ -606,7 +762,7 @@ typedef void (* GLFWwindowposfun)(GLFWwindow*,int,int); * * This is the function signature for window size callback functions. * - * @param[in] window The window that the user resized. + * @param[in] window The window that was resized. * @param[in] width The new width, in screen coordinates, of the window. * @param[in] height The new height, in screen coordinates, of the window. * @@ -644,9 +800,9 @@ typedef void (* GLFWwindowrefreshfun)(GLFWwindow*); * * This is the function signature for window focus callback functions. * - * @param[in] window The window that was focused or defocused. - * @param[in] focused `GL_TRUE` if the window was focused, or `GL_FALSE` if - * it was defocused. + * @param[in] window The window that gained or lost input focus. + * @param[in] focused `GL_TRUE` if the window was given input focus, or + * `GL_FALSE` if it lost it. * * @sa glfwSetWindowFocusCallback * @@ -750,7 +906,7 @@ typedef void (* GLFWscrollfun)(GLFWwindow*,double,double); * @param[in] window The window that received the event. * @param[in] key The [keyboard key](@ref keys) that was pressed or released. * @param[in] scancode The system-specific scancode of the key. - * @param[in] action @ref GLFW_PRESS, @ref GLFW_RELEASE or @ref GLFW_REPEAT. + * @param[in] action `GLFW_PRESS`, `GLFW_RELEASE` or `GLFW_REPEAT`. * @param[in] mods Bit field describing which [modifier keys](@ref mods) were * held down. * @@ -773,6 +929,38 @@ typedef void (* GLFWkeyfun)(GLFWwindow*,int,int,int,int); */ typedef void (* GLFWcharfun)(GLFWwindow*,unsigned int); +/*! @brief The function signature for Unicode character with modifiers + * callbacks. + * + * This is the function signature for Unicode character with modifiers callback + * functions. It is called for each input character, regardless of what + * modifier keys are held down. + * + * @param[in] window The window that received the event. + * @param[in] codepoint The Unicode code point of the character. + * @param[in] mods Bit field describing which [modifier keys](@ref mods) were + * held down. + * + * @sa glfwSetCharModsCallback + * + * @ingroup input + */ +typedef void (* GLFWcharmodsfun)(GLFWwindow*,unsigned int,int); + +/*! @brief The function signature for file drop callbacks. + * + * This is the function signature for file drop callbacks. + * + * @param[in] window The window that received the event. + * @param[in] count The number of dropped files. + * @param[in] paths The UTF-8 encoded file and/or directory path names. + * + * @sa glfwSetDropCallback + * + * @ingroup input + */ +typedef void (* GLFWdropfun)(GLFWwindow*,int,const char**); + /*! @brief The function signature for monitor configuration callbacks. * * This is the function signature for monitor configuration callback functions. @@ -838,6 +1026,21 @@ typedef struct GLFWgammaramp unsigned int size; } GLFWgammaramp; +/*! @brief Image data. + */ +typedef struct GLFWimage +{ + /*! The width, in pixels, of this image. + */ + int width; + /*! The height, in pixels, of this image. + */ + int height; + /*! The pixel data of this image, arranged left-to-right, top-to-bottom. + */ + unsigned char* pixels; +} GLFWimage; + /************************************************************************* * GLFW API functions @@ -846,53 +1049,70 @@ typedef struct GLFWgammaramp /*! @brief Initializes the GLFW library. * * This function initializes the GLFW library. Before most GLFW functions can - * be used, GLFW must be initialized, and before a program terminates GLFW + * be used, GLFW must be initialized, and before an application terminates GLFW * should be terminated in order to free any resources allocated during or * after initialization. * * If this function fails, it calls @ref glfwTerminate before returning. If it - * succeeds, you should call @ref glfwTerminate before the program exits. + * succeeds, you should call @ref glfwTerminate before the application exits. * * Additional calls to this function after successful initialization but before - * termination will succeed but will do nothing. + * termination will return `GL_TRUE` immediately. * - * @return `GL_TRUE` if successful, or `GL_FALSE` if an error occurred. + * @return `GL_TRUE` if successful, or `GL_FALSE` if an + * [error](@ref error_handling) occurred. * - * @par New in GLFW 3 - * This function no longer registers @ref glfwTerminate with `atexit`. + * @remarks __OS X:__ This function will change the current directory of the + * application to the `Contents/Resources` subdirectory of the application's + * bundle, if present. This can be disabled with a + * [compile-time option](@ref compile_options_osx). * - * @note This function may only be called from the main thread. + * @remarks __X11:__ If the `LC_CTYPE` category of the current locale is set to + * `"C"` then the environment's locale will be applied to that category. This + * is done because character input will not function when `LC_CTYPE` is set to + * `"C"`. If another locale was set before this function was called, it will + * be left untouched. * - * @note **OS X:** This function will change the current directory of the - * application to the `Contents/Resources` subdirectory of the application's - * bundle, if present. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref intro_init * @sa glfwTerminate * + * @since Added in GLFW 1.0. + * * @ingroup init */ GLFWAPI int glfwInit(void); /*! @brief Terminates the GLFW library. * - * This function destroys all remaining windows, frees any allocated resources - * and sets the library to an uninitialized state. Once this is called, you - * must again call @ref glfwInit successfully before you will be able to use - * most GLFW functions. + * This function destroys all remaining windows and cursors, restores any + * modified gamma ramps and frees any other allocated resources. Once this + * function is called, you must again call @ref glfwInit successfully before + * you will be able to use most GLFW functions. * * If GLFW has been successfully initialized, this function should be called - * before the program exits. If initialization fails, there is no need to call - * this function, as it is called by @ref glfwInit before it returns failure. + * before the application exits. If initialization fails, there is no need to + * call this function, as it is called by @ref glfwInit before it returns + * failure. * * @remarks This function may be called before @ref glfwInit. * - * @note This function may only be called from the main thread. - * * @warning No window's context may be current on another thread when this * function is called. * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref intro_init * @sa glfwInit * + * @since Added in GLFW 1.0. + * * @ingroup init */ GLFWAPI void glfwTerminate(void); @@ -903,46 +1123,55 @@ GLFWAPI void glfwTerminate(void); * library. It is intended for when you are using GLFW as a shared library and * want to ensure that you are using the minimum required version. * + * Any or all of the version arguments may be `NULL`. This function always + * succeeds. + * * @param[out] major Where to store the major version number, or `NULL`. * @param[out] minor Where to store the minor version number, or `NULL`. * @param[out] rev Where to store the revision number, or `NULL`. * * @remarks This function may be called before @ref glfwInit. * - * @remarks This function may be called from any thread. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref intro_version * @sa glfwGetVersionString * + * @since Added in GLFW 1.0. + * * @ingroup init */ GLFWAPI void glfwGetVersion(int* major, int* minor, int* rev); /*! @brief Returns a string describing the compile-time configuration. * - * This function returns a static string generated at compile-time according to - * which configuration macros were defined. This is intended for use when - * submitting bug reports, to allow developers to see which code paths are - * enabled in a binary. - * - * The format of the string is as follows: - * - The version of GLFW - * - The name of the window system API - * - The name of the context creation API - * - Any additional options or APIs + * This function returns the compile-time generated + * [version string](@ref intro_version_string) of the GLFW library binary. It + * describes the version, platform, compiler and any platform-specific + * compile-time options. * - * For example, when compiling GLFW 3.0 with MinGW using the Win32 and WGL - * back ends, the version string may look something like this: + * __Do not use the version string__ to parse the GLFW library version. The + * @ref glfwGetVersion function already provides the version of the running + * library binary. * - * 3.0.0 Win32 WGL MinGW + * This function always succeeds. * * @return The GLFW version string. * * @remarks This function may be called before @ref glfwInit. * - * @remarks This function may be called from any thread. + * @par Pointer Lifetime + * The returned string is static and compile-time generated. * + * @par Thread Safety + * This function may be called from any thread. + * + * @sa @ref intro_version * @sa glfwGetVersion * + * @since Added in GLFW 3.0. + * * @ingroup init */ GLFWAPI const char* glfwGetVersionString(void); @@ -952,23 +1181,31 @@ GLFWAPI const char* glfwGetVersionString(void); * This function sets the error callback, which is called with an error code * and a human-readable description each time a GLFW error occurs. * + * The error callback is called on the thread where the error occurred. If you + * are using GLFW from multiple threads, your error callback needs to be + * written accordingly. + * + * Because the description string may have been generated specifically for that + * error, it is not guaranteed to be valid after the callback has returned. If + * you wish to use it after the callback returns, you need to make a copy. + * + * Once set, the error callback remains set even after the library has been + * terminated. + * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set. * * @remarks This function may be called before @ref glfwInit. * - * @note The error callback is called by the thread where the error was - * generated. If you are using GLFW from multiple threads, your error callback - * needs to be written accordingly. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref error_handling * - * @note Because the description string provided to the callback may have been - * generated specifically for that error, it is not guaranteed to be valid - * after the callback has returned. If you wish to use it after that, you need - * to make your own copy of it before returning. + * @since Added in GLFW 3.0. * - * @ingroup error + * @ingroup init */ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); @@ -977,19 +1214,25 @@ GLFWAPI GLFWerrorfun glfwSetErrorCallback(GLFWerrorfun cbfun); * This function returns an array of handles for all currently connected * monitors. * - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. - * @return An array of monitor handles, or `NULL` if an error occurred. + * @param[out] count Where to store the number of monitors in the returned + * array. This is set to zero if an error occurred. + * @return An array of monitor handles, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is guaranteed to be valid only until the monitor configuration + * changes or the library is terminated. * - * @note The returned array is valid only until the monitor configuration - * changes. See @ref glfwSetMonitorCallback to receive notifications of - * configuration changes. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref monitor_monitors + * @sa @ref monitor_event * @sa glfwGetPrimaryMonitor * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); @@ -999,10 +1242,17 @@ GLFWAPI GLFWmonitor** glfwGetMonitors(int* count); * This function returns the primary monitor. This is usually the monitor * where elements like the Windows task bar or the OS X menu bar is located. * - * @return The primary monitor, or `NULL` if an error occurred. + * @return The primary monitor, or `NULL` if an [error](@ref error_handling) + * occurred. + * + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref monitor_monitors * @sa glfwGetMonitors * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); @@ -1012,10 +1262,20 @@ GLFWAPI GLFWmonitor* glfwGetPrimaryMonitor(void); * This function returns the position, in screen coordinates, of the upper-left * corner of the specified monitor. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] monitor The monitor to query. * @param[out] xpos Where to store the monitor x-coordinate, or `NULL`. * @param[out] ypos Where to store the monitor y-coordinate, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); @@ -1025,31 +1285,55 @@ GLFWAPI void glfwGetMonitorPos(GLFWmonitor* monitor, int* xpos, int* ypos); * This function returns the size, in millimetres, of the display area of the * specified monitor. * + * Some systems do not provide accurate monitor size information, either + * because the monitor + * [EDID](https://en.wikipedia.org/wiki/Extended_display_identification_data) + * data is incorrect or because the driver does not report it accurately. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * * @param[in] monitor The monitor to query. - * @param[out] width Where to store the width, in mm, of the monitor's display - * area, or `NULL`. - * @param[out] height Where to store the height, in mm, of the monitor's - * display area, or `NULL`. + * @param[out] widthMM Where to store the width, in millimetres, of the + * monitor's display area, or `NULL`. + * @param[out] heightMM Where to store the height, in millimetres, of the + * monitor's display area, or `NULL`. * - * @note Some operating systems do not provide accurate information, either - * because the monitor's EDID data is incorrect, or because the driver does not - * report it accurately. + * @remarks __Windows:__ The OS calculates the returned physical size from the + * current resolution and system DPI instead of querying the monitor EDID data. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_properties + * + * @since Added in GLFW 3.0. * * @ingroup monitor */ -GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* width, int* height); +GLFWAPI void glfwGetMonitorPhysicalSize(GLFWmonitor* monitor, int* widthMM, int* heightMM); /*! @brief Returns the name of the specified monitor. * * This function returns a human-readable name, encoded as UTF-8, of the - * specified monitor. + * specified monitor. The name typically reflects the make and model of the + * monitor and is not guaranteed to be unique among the connected monitors. * * @param[in] monitor The monitor to query. - * @return The UTF-8 encoded name of the monitor, or `NULL` if an error - * occurred. + * @return The UTF-8 encoded name of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Pointer Lifetime + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified monitor is disconnected or the + * library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_properties * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @since Added in GLFW 3.0. * * @ingroup monitor */ @@ -1063,12 +1347,19 @@ GLFWAPI const char* glfwGetMonitorName(GLFWmonitor* monitor); * * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @bug **X11:** This callback is not yet called on monitor configuration + * @bug __X11:__ This callback is not yet called on monitor configuration * changes. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_event + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); @@ -1083,16 +1374,25 @@ GLFWAPI GLFWmonitorfun glfwSetMonitorCallback(GLFWmonitorfun cbfun); * @param[in] monitor The monitor to query. * @param[out] count Where to store the number of video modes in the returned * array. This is set to zero if an error occurred. - * @return An array of video modes, or `NULL` if an error occurred. + * @return An array of video modes, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified monitor is disconnected, this + * function is called again for that monitor or the library is terminated. * - * @note The returned array is valid only until this function is called again - * for the specified monitor. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref monitor_modes * @sa glfwGetVideoMode * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Changed to return an array of modes for a specific monitor. + * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); @@ -1100,17 +1400,26 @@ GLFWAPI const GLFWvidmode* glfwGetVideoModes(GLFWmonitor* monitor, int* count); /*! @brief Returns the current mode of the specified monitor. * * This function returns the current video mode of the specified monitor. If - * you are using a full screen window, the return value will therefore depend - * on whether it is focused. + * you have created a full screen window for that monitor, the return value + * will depend on whether that window is iconified. * * @param[in] monitor The monitor to query. - * @return The current mode of the monitor, or `NULL` if an error occurred. + * @return The current mode of the monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified monitor is disconnected or the + * library is terminated. * - * @note The returned struct is allocated and freed by GLFW. You should not - * free it yourself. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref monitor_modes * @sa glfwGetVideoModes * + * @since Added in GLFW 3.0. Replaces `glfwGetDesktopMode`. + * * @ingroup monitor */ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); @@ -1118,24 +1427,43 @@ GLFWAPI const GLFWvidmode* glfwGetVideoMode(GLFWmonitor* monitor); /*! @brief Generates a gamma ramp and sets it for the specified monitor. * * This function generates a 256-element gamma ramp from the specified exponent - * and then calls @ref glfwSetGammaRamp with it. + * and then calls @ref glfwSetGammaRamp with it. The value must be a finite + * number greater than zero. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] gamma The desired exponent. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in GLFW 3.0. + * * @ingroup monitor */ GLFWAPI void glfwSetGamma(GLFWmonitor* monitor, float gamma); -/*! @brief Retrieves the current gamma ramp for the specified monitor. +/*! @brief Returns the current gamma ramp for the specified monitor. * - * This function retrieves the current gamma ramp of the specified monitor. + * This function returns the current gamma ramp of the specified monitor. * * @param[in] monitor The monitor to query. - * @return The current gamma ramp, or `NULL` if an error occurred. + * @return The current gamma ramp, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @note The value arrays of the returned ramp are allocated and freed by GLFW. - * You should not free them yourself. + * @par Pointer Lifetime + * The returned structure and its arrays are allocated and freed by GLFW. You + * should not free them yourself. They are valid until the specified monitor + * is disconnected, this function is called again for that monitor or the + * library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in GLFW 3.0. * * @ingroup monitor */ @@ -1143,12 +1471,27 @@ GLFWAPI const GLFWgammaramp* glfwGetGammaRamp(GLFWmonitor* monitor); /*! @brief Sets the current gamma ramp for the specified monitor. * - * This function sets the current gamma ramp for the specified monitor. + * This function sets the current gamma ramp for the specified monitor. The + * original gamma ramp for that monitor is saved by GLFW the first time this + * function is called and is restored by @ref glfwTerminate. * * @param[in] monitor The monitor whose gamma ramp to set. * @param[in] ramp The gamma ramp to use. * - * @note Gamma ramp sizes other than 256 are not supported by all hardware. + * @remarks Gamma ramp sizes other than 256 are not supported by all platforms + * or graphics hardware. + * + * @remarks __Windows:__ The gamma ramp size must be 256. + * + * @par Pointer Lifetime + * The specified gamma ramp is copied before this function returns. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref monitor_gamma + * + * @since Added in GLFW 3.0. * * @ingroup monitor */ @@ -1159,10 +1502,14 @@ GLFWAPI void glfwSetGammaRamp(GLFWmonitor* monitor, const GLFWgammaramp* ramp); * This function resets all window hints to their * [default values](@ref window_hints_values). * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hints * @sa glfwWindowHint * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwDefaultWindowHints(void); @@ -1172,51 +1519,69 @@ GLFWAPI void glfwDefaultWindowHints(void); * This function sets hints for the next call to @ref glfwCreateWindow. The * hints, once set, retain their values until changed by a call to @ref * glfwWindowHint or @ref glfwDefaultWindowHints, or until the library is - * terminated with @ref glfwTerminate. + * terminated. * * @param[in] target The [window hint](@ref window_hints) to set. * @param[in] hint The new value of the window hint. * - * @par New in GLFW 3 - * Hints are no longer reset to their default values on window creation. To - * set default hint values, use @ref glfwDefaultWindowHints. - * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hints * @sa glfwDefaultWindowHints * + * @since Added in GLFW 3.0. Replaces `glfwOpenWindowHint`. + * * @ingroup window */ GLFWAPI void glfwWindowHint(int target, int hint); /*! @brief Creates a window and its associated context. * - * This function creates a window and its associated context. Most of the - * options controlling how the window and its context should be created are - * specified through @ref glfwWindowHint. + * This function creates a window and its associated OpenGL or OpenGL ES + * context. Most of the options controlling how the window and its context + * should be created are specified with [window hints](@ref window_hints). * * Successful creation does not change which context is current. Before you - * can use the newly created context, you need to make it current using @ref - * glfwMakeContextCurrent. + * can use the newly created context, you need to + * [make it current](@ref context_current). For information about the `share` + * parameter, see @ref context_sharing. * - * Note that the created window and context may differ from what you requested, - * as not all parameters and hints are + * The created window, framebuffer and context may differ from what you + * requested, as not all parameters and hints are * [hard constraints](@ref window_hints_hard). This includes the size of the - * window, especially for full screen windows. To retrieve the actual - * attributes of the created window and context, use queries like @ref + * window, especially for full screen windows. To query the actual attributes + * of the created window, framebuffer and context, use queries like @ref * glfwGetWindowAttrib and @ref glfwGetWindowSize. * - * To create a full screen window, you need to specify the monitor to use. If - * no monitor is specified, windowed mode will be used. Unless you have a way - * for the user to choose a specific monitor, it is recommended that you pick - * the primary monitor. For more information on how to retrieve monitors, see - * @ref monitor_monitors. + * To create a full screen window, you need to specify the monitor the window + * will cover. If no monitor is specified, windowed mode will be used. Unless + * you have a way for the user to choose a specific monitor, it is recommended + * that you pick the primary monitor. For more information on how to query + * connected monitors, see @ref monitor_monitors. + * + * For full screen windows, the specified size becomes the resolution of the + * window's _desired video mode_. As long as a full screen window has input + * focus, the supported video mode most closely matching the desired video mode + * is set for the specified monitor. For more information about full screen + * windows, including the creation of so called _windowed full screen_ or + * _borderless full screen_ windows, see @ref window_windowed_full_screen. + * + * By default, newly created windows use the placement recommended by the + * window system. To create the window at a specific position, make it + * initially invisible using the [GLFW_VISIBLE](@ref window_hints_wnd) window + * hint, set its [position](@ref window_pos) and then [show](@ref window_hide) + * it. + * + * If a full screen window has input focus, the screensaver is prohibited from + * starting. * - * To create the window at a specific position, make it initially invisible - * using the `GLFW_VISIBLE` window hint, set its position and then show it. + * Window systems put limits on window sizes. Very large or very small window + * dimensions may be overridden by the window system on creation. Check the + * actual [size](@ref window_size) after creation. * - * If a full screen window is active, the screensaver is prohibited from - * starting. + * The [swap interval](@ref buffer_swap) is not set during window creation and + * the initial value may vary depending on driver settings and defaults. * * @param[in] width The desired width, in screen coordinates, of the window. * This must be greater than zero. @@ -1227,32 +1592,54 @@ GLFWAPI void glfwWindowHint(int target, int hint); * windowed mode. * @param[in] share The window whose context to share resources with, or `NULL` * to not share resources. - * @return The handle of the created window, or `NULL` if an error occurred. + * @return The handle of the created window, or `NULL` if an + * [error](@ref error_handling) occurred. * - * @remarks **Windows:** Window creation will fail if the Microsoft GDI + * @remarks __Windows:__ Window creation will fail if the Microsoft GDI * software OpenGL implementation is the only one available. * - * @remarks **Windows:** If the executable has an icon resource named + * @remarks __Windows:__ If the executable has an icon resource named * `GLFW_ICON,` it will be set as the icon for the window. If no such icon is * present, the `IDI_WINLOGO` icon will be used instead. * - * @remarks **OS X:** The GLFW window has no icon, as it is not a document + * @remarks __Windows:__ The context to share resources with may not be current + * on any other thread. + * + * @remarks __OS X:__ The GLFW window has no icon, as it is not a document * window, but the dock icon will be the same as the application bundle's icon. - * Also, the first time a window is opened the menu bar is populated with - * common commands like Hide, Quit and About. The (minimal) about dialog uses - * information from the application's bundle. For more information on bundles, - * see the Bundle Programming Guide provided by Apple. + * For more information on bundles, see the + * [Bundle Programming Guide](https://developer.apple.com/library/mac/documentation/CoreFoundation/Conceptual/CFBundles/) + * in the Mac Developer Library. + * + * @remarks __OS X:__ The first time a window is created the menu bar is + * populated with common commands like Hide, Quit and About. The About entry + * opens a minimal about dialog with information from the application's bundle. + * The menu bar can be disabled with a + * [compile-time option](@ref compile_options_osx). * - * @remarks **X11:** There is no mechanism for setting the window icon yet. + * @remarks __OS X:__ On OS X 10.10 and later the window frame will not be + * rendered at full resolution on Retina displays unless the + * `NSHighResolutionCapable` key is enabled in the application bundle's + * `Info.plist`. For more information, see + * [High Resolution Guidelines for OS X](https://developer.apple.com/library/mac/documentation/GraphicsAnimation/Conceptual/HighResolutionOSX/Explained/Explained.html) + * in the Mac Developer Library. * - * @remarks The swap interval is not set during window creation, but is left at - * the default value for that platform. For more information, see @ref - * glfwSwapInterval. + * @remarks __X11:__ There is no mechanism for setting the window icon yet. * - * @note This function may only be called from the main thread. + * @remarks __X11:__ Some window managers will not respect the placement of + * initially hidden windows. * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_creation * @sa glfwDestroyWindow * + * @since Added in GLFW 3.0. Replaces `glfwOpenWindow`. + * * @ingroup window */ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, GLFWmonitor* monitor, GLFWwindow* share); @@ -1262,19 +1649,25 @@ GLFWAPI GLFWwindow* glfwCreateWindow(int width, int height, const char* title, G * This function destroys the specified window and its context. On calling * this function, no further callbacks will be called for that window. * - * @param[in] window The window to destroy. + * If the context of the specified window is current on the main thread, it is + * detached before being destroyed. * - * @note This function may only be called from the main thread. + * @param[in] window The window to destroy. * - * @note This function may not be called from a callback. + * @note The context of the specified window must not be current on any other + * thread when this function is called. * - * @note If the window's context is current on the main thread, it is - * detached before being destroyed. + * @par Reentrancy + * This function may not be called from a callback. * - * @warning The window's context must not be current on any other thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_creation * @sa glfwCreateWindow * + * @since Added in GLFW 3.0. Replaces `glfwCloseWindow`. + * * @ingroup window */ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); @@ -1286,7 +1679,12 @@ GLFWAPI void glfwDestroyWindow(GLFWwindow* window); * @param[in] window The window to query. * @return The value of the close flag. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_close + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1301,7 +1699,12 @@ GLFWAPI int glfwWindowShouldClose(GLFWwindow* window); * @param[in] window The window whose flag to change. * @param[in] value The new value. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_close + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1315,7 +1718,15 @@ GLFWAPI void glfwSetWindowShouldClose(GLFWwindow* window, int value); * @param[in] window The window whose title to change. * @param[in] title The UTF-8 encoded window title. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_title + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. * * @ingroup window */ @@ -1326,14 +1737,23 @@ GLFWAPI void glfwSetWindowTitle(GLFWwindow* window, const char* title); * This function retrieves the position, in screen coordinates, of the * upper-left corner of the client area of the specified window. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] window The window to query. * @param[out] xpos Where to store the x-coordinate of the upper-left corner of * the client area, or `NULL`. * @param[out] ypos Where to store the y-coordinate of the upper-left corner of * the client area, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_pos * @sa glfwSetWindowPos * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); @@ -1341,26 +1761,29 @@ GLFWAPI void glfwGetWindowPos(GLFWwindow* window, int* xpos, int* ypos); /*! @brief Sets the position of the client area of the specified window. * * This function sets the position, in screen coordinates, of the upper-left - * corner of the client area of the window. + * corner of the client area of the specified windowed mode window. If the + * window is a full screen window, this function does nothing. * - * If the specified window is a full screen window, this function does nothing. + * __Do not use this function__ to move an already visible window unless you + * have very good reasons for doing so, as it will confuse and annoy the user. * - * If you wish to set an initial window position you should create a hidden - * window (using @ref glfwWindowHint and `GLFW_VISIBLE`), set its position and - * then show it. + * The window manager may put limits on what positions are allowed. GLFW + * cannot and should not override these limits. * * @param[in] window The window to query. * @param[in] xpos The x-coordinate of the upper-left corner of the client area. * @param[in] ypos The y-coordinate of the upper-left corner of the client area. * - * @note It is very rarely a good idea to move an already visible window, as it - * will confuse and annoy the user. + * @par Thread Safety + * This function may only be called from the main thread. * - * @note This function may only be called from the main thread. + * @sa @ref window_pos + * @sa glfwGetWindowPos * - * @note The window manager may put limits on what positions are allowed. + * @since Added in GLFW 1.0. * - * @sa glfwGetWindowPos + * @par + * __GLFW 3:__ Added window handle parameter. * * @ingroup window */ @@ -1370,7 +1793,10 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * * This function retrieves the size, in screen coordinates, of the client area * of the specified window. If you wish to retrieve the size of the - * framebuffer in pixels, see @ref glfwGetFramebufferSize. + * framebuffer of the window in pixels, see @ref glfwGetFramebufferSize. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. * * @param[in] window The window whose size to retrieve. * @param[out] width Where to store the width, in screen coordinates, of the @@ -1378,8 +1804,17 @@ GLFWAPI void glfwSetWindowPos(GLFWwindow* window, int xpos, int ypos); * @param[out] height Where to store the height, in screen coordinates, of the * client area, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_size * @sa glfwSetWindowSize * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); @@ -1394,16 +1829,24 @@ GLFWAPI void glfwGetWindowSize(GLFWwindow* window, int* width, int* height); * the context is unaffected, the bit depths of the framebuffer remain * unchanged. * + * The window manager may put limits on what sizes are allowed. GLFW cannot + * and should not override these limits. + * * @param[in] window The window to resize. * @param[in] width The desired width of the specified window. * @param[in] height The desired height of the specified window. * - * @note This function may only be called from the main thread. - * - * @note The window manager may put limits on what window sizes are allowed. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_size * @sa glfwGetWindowSize * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); @@ -1414,80 +1857,149 @@ GLFWAPI void glfwSetWindowSize(GLFWwindow* window, int width, int height); * specified window. If you wish to retrieve the size of the window in screen * coordinates, see @ref glfwGetWindowSize. * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * * @param[in] window The window whose framebuffer to query. * @param[out] width Where to store the width, in pixels, of the framebuffer, * or `NULL`. * @param[out] height Where to store the height, in pixels, of the framebuffer, * or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_fbsize * @sa glfwSetFramebufferSizeCallback * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwGetFramebufferSize(GLFWwindow* window, int* width, int* height); +/*! @brief Retrieves the size of the frame of the window. + * + * This function retrieves the size, in screen coordinates, of each edge of the + * frame of the specified window. This size includes the title bar, if the + * window has one. The size of the frame may vary depending on the + * [window-related hints](@ref window_hints_wnd) used to create it. + * + * Because this function retrieves the size of each window frame edge and not + * the offset along a particular coordinate axis, the retrieved values will + * always be zero or positive. + * + * Any or all of the size arguments may be `NULL`. If an error occurs, all + * non-`NULL` size arguments will be set to zero. + * + * @param[in] window The window whose frame size to query. + * @param[out] left Where to store the size, in screen coordinates, of the left + * edge of the window frame, or `NULL`. + * @param[out] top Where to store the size, in screen coordinates, of the top + * edge of the window frame, or `NULL`. + * @param[out] right Where to store the size, in screen coordinates, of the + * right edge of the window frame, or `NULL`. + * @param[out] bottom Where to store the size, in screen coordinates, of the + * bottom edge of the window frame, or `NULL`. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in GLFW 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwGetWindowFrameSize(GLFWwindow* window, int* left, int* top, int* right, int* bottom); + /*! @brief Iconifies the specified window. * - * This function iconifies/minimizes the specified window, if it was previously - * restored. If it is a full screen window, the original monitor resolution is - * restored until the window is restored. If the window is already iconified, - * this function does nothing. + * This function iconifies (minimizes) the specified window if it was + * previously restored. If the window is already iconified, this function does + * nothing. + * + * If the specified window is a full screen window, the original monitor + * resolution is restored until the window is restored. * * @param[in] window The window to iconify. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_iconify * @sa glfwRestoreWindow * + * @since Added in GLFW 2.1. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwIconifyWindow(GLFWwindow* window); /*! @brief Restores the specified window. * - * This function restores the specified window, if it was previously - * iconified/minimized. If it is a full screen window, the resolution chosen - * for the window is restored on the selected monitor. If the window is - * already restored, this function does nothing. + * This function restores the specified window if it was previously iconified + * (minimized). If the window is already restored, this function does nothing. + * + * If the specified window is a full screen window, the resolution chosen for + * the window is restored on the selected monitor. * * @param[in] window The window to restore. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_iconify * @sa glfwIconifyWindow * + * @since Added in GLFW 2.1. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup window */ GLFWAPI void glfwRestoreWindow(GLFWwindow* window); /*! @brief Makes the specified window visible. * - * This function makes the specified window visible, if it was previously + * This function makes the specified window visible if it was previously * hidden. If the window is already visible or is in full screen mode, this * function does nothing. * * @param[in] window The window to make visible. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hide * @sa glfwHideWindow * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwShowWindow(GLFWwindow* window); /*! @brief Hides the specified window. * - * This function hides the specified window, if it was previously visible. If + * This function hides the specified window if it was previously visible. If * the window is already hidden or is in full screen mode, this function does * nothing. * * @param[in] window The window to hide. * - * @note This function may only be called from the main thread. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref window_hide * @sa glfwShowWindow * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwHideWindow(GLFWwindow* window); @@ -1498,7 +2010,15 @@ GLFWAPI void glfwHideWindow(GLFWwindow* window); * in full screen on. * * @param[in] window The window to query. - * @return The monitor, or `NULL` if the window is in windowed mode. + * @return The monitor, or `NULL` if the window is in windowed mode or an error + * occurred. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_monitor + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1506,13 +2026,22 @@ GLFWAPI GLFWmonitor* glfwGetWindowMonitor(GLFWwindow* window); /*! @brief Returns an attribute of the specified window. * - * This function returns an attribute of the specified window. There are many - * attributes, some related to the window and others to its context. + * This function returns the value of an attribute of the specified window or + * its OpenGL or OpenGL ES context. * * @param[in] window The window to query. * @param[in] attrib The [window attribute](@ref window_attribs) whose value to * return. - * @return The value of the attribute, or zero if an error occurred. + * @return The value of the attribute, or zero if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_attribs + * + * @since Added in GLFW 3.0. Replaces `glfwGetWindowParam` and + * `glfwGetGLVersion`. * * @ingroup window */ @@ -1527,8 +2056,14 @@ GLFWAPI int glfwGetWindowAttrib(GLFWwindow* window, int attrib); * @param[in] window The window whose pointer to set. * @param[in] pointer The new value. * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_userptr * @sa glfwGetWindowUserPointer * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); @@ -1540,8 +2075,14 @@ GLFWAPI void glfwSetWindowUserPointer(GLFWwindow* window, void* pointer); * * @param[in] window The window whose pointer to return. * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @sa @ref window_userptr * @sa glfwSetWindowUserPointer * + * @since Added in GLFW 3.0. + * * @ingroup window */ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); @@ -1555,8 +2096,15 @@ GLFWAPI void* glfwGetWindowUserPointer(GLFWwindow* window); * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_pos + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1571,8 +2119,18 @@ GLFWAPI GLFWwindowposfun glfwSetWindowPosCallback(GLFWwindow* window, GLFWwindow * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_size + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup window */ @@ -1592,15 +2150,22 @@ GLFWAPI GLFWwindowsizefun glfwSetWindowSizeCallback(GLFWwindow* window, GLFWwind * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @par New in GLFW 3 - * The close callback no longer returns a value. - * - * @remarks **OS X:** Selecting Quit from the application menu will + * @remarks __OS X:__ Selecting Quit from the application menu will * trigger the close callback for all windows. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_close + * + * @since Added in GLFW 2.5. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * * @ingroup window */ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwindowclosefun cbfun); @@ -1618,12 +2183,18 @@ GLFWAPI GLFWwindowclosefun glfwSetWindowCloseCallback(GLFWwindow* window, GLFWwi * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). * - * @note On compositing window systems such as Aero, Compiz or Aqua, where the - * window contents are saved off-screen, this callback may be called only very - * infrequently or never at all. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_refresh + * + * @since Added in GLFW 2.5. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup window */ @@ -1632,18 +2203,25 @@ GLFWAPI GLFWwindowrefreshfun glfwSetWindowRefreshCallback(GLFWwindow* window, GL /*! @brief Sets the focus callback for the specified window. * * This function sets the focus callback of the specified window, which is - * called when the window gains or loses focus. + * called when the window gains or loses input focus. * - * After the focus callback is called for a window that lost focus, synthetic - * key and mouse button release events will be generated for all such that had - * been pressed. For more information, see @ref glfwSetKeyCallback and @ref - * glfwSetMouseButtonCallback. + * After the focus callback is called for a window that lost input focus, + * synthetic key and mouse button release events will be generated for all such + * that had been pressed. For more information, see @ref glfwSetKeyCallback + * and @ref glfwSetMouseButtonCallback. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_focus + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1657,8 +2235,15 @@ GLFWAPI GLFWwindowfocusfun glfwSetWindowFocusCallback(GLFWwindow* window, GLFWwi * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_iconify + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1672,8 +2257,15 @@ GLFWAPI GLFWwindowiconifyfun glfwSetWindowIconifyCallback(GLFWwindow* window, GL * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref window_fbsize + * + * @since Added in GLFW 3.0. * * @ingroup window */ @@ -1681,114 +2273,164 @@ GLFWAPI GLFWframebuffersizefun glfwSetFramebufferSizeCallback(GLFWwindow* window /*! @brief Processes all pending events. * - * This function processes only those events that have already been received - * and then returns immediately. Processing events will cause the window and - * input callbacks associated with those events to be called. - * - * This function is not required for joystick input to work. + * This function processes only those events that are already in the event + * queue and then returns immediately. Processing events will cause the window + * and input callbacks associated with those events to be called. * - * @par New in GLFW 3 - * This function is no longer called by @ref glfwSwapBuffers. You need to call - * it or @ref glfwWaitEvents yourself. + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. * - * @remarks On some platforms, a window move, resize or menu operation will - * cause event processing to block. This is due to how event processing is - * designed on those platforms. You can use the - * [window refresh callback](@ref GLFWwindowrefreshfun) to redraw the contents - * of your window when necessary during the operation. + * On some platforms, certain events are sent directly to the application + * without going through the event queue, causing callbacks to be called + * outside of a call to one of the event processing functions. * - * @note This function may only be called from the main thread. + * Event processing is not required for joystick input to work. * - * @note This function may not be called from a callback. + * @par Reentrancy + * This function may not be called from a callback. * - * @note On some platforms, certain callbacks may be called outside of a call - * to one of the event processing functions. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref events * @sa glfwWaitEvents * + * @since Added in GLFW 1.0. + * * @ingroup window */ GLFWAPI void glfwPollEvents(void); -/*! @brief Waits until events are pending and processes them. +/*! @brief Waits until events are queued and processes them. * - * This function puts the calling thread to sleep until at least one event has - * been received. Once one or more events have been received, it behaves as if - * @ref glfwPollEvents was called, i.e. the events are processed and the - * function then returns immediately. Processing events will cause the window - * and input callbacks associated with those events to be called. + * This function puts the calling thread to sleep until at least one event is + * available in the event queue. Once one or more events are available, + * it behaves exactly like @ref glfwPollEvents, i.e. the events in the queue + * are processed and the function then returns immediately. Processing events + * will cause the window and input callbacks associated with those events to be + * called. * * Since not all events are associated with callbacks, this function may return * without a callback having been called even if you are monitoring all * callbacks. * - * This function is not required for joystick input to work. + * On some platforms, a window move, resize or menu operation will cause event + * processing to block. This is due to how event processing is designed on + * those platforms. You can use the + * [window refresh callback](@ref window_refresh) to redraw the contents of + * your window when necessary during such operations. * - * @remarks On some platforms, a window move, resize or menu operation will - * cause event processing to block. This is due to how event processing is - * designed on those platforms. You can use the - * [window refresh callback](@ref GLFWwindowrefreshfun) to redraw the contents - * of your window when necessary during the operation. + * On some platforms, certain callbacks may be called outside of a call to one + * of the event processing functions. * - * @note This function may only be called from the main thread. + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. * - * @note This function may not be called from a callback. + * Event processing is not required for joystick input to work. * - * @note On some platforms, certain callbacks may be called outside of a call - * to one of the event processing functions. + * @par Reentrancy + * This function may not be called from a callback. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref events * @sa glfwPollEvents * + * @since Added in GLFW 2.5. + * * @ingroup window */ GLFWAPI void glfwWaitEvents(void); +/*! @brief Posts an empty event to the event queue. + * + * This function posts an empty event from the current thread to the event + * queue, causing @ref glfwWaitEvents to return. + * + * If no windows exist, this function returns immediately. For synchronization + * of threads in applications that do not create windows, use your threading + * library of choice. + * + * @par Thread Safety + * This function may be called from any thread. + * + * @sa @ref events + * @sa glfwWaitEvents + * + * @since Added in GLFW 3.1. + * + * @ingroup window + */ +GLFWAPI void glfwPostEmptyEvent(void); + /*! @brief Returns the value of an input option for the specified window. * + * This function returns the value of an input option for the specified window. + * The mode must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * * @param[in] window The window to query. * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. * + * @par Thread Safety + * This function may only be called from the main thread. + * * @sa glfwSetInputMode * + * @since Added in GLFW 3.0. + * * @ingroup input */ GLFWAPI int glfwGetInputMode(GLFWwindow* window, int mode); /*! @brief Sets an input option for the specified window. - * @param[in] window The window whose input mode to set. - * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * + * This function sets an input mode option for the specified window. The mode + * must be one of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or * `GLFW_STICKY_MOUSE_BUTTONS`. - * @param[in] value The new value of the specified input mode. * - * If `mode` is `GLFW_CURSOR`, the value must be one of the supported input + * If the mode is `GLFW_CURSOR`, the value must be one of the following cursor * modes: * - `GLFW_CURSOR_NORMAL` makes the cursor visible and behaving normally. * - `GLFW_CURSOR_HIDDEN` makes the cursor invisible when it is over the client - * area of the window but does not restrict the cursor from leaving. This is - * useful if you wish to render your own cursor or have no visible cursor at - * all. + * area of the window but does not restrict the cursor from leaving. * - `GLFW_CURSOR_DISABLED` hides and grabs the cursor, providing virtual * and unlimited cursor movement. This is useful for implementing for * example 3D camera controls. * - * If `mode` is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to + * If the mode is `GLFW_STICKY_KEYS`, the value must be either `GL_TRUE` to * enable sticky keys, or `GL_FALSE` to disable it. If sticky keys are - * enabled, a key press will ensure that @ref glfwGetKey returns @ref - * GLFW_PRESS the next time it is called even if the key had been released - * before the call. This is useful when you are only interested in whether - * keys have been pressed but not when or in which order. - * - * If `mode` is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either `GL_TRUE` - * to enable sticky mouse buttons, or `GL_FALSE` to disable it. If sticky - * mouse buttons are enabled, a mouse button press will ensure that @ref - * glfwGetMouseButton returns @ref GLFW_PRESS the next time it is called even - * if the mouse button had been released before the call. This is useful when - * you are only interested in whether mouse buttons have been pressed but not - * when or in which order. + * enabled, a key press will ensure that @ref glfwGetKey returns `GLFW_PRESS` + * the next time it is called even if the key had been released before the + * call. This is useful when you are only interested in whether keys have been + * pressed but not when or in which order. + * + * If the mode is `GLFW_STICKY_MOUSE_BUTTONS`, the value must be either + * `GL_TRUE` to enable sticky mouse buttons, or `GL_FALSE` to disable it. If + * sticky mouse buttons are enabled, a mouse button press will ensure that @ref + * glfwGetMouseButton returns `GLFW_PRESS` the next time it is called even if + * the mouse button had been released before the call. This is useful when you + * are only interested in whether mouse buttons have been pressed but not when + * or in which order. + * + * @param[in] window The window whose input mode to set. + * @param[in] mode One of `GLFW_CURSOR`, `GLFW_STICKY_KEYS` or + * `GLFW_STICKY_MOUSE_BUTTONS`. + * @param[in] value The new value of the specified input mode. + * + * @par Thread Safety + * This function may only be called from the main thread. * * @sa glfwGetInputMode * + * @since Added in GLFW 3.0. Replaces `glfwEnable` and `glfwDisable`. + * * @ingroup input */ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); @@ -1798,22 +2440,34 @@ GLFWAPI void glfwSetInputMode(GLFWwindow* window, int mode, int value); * * This function returns the last state reported for the specified key to the * specified window. The returned state is one of `GLFW_PRESS` or - * `GLFW_RELEASE`. The higher-level state `GLFW_REPEAT` is only reported to + * `GLFW_RELEASE`. The higher-level action `GLFW_REPEAT` is only reported to * the key callback. * * If the `GLFW_STICKY_KEYS` input mode is enabled, this function returns - * `GLFW_PRESS` the first time you call this function after a key has been - * pressed, even if the key has already been released. + * `GLFW_PRESS` the first time you call it for a key that was pressed, even if + * that key has already been released. * * The key functions deal with physical keys, with [key tokens](@ref keys) * named after their use on the standard US keyboard layout. If you want to * input text, use the Unicode character callback instead. * + * The [modifier key bit masks](@ref mods) are not key tokens and cannot be + * used with this function. + * * @param[in] window The desired window. - * @param[in] key The desired [keyboard key](@ref keys). + * @param[in] key The desired [keyboard key](@ref keys). `GLFW_KEY_UNKNOWN` is + * not a valid key for this function. * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * - * @note `GLFW_KEY_UNKNOWN` is not a valid key for this function. + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. * * @ingroup input */ @@ -1823,26 +2477,37 @@ GLFWAPI int glfwGetKey(GLFWwindow* window, int key); * window. * * This function returns the last state reported for the specified mouse button - * to the specified window. + * to the specified window. The returned state is one of `GLFW_PRESS` or + * `GLFW_RELEASE`. * * If the `GLFW_STICKY_MOUSE_BUTTONS` input mode is enabled, this function - * returns `GLFW_PRESS` the first time you call this function after a mouse - * button has been pressed, even if the mouse button has already been released. + * `GLFW_PRESS` the first time you call it for a mouse button that was pressed, + * even if that mouse button has already been released. * * @param[in] window The desired window. * @param[in] button The desired [mouse button](@ref buttons). * @return One of `GLFW_PRESS` or `GLFW_RELEASE`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * * @ingroup input */ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); -/*! @brief Retrieves the last reported cursor position, relative to the client - * area of the window. +/*! @brief Retrieves the position of the cursor relative to the client area of + * the window. * - * This function returns the last reported position of the cursor, in screen - * coordinates, relative to the upper-left corner of the client area of the - * specified window. + * This function returns the position of the cursor, in screen coordinates, + * relative to the upper-left corner of the client area of the specified + * window. * * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor * position is unbounded and limited only by the minimum and maximum values of @@ -1852,14 +2517,23 @@ GLFWAPI int glfwGetMouseButton(GLFWwindow* window, int button); * `floor` function. Casting directly to an integer type works for positive * coordinates, but fails for negative ones. * + * Any or all of the position arguments may be `NULL`. If an error occurs, all + * non-`NULL` position arguments will be set to zero. + * * @param[in] window The desired window. * @param[out] xpos Where to store the cursor x-coordinate, relative to the * left edge of the client area, or `NULL`. * @param[out] ypos Where to store the cursor y-coordinate, relative to the to * top edge of the client area, or `NULL`. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_pos * @sa glfwSetCursorPos * + * @since Added in GLFW 3.0. Replaces `glfwGetMousePos`. + * * @ingroup input */ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); @@ -1869,11 +2543,16 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * * This function sets the position, in screen coordinates, of the cursor * relative to the upper-left corner of the client area of the specified - * window. The window must be focused. If the window does not have focus when - * this function is called, it fails silently. + * window. The window must have input focus. If the window does not have + * input focus when this function is called, it fails silently. * - * If the cursor is disabled (with `GLFW_CURSOR_DISABLED`) then the cursor - * position is unbounded and limited only by the minimum and maximum values of + * __Do not use this function__ to implement things like camera controls. GLFW + * already provides the `GLFW_CURSOR_DISABLED` cursor mode that hides the + * cursor, transparently re-centers it and provides unconstrained cursor + * motion. See @ref glfwSetInputMode for more information. + * + * If the cursor mode is `GLFW_CURSOR_DISABLED` then the cursor position is + * unconstrained and limited only by the minimum and maximum values of * a `double`. * * @param[in] window The desired window. @@ -1882,15 +2561,138 @@ GLFWAPI void glfwGetCursorPos(GLFWwindow* window, double* xpos, double* ypos); * @param[in] ypos The desired y-coordinate, relative to the top edge of the * client area. * + * @remarks __X11:__ Due to the asynchronous nature of a modern X desktop, it + * may take a moment for the window focus event to arrive. This means you will + * not be able to set the cursor position directly after window creation. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_pos * @sa glfwGetCursorPos * + * @since Added in GLFW 3.0. Replaces `glfwSetMousePos`. + * * @ingroup input */ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); +/*! @brief Creates a custom cursor. + * + * Creates a new custom cursor image that can be set for a window with @ref + * glfwSetCursor. The cursor can be destroyed with @ref glfwDestroyCursor. + * Any remaining cursors are destroyed by @ref glfwTerminate. + * + * The pixels are 32-bit little-endian RGBA, i.e. eight bits per channel. They + * are arranged canonically as packed sequential rows, starting from the + * top-left corner. + * + * The cursor hotspot is specified in pixels, relative to the upper-left corner + * of the cursor image. Like all other coordinate systems in GLFW, the X-axis + * points to the right and the Y-axis points down. + * + * @param[in] image The desired cursor image. + * @param[in] xhot The desired x-coordinate, in pixels, of the cursor hotspot. + * @param[in] yhot The desired y-coordinate, in pixels, of the cursor hotspot. + * + * @return The handle of the created cursor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Pointer Lifetime + * The specified image data is copied before this function returns. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwDestroyCursor + * @sa glfwCreateStandardCursor + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateCursor(const GLFWimage* image, int xhot, int yhot); + +/*! @brief Creates a cursor with a standard shape. + * + * Returns a cursor with a [standard shape](@ref shapes), that can be set for + * a window with @ref glfwSetCursor. + * + * @param[in] shape One of the [standard shapes](@ref shapes). + * + * @return A new cursor ready to use or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWcursor* glfwCreateStandardCursor(int shape); + +/*! @brief Destroys a cursor. + * + * This function destroys a cursor previously created with @ref + * glfwCreateCursor. Any remaining cursors will be destroyed by @ref + * glfwTerminate. + * + * @param[in] cursor The cursor object to destroy. + * + * @par Reentrancy + * This function may not be called from a callback. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * @sa glfwCreateCursor + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwDestroyCursor(GLFWcursor* cursor); + +/*! @brief Sets the cursor for the window. + * + * This function sets the cursor image to be used when the cursor is over the + * client area of the specified window. The set cursor will only be visible + * when the [cursor mode](@ref cursor_mode) of the window is + * `GLFW_CURSOR_NORMAL`. + * + * On some platforms, the set cursor may not be visible unless the window also + * has input focus. + * + * @param[in] window The window to set the cursor for. + * @param[in] cursor The cursor to set, or `NULL` to switch back to the default + * arrow cursor. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_object + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI void glfwSetCursor(GLFWwindow* window, GLFWcursor* cursor); + /*! @brief Sets the key callback. * - * This function sets the key callback of the specific window, which is called + * This function sets the key callback of the specified window, which is called * when a key is pressed, repeated or released. * * The key functions deal with physical keys, with layout independent @@ -1898,16 +2700,16 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * layout. If you want to input text, use the * [character callback](@ref glfwSetCharCallback) instead. * - * When a window loses focus, it will generate synthetic key release events - * for all pressed keys. You can tell these events from user-generated events - * by the fact that the synthetic ones are generated after the window has lost - * focus, i.e. `GLFW_FOCUSED` will be false and the focus callback will have - * already been called. + * When a window loses input focus, it will generate synthetic key release + * events for all pressed keys. You can tell these events from user-generated + * events by the fact that the synthetic ones are generated after the focus + * loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * The scancode of a key is specific to that platform or sometimes even to that * machine. Scancodes are intended to allow users to bind keys that don't have * a GLFW key token. Such keys have `key` set to `GLFW_KEY_UNKNOWN`, their - * state is not saved and so it cannot be retrieved with @ref glfwGetKey. + * state is not saved and so it cannot be queried with @ref glfwGetKey. * * Sometimes GLFW needs to generate synthetic key events, in which case the * scancode may be zero. @@ -1915,8 +2717,18 @@ GLFWAPI void glfwSetCursorPos(GLFWwindow* window, double xpos, double ypos); * @param[in] window The window whose callback to set. * @param[in] cbfun The new key callback, or `NULL` to remove the currently * set callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_key + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup input */ @@ -1924,11 +2736,56 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); /*! @brief Sets the Unicode character callback. * - * This function sets the character callback of the specific window, which is + * This function sets the character callback of the specified window, which is * called when a Unicode character is input. * - * The character callback is intended for text input. If you want to know - * whether a specific key was pressed or released, use the + * The character callback is intended for Unicode text input. As it deals with + * characters, it is keyboard layout dependent, whereas the + * [key callback](@ref glfwSetKeyCallback) is not. Characters do not map 1:1 + * to physical keys, as a key may produce zero, one or more characters. If you + * want to know whether a specific physical key was pressed or released, see + * the key callback instead. + * + * The character callback behaves as system text input normally does and will + * not be called if modifier keys are held down that would prevent normal text + * input on that platform, for example a Super (Command) key on OS X or Alt key + * on Windows. There is a + * [character with modifiers callback](@ref glfwSetCharModsCallback) that + * receives these events. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new callback, or `NULL` to remove the currently set + * callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in GLFW 2.4. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. + * + * @ingroup input + */ +GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); + +/*! @brief Sets the Unicode character with modifiers callback. + * + * This function sets the character with modifiers callback of the specified + * window, which is called when a Unicode character is input regardless of what + * modifier keys are used. + * + * The character with modifiers callback is intended for implementing custom + * Unicode character input. For regular Unicode text input, see the + * [character callback](@ref glfwSetCharCallback). Like the character + * callback, the character with modifiers callback deals with characters and is + * keyboard layout dependent. Characters do not map 1:1 to physical keys, as + * a key may produce zero, one or more characters. If you want to know whether + * a specific physical key was pressed or released, see the * [key callback](@ref glfwSetKeyCallback) instead. * * @param[in] window The window whose callback to set. @@ -1937,26 +2794,43 @@ GLFWAPI GLFWkeyfun glfwSetKeyCallback(GLFWwindow* window, GLFWkeyfun cbfun); * @return The previously set callback, or `NULL` if no callback was set or an * error occurred. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_char + * + * @since Added in GLFW 3.1. + * * @ingroup input */ -GLFWAPI GLFWcharfun glfwSetCharCallback(GLFWwindow* window, GLFWcharfun cbfun); +GLFWAPI GLFWcharmodsfun glfwSetCharModsCallback(GLFWwindow* window, GLFWcharmodsfun cbfun); /*! @brief Sets the mouse button callback. * * This function sets the mouse button callback of the specified window, which * is called when a mouse button is pressed or released. * - * When a window loses focus, it will generate synthetic mouse button release - * events for all pressed mouse buttons. You can tell these events from - * user-generated events by the fact that the synthetic ones are generated - * after the window has lost focus, i.e. `GLFW_FOCUSED` will be false and the - * focus callback will have already been called. + * When a window loses input focus, it will generate synthetic mouse button + * release events for all pressed mouse buttons. You can tell these events + * from user-generated events by the fact that the synthetic ones are generated + * after the focus loss event has been processed, i.e. after the + * [window focus callback](@ref glfwSetWindowFocusCallback) has been called. * * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref input_mouse_button + * + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. Updated callback signature. * * @ingroup input */ @@ -1972,8 +2846,15 @@ GLFWAPI GLFWmousebuttonfun glfwSetMouseButtonCallback(GLFWwindow* window, GLFWmo * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_pos + * + * @since Added in GLFW 3.0. Replaces `glfwSetMousePosCallback`. * * @ingroup input */ @@ -1988,8 +2869,15 @@ GLFWAPI GLFWcursorposfun glfwSetCursorPosCallback(GLFWwindow* window, GLFWcursor * @param[in] window The window whose callback to set. * @param[in] cbfun The new callback, or `NULL` to remove the currently set * callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref cursor_enter + * + * @since Added in GLFW 3.0. * * @ingroup input */ @@ -2007,20 +2895,61 @@ GLFWAPI GLFWcursorenterfun glfwSetCursorEnterCallback(GLFWwindow* window, GLFWcu * @param[in] window The window whose callback to set. * @param[in] cbfun The new scroll callback, or `NULL` to remove the currently * set callback. - * @return The previously set callback, or `NULL` if no callback was set or an - * error occurred. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref scrolling + * + * @since Added in GLFW 3.0. Replaces `glfwSetMouseWheelCallback`. * * @ingroup input */ GLFWAPI GLFWscrollfun glfwSetScrollCallback(GLFWwindow* window, GLFWscrollfun cbfun); +/*! @brief Sets the file drop callback. + * + * This function sets the file drop callback of the specified window, which is + * called when one or more dragged files are dropped on the window. + * + * Because the path array and its strings may have been generated specifically + * for that event, they are not guaranteed to be valid after the callback has + * returned. If you wish to use them after the callback returns, you need to + * make a deep copy. + * + * @param[in] window The window whose callback to set. + * @param[in] cbfun The new file drop callback, or `NULL` to remove the + * currently set callback. + * @return The previously set callback, or `NULL` if no callback was set or the + * library had not been [initialized](@ref intro_init). + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref path_drop + * + * @since Added in GLFW 3.1. + * + * @ingroup input + */ +GLFWAPI GLFWdropfun glfwSetDropCallback(GLFWwindow* window, GLFWdropfun cbfun); + /*! @brief Returns whether the specified joystick is present. * * This function returns whether the specified joystick is present. * - * @param[in] joy The joystick to query. + * @param[in] joy The [joystick](@ref joysticks) to query. * @return `GL_TRUE` if the joystick is present, or `GL_FALSE` otherwise. * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref joystick + * + * @since Added in GLFW 3.0. Replaces `glfwGetJoystickParam`. + * * @ingroup input */ GLFWAPI int glfwJoystickPresent(int joy); @@ -2028,17 +2957,24 @@ GLFWAPI int glfwJoystickPresent(int joy); /*! @brief Returns the values of all axes of the specified joystick. * * This function returns the values of all axes of the specified joystick. + * Each element in the array is a value between -1.0 and 1.0. * - * @param[in] joy The joystick to query. - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of axis values in the returned + * array. This is set to zero if an error occurred. * @return An array of axis values, or `NULL` if the joystick is not present. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified joystick is disconnected, this + * function is called again for that joystick or the library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. * - * @note The returned array is valid only until the next call to @ref - * glfwGetJoystickAxes for that joystick. + * @sa @ref joystick_axis + * + * @since Added in GLFW 3.0. Replaces `glfwGetJoystickPos`. * * @ingroup input */ @@ -2047,17 +2983,27 @@ GLFWAPI const float* glfwGetJoystickAxes(int joy, int* count); /*! @brief Returns the state of all buttons of the specified joystick. * * This function returns the state of all buttons of the specified joystick. + * Each element in the array is either `GLFW_PRESS` or `GLFW_RELEASE`. * - * @param[in] joy The joystick to query. - * @param[out] count Where to store the size of the returned array. This is - * set to zero if an error occurred. + * @param[in] joy The [joystick](@ref joysticks) to query. + * @param[out] count Where to store the number of button states in the returned + * array. This is set to zero if an error occurred. * @return An array of button states, or `NULL` if the joystick is not present. * - * @note The returned array is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned array is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified joystick is disconnected, this + * function is called again for that joystick or the library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref joystick_button * - * @note The returned array is valid only until the next call to @ref - * glfwGetJoystickButtons for that joystick. + * @since Added in GLFW 2.2. + * + * @par + * __GLFW 3:__ Changed to return a dynamic array. * * @ingroup input */ @@ -2066,16 +3012,24 @@ GLFWAPI const unsigned char* glfwGetJoystickButtons(int joy, int* count); /*! @brief Returns the name of the specified joystick. * * This function returns the name, encoded as UTF-8, of the specified joystick. + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. * - * @param[in] joy The joystick to query. + * @param[in] joy The [joystick](@ref joysticks) to query. * @return The UTF-8 encoded name of the joystick, or `NULL` if the joystick * is not present. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. + * @par Pointer Lifetime + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the specified joystick is disconnected, this + * function is called again for that joystick or the library is terminated. + * + * @par Thread Safety + * This function may only be called from the main thread. * - * @note The returned string is valid only until the next call to @ref - * glfwGetJoystickName for that joystick. + * @sa @ref joystick_name + * + * @since Added in GLFW 3.0. * * @ingroup input */ @@ -2084,40 +3038,50 @@ GLFWAPI const char* glfwGetJoystickName(int joy); /*! @brief Sets the clipboard to the specified string. * * This function sets the system clipboard to the specified, UTF-8 encoded - * string. The string is copied before returning, so you don't have to retain - * it afterwards. + * string. * * @param[in] window The window that will own the clipboard contents. * @param[in] string A UTF-8 encoded string. * - * @note This function may only be called from the main thread. + * @par Pointer Lifetime + * The specified string is copied before this function returns. + * + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref clipboard * @sa glfwGetClipboardString * - * @ingroup clipboard + * @since Added in GLFW 3.0. + * + * @ingroup input */ GLFWAPI void glfwSetClipboardString(GLFWwindow* window, const char* string); -/*! @brief Retrieves the contents of the clipboard as a string. +/*! @brief Returns the contents of the clipboard as a string. * * This function returns the contents of the system clipboard, if it contains * or is convertible to a UTF-8 encoded string. * * @param[in] window The window that will request the clipboard contents. * @return The contents of the clipboard as a UTF-8 encoded string, or `NULL` - * if an error occurred. + * if an [error](@ref error_handling) occurred. * - * @note This function may only be called from the main thread. + * @par Pointer Lifetime + * The returned string is allocated and freed by GLFW. You should not free it + * yourself. It is valid until the next call to @ref + * glfwGetClipboardString or @ref glfwSetClipboardString, or until the library + * is terminated. * - * @note The returned string is allocated and freed by GLFW. You should not - * free it yourself. - * - * @note The returned string is valid only until the next call to @ref - * glfwGetClipboardString or @ref glfwSetClipboardString. + * @par Thread Safety + * This function may only be called from the main thread. * + * @sa @ref clipboard * @sa glfwSetClipboardString * - * @ingroup clipboard + * @since Added in GLFW 3.0. + * + * @ingroup input */ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); @@ -2127,63 +3091,91 @@ GLFWAPI const char* glfwGetClipboardString(GLFWwindow* window); * been set using @ref glfwSetTime, the timer measures time elapsed since GLFW * was initialized. * - * @return The current value, in seconds, or zero if an error occurred. + * The resolution of the timer is system dependent, but is usually on the order + * of a few micro- or nanoseconds. It uses the highest-resolution monotonic + * time source on each supported platform. + * + * @return The current value, in seconds, or zero if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. * - * @remarks This function may be called from secondary threads. + * @sa @ref time * - * @note The resolution of the timer is system dependent, but is usually on the - * order of a few micro- or nanoseconds. It uses the highest-resolution - * monotonic time source on each supported platform. + * @since Added in GLFW 1.0. * - * @ingroup time + * @ingroup input */ GLFWAPI double glfwGetTime(void); /*! @brief Sets the GLFW timer. * * This function sets the value of the GLFW timer. It then continues to count - * up from that value. + * up from that value. The value must be a positive finite number less than + * or equal to 18446744073.0, which is approximately 584.5 years. * * @param[in] time The new value, in seconds. * - * @note The resolution of the timer is system dependent, but is usually on the - * order of a few micro- or nanoseconds. It uses the highest-resolution - * monotonic time source on each supported platform. + * @remarks The upper limit of the timer is calculated as + * floor((2<sup>64</sup> - 1) / 10<sup>9</sup>) and is due to implementations + * storing nanoseconds in 64 bits. The limit may be increased in the future. + * + * @par Thread Safety + * This function may only be called from the main thread. + * + * @sa @ref time + * + * @since Added in GLFW 2.2. * - * @ingroup time + * @ingroup input */ GLFWAPI void glfwSetTime(double time); /*! @brief Makes the context of the specified window current for the calling * thread. * - * This function makes the context of the specified window current on the - * calling thread. A context can only be made current on a single thread at - * a time and each thread can have only a single current context at a time. + * This function makes the OpenGL or OpenGL ES context of the specified window + * current on the calling thread. A context can only be made current on + * a single thread at a time and each thread can have only a single current + * context at a time. + * + * By default, making a context non-current implicitly forces a pipeline flush. + * On machines that support `GL_KHR_context_flush_control`, you can control + * whether a context performs this flush by setting the + * [GLFW_CONTEXT_RELEASE_BEHAVIOR](@ref window_hints_ctx) window hint. * * @param[in] window The window whose context to make current, or `NULL` to * detach the current context. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref context_current * @sa glfwGetCurrentContext * + * @since Added in GLFW 3.0. + * * @ingroup context */ GLFWAPI void glfwMakeContextCurrent(GLFWwindow* window); /*! @brief Returns the window whose context is current on the calling thread. * - * This function returns the window whose context is current on the calling - * thread. + * This function returns the window whose OpenGL or OpenGL ES context is + * current on the calling thread. * * @return The window whose context is current, or `NULL` if no window's * context is current. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref context_current * @sa glfwMakeContextCurrent * + * @since Added in GLFW 3.0. + * * @ingroup context */ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); @@ -2196,24 +3188,28 @@ GLFWAPI GLFWwindow* glfwGetCurrentContext(void); * * @param[in] window The window whose buffers to swap. * - * @remarks This function may be called from secondary threads. - * - * @par New in GLFW 3 - * This function no longer calls @ref glfwPollEvents. You need to call it or - * @ref glfwWaitEvents yourself. + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref buffer_swap * @sa glfwSwapInterval * - * @ingroup context + * @since Added in GLFW 1.0. + * + * @par + * __GLFW 3:__ Added window handle parameter. + * + * @ingroup window */ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); /*! @brief Sets the swap interval for the current context. * * This function sets the swap interval for the current context, i.e. the - * number of screen updates to wait before swapping the buffers of a window and - * returning from @ref glfwSwapBuffers. This is sometimes called 'vertical - * synchronization', 'vertical retrace synchronization' or 'vsync'. + * number of screen updates to wait from the time @ref glfwSwapBuffers was + * called before swapping the buffers and returning. This is sometimes called + * _vertical synchronization_, _vertical retrace synchronization_ or just + * _vsync_. * * Contexts that support either of the `WGL_EXT_swap_control_tear` and * `GLX_EXT_swap_control_tear` extensions also accept negative swap intervals, @@ -2222,22 +3218,29 @@ GLFWAPI void glfwSwapBuffers(GLFWwindow* window); * glfwExtensionSupported. For more information about swap tearing, see the * extension specifications. * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * * @param[in] interval The minimum number of screen updates to wait for * until the buffers are swapped by @ref glfwSwapBuffers. * - * @remarks This function may be called from secondary threads. - * - * @note This function is not called during window creation, leaving the swap - * interval set to whatever is the default on that platform. This is done + * @remarks This function is not called during context creation, leaving the + * swap interval set to whatever is the default on that platform. This is done * because some swap interval extensions used by GLFW do not allow the swap * interval to be reset to zero once it has been set to a non-zero value. * - * @note Some GPU drivers do not honor the requested swap interval, either - * because of user settings that override the request or due to bugs in the - * driver. + * @remarks Some GPU drivers do not honor the requested swap interval, either + * because of a user setting that overrides the application's request or due to + * bugs in the driver. + * + * @par Thread Safety + * This function may be called from any thread. * + * @sa @ref buffer_swap * @sa glfwSwapBuffers * + * @since Added in GLFW 1.0. + * * @ingroup context */ GLFWAPI void glfwSwapInterval(int interval); @@ -2245,19 +3248,28 @@ GLFWAPI void glfwSwapInterval(int interval); /*! @brief Returns whether the specified extension is available. * * This function returns whether the specified - * [OpenGL or context creation API extension](@ref context_glext) is supported - * by the current context. For example, on Windows both the OpenGL and WGL - * extension strings are checked. + * [client API extension](@ref context_glext) is supported by the current + * OpenGL or OpenGL ES context. It searches both for OpenGL and OpenGL ES + * extension and platform-specific context creation API extensions. + * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * + * As this functions retrieves and searches one or more extension strings each + * call, it is recommended that you cache its results if it is going to be used + * frequently. The extension strings will not change during the lifetime of + * a context, so there is no danger in doing this. * * @param[in] extension The ASCII encoded name of the extension. * @return `GL_TRUE` if the extension is available, or `GL_FALSE` otherwise. * - * @remarks This function may be called from secondary threads. + * @par Thread Safety + * This function may be called from any thread. * - * @note As this functions searches one or more extension strings on each call, - * it is recommended that you cache its results if it's going to be used - * frequently. The extension strings will not change during the lifetime of - * a context, so there is no danger in doing this. + * @sa @ref context_glext + * @sa glfwGetProcAddress + * + * @since Added in GLFW 1.0. * * @ingroup context */ @@ -2267,18 +3279,34 @@ GLFWAPI int glfwExtensionSupported(const char* extension); * context. * * This function returns the address of the specified - * [client API or extension function](@ref context_glext), if it is supported + * [core or extension function](@ref context_glext), if it is supported * by the current context. * + * A context must be current on the calling thread. Calling this function + * without a current context will cause a @ref GLFW_NO_CURRENT_CONTEXT error. + * * @param[in] procname The ASCII encoded name of the function. * @return The address of the function, or `NULL` if the function is - * unavailable. + * unavailable or an [error](@ref error_handling) occurred. + * + * @remarks The addresses of a given function is not guaranteed to be the same + * between contexts. + * + * @remarks This function may return a non-`NULL` address despite the + * associated version or extension not being available. Always check the + * context version or extension string presence first. + * + * @par Pointer Lifetime + * The returned function pointer is valid until the context is destroyed or the + * library is terminated. + * + * @par Thread Safety + * This function may be called from any thread. * - * @remarks This function may be called from secondary threads. + * @sa @ref context_glext + * @sa glfwExtensionSupported * - * @note The addresses of these functions are not guaranteed to be the same for - * all contexts, especially if they use different client APIs or even different - * context creation hints. + * @since Added in GLFW 1.0. * * @ingroup context */ diff --git a/externals/glfw-3.1.1.bin/include/GLFW/glfw3native.h b/externals/glfw-3.1.1.bin/include/GLFW/glfw3native.h new file mode 100644 index 000000000..b3ce7482d --- /dev/null +++ b/externals/glfw-3.1.1.bin/include/GLFW/glfw3native.h @@ -0,0 +1,356 @@ +/************************************************************************* + * GLFW 3.1 - www.glfw.org + * A library for OpenGL, window and input + *------------------------------------------------------------------------ + * Copyright (c) 2002-2006 Marcus Geelnard + * Copyright (c) 2006-2010 Camilla Berglund <elmindreda@elmindreda.org> + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would + * be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not + * be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + * + *************************************************************************/ + +#ifndef _glfw3_native_h_ +#define _glfw3_native_h_ + +#ifdef __cplusplus +extern "C" { +#endif + + +/************************************************************************* + * Doxygen documentation + *************************************************************************/ + +/*! @defgroup native Native access + * + * **By using the native access functions you assert that you know what you're + * doing and how to fix problems caused by using them. If you don't, you + * shouldn't be using them.** + * + * Before the inclusion of @ref glfw3native.h, you must define exactly one + * window system API macro and exactly one context creation API macro. Failure + * to do this will cause a compile-time error. + * + * The available window API macros are: + * * `GLFW_EXPOSE_NATIVE_WIN32` + * * `GLFW_EXPOSE_NATIVE_COCOA` + * * `GLFW_EXPOSE_NATIVE_X11` + * + * The available context API macros are: + * * `GLFW_EXPOSE_NATIVE_WGL` + * * `GLFW_EXPOSE_NATIVE_NSGL` + * * `GLFW_EXPOSE_NATIVE_GLX` + * * `GLFW_EXPOSE_NATIVE_EGL` + * + * These macros select which of the native access functions that are declared + * and which platform-specific headers to include. It is then up your (by + * definition platform-specific) code to handle which of these should be + * defined. + */ + + +/************************************************************************* + * System headers and types + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) + // This is a workaround for the fact that glfw3.h needs to export APIENTRY (for + // example to allow applications to correctly declare a GL_ARB_debug_output + // callback) but windows.h assumes no one will define APIENTRY before it does + #undef APIENTRY + #include <windows.h> +#elif defined(GLFW_EXPOSE_NATIVE_COCOA) + #include <ApplicationServices/ApplicationServices.h> + #if defined(__OBJC__) + #import <Cocoa/Cocoa.h> + #else + typedef void* id; + #endif +#elif defined(GLFW_EXPOSE_NATIVE_X11) + #include <X11/Xlib.h> + #include <X11/extensions/Xrandr.h> +#else + #error "No window API selected" +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) + /* WGL is declared by windows.h */ +#elif defined(GLFW_EXPOSE_NATIVE_NSGL) + /* NSGL is declared by Cocoa.h */ +#elif defined(GLFW_EXPOSE_NATIVE_GLX) + #include <GL/glx.h> +#elif defined(GLFW_EXPOSE_NATIVE_EGL) + #include <EGL/egl.h> +#else + #error "No context API selected" +#endif + + +/************************************************************************* + * Functions + *************************************************************************/ + +#if defined(GLFW_EXPOSE_NATIVE_WIN32) +/*! @brief Returns the adapter device name of the specified monitor. + * + * @return The UTF-8 encoded adapter device name (for example `\\.\DISPLAY1`) + * of the specified monitor, or `NULL` if an [error](@ref error_handling) + * occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the display device name of the specified monitor. + * + * @return The UTF-8 encoded display device name (for example + * `\\.\DISPLAY1\Monitor0`) of the specified monitor, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI const char* glfwGetWin32Monitor(GLFWmonitor* monitor); + +/*! @brief Returns the `HWND` of the specified window. + * + * @return The `HWND` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI HWND glfwGetWin32Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_WGL) +/*! @brief Returns the `HGLRC` of the specified window. + * + * @return The `HGLRC` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI HGLRC glfwGetWGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_COCOA) +/*! @brief Returns the `CGDirectDisplayID` of the specified monitor. + * + * @return The `CGDirectDisplayID` of the specified monitor, or + * `kCGNullDirectDisplay` if an [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI CGDirectDisplayID glfwGetCocoaMonitor(GLFWmonitor* monitor); + +/*! @brief Returns the `NSWindow` of the specified window. + * + * @return The `NSWindow` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetCocoaWindow(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_NSGL) +/*! @brief Returns the `NSOpenGLContext` of the specified window. + * + * @return The `NSOpenGLContext` of the specified window, or `nil` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI id glfwGetNSGLContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_X11) +/*! @brief Returns the `Display` used by GLFW. + * + * @return The `Display` used by GLFW, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI Display* glfwGetX11Display(void); + +/*! @brief Returns the `RRCrtc` of the specified monitor. + * + * @return The `RRCrtc` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI RRCrtc glfwGetX11Adapter(GLFWmonitor* monitor); + +/*! @brief Returns the `RROutput` of the specified monitor. + * + * @return The `RROutput` of the specified monitor, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.1. + * + * @ingroup native + */ +GLFWAPI RROutput glfwGetX11Monitor(GLFWmonitor* monitor); + +/*! @brief Returns the `Window` of the specified window. + * + * @return The `Window` of the specified window, or `None` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI Window glfwGetX11Window(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_GLX) +/*! @brief Returns the `GLXContext` of the specified window. + * + * @return The `GLXContext` of the specified window, or `NULL` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI GLXContext glfwGetGLXContext(GLFWwindow* window); +#endif + +#if defined(GLFW_EXPOSE_NATIVE_EGL) +/*! @brief Returns the `EGLDisplay` used by GLFW. + * + * @return The `EGLDisplay` used by GLFW, or `EGL_NO_DISPLAY` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI EGLDisplay glfwGetEGLDisplay(void); + +/*! @brief Returns the `EGLContext` of the specified window. + * + * @return The `EGLContext` of the specified window, or `EGL_NO_CONTEXT` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI EGLContext glfwGetEGLContext(GLFWwindow* window); + +/*! @brief Returns the `EGLSurface` of the specified window. + * + * @return The `EGLSurface` of the specified window, or `EGL_NO_SURFACE` if an + * [error](@ref error_handling) occurred. + * + * @par Thread Safety + * This function may be called from any thread. Access is not synchronized. + * + * @par History + * Added in GLFW 3.0. + * + * @ingroup native + */ +GLFWAPI EGLSurface glfwGetEGLSurface(GLFWwindow* window); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* _glfw3_native_h_ */ + diff --git a/externals/glfw-3.1.1.bin/lib-mingw-i686/glfw3.dll b/externals/glfw-3.1.1.bin/lib-mingw-i686/glfw3.dll Binary files differnew file mode 100644 index 000000000..84c2e1bc2 --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-mingw-i686/glfw3.dll diff --git a/externals/glfw-3.0.4.bin/lib-mingw-i686/glfw3dll.a b/externals/glfw-3.1.1.bin/lib-mingw-i686/glfw3dll.a Binary files differindex 415d85630..dc593d062 100644 --- a/externals/glfw-3.0.4.bin/lib-mingw-i686/glfw3dll.a +++ b/externals/glfw-3.1.1.bin/lib-mingw-i686/glfw3dll.a diff --git a/externals/glfw-3.1.1.bin/lib-mingw-i686/libglfw3.a b/externals/glfw-3.1.1.bin/lib-mingw-i686/libglfw3.a Binary files differnew file mode 100644 index 000000000..59eae0868 --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-mingw-i686/libglfw3.a diff --git a/externals/glfw-3.1.1.bin/lib-mingw-x86_64/glfw3.dll b/externals/glfw-3.1.1.bin/lib-mingw-x86_64/glfw3.dll Binary files differnew file mode 100644 index 000000000..437918eda --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-mingw-x86_64/glfw3.dll diff --git a/externals/glfw-3.0.4.bin/lib-mingw-x86_64/glfw3dll.a b/externals/glfw-3.1.1.bin/lib-mingw-x86_64/glfw3dll.a Binary files differindex d71c65377..be08358ab 100644 --- a/externals/glfw-3.0.4.bin/lib-mingw-x86_64/glfw3dll.a +++ b/externals/glfw-3.1.1.bin/lib-mingw-x86_64/glfw3dll.a diff --git a/externals/glfw-3.1.1.bin/lib-mingw-x86_64/libglfw3.a b/externals/glfw-3.1.1.bin/lib-mingw-x86_64/libglfw3.a Binary files differnew file mode 100644 index 000000000..e9e7be933 --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-mingw-x86_64/libglfw3.a diff --git a/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3.dll b/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3.dll Binary files differnew file mode 100644 index 000000000..f15748d7a --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3.dll diff --git a/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3.lib b/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3.lib Binary files differnew file mode 100644 index 000000000..6a5a85a1d --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3.lib diff --git a/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3dll.lib b/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3dll.lib Binary files differnew file mode 100644 index 000000000..248a5cadf --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-msvc_v120-Win32/glfw3dll.lib diff --git a/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3.dll b/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3.dll Binary files differnew file mode 100644 index 000000000..cba172f64 --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3.dll diff --git a/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3.lib b/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3.lib Binary files differnew file mode 100644 index 000000000..efdd64332 --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3.lib diff --git a/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3dll.lib b/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3dll.lib Binary files differnew file mode 100644 index 000000000..49ed2bb67 --- /dev/null +++ b/externals/glfw-3.1.1.bin/lib-msvc_v120-x64/glfw3dll.lib diff --git a/src/citra/citra.rc b/src/citra/citra.rc index 0165e93da..b0edb2e6b 100644 --- a/src/citra/citra.rc +++ b/src/citra/citra.rc @@ -1,9 +1,9 @@ -/////////////////////////////////////////////////////////////////////////////
-//
-// Icon
-//
-
-// Icon with lowest ID value placed first to ensure application icon
-// remains consistent on all systems.
-GLFW_ICON ICON "..\\assets\\citra.ico"
-
+///////////////////////////////////////////////////////////////////////////// +// +// Icon +// + +// Icon with lowest ID value placed first to ensure application icon +// remains consistent on all systems. +GLFW_ICON ICON "..\\..\\dist\\citra.ico" + diff --git a/src/citra/config.cpp b/src/citra/config.cpp index 846479fd7..1378567c1 100644 --- a/src/citra/config.cpp +++ b/src/citra/config.cpp @@ -66,7 +66,6 @@ void Config::ReadValues() { Settings::values.pad_cright_key = glfw_config->GetInteger("Controls", "pad_cright", GLFW_KEY_L); // Core - Settings::values.gpu_refresh_rate = glfw_config->GetInteger("Core", "gpu_refresh_rate", 30); Settings::values.frame_skip = glfw_config->GetInteger("Core", "frame_skip", 0); // Renderer diff --git a/src/citra/resource.h b/src/citra/resource.h Binary files differindex 0d42c8a8a..127896424 100644 --- a/src/citra/resource.h +++ b/src/citra/resource.h diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt index efccdbec6..c2d1ad240 100644 --- a/src/citra_qt/CMakeLists.txt +++ b/src/citra_qt/CMakeLists.txt @@ -89,15 +89,15 @@ if (Qt5_FOUND AND MSVC) ) set(DLL_DEST "${CMAKE_BINARY_DIR}/bin/$<CONFIG>/") set(PLATFORMS ${DLL_DEST}platforms/) - + # windows commandline expects the / to be \ so switch them - string(REPLACE "/" "\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) - string(REPLACE "/" "\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) - string(REPLACE "/" "\\" DLL_DEST ${DLL_DEST}) - string(REPLACE "/" "\\" PLATFORMS ${PLATFORMS}) - + string(REPLACE "/" "\\\\" Qt5_DLL_DIR ${Qt5_DLL_DIR}) + string(REPLACE "/" "\\\\" Qt5_PLATFORMS_DIR ${Qt5_PLATFORMS_DIR}) + string(REPLACE "/" "\\\\" DLL_DEST ${DLL_DEST}) + string(REPLACE "/" "\\\\" PLATFORMS ${PLATFORMS}) + # /NJH /NJS /NDL /NFL /NC /NS /NP - Silence any output - # cmake adds an extra check for command success which doesn't work too well with robocopy + # cmake adds an extra check for command success which doesn't work too well with robocopy # so trick it into thinking the command was successful with the || cmd /c "exit /b 0" add_custom_command(TARGET citra-qt POST_BUILD 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() { Core::SingleStep(); emit DebugModeEntered(); yieldCurrentThread(); - + was_active = false; } else { 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: * @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) */ void DebugModeEntered(); - + /** * Emitted right before the CPU continues execution * diff --git a/src/citra_qt/citra-qt.rc b/src/citra_qt/citra-qt.rc Binary files differindex dd6f834f5..3c7239853 100644 --- a/src/citra_qt/citra-qt.rc +++ b/src/citra_qt/citra-qt.rc diff --git a/src/citra_qt/config.cpp b/src/citra_qt/config.cpp index 460f4ec07..2a9af1f38 100644 --- a/src/citra_qt/config.cpp +++ b/src/citra_qt/config.cpp @@ -49,7 +49,6 @@ void Config::ReadValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - Settings::values.gpu_refresh_rate = qt_config->value("gpu_refresh_rate", 30).toInt(); Settings::values.frame_skip = qt_config->value("frame_skip", 0).toInt(); qt_config->endGroup(); @@ -102,7 +101,6 @@ void Config::SaveValues() { qt_config->endGroup(); qt_config->beginGroup("Core"); - qt_config->setValue("gpu_refresh_rate", Settings::values.gpu_refresh_rate); qt_config->setValue("frame_skip", Settings::values.frame_skip); qt_config->endGroup(); 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() { ret_addr = Memory::Read32(addr); call_addr = ret_addr - 4; //get call address??? - + if (Memory::GetPointer(call_addr) == nullptr) break; diff --git a/src/citra_qt/debugger/callstack.ui b/src/citra_qt/debugger/callstack.ui index b0e31120f..248ea3dd7 100644 --- a/src/citra_qt/debugger/callstack.ui +++ b/src/citra_qt/debugger/callstack.ui @@ -17,6 +17,9 @@ <layout class="QVBoxLayout" name="verticalLayout"> <item> <widget class="QTreeView" name="treeView"> + <property name="editTriggers"> + <set>QAbstractItemView::NoEditTriggers</set> + </property> <property name="alternatingRowColors"> <bool>true</bool> </property> diff --git a/src/citra_qt/debugger/graphics_cmdlists.cpp b/src/citra_qt/debugger/graphics_cmdlists.cpp index 804c735a3..cabf5fe07 100644 --- a/src/citra_qt/debugger/graphics_cmdlists.cpp +++ b/src/citra_qt/debugger/graphics_cmdlists.cpp @@ -11,10 +11,10 @@ #include <QSpinBox> #include <QComboBox> -#include "video_core/pica.h" -#include "video_core/math.h" +#include "common/vector_math.h" #include "video_core/debug_utils/debug_utils.h" +#include "video_core/pica.h" #include "graphics_cmdlists.h" diff --git a/src/citra_qt/debugger/graphics_framebuffer.cpp b/src/citra_qt/debugger/graphics_framebuffer.cpp index e07344591..6bbe7572c 100644 --- a/src/citra_qt/debugger/graphics_framebuffer.cpp +++ b/src/citra_qt/debugger/graphics_framebuffer.cpp @@ -9,10 +9,11 @@ #include <QPushButton> #include <QSpinBox> +#include "common/color.h" + #include "core/hw/gpu.h" #include "core/memory.h" -#include "video_core/color.h" #include "video_core/pica.h" #include "video_core/utils.h" 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) ui.action_Use_Hardware_Renderer->setChecked(Settings::values.use_hw_renderer); SetHardwareRendererEnabled(ui.action_Use_Hardware_Renderer->isChecked()); - + ui.action_Single_Window_Mode->setChecked(settings.value("singleWindowMode", true).toBool()); ToggleWindowMode(); 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 @@ <bool>true</bool> </property> <widget class="QWidget" name="centralwidget"> - <layout class="QHBoxLayout" name="horizontalLayout"/> + <layout class="QHBoxLayout" name="horizontalLayout"> + <property name="leftMargin"> + <number>0</number> + </property> + <property name="topMargin"> + <number>0</number> + </property> + <property name="rightMargin"> + <number>0</number> + </property> + <property name="bottomMargin"> + <number>0</number> + </property> + </layout> </widget> <widget class="QMenuBar" name="menubar"> <property name="geometry"> @@ -92,7 +105,7 @@ </action> <action name="action_Start"> <property name="enabled"> - <bool>false</bool> + <bool>false</bool> </property> <property name="text"> <string>&Start</string> diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index dbaaac77b..e78f4f144 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -24,6 +24,7 @@ set(HEADERS bit_field.h break_points.h chunk_file.h + color.h common_funcs.h common_paths.h common_types.h @@ -54,6 +55,7 @@ set(HEADERS thread_queue_list.h thunk.h timer.h + vector_math.h ) create_directory_groups(${SRCS} ${HEADERS}) diff --git a/src/video_core/color.h b/src/common/color.h index 4d2026eb0..422fdc8af 100644 --- a/src/video_core/color.h +++ b/src/common/color.h @@ -6,8 +6,7 @@ #include "common/common_types.h" #include "common/swap.h" - -#include "video_core/math.h" +#include "common/vector_math.h" namespace Color { 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 new_x = std::max(new_x, framebuffer_layout.bottom_screen.left); new_x = std::min(new_x, framebuffer_layout.bottom_screen.right-1); - + new_y = std::max(new_y, framebuffer_layout.bottom_screen.top); new_y = std::min(new_y, framebuffer_layout.bottom_screen.bottom-1); 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 @@ #include <io.h> #include <direct.h> // getcwd #include <tchar.h> - + // 64 bit offsets for windows #define fseeko _fseeki64 #define ftello _ftelli64 diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 6ca8cb78d..d85e58373 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -37,6 +37,7 @@ namespace Log { SUB(Service, APT) \ SUB(Service, GSP) \ SUB(Service, AC) \ + SUB(Service, AM) \ SUB(Service, PTM) \ SUB(Service, LDR) \ SUB(Service, NIM) \ diff --git a/src/common/logging/log.h b/src/common/logging/log.h index d720d7fe0..5b3a731e9 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h @@ -57,13 +57,14 @@ enum class Class : ClassType { Service_APT, ///< The APT (Applets) service Service_GSP, ///< The GSP (GPU control) service Service_AC, ///< The AC (WiFi status) service + Service_AM, ///< The AM (Application manager) service Service_PTM, ///< The PTM (Power status & misc.) service Service_LDR, ///< The LDR (3ds dll loader) service Service_NIM, ///< The NIM (Network interface manager) service - Service_NWM, ///< The NWM (Network manager) service + Service_NWM, ///< The NWM (Network wlan manager) service Service_CFG, ///< The CFG (Configuration) service Service_DSP, ///< The DSP (DSP control) service - Service_HID, ///< The HID (User input) service + Service_HID, ///< The HID (Human interface device) service Service_SOC, ///< The SOC (Socket) service Service_Y2R, ///< The Y2R (YUV to RGB conversion) service HW, ///< Low-level hardware emulation diff --git a/src/common/math_util.h b/src/common/math_util.h index 4b0910741..d44b06e74 100644 --- a/src/common/math_util.h +++ b/src/common/math_util.h @@ -12,7 +12,7 @@ namespace MathUtil { inline bool IntervalsIntersect(unsigned start0, unsigned length0, unsigned start1, unsigned length1) { - return (std::max(start0, start1) <= std::min(start0 + length0, start1 + length1)); + return (std::max(start0, start1) < std::min(start0 + length0, start1 + length1)); } template<typename T> 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 <> inline void swap<8>(u8* data) { *reinterpret_cast<u64*>(data) = swap64(data); } - + } // Namespace Common diff --git a/src/video_core/math.h b/src/common/vector_math.h index f9a822658..4928c9bf2 100644 --- a/src/video_core/math.h +++ b/src/common/vector_math.h @@ -461,7 +461,7 @@ public: // e.g. Vec2 uv() { return Vec2(x,y); } // _DEFINE_SWIZZLER2 defines a single such function - // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) + // DEFINE_SWIZZLER2_COMP1 defines one-component functions for all component names (x<->r) // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and permutations (xy<->yx) #define _DEFINE_SWIZZLER2(a, b, name) const Vec2<T> name() const { return Vec2<T>(a, b); } #define DEFINE_SWIZZLER2_COMP1(a, a2) \ diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 5caaee474..057b8ca0c 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -36,20 +36,29 @@ set(SRCS hle/kernel/shared_memory.cpp hle/kernel/thread.cpp hle/kernel/timer.cpp + hle/kernel/vm_manager.cpp hle/service/ac_u.cpp hle/service/act_u.cpp - hle/service/am_app.cpp - hle/service/am_net.cpp - hle/service/am_sys.cpp + hle/service/am/am.cpp + hle/service/am/am_app.cpp + hle/service/am/am_net.cpp + hle/service/am/am_sys.cpp + hle/service/am/am_u.cpp hle/service/apt/apt.cpp hle/service/apt/apt_a.cpp hle/service/apt/apt_s.cpp hle/service/apt/apt_u.cpp - hle/service/boss_p.cpp - hle/service/boss_u.cpp - hle/service/cam_u.cpp - hle/service/cecd_s.cpp - hle/service/cecd_u.cpp + hle/service/boss/boss.cpp + hle/service/boss/boss_p.cpp + hle/service/boss/boss_u.cpp + hle/service/cam/cam.cpp + hle/service/cam/cam_c.cpp + hle/service/cam/cam_q.cpp + hle/service/cam/cam_s.cpp + hle/service/cam/cam_u.cpp + hle/service/cecd/cecd.cpp + hle/service/cecd/cecd_s.cpp + hle/service/cecd/cecd_u.cpp hle/service/cfg/cfg.cpp hle/service/cfg/cfg_i.cpp hle/service/cfg/cfg_s.cpp @@ -57,8 +66,9 @@ set(SRCS hle/service/csnd_snd.cpp hle/service/dsp_dsp.cpp hle/service/err_f.cpp - hle/service/frd_a.cpp - hle/service/frd_u.cpp + hle/service/frd/frd.cpp + hle/service/frd/frd_a.cpp + hle/service/frd/frd_u.cpp hle/service/fs/archive.cpp hle/service/fs/fs_user.cpp hle/service/gsp_gpu.cpp @@ -74,10 +84,13 @@ set(SRCS hle/service/ldr_ro.cpp hle/service/mic_u.cpp hle/service/ndm_u.cpp - hle/service/news_s.cpp - hle/service/news_u.cpp - hle/service/nim_aoc.cpp - hle/service/nim_u.cpp + hle/service/news/news.cpp + hle/service/news/news_s.cpp + hle/service/news/news_u.cpp + hle/service/nim/nim.cpp + hle/service/nim/nim_aoc.cpp + hle/service/nim/nim_s.cpp + hle/service/nim/nim_u.cpp hle/service/ns_s.cpp hle/service/nwm_uds.cpp hle/service/pm_app.cpp @@ -116,7 +129,6 @@ set(HEADERS arm/dyncom/arm_dyncom_thumb.h arm/skyeye_common/arm_regformat.h arm/skyeye_common/armdefs.h - arm/skyeye_common/armemu.h arm/skyeye_common/armmmu.h arm/skyeye_common/vfp/asm_vfp.h arm/skyeye_common/vfp/vfp.h @@ -148,21 +160,30 @@ set(HEADERS hle/kernel/shared_memory.h hle/kernel/thread.h hle/kernel/timer.h + hle/kernel/vm_manager.h hle/result.h hle/service/ac_u.h hle/service/act_u.h - hle/service/am_app.h - hle/service/am_net.h - hle/service/am_sys.h + hle/service/am/am.h + hle/service/am/am_app.h + hle/service/am/am_net.h + hle/service/am/am_sys.h + hle/service/am/am_u.h hle/service/apt/apt.h hle/service/apt/apt_a.h hle/service/apt/apt_s.h hle/service/apt/apt_u.h - hle/service/boss_p.h - hle/service/boss_u.h - hle/service/cam_u.h - hle/service/cecd_s.h - hle/service/cecd_u.h + hle/service/boss/boss.h + hle/service/boss/boss_p.h + hle/service/boss/boss_u.h + hle/service/cam/cam.h + hle/service/cam/cam_c.h + hle/service/cam/cam_q.h + hle/service/cam/cam_s.h + hle/service/cam/cam_u.h + hle/service/cecd/cecd.h + hle/service/cecd/cecd_s.h + hle/service/cecd/cecd_u.h hle/service/cfg/cfg.h hle/service/cfg/cfg_i.h hle/service/cfg/cfg_s.h @@ -170,8 +191,9 @@ set(HEADERS hle/service/csnd_snd.h hle/service/dsp_dsp.h hle/service/err_f.h - hle/service/frd_a.h - hle/service/frd_u.h + hle/service/frd/frd.h + hle/service/frd/frd_a.h + hle/service/frd/frd_u.h hle/service/fs/archive.h hle/service/fs/fs_user.h hle/service/gsp_gpu.h @@ -187,10 +209,13 @@ set(HEADERS hle/service/ldr_ro.h hle/service/mic_u.h hle/service/ndm_u.h - hle/service/news_s.h - hle/service/news_u.h - hle/service/nim_aoc.h - hle/service/nim_u.h + hle/service/news/news.h + hle/service/news/news_s.h + hle/service/news/news_u.h + hle/service/nim/nim.h + hle/service/nim/nim_aoc.h + hle/service/nim/nim_s.h + hle/service/nim/nim_u.h hle/service/ns_s.h hle/service/nwm_uds.h hle/service/pm_app.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) { // SWI return OP_SWI; } - + uint8_t bit4 = (insn >> 4) & 0x1; uint8_t cpnum = (insn >> 8) & 0xf; diff --git a/src/core/arm/dyncom/arm_dyncom.cpp b/src/core/arm/dyncom/arm_dyncom.cpp index 0072ae533..529c4ac70 100644 --- a/src/core/arm/dyncom/arm_dyncom.cpp +++ b/src/core/arm/dyncom/arm_dyncom.cpp @@ -6,7 +6,7 @@ #include "common/make_unique.h" -#include "core/arm/skyeye_common/armemu.h" +#include "core/arm/skyeye_common/armdefs.h" #include "core/arm/skyeye_common/vfp/vfp.h" #include "core/arm/dyncom/arm_dyncom.h" diff --git a/src/core/arm/dyncom/arm_dyncom_interpreter.cpp b/src/core/arm/dyncom/arm_dyncom_interpreter.cpp index e4b5486e0..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) { unsigned int immed_8 = BITS(sht_oper, 0, 7); unsigned int rotate_imm = BITS(sht_oper, 8, 11); unsigned int shifter_operand = ROTATE_RIGHT_32(immed_8, rotate_imm * 2); - if (rotate_imm == 0) + if (rotate_imm == 0) cpu->shifter_carry_out = cpu->CFlag; else cpu->shifter_carry_out = BIT(shifter_operand, 31); @@ -521,7 +521,7 @@ static void MLnS(ImmediateOffset)(ARMul_State* cpu, unsigned int inst, unsigned addr = CHECK_READ_REG15_WA(cpu, Rn) + offset_8; else addr = CHECK_READ_REG15_WA(cpu, Rn) - offset_8; - + virt_addr = addr; } @@ -550,7 +550,7 @@ static void MLnS(ImmediatePreIndexed)(ARMul_State* cpu, unsigned int inst, unsig if (U_BIT) addr = rn + offset_8; - else + else addr = rn - offset_8; virt_addr = addr; @@ -1306,8 +1306,8 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(and)(unsigned int inst, int index) inst_cream->Rd = BITS(inst, 12, 15); inst_cream->shifter_operand = BITS(inst, 0, 11); inst_cream->shtop_func = get_shtop(inst); - - if (inst_cream->Rd == 15) + + if (inst_cream->Rd == 15) inst_base->br = INDIRECT_BRANCH; return inst_base; @@ -1350,7 +1350,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(bic)(unsigned int inst, int index) inst_cream->shifter_operand = BITS(inst, 0, 11); inst_cream->shtop_func = get_shtop(inst); - if (inst_cream->Rd == 15) + if (inst_cream->Rd == 15) inst_base->br = INDIRECT_BRANCH; return inst_base; } @@ -3269,7 +3269,7 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(yield)(unsigned int inst, int index) #define VFP_INTERPRETER_STRUCT #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" #undef VFP_INTERPRETER_STRUCT - + #define VFP_INTERPRETER_TRANS #include "core/arm/skyeye_common/vfp/vfpinstr.cpp" #undef VFP_INTERPRETER_TRANS @@ -3478,9 +3478,9 @@ const transop_fp_t arm_instruction_trans[] = { INTERPRETER_TRANSLATE(bbl), // All the thumb instructions should be placed the end of table - INTERPRETER_TRANSLATE(b_2_thumb), - INTERPRETER_TRANSLATE(b_cond_thumb), - INTERPRETER_TRANSLATE(bl_1_thumb), + INTERPRETER_TRANSLATE(b_2_thumb), + INTERPRETER_TRANSLATE(b_cond_thumb), + INTERPRETER_TRANSLATE(bl_1_thumb), INTERPRETER_TRANSLATE(bl_2_thumb), INTERPRETER_TRANSLATE(blx_1_thumb) }; @@ -3564,17 +3564,13 @@ static int InterpreterTranslate(ARMul_State* cpu, int& bb_start, u32 addr) { unsigned int inst, inst_size = 4; int idx; int ret = NON_BRANCH; - int thumb = 0; int size = 0; // instruction size of basic block bb_start = top; - if (cpu->TFlag) - thumb = THUMB; - u32 phys_addr = addr; u32 pc_start = cpu->Reg[15]; - while(ret == NON_BRANCH) { + while (ret == NON_BRANCH) { inst = Memory::Read32(phys_addr & 0xFFFFFFFC); size++; @@ -3890,7 +3886,6 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { #define CurrentModeHasSPSR (cpu->Mode != SYSTEM32MODE) && (cpu->Mode != USER32MODE) #define PC (cpu->Reg[15]) - #define CHECK_EXT_INT if (!cpu->NirqSig && !(cpu->Cpsr & 0x80)) goto END; // GCC and Clang have a C++ extension to support a lookup table of labels. Otherwise, fallback // to a clunky switch statement. @@ -4343,7 +4338,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { } } if (BIT(inst, 13)) { - if (cpu->Mode == USER32MODE) + if (cpu->Mode == USER32MODE) cpu->Reg[13] = ReadMemory32(cpu, addr); else cpu->Reg_usr[0] = ReadMemory32(cpu, addr); @@ -4351,7 +4346,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { addr += 4; } if (BIT(inst, 14)) { - if (cpu->Mode == USER32MODE) + if (cpu->Mode == USER32MODE) cpu->Reg[14] = ReadMemory32(cpu, addr); else cpu->Reg_usr[1] = ReadMemory32(cpu, addr); @@ -5153,7 +5148,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { REV16_INST: REVSH_INST: { - + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { rev_inst* const inst_cream = (rev_inst*)inst_base->component; @@ -5726,7 +5721,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { if (do_swap) rm_val = (((rm_val & 0xFFFF) << 16) | (rm_val >> 16)); - + const s32 product1 = (s16)(rn_val & 0xFFFF) * (s16)(rm_val & 0xFFFF); const s32 product2 = (s16)((rn_val >> 16) & 0xFFFF) * (s16)((rm_val >> 16) & 0xFFFF); s64 result; @@ -6588,7 +6583,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { { u32 lo_val = 0; u32 hi_val = 0; - + // UHADD16 if (op2 == 0x00) { lo_val = (rn_val & 0xFFFF) + (rm_val & 0xFFFF); @@ -6777,7 +6772,7 @@ unsigned InterpreterMainLoop(ARMul_State* cpu) { u16 lo_val = 0; u16 hi_val = 0; - + // UQADD16 if (op2 == 0x00) { 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 08b5c0b77..3e79c44c0 100644 --- a/src/core/arm/dyncom/arm_dyncom_thumb.cpp +++ b/src/core/arm/dyncom/arm_dyncom_thumb.cpp @@ -184,38 +184,27 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { case 9: // LDR Rd,[PC,#imm8] *ainstr = 0xE59F0000 // base | ((tinstr & 0x0700) << (12 - 8)) // Rd - |((tinstr & 0x00FF) << (2 - 0)); // off8 + |((tinstr & 0x00FF) << (2 - 0)); // off8 break; case 10: case 11: - // TODO: Format 7 and Format 8 perform the same ARM encoding, so the following could be - // merged into a single subset, saving on the following boolean: - - if ((tinstr & (1 << 9)) == 0) { - static const ARMword subset[4] = { - 0xE7800000, // STR Rd,[Rb,Ro] - 0xE7C00000, // STRB Rd,[Rb,Ro] - 0xE7900000, // LDR Rd,[Rb,Ro] - 0xE7D00000 // LDRB Rd,[Rb,Ro] - }; - - *ainstr = subset[(tinstr & 0x0C00) >> 10] // base - |((tinstr & 0x0007) << (12 - 0)) // Rd - |((tinstr & 0x0038) << (16 - 3)) // Rb - |((tinstr & 0x01C0) >> 6); // Ro - - } else { - static const ARMword subset[4] = { + { + static const ARMword subset[8] = { + 0xE7800000, // STR Rd,[Rb,Ro] 0xE18000B0, // STRH Rd,[Rb,Ro] + 0xE7C00000, // STRB Rd,[Rb,Ro] 0xE19000D0, // LDRSB Rd,[Rb,Ro] + 0xE7900000, // LDR Rd,[Rb,Ro] 0xE19000B0, // LDRH Rd,[Rb,Ro] + 0xE7D00000, // LDRB Rd,[Rb,Ro] 0xE19000F0 // LDRSH Rd,[Rb,Ro] }; - *ainstr = subset[(tinstr & 0x0C00) >> 10] // base - |((tinstr & 0x0007) << (12 - 0)) // Rd - |((tinstr & 0x0038) << (16 - 3)) // Rb - |((tinstr & 0x01C0) >> 6); // Ro + + *ainstr = subset[(tinstr & 0xE00) >> 9] // base + |((tinstr & 0x0007) << (12 - 0)) // Rd + |((tinstr & 0x0038) << (16 - 3)) // Rb + |((tinstr & 0x01C0) >> 6); // Ro } break; @@ -285,9 +274,46 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { ? 0xE24DDF00 // SUB : 0xE28DDF00) // ADD |(tinstr & 0x007F); // off7 - } else if ((tinstr & 0x0F00) == 0x0e00) - *ainstr = 0xEF000000 | 0x180000; // base | BKPT mask - else { + } else if ((tinstr & 0x0F00) == 0x0e00) { + // BKPT + *ainstr = 0xEF000000 // base + | BITS(tinstr, 0, 3) // imm4 field; + | (BITS(tinstr, 4, 7) << 8); // beginning 4 bits of imm12 + } else if ((tinstr & 0x0F00) == 0x0200) { + static const ARMword subset[4] = { + 0xE6BF0070, // SXTH + 0xE6AF0070, // SXTB + 0xE6FF0070, // UXTH + 0xE6EF0070, // UXTB + }; + + *ainstr = subset[BITS(tinstr, 6, 7)] // base + | (BITS(tinstr, 0, 2) << 12) // Rd + | BITS(tinstr, 3, 5); // Rm + } else if ((tinstr & 0x0F00) == 0x600) { + if (BIT(tinstr, 5) == 0) { + // SETEND + *ainstr = 0xF1010000 // base + | (BIT(tinstr, 3) << 9); // endian specifier + } else { + // CPS + *ainstr = 0xF1080000 // base + | (BIT(tinstr, 0) << 6) // fiq bit + | (BIT(tinstr, 1) << 7) // irq bit + | (BIT(tinstr, 2) << 8) // abort bit + | (BIT(tinstr, 4) << 18); // enable bit + } + } else if ((tinstr & 0x0F00) == 0x0a00) { + static const ARMword subset[3] = { + 0xE6BF0F30, // REV + 0xE6BF0FB0, // REV16 + 0xE6FF0FB0, // REVSH + }; + + *ainstr = subset[BITS(tinstr, 6, 7)] // base + | (BITS(tinstr, 0, 2) << 12) // Rd + | BITS(tinstr, 3, 5); // Rm + } else { static const ARMword subset[4] = { 0xE92D0000, // STMDB sp!,{rlist} 0xE92D4000, // STMDB sp!,{rlist,lr} @@ -301,11 +327,25 @@ tdstate thumb_translate(u32 addr, u32 instr, u32* ainstr, u32* inst_size) { case 24: // STMIA case 25: // LDMIA - *ainstr = ((tinstr & (1 << 11)) // base - ? 0xE8B00000 // LDMIA - : 0xE8A00000) // STMIA - |((tinstr & 0x0700) << (16 - 8)) // Rb - |(tinstr & 0x00FF); // mask8 + if (tinstr & (1 << 11)) + { + unsigned int base = 0xE8900000; + unsigned int rn = BITS(tinstr, 8, 10); + + // Writeback + if ((tinstr & (1 << rn)) == 0) + base |= (1 << 21); + + *ainstr = base // base (LDMIA) + | (rn << 16) // Rn + | (tinstr & 0x00FF); // Register list + } + else + { + *ainstr = 0xE8A00000 // base (STMIA) + | (BITS(tinstr, 8, 10) << 16) // Rn + | (tinstr & 0x00FF); // Register list + } break; case 26: // Bcc diff --git a/src/core/arm/interpreter/arminit.cpp b/src/core/arm/interpreter/arminit.cpp index 680a94a39..4f7a48fab 100644 --- a/src/core/arm/interpreter/arminit.cpp +++ b/src/core/arm/interpreter/arminit.cpp @@ -17,7 +17,6 @@ #include <cstring> #include "core/arm/skyeye_common/armdefs.h" -#include "core/arm/skyeye_common/armemu.h" #include "core/arm/skyeye_common/vfp/vfp.h" /***************************************************************************\ 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 cpu->CP15[CP15_DATA_SYNC_BARRIER] = value; else if (opcode_2 == 5) cpu->CP15[CP15_DATA_MEMORY_BARRIER] = value; - + } else if (crn == 13 && opcode_1 == 0 && crm == 0 && opcode_2 == 2) { diff --git a/src/core/arm/skyeye_common/arm_regformat.h b/src/core/arm/skyeye_common/arm_regformat.h index 6c89774eb..a92effbb4 100644 --- a/src/core/arm/skyeye_common/arm_regformat.h +++ b/src/core/arm/skyeye_common/arm_regformat.h @@ -59,6 +59,8 @@ enum { VFP_FPSID, VFP_FPSCR, VFP_FPEXC, + VFP_MVFR0, + VFP_MVFR1, // Not an actual register. // All VFP system registers should be defined above this. diff --git a/src/core/arm/skyeye_common/armdefs.h b/src/core/arm/skyeye_common/armdefs.h index 470f9508d..d2c901100 100644 --- a/src/core/arm/skyeye_common/armdefs.h +++ b/src/core/arm/skyeye_common/armdefs.h @@ -1,16 +1,16 @@ /* armdefs.h -- ARMulator common definitions: ARM6 Instruction Emulator. Copyright (C) 1994 Advanced RISC Machines Ltd. - + This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. - + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. - + You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ @@ -262,6 +262,34 @@ enum ConditionCode { NV = 15, }; +// Flags for use with the APSR. +enum : u32 { + NBIT = (1U << 31U), + ZBIT = (1 << 30), + CBIT = (1 << 29), + VBIT = (1 << 28), + QBIT = (1 << 27), + JBIT = (1 << 24), + EBIT = (1 << 9), + ABIT = (1 << 8), + IBIT = (1 << 7), + FBIT = (1 << 6), + TBIT = (1 << 5), + + // Masks for groups of bits in the APSR. + MODEBITS = 0x1F, + INTBITS = 0x1C0, +}; + +// Values for Emulate. +enum { + STOP = 0, // Stop + CHANGEMODE = 1, // Change mode + ONCE = 2, // Execute just one iteration + RUN = 3 // Continuous execution +}; + + extern bool AddOverflow(ARMword, ARMword, ARMword); extern bool SubOverflow(ARMword, ARMword, ARMword); diff --git a/src/core/arm/skyeye_common/armemu.h b/src/core/arm/skyeye_common/armemu.h deleted file mode 100644 index 7e0965052..000000000 --- a/src/core/arm/skyeye_common/armemu.h +++ /dev/null @@ -1,47 +0,0 @@ -/* armemu.h -- ARMulator emulation macros: ARM6 Instruction Emulator. - Copyright (C) 1994 Advanced RISC Machines Ltd. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ - -#pragma once - -#include "core/arm/skyeye_common/armdefs.h" - -// Flags for use with the APSR. -enum : u32 { - NBIT = (1U << 31U), - ZBIT = (1 << 30), - CBIT = (1 << 29), - VBIT = (1 << 28), - QBIT = (1 << 27), - JBIT = (1 << 24), - EBIT = (1 << 9), - ABIT = (1 << 8), - IBIT = (1 << 7), - FBIT = (1 << 6), - TBIT = (1 << 5), - - // Masks for groups of bits in the APSR. - MODEBITS = 0x1F, - INTBITS = 0x1C0, -}; - -// Values for Emulate. -enum { - STOP = 0, // Stop - CHANGEMODE = 1, // Change mode - ONCE = 2, // Execute just one interation - RUN = 3 // Continuous execution -}; diff --git a/src/core/arm/skyeye_common/vfp/vfp.cpp b/src/core/arm/skyeye_common/vfp/vfp.cpp index b88d47750..571d6c2f2 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.cpp +++ b/src/core/arm/skyeye_common/vfp/vfp.cpp @@ -33,6 +33,10 @@ unsigned VFPInit(ARMul_State* state) state->VFP[VFP_FPEXC] = 0; state->VFP[VFP_FPSCR] = 0; + // ARM11 MPCore feature register values. + state->VFP[VFP_MVFR0] = 0x11111111; + state->VFP[VFP_MVFR1] = 0; + return 0; } diff --git a/src/core/arm/skyeye_common/vfp/vfp.h b/src/core/arm/skyeye_common/vfp/vfp.h index 727350f14..acefae9bb 100644 --- a/src/core/arm/skyeye_common/vfp/vfp.h +++ b/src/core/arm/skyeye_common/vfp/vfp.h @@ -22,7 +22,6 @@ #include "core/arm/skyeye_common/vfp/vfp_helper.h" /* for references to cdp SoftFloat functions */ -#define VFP_DEBUG_UNIMPLEMENTED(x) LOG_ERROR(Core_ARM11, "in func %s, " #x " unimplemented\n", __FUNCTION__); exit(-1); #define VFP_DEBUG_UNTESTED(x) LOG_TRACE(Core_ARM11, "in func %s, " #x " untested\n", __FUNCTION__); #define CHECK_VFP_ENABLED #define CHECK_VFP_CDP_RET vfp_raise_exceptions(cpu, ret, inst_cream->instr, cpu->VFP[VFP_FPSCR]); 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 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ -/* +/* * The following code is derivative from Linux Android kernel vfp * floating point support. - * + * * Copyright (C) 2004 ARM Limited. * Written by Deep Blue Solutions Limited. * diff --git a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp index 3ed918a93..67fe63aa4 100644 --- a/src/core/arm/skyeye_common/vfp/vfpinstr.cpp +++ b/src/core/arm/skyeye_common/vfp/vfpinstr.cpp @@ -1068,10 +1068,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbrc)(unsigned int inst, int index) #ifdef VFP_INTERPRETER_IMPL VMOVBRC_INST: { - if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { CHECK_VFP_ENABLED; - VFP_DEBUG_UNIMPLEMENTED(VMOVBRC); + vmovbrc_inst* const inst_cream = (vmovbrc_inst*)inst_base->component; + + cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index] = cpu->Reg[inst_cream->t]; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(vmovbrc_inst)); @@ -1139,12 +1141,10 @@ VMRS_INST: cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPSID]; break; case 6: - /* MVFR1, VFPv3 only ? */ - LOG_TRACE(Core_ARM11, "\tr%d <= MVFR1 unimplemented\n", inst_cream->Rt); + cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR1]; break; case 7: - /* MVFR0, VFPv3 only? */ - LOG_TRACE(Core_ARM11, "\tr%d <= MVFR0 unimplemented\n", inst_cream->Rt); + cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_MVFR0]; break; case 8: cpu->Reg[inst_cream->Rt] = cpu->VFP[VFP_FPEXC]; @@ -1195,10 +1195,12 @@ static ARM_INST_PTR INTERPRETER_TRANSLATE(vmovbcr)(unsigned int inst, int index) #ifdef VFP_INTERPRETER_IMPL VMOVBCR_INST: { - if ((inst_base->cond == 0xe) || CondPassed(cpu, inst_base->cond)) { + if (inst_base->cond == 0xE || CondPassed(cpu, inst_base->cond)) { CHECK_VFP_ENABLED; - VFP_DEBUG_UNIMPLEMENTED(VMOVBCR); + vmovbcr_inst* const inst_cream = (vmovbcr_inst*) inst_base->component; + + cpu->Reg[inst_cream->t] = cpu->ExtReg[(2 * inst_cream->d) + inst_cream->index]; } cpu->Reg[15] += GET_INST_SIZE(cpu); INC_PC(sizeof(vmovbcr_inst)); 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() { const char* name = event_types[event->type].name; if (!name) name = "[unknown]"; - text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, + text += Common::StringFromFormat("%s : %i %08x%08x\n", name, (int)event->time, (u32)(event->userdata >> 32), (u32)(event->userdata)); event = event->next; } 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(); /// userdata MAY NOT CONTAIN POINTERS. userdata might get written and reloaded from disk, /// when we implement state saves. /** - * Schedules an event to run after the specified number of cycles, + * Schedules an event to run after the specified number of cycles, * with an optional parameter to be passed to the callback handler. * This must be run ONLY from within the cpu thread. * @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..e50c58a52 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) std::string GetExtDataContainerPath(const std::string& mount_point, bool shared) { if (shared) return Common::StringFromFormat("%sdata/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str()); - - return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), + + return Common::StringFromFormat("%sNintendo 3DS/%s/%s/extdata/", mount_point.c_str(), SYSTEM_ID.c_str(), SDCARD_ID.c_str()); } @@ -71,7 +71,7 @@ bool ArchiveFactory_ExtSaveData::Initialize() { } ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(const Path& path) { - std::string fullpath = GetExtSaveDataPath(mount_point, path); + std::string fullpath = GetExtSaveDataPath(mount_point, path) + "user/"; if (!FileUtil::Exists(fullpath)) { // TODO(Subv): Check error code, this one is probably wrong return ResultCode(ErrorDescription::FS_NotFormatted, ErrorModule::FS, @@ -82,8 +82,11 @@ ResultVal<std::unique_ptr<ArchiveBackend>> ArchiveFactory_ExtSaveData::Open(cons } ResultCode ArchiveFactory_ExtSaveData::Format(const Path& path) { - std::string fullpath = GetExtSaveDataPath(mount_point, path); - FileUtil::CreateFullPath(fullpath); + // These folders are always created with the ExtSaveData + std::string user_path = GetExtSaveDataPath(mount_point, path) + "user/"; + std::string boss_path = GetExtSaveDataPath(mount_point, path) + "boss/"; + FileUtil::CreateFullPath(user_path); + FileUtil::CreateFullPath(boss_path); return RESULT_SUCCESS; } 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: private: /** * This holds the full directory path for this archive, it is only set after a successful call - * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. + * to Open, this is formed as <base extsavedatapath>/<type>/<high>/<low>. * See GetExtSaveDataPath for the code that extracts this data from an archive path. */ std::string mount_point; }; /** - * Constructs a path to the concrete ExtData archive in the host filesystem based on the + * Constructs a path to the concrete ExtData archive in the host filesystem based on the * input Path and base mount point. * @param mount_point The base mount point of the ExtSaveData archives. * @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 @@ namespace FileSys { static std::string GetSaveDataContainerPath(const std::string& sdmc_directory) { - return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), + return Common::StringFromFormat("%sNintendo 3DS/%s/%s/title/", sdmc_directory.c_str(), SYSTEM_ID.c_str(), SDCARD_ID.c_str()); } diff --git a/src/core/hle/function_wrappers.h b/src/core/hle/function_wrappers.h index 23c86a72d..5949cb470 100644 --- a/src/core/hle/function_wrappers.h +++ b/src/core/hle/function_wrappers.h @@ -9,11 +9,15 @@ #include "core/arm/arm_interface.h" #include "core/memory.h" #include "core/hle/hle.h" +#include "core/hle/result.h" namespace HLE { #define PARAM(n) Core::g_app_core->GetReg(n) +/// An invalid result code that is meant to be overwritten when a thread resumes from waiting +static const ResultCode RESULT_INVALID(0xDEADC0DE); + /** * HLE a function return from the current ARM11 userland process * @param res Result to return @@ -57,8 +61,11 @@ template<ResultCode func(s32*, u32*, s32, bool, s64)> void Wrap() { s32 param_1 = 0; s32 retval = func(¶m_1, (Handle*)Memory::GetPointer(PARAM(1)), (s32)PARAM(2), (PARAM(3) != 0), (((s64)PARAM(4) << 32) | PARAM(0))).raw; - Core::g_app_core->SetReg(1, (u32)param_1); - FuncReturn(retval); + + if (retval != RESULT_INVALID.raw) { + Core::g_app_core->SetReg(1, (u32)param_1); + FuncReturn(retval); + } } template<ResultCode func(u32, u32, u32, u32, s64)> void Wrap() { @@ -73,7 +80,11 @@ template<ResultCode func(u32*)> void Wrap(){ } template<ResultCode func(u32, s64)> void Wrap() { - FuncReturn(func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw); + s32 retval = func(PARAM(0), (((s64)PARAM(3) << 32) | PARAM(2))).raw; + + if (retval != RESULT_INVALID.raw) { + FuncReturn(retval); + } } template<ResultCode func(void*, void*, u32)> void Wrap(){ diff --git a/src/core/hle/kernel/event.cpp b/src/core/hle/kernel/event.cpp index e45deb1c6..f338f3266 100644 --- a/src/core/hle/kernel/event.cpp +++ b/src/core/hle/kernel/event.cpp @@ -41,10 +41,7 @@ void Event::Acquire() { void Event::Signal() { signaled = true; - WakeupAllWaitingThreads(); - - HLE::Reschedule(__func__); } void Event::Clear() { diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index 726e4d2ff..20e11da16 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -32,27 +32,13 @@ void WaitObject::RemoveWaitingThread(Thread* thread) { waiting_threads.erase(itr); } -SharedPtr<Thread> WaitObject::WakeupNextThread() { - if (waiting_threads.empty()) - return nullptr; - - auto next_thread = std::move(waiting_threads.front()); - waiting_threads.erase(waiting_threads.begin()); - - next_thread->ReleaseWaitObject(this); - - return next_thread; -} - void WaitObject::WakeupAllWaitingThreads() { - auto waiting_threads_copy = waiting_threads; + for (auto thread : waiting_threads) + thread->ResumeFromWait(); - // We use a copy because ReleaseWaitObject will remove the thread from this object's - // waiting_threads list - for (auto thread : waiting_threads_copy) - thread->ReleaseWaitObject(this); + waiting_threads.clear(); - ASSERT_MSG(waiting_threads.empty(), "failed to awaken all waiting threads!"); + HLE::Reschedule(__func__); } HandleTable::HandleTable() { diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index a5a0f4800..64595f758 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -140,12 +140,6 @@ public: */ void RemoveWaitingThread(Thread* thread); - /** - * Wake up the next thread waiting on this object - * @return Pointer to the thread that was resumed, nullptr if no threads are waiting - */ - SharedPtr<Thread> WakeupNextThread(); - /// Wake up all threads waiting on this object void WakeupAllWaitingThreads(); diff --git a/src/core/hle/kernel/mutex.cpp b/src/core/hle/kernel/mutex.cpp index 6aa73df86..edb97d324 100644 --- a/src/core/hle/kernel/mutex.cpp +++ b/src/core/hle/kernel/mutex.cpp @@ -23,12 +23,7 @@ static void ResumeWaitingThread(Mutex* mutex) { // Reset mutex lock thread handle, nothing is waiting mutex->lock_count = 0; mutex->holding_thread = nullptr; - - // Find the next waiting thread for the mutex... - auto next_thread = mutex->WakeupNextThread(); - if (next_thread != nullptr) { - mutex->Acquire(next_thread); - } + mutex->WakeupAllWaitingThreads(); } void ReleaseThreadMutexes(Thread* thread) { @@ -94,8 +89,6 @@ void Mutex::Release() { ResumeWaitingThread(this); } } - - HLE::Reschedule(__func__); } } // namespace 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: s32 max_timers = 0; s32 max_shared_mems = 0; s32 max_address_arbiters = 0; - + /// Max CPU time that the processes in this category can utilize s32 max_cpu_time = 0; - // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that - // APPLICATION resource limits should not be affected by the objects created by service modules. - // Currently we have no way of distinguishing if a Create was called by the running application, + // TODO(Subv): Increment these in their respective Kernel::T::Create functions, keeping in mind that + // APPLICATION resource limits should not be affected by the objects created by service modules. + // Currently we have no way of distinguishing if a Create was called by the running application, // or by a service module. Approach this once we have separated the service modules into their own processes /// 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..4b359ed07 100644 --- a/src/core/hle/kernel/semaphore.cpp +++ b/src/core/hle/kernel/semaphore.cpp @@ -42,19 +42,13 @@ void Semaphore::Acquire() { ResultVal<s32> Semaphore::Release(s32 release_count) { if (max_count - available_count < release_count) - return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, + return ResultCode(ErrorDescription::OutOfRange, ErrorModule::Kernel, ErrorSummary::InvalidArgument, ErrorLevel::Permanent); s32 previous_count = available_count; available_count += release_count; - // Notify some of the threads that the semaphore has been released - // stop once the semaphore is full again or there are no more waiting threads - while (!ShouldWait() && WakeupNextThread() != nullptr) { - Acquire(); - } - - HLE::Reschedule(__func__); + WakeupAllWaitingThreads(); return MakeResult<s32>(previous_count); } diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index 690d33b55..4729a7fe0 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp @@ -13,6 +13,7 @@ #include "common/thread_queue_list.h" #include "core/arm/arm_interface.h" +#include "core/arm/skyeye_common/armdefs.h" #include "core/core.h" #include "core/core_timing.h" #include "core/hle/hle.h" @@ -100,7 +101,7 @@ void Thread::Stop() { } status = THREADSTATUS_DEAD; - + WakeupAllWaitingThreads(); // Clean up any dangling references in objects that this thread was waiting for @@ -169,7 +170,7 @@ static void PriorityBoostStarvedThreads() { } } -/** +/** * Switches the CPU's active thread context to that of the specified thread * @param new_thread The thread to switch to */ @@ -193,8 +194,22 @@ static void SwitchContext(Thread* new_thread) { if (new_thread) { DEBUG_ASSERT_MSG(new_thread->status == THREADSTATUS_READY, "Thread must be ready to become running."); + // Cancel any outstanding wakeup events for this thread + CoreTiming::UnscheduleEvent(ThreadWakeupEventType, new_thread->callback_handle); + current_thread = new_thread; + // If the thread was waited by a svcWaitSynch call, step back PC by one instruction to rerun + // the SVC when the thread wakes up. This is necessary to ensure that the thread can acquire + // the requested wait object(s) before continuing. + if (new_thread->waitsynch_waited) { + // CPSR flag indicates CPU mode + bool thumb_mode = (new_thread->context.cpsr & TBIT) != 0; + + // SVC instruction is 2 bytes for THUMB, 4 bytes for ARM + new_thread->context.pc -= thumb_mode ? 2 : 4; + } + ready_queue.remove(new_thread->current_priority, new_thread); new_thread->status = THREADSTATUS_RUNNING; @@ -243,6 +258,7 @@ void WaitCurrentThread_WaitSynchronization(std::vector<SharedPtr<WaitObject>> wa thread->wait_set_output = wait_set_output; thread->wait_all = wait_all; thread->wait_objects = std::move(wait_objects); + thread->waitsynch_waited = true; thread->status = THREADSTATUS_WAIT_SYNCH; } @@ -268,6 +284,8 @@ static void ThreadWakeupCallback(u64 thread_handle, int cycles_late) { return; } + thread->waitsynch_waited = false; + if (thread->status == THREADSTATUS_WAIT_SYNCH) { thread->SetWaitSynchronizationResult(ResultCode(ErrorDescription::Timeout, ErrorModule::OS, ErrorSummary::StatusChanged, ErrorLevel::Info)); @@ -288,63 +306,20 @@ void Thread::WakeAfterDelay(s64 nanoseconds) { CoreTiming::ScheduleEvent(usToCycles(microseconds), ThreadWakeupEventType, callback_handle); } -void Thread::ReleaseWaitObject(WaitObject* wait_object) { - if (status != THREADSTATUS_WAIT_SYNCH || wait_objects.empty()) { - LOG_CRITICAL(Kernel, "thread is not waiting on any objects!"); - return; - } - - // Remove this thread from the waiting object's thread list - wait_object->RemoveWaitingThread(this); - - unsigned index = 0; - bool wait_all_failed = false; // Will be set to true if any object is unavailable - - // Iterate through all waiting objects to check availability... - for (auto itr = wait_objects.begin(); itr != wait_objects.end(); ++itr) { - if ((*itr)->ShouldWait()) - wait_all_failed = true; - - // The output should be the last index of wait_object - if (*itr == wait_object) - index = itr - wait_objects.begin(); - } - - // If we are waiting on all objects... - if (wait_all) { - // Resume the thread only if all are available... - if (!wait_all_failed) { - SetWaitSynchronizationResult(RESULT_SUCCESS); - SetWaitSynchronizationOutput(-1); - - ResumeFromWait(); - } - } else { - // Otherwise, resume - SetWaitSynchronizationResult(RESULT_SUCCESS); - - if (wait_set_output) - SetWaitSynchronizationOutput(index); - - ResumeFromWait(); - } -} - void Thread::ResumeFromWait() { - // Cancel any outstanding wakeup events for this thread - CoreTiming::UnscheduleEvent(ThreadWakeupEventType, callback_handle); - switch (status) { case THREADSTATUS_WAIT_SYNCH: - // Remove this thread from all other WaitObjects - for (auto wait_object : wait_objects) - wait_object->RemoveWaitingThread(this); - break; case THREADSTATUS_WAIT_ARB: case THREADSTATUS_WAIT_SLEEP: break; - case THREADSTATUS_RUNNING: + case THREADSTATUS_READY: + // If the thread is waiting on multiple wait objects, it might be awoken more than once + // before actually resuming. We can ignore subsequent wakeups if the thread status has + // already been set to THREADSTATUS_READY. + return; + + case THREADSTATUS_RUNNING: DEBUG_ASSERT_MSG(false, "Thread with object id %u has already resumed.", GetObjectId()); return; case THREADSTATUS_DEAD: @@ -353,7 +328,7 @@ void Thread::ResumeFromWait() { GetObjectId()); return; } - + ready_queue.push_back(current_priority, this); status = THREADSTATUS_READY; } @@ -415,6 +390,7 @@ ResultVal<SharedPtr<Thread>> Thread::Create(std::string name, VAddr entry_point, thread->callback_handle = wakeup_callback_handle_table.Create(thread).MoveFrom(); thread->owner_process = g_current_process; thread->tls_index = -1; + thread->waitsynch_waited = false; // Find the next available TLS index, and mark it as used auto& used_tls_slots = Kernel::g_current_process->used_tls_slots; @@ -504,7 +480,7 @@ void Reschedule() { } else if (next) { LOG_TRACE(Kernel, "context switch idle -> %u", next->GetObjectId()); } - + SwitchContext(next); } diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index 389928178..b8160bb2c 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h @@ -94,12 +94,6 @@ public: * @return The thread's ID */ u32 GetThreadId() const { return thread_id; } - - /** - * Release an acquired wait object - * @param wait_object WaitObject to release - */ - void ReleaseWaitObject(WaitObject* wait_object); /** * Resumes a thread from waiting @@ -152,6 +146,8 @@ public: s32 tls_index; ///< Index of the Thread Local Storage of the thread + bool waitsynch_waited; ///< Set to true if the last svcWaitSynch call caused the thread to wait + /// Mutexes currently held by this thread, which will be released when it exits. boost::container::flat_set<SharedPtr<Mutex>> held_mutexes; @@ -163,12 +159,12 @@ public: std::string name; + /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. + Handle callback_handle; + private: Thread(); ~Thread() override; - - /// Handle used as userdata to reference this object when inserting into the CoreTiming queue. - Handle callback_handle; }; /** 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) { if (timer->interval_delay != 0) { // Reschedule the timer with the interval delay u64 interval_microseconds = timer->interval_delay / 1000; - CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, + CoreTiming::ScheduleEvent(usToCycles(interval_microseconds) - cycles_late, timer_callback_event_type, timer_handle); } } 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 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/assert.h" + +#include "core/hle/kernel/vm_manager.h" +#include "core/memory_setup.h" + +namespace Kernel { + +bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { + ASSERT(base + size == next.base); + if (permissions != next.permissions || + meminfo_state != next.meminfo_state || + type != next.type) { + return false; + } + if (type == VMAType::AllocatedMemoryBlock && + (backing_block != next.backing_block || offset + size != next.offset)) { + return false; + } + if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { + return false; + } + if (type == VMAType::MMIO && paddr + size != next.paddr) { + return false; + } + return true; +} + +VMManager::VMManager() { + Reset(); +} + +void VMManager::Reset() { + vma_map.clear(); + + // Initialize the map with a single free region covering the entire managed space. + VirtualMemoryArea initial_vma; + initial_vma.size = MAX_ADDRESS; + vma_map.emplace(initial_vma.base, initial_vma); + + UpdatePageTableForVMA(initial_vma); +} + +VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { + return std::prev(vma_map.upper_bound(target)); +} + +ResultVal<VMManager::VMAHandle> VMManager::MapMemoryBlock(VAddr target, + std::shared_ptr<std::vector<u8>> block, u32 offset, u32 size, MemoryState state) { + ASSERT(block != nullptr); + ASSERT(offset + size <= block->size()); + + // This is the appropriately sized VMA that will turn into our allocation. + CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); + VirtualMemoryArea& final_vma = vma_handle->second; + ASSERT(final_vma.size == size); + + final_vma.type = VMAType::AllocatedMemoryBlock; + final_vma.permissions = VMAPermission::ReadWrite; + final_vma.meminfo_state = state; + final_vma.backing_block = block; + final_vma.offset = offset; + UpdatePageTableForVMA(final_vma); + + return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); +} + +ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8 * memory, u32 size, MemoryState state) { + ASSERT(memory != nullptr); + + // This is the appropriately sized VMA that will turn into our allocation. + CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); + VirtualMemoryArea& final_vma = vma_handle->second; + ASSERT(final_vma.size == size); + + final_vma.type = VMAType::BackingMemory; + final_vma.permissions = VMAPermission::ReadWrite; + final_vma.meminfo_state = state; + final_vma.backing_memory = memory; + UpdatePageTableForVMA(final_vma); + + return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); +} + +ResultVal<VMManager::VMAHandle> VMManager::MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state) { + // This is the appropriately sized VMA that will turn into our allocation. + CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); + VirtualMemoryArea& final_vma = vma_handle->second; + ASSERT(final_vma.size == size); + + final_vma.type = VMAType::MMIO; + final_vma.permissions = VMAPermission::ReadWrite; + final_vma.meminfo_state = state; + final_vma.paddr = paddr; + UpdatePageTableForVMA(final_vma); + + return MakeResult<VMAHandle>(MergeAdjacent(vma_handle)); +} + +void VMManager::Unmap(VMAHandle vma_handle) { + VMAIter iter = StripIterConstness(vma_handle); + + VirtualMemoryArea& vma = iter->second; + vma.type = VMAType::Free; + vma.permissions = VMAPermission::None; + vma.meminfo_state = MemoryState::Free; + + vma.backing_block = nullptr; + vma.offset = 0; + vma.backing_memory = nullptr; + vma.paddr = 0; + + UpdatePageTableForVMA(vma); + + MergeAdjacent(iter); +} + +void VMManager::Reprotect(VMAHandle vma_handle, VMAPermission new_perms) { + VMAIter iter = StripIterConstness(vma_handle); + + VirtualMemoryArea& vma = iter->second; + vma.permissions = new_perms; + UpdatePageTableForVMA(vma); + + MergeAdjacent(iter); +} + +VMManager::VMAIter VMManager::StripIterConstness(const VMAHandle & iter) { + // This uses a neat C++ trick to convert a const_iterator to a regular iterator, given + // non-const access to its container. + return vma_map.erase(iter, iter); // Erases an empty range of elements +} + +ResultVal<VMManager::VMAIter> VMManager::CarveVMA(VAddr base, u32 size) { + ASSERT_MSG((size & Memory::PAGE_MASK) == 0, "non-page aligned size: %8X", size); + ASSERT_MSG((base & Memory::PAGE_MASK) == 0, "non-page aligned base: %08X", base); + + VMAIter vma_handle = StripIterConstness(FindVMA(base)); + if (vma_handle == vma_map.end()) { + // Target address is outside the range managed by the kernel + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E01BF5 + } + + VirtualMemoryArea& vma = vma_handle->second; + if (vma.type != VMAType::Free) { + // Region is already allocated + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5 + } + + u32 start_in_vma = base - vma.base; + u32 end_in_vma = start_in_vma + size; + + if (end_in_vma > vma.size) { + // Requested allocation doesn't fit inside VMA + return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::OS, + ErrorSummary::InvalidState, ErrorLevel::Usage); // 0xE0A01BF5 + } + + if (end_in_vma != vma.size) { + // Split VMA at the end of the allocated region + SplitVMA(vma_handle, end_in_vma); + } + if (start_in_vma != 0) { + // Split VMA at the start of the allocated region + vma_handle = SplitVMA(vma_handle, start_in_vma); + } + + return MakeResult<VMAIter>(vma_handle); +} + +VMManager::VMAIter VMManager::SplitVMA(VMAIter vma_handle, u32 offset_in_vma) { + VirtualMemoryArea& old_vma = vma_handle->second; + VirtualMemoryArea new_vma = old_vma; // Make a copy of the VMA + + // For now, don't allow no-op VMA splits (trying to split at a boundary) because it's probably + // a bug. This restriction might be removed later. + ASSERT(offset_in_vma < old_vma.size); + ASSERT(offset_in_vma > 0); + + old_vma.size = offset_in_vma; + new_vma.base += offset_in_vma; + new_vma.size -= offset_in_vma; + + switch (new_vma.type) { + case VMAType::Free: + break; + case VMAType::AllocatedMemoryBlock: + new_vma.offset += offset_in_vma; + break; + case VMAType::BackingMemory: + new_vma.backing_memory += offset_in_vma; + break; + case VMAType::MMIO: + new_vma.paddr += offset_in_vma; + break; + } + + ASSERT(old_vma.CanBeMergedWith(new_vma)); + + return vma_map.emplace_hint(std::next(vma_handle), new_vma.base, new_vma); +} + +VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) { + VMAIter next_vma = std::next(iter); + if (next_vma != vma_map.end() && iter->second.CanBeMergedWith(next_vma->second)) { + iter->second.size += next_vma->second.size; + vma_map.erase(next_vma); + } + + if (iter != vma_map.begin()) { + VMAIter prev_vma = std::prev(iter); + if (prev_vma->second.CanBeMergedWith(iter->second)) { + prev_vma->second.size += iter->second.size; + vma_map.erase(iter); + iter = prev_vma; + } + } + + return iter; +} + +void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { + switch (vma.type) { + case VMAType::Free: + Memory::UnmapRegion(vma.base, vma.size); + break; + case VMAType::AllocatedMemoryBlock: + Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_block->data() + vma.offset); + break; + case VMAType::BackingMemory: + Memory::MapMemoryRegion(vma.base, vma.size, vma.backing_memory); + break; + case VMAType::MMIO: + // TODO(yuriks): Add support for MMIO handlers. + Memory::MapIoRegion(vma.base, vma.size); + break; + } +} + +} 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 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <map> +#include <memory> +#include <string> +#include <vector> + +#include "common/common_types.h" + +#include "core/hle/result.h" + +namespace Kernel { + +enum class VMAType : u8 { + /// VMA represents an unmapped region of the address space. + Free, + /// VMA is backed by a ref-counted allocate memory block. + AllocatedMemoryBlock, + /// VMA is backed by a raw, unmanaged pointer. + BackingMemory, + /// VMA is mapped to MMIO registers at a fixed PAddr. + MMIO, + // TODO(yuriks): Implement MemoryAlias to support MAP/UNMAP +}; + +/// Permissions for mapped memory blocks +enum class VMAPermission : u8 { + None = 0, + Read = 1, + Write = 2, + Execute = 4, + + ReadWrite = Read | Write, + ReadExecute = Read | Execute, + WriteExecute = Write | Execute, + ReadWriteExecute = Read | Write | Execute, +}; + +/// Set of values returned in MemoryInfo.state by svcQueryMemory. +enum class MemoryState : u8 { + Free = 0, + Reserved = 1, + IO = 2, + Static = 3, + Code = 4, + Private = 5, + Shared = 6, + Continuous = 7, + Aliased = 8, + Alias = 9, + AliasCode = 10, + Locked = 11, +}; + +/** + * Represents a VMA in an address space. A VMA is a contiguous region of virtual addressing space + * with homogeneous attributes across its extents. In this particular implementation each VMA is + * also backed by a single host memory allocation. + */ +struct VirtualMemoryArea { + /// Virtual base address of the region. + VAddr base = 0; + /// Size of the region. + u32 size = 0; + + VMAType type = VMAType::Free; + VMAPermission permissions = VMAPermission::None; + /// Tag returned by svcQueryMemory. Not otherwise used. + MemoryState meminfo_state = MemoryState::Free; + + // Settings for type = AllocatedMemoryBlock + /// Memory block backing this VMA. + std::shared_ptr<std::vector<u8>> backing_block = nullptr; + /// Offset into the backing_memory the mapping starts from. + u32 offset = 0; + + // Settings for type = BackingMemory + /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed. + u8* backing_memory = nullptr; + + // Settings for type = MMIO + /// Physical address of the register area this VMA maps to. + PAddr paddr = 0; + + /// Tests if this area can be merged to the right with `next`. + bool CanBeMergedWith(const VirtualMemoryArea& next) const; +}; + +/** + * Manages a process' virtual addressing space. This class maintains a list of allocated and free + * regions in the address space, along with their attributes, and allows kernel clients to + * manipulate it, adjusting the page table to match. + * + * This is similar in idea and purpose to the VM manager present in operating system kernels, with + * the main difference being that it doesn't have to support swapping or memory mapping of files. + * The implementation is also simplified by not having to allocate page frames. See these articles + * about the Linux kernel for an explantion of the concept and implementation: + * - http://duartes.org/gustavo/blog/post/how-the-kernel-manages-your-memory/ + * - http://duartes.org/gustavo/blog/post/page-cache-the-affair-between-memory-and-files/ + */ +class VMManager { + // TODO(yuriks): Make page tables switchable to support multiple VMManagers +public: + /** + * The maximum amount of address space managed by the kernel. Addresses above this are never used. + * @note This is the limit used by the New 3DS kernel. Old 3DS used 0x20000000. + */ + static const u32 MAX_ADDRESS = 0x40000000; + + /** + * A map covering the entirety of the managed address space, keyed by the `base` field of each + * VMA. It must always be modified by splitting or merging VMAs, so that the invariant + * `elem.base + elem.size == next.base` is preserved, and mergeable regions must always be + * merged when possible so that no two similar and adjacent regions exist that have not been + * merged. + */ + std::map<VAddr, VirtualMemoryArea> vma_map; + using VMAHandle = decltype(vma_map)::const_iterator; + + VMManager(); + + /// Clears the address space map, re-initializing with a single free area. + void Reset(); + + /// Finds the VMA in which the given address is included in, or `vma_map.end()`. + VMAHandle FindVMA(VAddr target) const; + + // TODO(yuriks): Should these functions actually return the handle? + + /** + * Maps part of a ref-counted block of memory at a given address. + * + * @param target The guest address to start the mapping at. + * @param block The block to be mapped. + * @param offset Offset into `block` to map from. + * @param size Size of the mapping. + * @param state MemoryState tag to attach to the VMA. + */ + ResultVal<VMAHandle> MapMemoryBlock(VAddr target, std::shared_ptr<std::vector<u8>> block, + u32 offset, u32 size, MemoryState state); + + /** + * Maps an unmanaged host memory pointer at a given address. + * + * @param target The guest address to start the mapping at. + * @param memory The memory to be mapped. + * @param size Size of the mapping. + * @param state MemoryState tag to attach to the VMA. + */ + ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state); + + /** + * Maps a memory-mapped IO region at a given address. + * + * @param target The guest address to start the mapping at. + * @param paddr The physical address where the registers are present. + * @param size Size of the mapping. + * @param state MemoryState tag to attach to the VMA. + */ + ResultVal<VMAHandle> MapMMIO(VAddr target, PAddr paddr, u32 size, MemoryState state); + + /// Unmaps the given VMA. + void Unmap(VMAHandle vma); + + /// Changes the permissions of the given VMA. + void Reprotect(VMAHandle vma, VMAPermission new_perms); + +private: + using VMAIter = decltype(vma_map)::iterator; + + /// Converts a VMAHandle to a mutable VMAIter. + VMAIter StripIterConstness(const VMAHandle& iter); + + /** + * Carves a VMA of a specific size at the specified address by splitting Free VMAs while doing + * the appropriate error checking. + */ + ResultVal<VMAIter> CarveVMA(VAddr base, u32 size); + + /** + * Splits a VMA in two, at the specified offset. + * @returns the right side of the split, with the original iterator becoming the left side. + */ + VMAIter SplitVMA(VMAIter vma, u32 offset_in_vma); + + /** + * Checks for and merges the specified VMA with adjacent ones if possible. + * @returns the merged VMA or the original if no merging was possible. + */ + VMAIter MergeAdjacent(VMAIter vma); + + /// Updates the pages corresponding to this VMA so they match the VMA's attributes. + void UpdatePageTableForVMA(const VirtualMemoryArea& vma); +}; + +} diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp new file mode 100644 index 000000000..57dc1ece7 --- /dev/null +++ b/src/core/hle/service/am/am.cpp @@ -0,0 +1,55 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/am/am_app.h" +#include "core/hle/service/am/am_net.h" +#include "core/hle/service/am/am_sys.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" + +namespace Service { +namespace AM { + +void TitleIDListGetTotal(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 media_type = cmd_buff[1] & 0xFF; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + + LOG_WARNING(Service_AM, "(STUBBED) media_type %u", media_type); +} + +void GetTitleIDList(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + u32 num_titles = cmd_buff[1]; + u32 media_type = cmd_buff[2] & 0xFF; + u32 addr = cmd_buff[4]; + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; + + LOG_WARNING(Service_AM, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); +} + +void Init() { + using namespace Kernel; + + AddService(new AM_APP_Interface); + AddService(new AM_NET_Interface); + AddService(new AM_SYS_Interface); +} + +void Shutdown() { + +} + +} // namespace AM + +} // namespace Service diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h new file mode 100644 index 000000000..063b8bd09 --- /dev/null +++ b/src/core/hle/service/am/am.h @@ -0,0 +1,47 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +/** + * AM::TitleIDListGetTotal service function + * Gets the number of installed titles in the requested media type + * Inputs: + * 0 : Command header (0x00010040) + * 1 : Media type to load the titles from + * Outputs: + * 1 : Result, 0 on success, otherwise error code + * 2 : The number of titles in the requested media type + */ +void TitleIDListGetTotal(Service::Interface* self); + +/** + * AM::GetTitleIDList service function + * Loads information about the desired number of titles from the desired media type into an array + * Inputs: + * 0 : Command header (0x00020082) + * 1 : The maximum number of titles to load + * 2 : Media type to load the titles from + * 3 : Descriptor of the output buffer pointer + * 4 : Address of the output buffer + * Outputs: + * 1 : Result, 0 on success, otherwise error code + * 2 : The number of titles loaded from the requested media type + */ +void GetTitleIDList(Service::Interface* self); + +/// Initialize AM service +void Init(); + +/// Shutdown AM service +void Shutdown(); + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_app.cpp b/src/core/hle/service/am/am_app.cpp new file mode 100644 index 000000000..c6fc81bc3 --- /dev/null +++ b/src/core/hle/service/am/am_app.cpp @@ -0,0 +1,20 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_app.h" + +namespace Service { +namespace AM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +AM_APP_Interface::AM_APP_Interface() { + //Register(FunctionTable); +} + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_app.h b/src/core/hle/service/am/am_app.h new file mode 100644 index 000000000..fd6017d14 --- /dev/null +++ b/src/core/hle/service/am/am_app.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_APP_Interface : public Service::Interface { +public: + AM_APP_Interface(); + + std::string GetPortName() const override { + return "am:app"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am_net.cpp b/src/core/hle/service/am/am_net.cpp index ba2a499f1..b1af0e9d8 100644 --- a/src/core/hle/service/am_net.cpp +++ b/src/core/hle/service/am/am_net.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/am_net.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_net.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_NET - -namespace AM_NET { +namespace Service { +namespace AM { const Interface::FunctionInfo FunctionTable[] = { {0x08010000, nullptr, "OpenTicket"}, @@ -33,11 +32,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x081B00C2, nullptr, "InstallTitlesFinish"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +AM_NET_Interface::AM_NET_Interface() { Register(FunctionTable); } -} // namespace +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_net.h b/src/core/hle/service/am/am_net.h new file mode 100644 index 000000000..25d2c3f23 --- /dev/null +++ b/src/core/hle/service/am/am_net.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_NET_Interface : public Service::Interface { +public: + AM_NET_Interface(); + + std::string GetPortName() const override { + return "am:net"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_sys.cpp b/src/core/hle/service/am/am_sys.cpp new file mode 100644 index 000000000..864fc14df --- /dev/null +++ b/src/core/hle/service/am/am_sys.cpp @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_sys.h" + +namespace Service { +namespace AM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, + {0x00020082, GetTitleIDList, "GetTitleIDList"}, +}; + +AM_SYS_Interface::AM_SYS_Interface() { + Register(FunctionTable); +} + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_sys.h b/src/core/hle/service/am/am_sys.h new file mode 100644 index 000000000..b114f1d35 --- /dev/null +++ b/src/core/hle/service/am/am_sys.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_SYS_Interface : public Service::Interface { +public: + AM_SYS_Interface(); + + std::string GetPortName() const override { + return "am:sys"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_u.cpp b/src/core/hle/service/am/am_u.cpp new file mode 100644 index 000000000..6bf84b36b --- /dev/null +++ b/src/core/hle/service/am/am_u.cpp @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/am_u.h" + +namespace Service { +namespace AM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, + {0x00020082, GetTitleIDList, "GetTitleIDList"}, +}; + +AM_U_Interface::AM_U_Interface() { + Register(FunctionTable); +} + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am/am_u.h b/src/core/hle/service/am/am_u.h new file mode 100644 index 000000000..3b2454b6c --- /dev/null +++ b/src/core/hle/service/am/am_u.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace AM { + +class AM_U_Interface : public Service::Interface { +public: + AM_U_Interface(); + + std::string GetPortName() const override { + return "am:u"; + } +}; + +} // namespace AM +} // namespace Service diff --git a/src/core/hle/service/am_app.cpp b/src/core/hle/service/am_app.cpp deleted file mode 100644 index 684b753f0..000000000 --- a/src/core/hle/service/am_app.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/am_app.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_APP - -namespace AM_APP { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/am_app.h b/src/core/hle/service/am_app.h deleted file mode 100644 index 50dc2f5a2..000000000 --- a/src/core/hle/service/am_app.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_APP - -namespace AM_APP { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "am:app"; - } -}; - -} // namespace diff --git a/src/core/hle/service/am_net.h b/src/core/hle/service/am_net.h deleted file mode 100644 index 616c33ee8..000000000 --- a/src/core/hle/service/am_net.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_NET - -namespace AM_NET { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "am:net"; - } -}; - -} // namespace diff --git a/src/core/hle/service/am_sys.cpp b/src/core/hle/service/am_sys.cpp deleted file mode 100644 index f9e3fe4b7..000000000 --- a/src/core/hle/service/am_sys.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" - -#include "core/hle/hle.h" -#include "core/hle/service/am_sys.h" - -namespace AM_SYS { - -/** - * Gets the number of installed titles in the requested media type - * Inputs: - * 0: Command header (0x00010040) - * 1: Media type to load the titles from - * Outputs: - * 1: Result, 0 on success, otherwise error code - * 2: The number of titles in the requested media type - */ -static void TitleIDListGetTotal(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 media_type = cmd_buff[1] & 0xFF; - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; - LOG_WARNING(Service_CFG, "(STUBBED) media_type %u", media_type); -} - -/** - * Loads information about the desired number of titles from the desired media type into an array - * Inputs: - * 0: Command header (0x00020082) - * 1: The maximum number of titles to load - * 2: Media type to load the titles from - * 3: Descriptor of the output buffer pointer - * 4: Address of the output buffer - * Outputs: - * 1: Result, 0 on success, otherwise error code - * 2: The number of titles loaded from the requested media type - */ -static void GetTitleIDList(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - u32 num_titles = cmd_buff[1]; - u32 media_type = cmd_buff[2] & 0xFF; - u32 addr = cmd_buff[4]; - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; - LOG_WARNING(Service_CFG, "(STUBBED) Requested %u titles from media type %u", num_titles, media_type); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010040, TitleIDListGetTotal, "TitleIDListGetTotal"}, - {0x00020082, GetTitleIDList, "GetTitleIDList"}, -}; - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/am_sys.h b/src/core/hle/service/am_sys.h deleted file mode 100644 index bb6178a43..000000000 --- a/src/core/hle/service/am_sys.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace AM_SYS - -namespace AM_SYS { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "am:sys"; - } -}; - -} // namespace 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) { u32 handle = cmd_buff[6]; u32 size = cmd_buff[7]; u32 in_param_buffer_ptr = cmd_buff[8]; - + cmd_buff[1] = RESULT_SUCCESS.raw; // No error 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() { AddService(new APT_A_Interface); AddService(new APT_S_Interface); AddService(new APT_U_Interface); - + // Load the shared system font (if available). // The expected format is a decrypted, uncompressed BCFNT file with the 0x80 byte header // 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); * 4 : Handle to shared font memory */ void GetSharedFont(Service::Interface* self); - + /** * APT::NotifyToWait service function * Inputs: @@ -88,7 +88,7 @@ void Enable(Service::Interface* self); * 4 : Home Menu AppId * 5 : AppID of currently active app */ -void GetAppletManInfo(Service::Interface* self); +void GetAppletManInfo(Service::Interface* self); /** * APT::IsRegistered service function. This returns whether the specified AppID is registered with NS yet. @@ -100,14 +100,14 @@ void GetAppletManInfo(Service::Interface* self); * Outputs: * 0 : Return header * 1 : Result of function, 0 on success, otherwise error code - * 2 : Output, 0 = not registered, 1 = registered. + * 2 : Output, 0 = not registered, 1 = registered. */ void IsRegistered(Service::Interface* self); void InquireNotification(Service::Interface* self); /** - * APT::SendParameter service function. This sets the parameter data state. + * APT::SendParameter service function. This sets the parameter data state. * Inputs: * 1 : Source AppID * 2 : Destination AppID diff --git a/src/core/hle/service/boss/boss.cpp b/src/core/hle/service/boss/boss.cpp new file mode 100644 index 000000000..d38140f19 --- /dev/null +++ b/src/core/hle/service/boss/boss.cpp @@ -0,0 +1,29 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/boss/boss_p.h" +#include "core/hle/service/boss/boss_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace BOSS { + +void Init() { + using namespace Kernel; + + AddService(new BOSS_P_Interface); + AddService(new BOSS_U_Interface); +} + +void Shutdown() { +} + +} // namespace BOSS + +} // namespace Service diff --git a/src/core/hle/service/boss/boss.h b/src/core/hle/service/boss/boss.h new file mode 100644 index 000000000..a6942ada6 --- /dev/null +++ b/src/core/hle/service/boss/boss.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace BOSS { + +/// Initialize BOSS service(s) +void Init(); + +/// Shutdown BOSS service(s) +void Shutdown(); + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_p.cpp b/src/core/hle/service/boss/boss_p.cpp new file mode 100644 index 000000000..089f5f186 --- /dev/null +++ b/src/core/hle/service/boss/boss_p.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/boss/boss_p.h" + +namespace Service { +namespace BOSS { + +// Empty arrays are illegal -- commented out until an entry is added. +// const Interface::FunctionInfo FunctionTable[] = { }; + +BOSS_P_Interface::BOSS_P_Interface() { + //Register(FunctionTable); +} + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_p.h b/src/core/hle/service/boss/boss_p.h new file mode 100644 index 000000000..32112c251 --- /dev/null +++ b/src/core/hle/service/boss/boss_p.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace BOSS { + +class BOSS_P_Interface : public Service::Interface { +public: + BOSS_P_Interface(); + + std::string GetPortName() const override { + return "boss:P"; + } +}; + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_u.cpp b/src/core/hle/service/boss/boss_u.cpp new file mode 100644 index 000000000..ed978b963 --- /dev/null +++ b/src/core/hle/service/boss/boss_u.cpp @@ -0,0 +1,21 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/boss/boss_u.h" + +namespace Service { +namespace BOSS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00020100, nullptr, "GetStorageInfo"}, +}; + +BOSS_U_Interface::BOSS_U_Interface() { + Register(FunctionTable); +} + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss/boss_u.h b/src/core/hle/service/boss/boss_u.h new file mode 100644 index 000000000..d047d8cf2 --- /dev/null +++ b/src/core/hle/service/boss/boss_u.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace BOSS { + +class BOSS_U_Interface : public Service::Interface { +public: + BOSS_U_Interface(); + + std::string GetPortName() const override { + return "boss:U"; + } +}; + +} // namespace BOSS +} // namespace Service diff --git a/src/core/hle/service/boss_p.cpp b/src/core/hle/service/boss_p.cpp deleted file mode 100644 index 8280830e5..000000000 --- a/src/core/hle/service/boss_p.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/boss_p.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_P - -namespace BOSS_P { - -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/boss_p.h b/src/core/hle/service/boss_p.h deleted file mode 100644 index 71f1e7464..000000000 --- a/src/core/hle/service/boss_p.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_P - -namespace BOSS_P { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "boss:P"; - } -}; - -} // namespace diff --git a/src/core/hle/service/boss_u.cpp b/src/core/hle/service/boss_u.cpp deleted file mode 100644 index 2c322bdfd..000000000 --- a/src/core/hle/service/boss_u.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/boss_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_U - -namespace BOSS_U { - -const Interface::FunctionInfo FunctionTable[] = { - {0x00020100, nullptr, "GetStorageInfo"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/boss_u.h b/src/core/hle/service/boss_u.h deleted file mode 100644 index 2668f2dfd..000000000 --- a/src/core/hle/service/boss_u.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace BOSS_U - -namespace BOSS_U { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "boss:U"; - } -}; - -} // namespace diff --git a/src/core/hle/service/cam/cam.cpp b/src/core/hle/service/cam/cam.cpp new file mode 100644 index 000000000..4f34b699b --- /dev/null +++ b/src/core/hle/service/cam/cam.cpp @@ -0,0 +1,35 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_c.h" +#include "core/hle/service/cam/cam_q.h" +#include "core/hle/service/cam/cam_s.h" +#include "core/hle/service/cam/cam_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace CAM { + +void Init() { + using namespace Kernel; + + AddService(new CAM_C_Interface); + AddService(new CAM_Q_Interface); + AddService(new CAM_S_Interface); + AddService(new CAM_U_Interface); +} + +void Shutdown() { +} + +} // namespace CAM + +} // namespace Service diff --git a/src/core/hle/service/cam/cam.h b/src/core/hle/service/cam/cam.h new file mode 100644 index 000000000..edd524841 --- /dev/null +++ b/src/core/hle/service/cam/cam.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +/// Initialize CAM service(s) +void Init(); + +/// Shutdown CAM service(s) +void Shutdown(); + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_c.cpp b/src/core/hle/service/cam/cam_c.cpp new file mode 100644 index 000000000..d35adcb9f --- /dev/null +++ b/src/core/hle/service/cam/cam_c.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_c.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_C_Interface::CAM_C_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_c.h b/src/core/hle/service/cam/cam_c.h new file mode 100644 index 000000000..6b296c00d --- /dev/null +++ b/src/core/hle/service/cam/cam_c.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_C_Interface : public Service::Interface { +public: + CAM_C_Interface(); + + std::string GetPortName() const override { + return "cam:c"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_q.cpp b/src/core/hle/service/cam/cam_q.cpp new file mode 100644 index 000000000..c2760a102 --- /dev/null +++ b/src/core/hle/service/cam/cam_q.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_q.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_Q_Interface::CAM_Q_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_q.h b/src/core/hle/service/cam/cam_q.h new file mode 100644 index 000000000..07cc12534 --- /dev/null +++ b/src/core/hle/service/cam/cam_q.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_Q_Interface : public Service::Interface { +public: + CAM_Q_Interface(); + + std::string GetPortName() const override { + return "cam:q"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_s.cpp b/src/core/hle/service/cam/cam_s.cpp new file mode 100644 index 000000000..aefbf7df4 --- /dev/null +++ b/src/core/hle/service/cam/cam_s.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_s.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_S_Interface::CAM_S_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_s.h b/src/core/hle/service/cam/cam_s.h new file mode 100644 index 000000000..0a5d6fca2 --- /dev/null +++ b/src/core/hle/service/cam/cam_s.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_S_Interface : public Service::Interface { +public: + CAM_S_Interface(); + + std::string GetPortName() const override { + return "cam:s"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_u.cpp b/src/core/hle/service/cam/cam_u.cpp new file mode 100644 index 000000000..1c6aca955 --- /dev/null +++ b/src/core/hle/service/cam/cam_u.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cam/cam_u.h" + +namespace Service { +namespace CAM { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CAM_U_Interface::CAM_U_Interface() { + //Register(FunctionTable); +} + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam/cam_u.h b/src/core/hle/service/cam/cam_u.h new file mode 100644 index 000000000..369264037 --- /dev/null +++ b/src/core/hle/service/cam/cam_u.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace CAM { + +class CAM_U_Interface : public Service::Interface { +public: + CAM_U_Interface(); + + std::string GetPortName() const override { + return "cam:u"; + } +}; + +} // namespace CAM +} // namespace Service diff --git a/src/core/hle/service/cam_u.cpp b/src/core/hle/service/cam_u.cpp deleted file mode 100644 index fcfd87715..000000000 --- a/src/core/hle/service/cam_u.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/cam_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CAM_U - -namespace CAM_U { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cam_u.h b/src/core/hle/service/cam_u.h deleted file mode 100644 index 878c20a84..000000000 --- a/src/core/hle/service/cam_u.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CAM_U - -namespace CAM_U { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "cam:u"; - } -}; - -} // namespace diff --git a/src/core/hle/service/cecd/cecd.cpp b/src/core/hle/service/cecd/cecd.cpp new file mode 100644 index 000000000..db0e52b79 --- /dev/null +++ b/src/core/hle/service/cecd/cecd.cpp @@ -0,0 +1,31 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_s.h" +#include "core/hle/service/cecd/cecd_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace CECD { + +void Init() { + using namespace Kernel; + + AddService(new CECD_S_Interface); + AddService(new CECD_U_Interface); +} + +void Shutdown() { +} + +} // namespace CECD + +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd.h b/src/core/hle/service/cecd/cecd.h new file mode 100644 index 000000000..32fd2045d --- /dev/null +++ b/src/core/hle/service/cecd/cecd.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace CECD { + +/// Initialize CECD service(s) +void Init(); + +/// Shutdown CECD service(s) +void Shutdown(); + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_s.cpp b/src/core/hle/service/cecd/cecd_s.cpp new file mode 100644 index 000000000..72d7e8d44 --- /dev/null +++ b/src/core/hle/service/cecd/cecd_s.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_s.h" + +namespace Service { +namespace CECD { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CECD_S_Interface::CECD_S_Interface() { + //Register(FunctionTable); +} + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd_s.h b/src/core/hle/service/cecd/cecd_s.h index d880d0391..df5c01849 100644 --- a/src/core/hle/service/cecd_s.h +++ b/src/core/hle/service/cecd/cecd_s.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_S +namespace Service { +namespace CECD { -namespace CECD_S { - -class Interface : public Service::Interface { +class CECD_S_Interface : public Interface { public: - Interface(); + CECD_S_Interface(); std::string GetPortName() const override { return "cecd:s"; } }; -} // namespace +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd/cecd_u.cpp b/src/core/hle/service/cecd/cecd_u.cpp new file mode 100644 index 000000000..0a23bafbc --- /dev/null +++ b/src/core/hle/service/cecd/cecd_u.cpp @@ -0,0 +1,20 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/cecd/cecd_u.h" + +namespace Service { +namespace CECD { + +// Empty arrays are illegal -- commented out until an entry is added. +//const Interface::FunctionInfo FunctionTable[] = { }; + +CECD_U_Interface::CECD_U_Interface() { + //Register(FunctionTable); +} + +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd_u.h b/src/core/hle/service/cecd/cecd_u.h index e67564135..394030ffc 100644 --- a/src/core/hle/service/cecd_u.h +++ b/src/core/hle/service/cecd/cecd_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_U +namespace Service { +namespace CECD { -namespace CECD_U { - -class Interface : public Service::Interface { +class CECD_U_Interface : public Interface { public: - Interface(); + CECD_U_Interface(); std::string GetPortName() const override { return "cecd:u"; } }; -} // namespace +} // namespace CECD +} // namespace Service diff --git a/src/core/hle/service/cecd_s.cpp b/src/core/hle/service/cecd_s.cpp deleted file mode 100644 index b298f151d..000000000 --- a/src/core/hle/service/cecd_s.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/cecd_s.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_S - -namespace CECD_S { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/cecd_u.cpp b/src/core/hle/service/cecd_u.cpp deleted file mode 100644 index 9125364bc..000000000 --- a/src/core/hle/service/cecd_u.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/cecd_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace CECD_U - -namespace CECD_U { - -// Empty arrays are illegal -- commented out until an entry is added. -//const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // 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() { AddService(new CFG_I_Interface); AddService(new CFG_S_Interface); AddService(new CFG_U_Interface); - + // Open the SystemSaveData archive 0x00010017 FileSys::Path archive_path(cfg_system_savedata_id); auto archive_result = Service::FS::OpenArchive(Service::FS::ArchiveIdCode::SystemSaveData, archive_path); - + // If the archive didn't exist, create the files inside if (archive_result.Code().description == ErrorDescription::FS_NotFormatted) { // Format the archive to create the directories diff --git a/src/core/hle/service/frd/frd.cpp b/src/core/hle/service/frd/frd.cpp new file mode 100644 index 000000000..2911ab402 --- /dev/null +++ b/src/core/hle/service/frd/frd.cpp @@ -0,0 +1,29 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/service/service.h" +#include "core/hle/service/frd/frd.h" +#include "core/hle/service/frd/frd_a.h" +#include "core/hle/service/frd/frd_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace FRD { + +void Init() { + using namespace Kernel; + + AddService(new FRD_A_Interface); + AddService(new FRD_U_Interface); +} + +void Shutdown() { +} + +} // namespace FRD + +} // namespace Service diff --git a/src/core/hle/service/frd/frd.h b/src/core/hle/service/frd/frd.h new file mode 100644 index 000000000..41f7a2f6b --- /dev/null +++ b/src/core/hle/service/frd/frd.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace FRD { + +/// Initialize FRD service(s) +void Init(); + +/// Shutdown FRD service(s) +void Shutdown(); + +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd/frd_a.cpp b/src/core/hle/service/frd/frd_a.cpp new file mode 100644 index 000000000..1c438a337 --- /dev/null +++ b/src/core/hle/service/frd/frd_a.cpp @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/frd/frd.h" +#include "core/hle/service/frd/frd_a.h" + +namespace Service { +namespace FRD { + +// Empty arrays are illegal -- commented out until an entry is added. +// const Interface::FunctionInfo FunctionTable[] = { }; + +FRD_A_Interface::FRD_A_Interface() { + //Register(FunctionTable); +} + +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_a.h b/src/core/hle/service/frd/frd_a.h index f068c6108..006d1cadd 100644 --- a/src/core/hle/service/frd_a.h +++ b/src/core/hle/service/frd/frd_a.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_A +namespace Service { +namespace FRD { -namespace FRD_A { - -class Interface : public Service::Interface { +class FRD_A_Interface : public Service::Interface { public: - Interface(); + FRD_A_Interface(); std::string GetPortName() const override { return "frd:a"; } }; -} // namespace +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_u.cpp b/src/core/hle/service/frd/frd_u.cpp index 6d2ff1e21..439c7282e 100644 --- a/src/core/hle/service/frd_u.cpp +++ b/src/core/hle/service/frd/frd_u.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/frd_u.h" +#include "core/hle/service/frd/frd.h" +#include "core/hle/service/frd/frd_u.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_U - -namespace FRD_U { +namespace Service { +namespace FRD { const Interface::FunctionInfo FunctionTable[] = { {0x00050000, nullptr, "GetFriendKey"}, @@ -22,11 +21,9 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00320042, nullptr, "SetClientSdkVersion"} }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { +FRD_U_Interface::FRD_U_Interface() { Register(FunctionTable); } -} // namespace +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_u.h b/src/core/hle/service/frd/frd_u.h index ab8897d5b..07e43f155 100644 --- a/src/core/hle/service/frd_u.h +++ b/src/core/hle/service/frd/frd_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_U +namespace Service { +namespace FRD { -namespace FRD_U { - -class Interface : public Service::Interface { +class FRD_U_Interface : public Service::Interface { public: - Interface(); + FRD_U_Interface(); std::string GetPortName() const override { return "frd:u"; } }; -} // namespace +} // namespace FRD +} // namespace Service diff --git a/src/core/hle/service/frd_a.cpp b/src/core/hle/service/frd_a.cpp deleted file mode 100644 index 569979319..000000000 --- a/src/core/hle/service/frd_a.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/frd_a.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace FRD_A - -namespace FRD_A { - -// Empty arrays are illegal -- commented out until an entry is added. -// const Interface::FunctionInfo FunctionTable[] = { }; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - //Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/fs/archive.cpp b/src/core/hle/service/fs/archive.cpp index 6d4a9c7c9..4e275cb13 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 CASCADE_RESULT(std::unique_ptr<ArchiveBackend> res, itr->second->Open(archive_path)); - // This should never even happen in the first place with 64-bit handles, + // This should never even happen in the first place with 64-bit handles, while (handle_map.count(next_handle) != 0) { ++next_handle; } @@ -406,7 +406,7 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path) { return archive_itr->second->Format(path); } -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size) { // Construct the binary path to the archive first FileSys::Path path = FileSys::ConstructExtDataBinaryPath(static_cast<u32>(media_type), high, low); @@ -421,9 +421,25 @@ ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low) { } std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); - std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); - if (!FileUtil::CreateFullPath(extsavedata_path)) + std::string game_path = FileSys::GetExtSaveDataPath(base_path, path); + // These two folders are always created with the ExtSaveData + std::string user_path = game_path + "user/"; + std::string boss_path = game_path + "boss/"; + if (!FileUtil::CreateFullPath(user_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + if (!FileUtil::CreateFullPath(boss_path)) + return ResultCode(-1); // TODO(Subv): Find the right error code + + u8* smdh_icon = Memory::GetPointer(icon_buffer); + if (!smdh_icon) return ResultCode(-1); // TODO(Subv): Find the right error code + + // Create the icon + FileUtil::IOFile icon_file(game_path + "icon", "wb+"); + if (!icon_file.IsGood()) + return ResultCode(-1); // TODO(Subv): Find the right error code + + icon_file.WriteBytes(smdh_icon, icon_size); return RESULT_SUCCESS; } @@ -441,6 +457,7 @@ ResultCode DeleteExtSaveData(MediaType media_type, u32 high, u32 low) { return ResultCode(-1); // TODO(Subv): Find the right error code } + // Delete all directories (/user, /boss) and the icon file. std::string base_path = FileSys::GetExtDataContainerPath(media_type_directory, media_type == MediaType::NAND); std::string extsavedata_path = FileSys::GetExtSaveDataPath(base_path, path); if (!FileUtil::DeleteDirRecursively(extsavedata_path)) @@ -488,7 +505,7 @@ void ArchiveInit() { RegisterArchiveType(std::move(sdmc_factory), ArchiveIdCode::SDMC); else LOG_ERROR(Service_FS, "Can't instantiate SDMC archive with path %s", sdmc_directory.c_str()); - + // Create the SaveData archive auto savedata_factory = Common::make_unique<FileSys::ArchiveFactory_SaveData>(sdmc_directory); RegisterArchiveType(std::move(savedata_factory), ArchiveIdCode::SaveData); @@ -503,7 +520,7 @@ void ArchiveInit() { if (sharedextsavedata_factory->Initialize()) RegisterArchiveType(std::move(sharedextsavedata_factory), ArchiveIdCode::SharedExtSaveData); else - LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", + LOG_ERROR(Service_FS, "Can't instantiate SharedExtSaveData archive with path %s", sharedextsavedata_factory->GetMountPoint().c_str()); // Create the SaveDataCheck archive, basically a small variation of the RomFS archive diff --git a/src/core/hle/service/fs/archive.h b/src/core/hle/service/fs/archive.h index faab0cb79..357b6b096 100644 --- a/src/core/hle/service/fs/archive.h +++ b/src/core/hle/service/fs/archive.h @@ -177,9 +177,11 @@ ResultCode FormatArchive(ArchiveIdCode id_code, const FileSys::Path& path = File * @param media_type The media type of the archive to create (NAND / SDMC) * @param high The high word of the extdata id to create * @param low The low word of the extdata id to create + * @param icon_buffer VAddr of the SMDH icon for this ExtSaveData + * @param icon_size Size of the SMDH icon * @return ResultCode 0 on success or the corresponding code on error */ -ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low); +ResultCode CreateExtSaveData(MediaType media_type, u32 high, u32 low, VAddr icon_buffer, u32 icon_size); /** * Deletes the SharedExtSaveData archive for the specified extdata ID diff --git a/src/core/hle/service/fs/fs_user.cpp b/src/core/hle/service/fs/fs_user.cpp index b25c8941d..0ad44e55e 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) { } /** - * FS_User::FormatSaveData service function, + * FS_User::FormatSaveData service function, * formats the SaveData specified by the input path. * Inputs: * 0 : 0x084C0242 @@ -504,9 +504,9 @@ static void FormatThisUserSaveData(Service::Interface* self) { * 6 : Unknown * 7 : Unknown * 8 : Unknown - * 9 : Unknown - * 10: Unknown - * 11: Unknown + * 9 : Size of the SMDH icon + * 10: (SMDH Size << 4) | 0x0000000A + * 11: Pointer to the SMDH icon for the new ExtSaveData * Outputs: * 1 : Result of function, 0 on success, otherwise error code */ @@ -516,14 +516,16 @@ static void CreateExtSaveData(Service::Interface* self) { MediaType media_type = static_cast<MediaType>(cmd_buff[1] & 0xFF); u32 save_low = cmd_buff[2]; u32 save_high = cmd_buff[3]; + u32 icon_size = cmd_buff[9]; + VAddr icon_buffer = cmd_buff[11]; LOG_WARNING(Service_FS, "(STUBBED) savedata_high=%08X savedata_low=%08X cmd_buff[3]=%08X " "cmd_buff[4]=%08X cmd_buff[5]=%08X cmd_buff[6]=%08X cmd_buff[7]=%08X cmd_buff[8]=%08X " - "cmd_buff[9]=%08X cmd_buff[10]=%08X cmd_buff[11]=%08X", save_high, save_low, - cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], cmd_buff[9], - cmd_buff[10], cmd_buff[11]); + "icon_size=%08X icon_descriptor=%08X icon_buffer=%08X", save_high, save_low, + cmd_buff[3], cmd_buff[4], cmd_buff[5], cmd_buff[6], cmd_buff[7], cmd_buff[8], icon_size, + cmd_buff[10], icon_buffer); - cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low).raw; + cmd_buff[1] = CreateExtSaveData(media_type, save_high, save_low, icon_buffer, icon_size).raw; } /** @@ -544,7 +546,7 @@ static void DeleteExtSaveData(Service::Interface* self) { u32 save_high = cmd_buff[3]; u32 unknown = cmd_buff[4]; // TODO(Subv): Figure out what this is - LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", + LOG_WARNING(Service_FS, "(STUBBED) save_low=%08X save_high=%08X media_type=%08X unknown=%08X", save_low, save_high, cmd_buff[1] & 0xFF, unknown); 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 c56475ae4..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) { u32* cmd_buff = Kernel::GetCommandBuffer(); u32 reg_addr = cmd_buff[1]; u32 size = cmd_buff[2]; - + u32* src_data = (u32*)Memory::GetPointer(cmd_buff[4]); u32* mask_data = (u32*)Memory::GetPointer(cmd_buff[6]); @@ -208,21 +208,21 @@ static void SetBufferSwap(u32 screen_id, const FrameBufferInfo& info) { PAddr phys_address_left = Memory::VirtualToPhysicalAddress(info.address_left); PAddr phys_address_right = Memory::VirtualToPhysicalAddress(info.address_right); if (info.active_fb == 0) { - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left1)), 4, &phys_address_left); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right1)), 4, &phys_address_right); } else { - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_left2)), 4, &phys_address_left); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].address_right2)), 4, &phys_address_right); } - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].stride)), 4, &info.stride); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].color_format)), 4, &info.format); - WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, + WriteHWRegs(base_address + 4 * static_cast<u32>(GPU_REG_INDEX(framebuffer_config[screen_id].active_fb)), 4, &info.shown_fb); } @@ -374,7 +374,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) { { auto& params = command.set_command_list_last; - WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), + WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.address)), Memory::VirtualToPhysicalAddress(params.address) >> 3); WriteGPURegister(static_cast<u32>(GPU_REG_INDEX(command_processor_config.size)), params.size); @@ -470,7 +470,7 @@ static void SetLcdForceBlack(Service::Interface* self) { LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_top), data.raw); // Top LCD LCD::Write(HW::VADDR_LCD + 4 * LCD_REG_INDEX(color_fill_bottom), data.raw); // Bottom LCD - + cmd_buff[1] = RESULT_SUCCESS.raw; } @@ -496,6 +496,52 @@ static void TriggerCmdReqQueue(Service::Interface* self) { cmd_buff[1] = 0; // No error } +/** + * GSP_GPU::ImportDisplayCaptureInfo service function + * + * Returns information about the current framebuffer state + * + * Inputs: + * 0: Header 0x00180000 + * Outputs: + * 1: Result code + * 2: Left framebuffer virtual address for the main screen + * 3: Right framebuffer virtual address for the main screen + * 4: Main screen framebuffer format + * 5: Main screen framebuffer width + * 6: Left framebuffer virtual address for the bottom screen + * 7: Right framebuffer virtual address for the bottom screen + * 8: Bottom screen framebuffer format + * 9: Bottom screen framebuffer width + */ +static void ImportDisplayCaptureInfo(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + // TODO(Subv): We're always returning the framebuffer structures for thread_id = 0, + // because we only support a single running application at a time. + // This should always return the framebuffer data that is currently displayed on the screen. + + u32 thread_id = 0; + + FrameBufferUpdate* top_screen = GetFrameBufferInfo(thread_id, 0); + FrameBufferUpdate* bottom_screen = GetFrameBufferInfo(thread_id, 1); + + cmd_buff[2] = top_screen->framebuffer_info[top_screen->index].address_left; + cmd_buff[3] = top_screen->framebuffer_info[top_screen->index].address_right; + cmd_buff[4] = top_screen->framebuffer_info[top_screen->index].format; + cmd_buff[5] = top_screen->framebuffer_info[top_screen->index].stride; + + cmd_buff[6] = bottom_screen->framebuffer_info[bottom_screen->index].address_left; + cmd_buff[7] = bottom_screen->framebuffer_info[bottom_screen->index].address_right; + cmd_buff[8] = bottom_screen->framebuffer_info[bottom_screen->index].format; + cmd_buff[9] = bottom_screen->framebuffer_info[bottom_screen->index].stride; + + cmd_buff[1] = RESULT_SUCCESS.raw; + + LOG_WARNING(Service_GSP, "called"); +} + + const Interface::FunctionInfo FunctionTable[] = { {0x00010082, WriteHWRegs, "WriteHWRegs"}, {0x00020084, WriteHWRegsWithMask, "WriteHWRegsWithMask"}, @@ -520,7 +566,7 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00150002, nullptr, "TryAcquireRight"}, {0x00160042, nullptr, "AcquireRight"}, {0x00170000, nullptr, "ReleaseRight"}, - {0x00180000, nullptr, "ImportDisplayCaptureInfo"}, + {0x00180000, ImportDisplayCaptureInfo, "ImportDisplayCaptureInfo"}, {0x00190000, nullptr, "SaveVramSysArea"}, {0x001A0000, nullptr, "RestoreVramSysArea"}, {0x001B0000, nullptr, "ResetGpuCore"}, diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 2d2133b2e..c7c1bb5ab 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -58,7 +58,7 @@ void Update() { mem->pad.current_state.hex = state.hex; mem->pad.index = next_pad_index; - ++next_touch_index %= mem->pad.entries.size(); + next_touch_index = (next_touch_index + 1) % mem->pad.entries.size(); // Get the previous Pad state u32 last_entry_index = (mem->pad.index - 1) % mem->pad.entries.size(); @@ -88,7 +88,7 @@ void Update() { } mem->touch.index = next_touch_index; - ++next_touch_index %= mem->touch.entries.size(); + next_touch_index = (next_touch_index + 1) % mem->touch.entries.size(); // Get the current touch entry TouchDataEntry* touch_entry = &mem->touch.entries[mem->touch.index]; @@ -106,7 +106,7 @@ void Update() { mem->touch.index_reset_ticks_previous = mem->touch.index_reset_ticks; mem->touch.index_reset_ticks = (s64)CoreTiming::GetTicks(); } - + // Signal both handles when there's an update to Pad or touch event_pad_or_touch_1->Signal(); 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[] = { HID_SPVR_Interface::HID_SPVR_Interface() { Register(FunctionTable); } - + } // namespace HID } // 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 @@ namespace Service { namespace HID { - + /** * HID service interface. */ diff --git a/src/core/hle/service/news/news.cpp b/src/core/hle/service/news/news.cpp new file mode 100644 index 000000000..63cbd3850 --- /dev/null +++ b/src/core/hle/service/news/news.cpp @@ -0,0 +1,31 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/news/news_s.h" +#include "core/hle/service/news/news_u.h" + +#include "core/hle/hle.h" +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" + +namespace Service { +namespace NEWS { + +void Init() { + using namespace Kernel; + + AddService(new NEWS_S_Interface); + AddService(new NEWS_U_Interface); +} + +void Shutdown() { +} + +} // namespace NEWS + +} // namespace Service diff --git a/src/core/hle/service/news/news.h b/src/core/hle/service/news/news.h new file mode 100644 index 000000000..b31ade255 --- /dev/null +++ b/src/core/hle/service/news/news.h @@ -0,0 +1,20 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace NEWS { + +/// Initialize NEWS service(s) +void Init(); + +/// Shutdown NEWS service(s) +void Shutdown(); + +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news/news_s.cpp b/src/core/hle/service/news/news_s.cpp new file mode 100644 index 000000000..2f8c37d9e --- /dev/null +++ b/src/core/hle/service/news/news_s.cpp @@ -0,0 +1,21 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/news/news_s.h" + +namespace Service { +namespace NEWS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C6, nullptr, "AddNotification"}, +}; + +NEWS_S_Interface::NEWS_S_Interface() { + Register(FunctionTable); +} + +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news_s.h b/src/core/hle/service/news/news_s.h index f8b4636d5..f58b969a8 100644 --- a/src/core/hle/service/news_s.h +++ b/src/core/hle/service/news/news_s.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_S +namespace Service { +namespace NEWS { -namespace NEWS_S { - -class Interface : public Service::Interface { +class NEWS_S_Interface : public Service::Interface { public: - Interface(); + NEWS_S_Interface(); std::string GetPortName() const override { return "news:s"; } }; -} // namespace +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news/news_u.cpp b/src/core/hle/service/news/news_u.cpp new file mode 100644 index 000000000..81f45a244 --- /dev/null +++ b/src/core/hle/service/news/news_u.cpp @@ -0,0 +1,21 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/news/news_u.h" + +namespace Service { +namespace NEWS { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000100C6, nullptr, "AddNotification"}, +}; + +NEWS_U_Interface::NEWS_U_Interface() { + Register(FunctionTable); +} + +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news_u.h b/src/core/hle/service/news/news_u.h index 0473cd19c..2720053d0 100644 --- a/src/core/hle/service/news_u.h +++ b/src/core/hle/service/news/news_u.h @@ -6,18 +6,17 @@ #include "core/hle/service/service.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_U +namespace Service { +namespace NEWS { -namespace NEWS_U { - -class Interface : public Service::Interface { +class NEWS_U_Interface : public Service::Interface { public: - Interface(); + NEWS_U_Interface(); std::string GetPortName() const override { return "news:u"; } }; -} // namespace +} // namespace NEWS +} // namespace Service diff --git a/src/core/hle/service/news_s.cpp b/src/core/hle/service/news_s.cpp deleted file mode 100644 index 302d588c7..000000000 --- a/src/core/hle/service/news_s.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/news_s.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_S - -namespace NEWS_S { - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C6, nullptr, "AddNotification"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/news_u.cpp b/src/core/hle/service/news_u.cpp deleted file mode 100644 index 7d835aa30..000000000 --- a/src/core/hle/service/news_u.cpp +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "core/hle/hle.h" -#include "core/hle/service/news_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NEWS_U - -namespace NEWS_U { - -const Interface::FunctionInfo FunctionTable[] = { - {0x000100C8, nullptr, "AddNotification"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp new file mode 100644 index 000000000..73b0ee52a --- /dev/null +++ b/src/core/hle/service/nim/nim.cpp @@ -0,0 +1,42 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" + +#include "core/hle/service/service.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_aoc.h" +#include "core/hle/service/nim/nim_s.h" +#include "core/hle/service/nim/nim_u.h" + +#include "core/hle/kernel/event.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/hle.h" + +namespace Service { +namespace NIM { + +void CheckSysUpdateAvailable(Service::Interface* self) { + u32* cmd_buff = Kernel::GetCommandBuffer(); + + cmd_buff[1] = RESULT_SUCCESS.raw; + cmd_buff[2] = 0; // No update available + + LOG_WARNING(Service_NWM, "(STUBBED) called"); +} + +void Init() { + using namespace Kernel; + + AddService(new NIM_AOC_Interface); + AddService(new NIM_S_Interface); + AddService(new NIM_U_Interface); +} + +void Shutdown() { +} + +} // namespace NIM + +} // namespace Service diff --git a/src/core/hle/service/nim/nim.h b/src/core/hle/service/nim/nim.h new file mode 100644 index 000000000..f7635c747 --- /dev/null +++ b/src/core/hle/service/nim/nim.h @@ -0,0 +1,30 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include "core/hle/kernel/kernel.h" +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +/** + * NIM::CheckSysUpdateAvailable service function + * Inputs: + * 1 : None + * Outputs: + * 1 : Result of function, 0 on success, otherwise error code + * 2 : flag, 0 = no system update available, 1 = system update available. + */ +void CheckSysUpdateAvailable(Service::Interface* self); + +/// Initialize NIM service(s) +void Init(); + +/// Shutdown NIM service(s) +void Shutdown(); + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim_aoc.cpp b/src/core/hle/service/nim/nim_aoc.cpp index 7a6aea91a..e6b1b6145 100644 --- a/src/core/hle/service/nim_aoc.cpp +++ b/src/core/hle/service/nim/nim_aoc.cpp @@ -3,12 +3,11 @@ // Refer to the license.txt file included. #include "core/hle/hle.h" -#include "core/hle/service/nim_aoc.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_aoc.h" -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_AOC - -namespace NIM_AOC { +namespace Service { +namespace NIM { const Interface::FunctionInfo FunctionTable[] = { {0x00030042, nullptr, "SetApplicationId"}, @@ -20,11 +19,10 @@ const Interface::FunctionInfo FunctionTable[] = { {0x00240282, nullptr, "CalculateContentsRequiredSize"}, {0x00250000, nullptr, "RefreshServerTime"}, }; -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class -Interface::Interface() { +NIM_AOC_Interface::NIM_AOC_Interface() { Register(FunctionTable); } -} // namespace +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim/nim_aoc.h b/src/core/hle/service/nim/nim_aoc.h new file mode 100644 index 000000000..aace45b5a --- /dev/null +++ b/src/core/hle/service/nim/nim_aoc.h @@ -0,0 +1,22 @@ +// Copyright 2014 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +class NIM_AOC_Interface : public Service::Interface { +public: + NIM_AOC_Interface(); + + std::string GetPortName() const override { + return "nim:aoc"; + } +}; + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim/nim_s.cpp b/src/core/hle/service/nim/nim_s.cpp new file mode 100644 index 000000000..5d8bc059f --- /dev/null +++ b/src/core/hle/service/nim/nim_s.cpp @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_s.h" + +namespace Service { +namespace NIM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x000A0000, nullptr, "CheckSysupdateAvailableSOAP"}, +}; + +NIM_S_Interface::NIM_S_Interface() { + Register(FunctionTable); +} + +} // namespace NIM +} // namespace Service + diff --git a/src/core/hle/service/nim/nim_s.h b/src/core/hle/service/nim/nim_s.h new file mode 100644 index 000000000..f4bf73d26 --- /dev/null +++ b/src/core/hle/service/nim/nim_s.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +class NIM_S_Interface : public Service::Interface { +public: + NIM_S_Interface(); + + std::string GetPortName() const override { + return "nim:s"; + } +}; + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim/nim_u.cpp b/src/core/hle/service/nim/nim_u.cpp new file mode 100644 index 000000000..066570a85 --- /dev/null +++ b/src/core/hle/service/nim/nim_u.cpp @@ -0,0 +1,27 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "core/hle/hle.h" +#include "core/hle/service/nim/nim.h" +#include "core/hle/service/nim/nim_u.h" + +namespace Service { +namespace NIM { + +const Interface::FunctionInfo FunctionTable[] = { + {0x00010000, nullptr, "StartSysUpdate"}, + {0x00020000, nullptr, "GetUpdateDownloadProgress"}, + {0x00040000, nullptr, "FinishTitlesInstall"}, + {0x00050000, nullptr, "CheckForSysUpdateEvent"}, + {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, + {0x000A0000, nullptr, "GetState"}, +}; + +NIM_U_Interface::NIM_U_Interface() { + Register(FunctionTable); +} + +} // namespace NIM +} // namespace Service + diff --git a/src/core/hle/service/nim/nim_u.h b/src/core/hle/service/nim/nim_u.h new file mode 100644 index 000000000..bc89dc0f3 --- /dev/null +++ b/src/core/hle/service/nim/nim_u.h @@ -0,0 +1,22 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included.. + +#pragma once + +#include "core/hle/service/service.h" + +namespace Service { +namespace NIM { + +class NIM_U_Interface : public Service::Interface { +public: + NIM_U_Interface(); + + std::string GetPortName() const override { + return "nim:u"; + } +}; + +} // namespace NIM +} // namespace Service diff --git a/src/core/hle/service/nim_aoc.h b/src/core/hle/service/nim_aoc.h deleted file mode 100644 index aeb71eed2..000000000 --- a/src/core/hle/service/nim_aoc.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_AOC - -namespace NIM_AOC { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "nim:aoc"; - } -}; - -} // namespace diff --git a/src/core/hle/service/nim_u.cpp b/src/core/hle/service/nim_u.cpp deleted file mode 100644 index 5f13bd98e..000000000 --- a/src/core/hle/service/nim_u.cpp +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include "common/logging/log.h" - -#include "core/hle/hle.h" -#include "core/hle/service/nim_u.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_U - -namespace NIM_U { - -/** - * NIM_U::CheckSysUpdateAvailable service function - * Inputs: - * 1 : None - * Outputs: - * 1 : Result of function, 0 on success, otherwise error code - * 2 : flag, 0 = no system update available, 1 = system update available. - */ -static void CheckSysUpdateAvailable(Service::Interface* self) { - u32* cmd_buff = Kernel::GetCommandBuffer(); - - cmd_buff[1] = RESULT_SUCCESS.raw; - cmd_buff[2] = 0; // No update available - - LOG_WARNING(Service_NWM, "(STUBBED) called"); -} - -const Interface::FunctionInfo FunctionTable[] = { - {0x00010000, nullptr, "StartSysUpdate"}, - {0x00020000, nullptr, "GetUpdateDownloadProgress"}, - {0x00040000, nullptr, "FinishTitlesInstall"}, - {0x00050000, nullptr, "CheckForSysUpdateEvent"}, - {0x00090000, CheckSysUpdateAvailable, "CheckSysUpdateAvailable"}, - {0x000A0000, nullptr, "GetState"}, -}; - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Interface class - -Interface::Interface() { - Register(FunctionTable); -} - -} // namespace diff --git a/src/core/hle/service/nim_u.h b/src/core/hle/service/nim_u.h deleted file mode 100644 index 57a1f6acf..000000000 --- a/src/core/hle/service/nim_u.h +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2015 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/hle/service/service.h" - -//////////////////////////////////////////////////////////////////////////////////////////////////// -// Namespace NIM_U - -namespace NIM_U { - -class Interface : public Service::Interface { -public: - Interface(); - - std::string GetPortName() const override { - return "nim:u"; - } -}; - -} // namespace 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 { CompletelyFull = 5, }; -/** +/** * Represents the gamecoin file structure in the SharedExtData archive * More information in 3dbrew (http://www.3dbrew.org/wiki/Extdata#Shared_Extdata_0xf000000b_gamecoin.dat) */ struct GameCoin { u32 magic; ///< Magic number: 0x4F00 - u16 total_coins; ///< Total Play Coins + u16 total_coins; ///< Total Play Coins u16 total_coins_on_date; ///< Total Play Coins obtained on the date stored below. - u32 step_count; ///< Total step count at the time a new Play Coin was obtained. + u32 step_count; ///< Total step count at the time a new Play Coin was obtained. u32 last_step_count; ///< Step count for the day the last Play Coin was obtained u16 year; 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[] = { PTM_Play_Interface::PTM_Play_Interface() { Register(FunctionTable); } - + } // namespace PTM } // 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..d681cc3dc 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -8,29 +8,15 @@ #include "core/hle/service/service.h" #include "core/hle/service/ac_u.h" #include "core/hle/service/act_u.h" -#include "core/hle/service/am_app.h" -#include "core/hle/service/am_net.h" -#include "core/hle/service/am_sys.h" -#include "core/hle/service/boss_p.h" -#include "core/hle/service/boss_u.h" -#include "core/hle/service/cam_u.h" -#include "core/hle/service/cecd_u.h" -#include "core/hle/service/cecd_s.h" #include "core/hle/service/csnd_snd.h" #include "core/hle/service/dsp_dsp.h" #include "core/hle/service/err_f.h" -#include "core/hle/service/frd_a.h" -#include "core/hle/service/frd_u.h" #include "core/hle/service/gsp_gpu.h" #include "core/hle/service/gsp_lcd.h" #include "core/hle/service/http_c.h" #include "core/hle/service/ldr_ro.h" #include "core/hle/service/mic_u.h" #include "core/hle/service/ndm_u.h" -#include "core/hle/service/news_s.h" -#include "core/hle/service/news_u.h" -#include "core/hle/service/nim_aoc.h" -#include "core/hle/service/nim_u.h" #include "core/hle/service/ns_s.h" #include "core/hle/service/nwm_uds.h" #include "core/hle/service/pm_app.h" @@ -39,11 +25,18 @@ #include "core/hle/service/ssl_c.h" #include "core/hle/service/y2r_u.h" +#include "core/hle/service/am/am.h" #include "core/hle/service/apt/apt.h" +#include "core/hle/service/boss/boss.h" +#include "core/hle/service/cam/cam.h" +#include "core/hle/service/cecd/cecd.h" +#include "core/hle/service/frd/frd.h" #include "core/hle/service/fs/archive.h" #include "core/hle/service/cfg/cfg.h" #include "core/hle/service/hid/hid.h" #include "core/hle/service/ir/ir.h" +#include "core/hle/service/news/news.h" +#include "core/hle/service/nim/nim.h" #include "core/hle/service/ptm/ptm.h" namespace Service { @@ -52,7 +45,7 @@ std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_kernel_named_por std::unordered_map<std::string, Kernel::SharedPtr<Interface>> g_srv_services; /** - * Creates a function string for logging, complete with the name (or header code, depending + * Creates a function string for logging, complete with the name (or header code, depending * on what's passed in) the port name, and all the cmd_buff arguments. */ static std::string MakeFunctionString(const char* name, const char* port_name, const u32* cmd_buff) { @@ -111,36 +104,29 @@ void Init() { AddNamedPort(new ERR_F::Interface); Service::FS::ArchiveInit(); - Service::CFG::Init(); + Service::AM::Init(); Service::APT::Init(); - Service::PTM::Init(); + Service::BOSS::Init(); + Service::CAM::Init(); + Service::CECD::Init(); + Service::CFG::Init(); + Service::FRD::Init(); Service::HID::Init(); Service::IR::Init(); + Service::NEWS::Init(); + Service::NIM::Init(); + Service::PTM::Init(); AddService(new AC_U::Interface); AddService(new ACT_U::Interface); - AddService(new AM_APP::Interface); - AddService(new AM_NET::Interface); - AddService(new AM_SYS::Interface); - AddService(new BOSS_P::Interface); - AddService(new BOSS_U::Interface); - AddService(new CAM_U::Interface); - AddService(new CECD_S::Interface); - AddService(new CECD_U::Interface); AddService(new CSND_SND::Interface); AddService(new DSP_DSP::Interface); - AddService(new FRD_A::Interface); - AddService(new FRD_U::Interface); AddService(new GSP_GPU::Interface); AddService(new GSP_LCD::Interface); AddService(new HTTP_C::Interface); AddService(new LDR_RO::Interface); AddService(new MIC_U::Interface); AddService(new NDM_U::Interface); - AddService(new NEWS_S::Interface); - AddService(new NEWS_U::Interface); - AddService(new NIM_AOC::Interface); - AddService(new NIM_U::Interface); AddService(new NS_S::Interface); AddService(new NWM_UDS::Interface); AddService(new PM_APP::Interface); @@ -153,11 +139,19 @@ void Init() { /// Shutdown ServiceManager void Shutdown() { + + Service::PTM::Shutdown(); + Service::NIM::Shutdown(); + Service::NEWS::Shutdown(); Service::IR::Shutdown(); Service::HID::Shutdown(); - Service::PTM::Shutdown(); - Service::APT::Shutdown(); + Service::FRD::Shutdown(); Service::CFG::Shutdown(); + Service::CECD::Shutdown(); + Service::CAM::Shutdown(); + Service::BOSS::Shutdown(); + Service::APT::Shutdown(); + Service::AM::Shutdown(); Service::FS::ArchiveShutdown(); g_srv_services.clear(); 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) { auto found = error_map.find(error); if (found != error_map.end()) return -found->second; - + return error; } @@ -346,7 +346,7 @@ static void Bind(Service::Interface* self) { sockaddr sock_addr = CTRSockAddr::ToPlatform(*ctr_sock_addr); int res = ::bind(socket_handle, &sock_addr, std::max<u32>(sizeof(sock_addr), len)); - + int result = 0; if (res != 0) result = TranslateError(GET_ERRNO); @@ -360,14 +360,14 @@ static void Fcntl(Service::Interface* self) { u32 socket_handle = cmd_buffer[1]; u32 ctr_cmd = cmd_buffer[2]; u32 ctr_arg = cmd_buffer[3]; - + int result = 0; u32 posix_ret = 0; // TODO: Check what hardware returns for F_SETFL (unspecified by POSIX) SCOPE_EXIT({ cmd_buffer[1] = result; cmd_buffer[2] = posix_ret; }); - + if (ctr_cmd == 3) { // F_GETFL #if EMU_PLATFORM == PLATFORM_WINDOWS posix_ret = 0; @@ -404,11 +404,11 @@ static void Fcntl(Service::Interface* self) { posix_ret = -1; return; } - + flags &= ~O_NONBLOCK; if (ctr_arg & 4) // O_NONBLOCK flags |= O_NONBLOCK; - + int ret = ::fcntl(socket_handle, F_SETFL, flags); if (ret == SOCKET_ERROR_VALUE) { result = TranslateError(GET_ERRNO); @@ -439,8 +439,8 @@ static void Listen(Service::Interface* self) { } static void Accept(Service::Interface* self) { - // TODO(Subv): Calling this function on a blocking socket will block the emu thread, - // preventing graceful shutdown when closing the emulator, this can be fixed by always + // TODO(Subv): Calling this function on a blocking socket will block the emu thread, + // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; @@ -448,7 +448,7 @@ static void Accept(Service::Interface* self) { sockaddr addr; socklen_t addr_len = sizeof(addr); u32 ret = static_cast<u32>(::accept(socket_handle, &addr, &addr_len)); - + if ((s32)ret != SOCKET_ERROR_VALUE) open_sockets[ret] = { ret, true }; @@ -525,8 +525,8 @@ static void SendTo(Service::Interface* self) { } static void RecvFrom(Service::Interface* self) { - // TODO(Subv): Calling this function on a blocking socket will block the emu thread, - // preventing graceful shutdown when closing the emulator, this can be fixed by always + // TODO(Subv): Calling this function on a blocking socket will block the emu thread, + // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; @@ -568,7 +568,7 @@ static void Poll(Service::Interface* self) { pollfd* platform_pollfd = new pollfd[nfds]; for (unsigned current_fds = 0; current_fds < nfds; ++current_fds) platform_pollfd[current_fds] = CTRPollFD::ToPlatform(input_fds[current_fds]); - + int ret = ::poll(platform_pollfd, nfds, timeout); // Now update the output pollfd structure @@ -630,7 +630,7 @@ static void GetPeerName(Service::Interface* self) { socklen_t len = cmd_buffer[2]; CTRSockAddr* ctr_dest_addr = reinterpret_cast<CTRSockAddr*>(Memory::GetPointer(cmd_buffer[0x104 >> 2])); - + sockaddr dest_addr; socklen_t dest_addr_len = sizeof(dest_addr); int ret = ::getpeername(socket_handle, &dest_addr, &dest_addr_len); @@ -651,8 +651,8 @@ static void GetPeerName(Service::Interface* self) { } static void Connect(Service::Interface* self) { - // TODO(Subv): Calling this function on a blocking socket will block the emu thread, - // preventing graceful shutdown when closing the emulator, this can be fixed by always + // TODO(Subv): Calling this function on a blocking socket will block the emu thread, + // preventing graceful shutdown when closing the emulator, this can be fixed by always // performing nonblocking operations and spinlock until the data is available u32* cmd_buffer = Kernel::GetCommandBuffer(); u32 socket_handle = cmd_buffer[1]; diff --git a/src/core/hle/svc.cpp b/src/core/hle/svc.cpp index 347d241f9..6cde4fc87 100644 --- a/src/core/hle/svc.cpp +++ b/src/core/hle/svc.cpp @@ -40,9 +40,6 @@ const ResultCode ERR_NOT_FOUND(ErrorDescription::NotFound, ErrorModule::Kernel, const ResultCode ERR_PORT_NAME_TOO_LONG(ErrorDescription(30), ErrorModule::OS, ErrorSummary::InvalidArgument, ErrorLevel::Usage); // 0xE0E0181E -/// An invalid result code that is meant to be overwritten when a thread resumes from waiting -const ResultCode RESULT_INVALID(0xDEADC0DE); - enum ControlMemoryOperation { MEMORY_OPERATION_HEAP = 0x00000003, MEMORY_OPERATION_GSP_HEAP = 0x00010003, @@ -143,6 +140,10 @@ static ResultCode CloseHandle(Handle handle) { /// Wait for a handle to synchronize, timeout after the specified nanoseconds static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { auto object = Kernel::g_handle_table.GetWaitObject(handle); + Kernel::Thread* thread = Kernel::GetCurrentThread(); + + thread->waitsynch_waited = false; + if (object == nullptr) return ERR_INVALID_HANDLE; @@ -154,14 +155,14 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { // Check for next thread to schedule if (object->ShouldWait()) { - object->AddWaitingThread(Kernel::GetCurrentThread()); + object->AddWaitingThread(thread); Kernel::WaitCurrentThread_WaitSynchronization({ object }, false, false); // Create an event to wake the thread up after the specified nanosecond delay has passed - Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); + thread->WakeAfterDelay(nano_seconds); // NOTE: output of this SVC will be set later depending on how the thread resumes - return RESULT_INVALID; + return HLE::RESULT_INVALID; } object->Acquire(); @@ -173,6 +174,9 @@ static ResultCode WaitSynchronization1(Handle handle, s64 nano_seconds) { static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_count, bool wait_all, s64 nano_seconds) { bool wait_thread = !wait_all; int handle_index = 0; + Kernel::Thread* thread = Kernel::GetCurrentThread(); + bool was_waiting = thread->waitsynch_waited; + thread->waitsynch_waited = false; // Check if 'handles' is invalid if (handles == nullptr) @@ -190,6 +194,9 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // necessary if (handle_count != 0) { bool selected = false; // True once an object has been selected + + Kernel::SharedPtr<Kernel::WaitObject> wait_object; + for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); if (object == nullptr) @@ -204,10 +211,11 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou wait_thread = true; } else { // Do not wait on this object, check if this object should be selected... - if (!wait_all && !selected) { + if (!wait_all && (!selected || (wait_object == object && was_waiting))) { // Do not wait the thread wait_thread = false; handle_index = i; + wait_object = object; selected = true; } } @@ -228,7 +236,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // Actually wait the current thread on each object if we decided to wait... std::vector<SharedPtr<Kernel::WaitObject>> wait_objects; wait_objects.reserve(handle_count); - + for (int i = 0; i < handle_count; ++i) { auto object = Kernel::g_handle_table.GetWaitObject(handles[i]); object->AddWaitingThread(Kernel::GetCurrentThread()); @@ -241,7 +249,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou Kernel::GetCurrentThread()->WakeAfterDelay(nano_seconds); // NOTE: output of this SVC will be set later depending on how the thread resumes - return RESULT_INVALID; + return HLE::RESULT_INVALID; } // Acquire objects if we did not wait... @@ -261,7 +269,7 @@ static ResultCode WaitSynchronizationN(s32* out, Handle* handles, s32 handle_cou // TODO(bunnei): If 'wait_all' is true, this is probably wrong. However, real hardware does // not seem to set it to any meaningful value. - *out = wait_all ? 0 : handle_index; + *out = handle_count != 0 ? (wait_all ? -1 : handle_index) : 0; return RESULT_SUCCESS; } @@ -475,7 +483,7 @@ static ResultCode GetProcessIdOfThread(u32* process_id, Handle thread_handle) { return ERR_INVALID_HANDLE; const SharedPtr<Kernel::Process> process = thread->owner_process; - + ASSERT_MSG(process != nullptr, "Invalid parent process for thread=0x%08X", thread_handle); *process_id = process->process_id; @@ -654,6 +662,8 @@ static ResultCode CreateMemoryBlock(Handle* out_handle, u32 addr, u32 size, u32 using Kernel::MemoryPermission; SharedPtr<SharedMemory> shared_memory = SharedMemory::Create(size, (MemoryPermission)my_permission, (MemoryPermission)other_permission); + // Map the SharedMemory to the specified address + shared_memory->base_address = addr; CASCADE_RESULT(*out_handle, Kernel::g_handle_table.Create(std::move(shared_memory))); LOG_WARNING(Kernel_SVC, "(STUBBED) called addr=0x%08X", addr); diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp index ddc5d647e..7471def57 100644 --- a/src/core/hw/gpu.cpp +++ b/src/core/hw/gpu.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/color.h" #include "common/common_types.h" #include "core/arm/arm_interface.h" @@ -22,7 +23,6 @@ #include "video_core/command_processor.h" #include "video_core/utils.h" #include "video_core/video_core.h" -#include "video_core/color.h" namespace GPU { @@ -30,8 +30,8 @@ Regs g_regs; /// True if the current frame was skipped bool g_skip_frame; -/// 268MHz / gpu_refresh_rate frames per second -static u64 frame_ticks; +/// 268MHz CPU clocks / 60Hz frames per second +const u64 frame_ticks = 268123480ull / 60; /// Event id for CoreTiming static int vblank_event; /// Total number of frames drawn @@ -140,7 +140,7 @@ inline void Write(u32 addr, const T data) { // Raw copies do not perform color conversion nor tiled->linear / linear->tiled conversions // TODO(Subv): Verify if raw copies perform scaling memcpy(dst_pointer, src_pointer, output_size); - + 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", output_size, config.GetPhysicalInputAddress(), config.input_width.Value(), config.input_height.Value(), @@ -159,14 +159,14 @@ inline void Write(u32 addr, const T data) { for (u32 x = 0; x < output_width; ++x) { Math::Vec4<u8> src_color = { 0, 0, 0, 0 }; - // Calculate the [x,y] position of the input image + // Calculate the [x,y] position of the input image // based on the current output position and the scale u32 input_x = x * horizontal_scale; u32 input_y = y * vertical_scale; if (config.flip_vertically) { - // Flip the y value of the output data, - // we do this after calculating the [x,y] position of the input image + // Flip the y value of the output data, + // we do this after calculating the [x,y] position of the input image // to account for the scaling options. y = output_height - y - 1; } @@ -302,7 +302,7 @@ static void VBlankCallback(u64 userdata, int cycles_late) { // - If frameskip == 0 (disabled), always swap buffers // - If frameskip == 1, swap buffers every other frame (starting from the first frame) // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame) - if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || + if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || Settings::values.frame_skip == 0) { VideoCore::g_renderer->SwapBuffers(); } @@ -357,7 +357,6 @@ void Init() { framebuffer_sub.color_format = Regs::PixelFormat::RGB8; framebuffer_sub.active_fb = 0; - frame_ticks = 268123480 / Settings::values.gpu_refresh_rate; last_skip_frame = false; g_skip_frame = false; frame_count = 0; diff --git a/src/core/hw/hw.cpp b/src/core/hw/hw.cpp index f4906cc7e..c7006a498 100644 --- a/src/core/hw/hw.cpp +++ b/src/core/hw/hw.cpp @@ -18,7 +18,7 @@ inline void Read(T &var, const u32 addr) { GPU::Read(var, addr); break; case VADDR_LCD: - LCD::Write(var, addr); + LCD::Read(var, addr); break; default: LOG_ERROR(HW_Memory, "unknown Read%lu @ 0x%08X", sizeof(var) * 8, addr); 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() { void Shutdown() { LOG_DEBUG(HW_LCD, "shutdown OK"); } - + } // 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(); /// Shutdown hardware void Shutdown(); - + } // 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() { Kernel::g_current_process = Kernel::Process::Create(filename, 0); Kernel::g_current_process->svc_access_mask.set(); Kernel::g_current_process->address_mappings = default_address_mappings; - + // Attach the default resource limit (APPLICATION) to the process Kernel::g_current_process->resource_limit = Kernel::ResourceLimit::GetForCategory(Kernel::ResourceLimitCategory::APPLICATION); 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 @@ #include "common/logging/log.h" #include "core/hle/config_mem.h" +#include "core/hle/kernel/kernel.h" +#include "core/hle/kernel/shared_memory.h" +#include "core/hle/kernel/vm_manager.h" +#include "core/hle/result.h" #include "core/hle/shared_page.h" #include "core/mem_map.h" #include "core/memory.h" @@ -17,31 +21,23 @@ namespace Memory { -u8* g_exefs_code; ///< ExeFS:/.code is loaded here -u8* g_heap; ///< Application heap (main memory) -u8* g_shared_mem; ///< Shared memory -u8* g_heap_linear; ///< Linear heap -u8* g_vram; ///< Video memory (VRAM) pointer -u8* g_dsp_mem; ///< DSP memory -u8* g_tls_mem; ///< TLS memory - namespace { struct MemoryArea { - u8** ptr; u32 base; u32 size; + const char* name; }; // We don't declare the IO regions in here since its handled by other means. static MemoryArea memory_areas[] = { - {&g_exefs_code, PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE}, - {&g_heap, HEAP_VADDR, HEAP_SIZE }, - {&g_shared_mem, SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE }, - {&g_heap_linear, LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE }, - {&g_vram, VRAM_VADDR, VRAM_SIZE }, - {&g_dsp_mem, DSP_RAM_VADDR, DSP_RAM_SIZE }, - {&g_tls_mem, TLS_AREA_VADDR, TLS_AREA_SIZE }, + {PROCESS_IMAGE_VADDR, PROCESS_IMAGE_MAX_SIZE, "Process Image"}, // ExeFS:/.code is loaded here + {HEAP_VADDR, HEAP_SIZE, "Heap"}, // Application heap (main memory) + {SHARED_MEMORY_VADDR, SHARED_MEMORY_SIZE, "Shared Memory"}, // Shared memory + {LINEAR_HEAP_VADDR, LINEAR_HEAP_SIZE, "Linear Heap"}, // Linear heap (main memory) + {VRAM_VADDR, VRAM_SIZE, "VRAM"}, // Video memory (VRAM) + {DSP_RAM_VADDR, DSP_RAM_SIZE, "DSP RAM"}, // DSP memory + {TLS_AREA_VADDR, TLS_AREA_SIZE, "TLS Area"}, // TLS memory }; /// Represents a block of memory mapped by ControlMemory/MapMemoryBlock @@ -135,27 +131,34 @@ VAddr PhysicalToVirtualAddress(const PAddr addr) { return addr | 0x80000000; } +// TODO(yuriks): Move this into Process +static Kernel::VMManager address_space; + void Init() { + using namespace Kernel; + InitMemoryMap(); for (MemoryArea& area : memory_areas) { - *area.ptr = new u8[area.size]; - MapMemoryRegion(area.base, area.size, *area.ptr); + auto block = std::make_shared<std::vector<u8>>(area.size); + address_space.MapMemoryBlock(area.base, std::move(block), 0, area.size, MemoryState::Private).Unwrap(); } - MapMemoryRegion(CONFIG_MEMORY_VADDR, CONFIG_MEMORY_SIZE, (u8*)&ConfigMem::config_mem); - MapMemoryRegion(SHARED_PAGE_VADDR, SHARED_PAGE_SIZE, (u8*)&SharedPage::shared_page); - LOG_DEBUG(HW_Memory, "initialized OK, RAM at %p", g_heap); + auto cfg_mem_vma = address_space.MapBackingMemory(CONFIG_MEMORY_VADDR, + (u8*)&ConfigMem::config_mem, CONFIG_MEMORY_SIZE, MemoryState::Shared).MoveFrom(); + address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); + + auto shared_page_vma = address_space.MapBackingMemory(SHARED_PAGE_VADDR, + (u8*)&SharedPage::shared_page, SHARED_PAGE_SIZE, MemoryState::Shared).MoveFrom(); + address_space.Reprotect(shared_page_vma, VMAPermission::Read); + + LOG_DEBUG(HW_Memory, "initialized OK"); } void Shutdown() { heap_map.clear(); heap_linear_map.clear(); - - for (MemoryArea& area : memory_areas) { - delete[] *area.ptr; - *area.ptr = nullptr; - } + address_space.Reset(); LOG_DEBUG(HW_Memory, "shutdown OK"); } 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 @@ namespace Memory { -extern u8* g_exefs_code; ///< ExeFS:/.code is loaded here -extern u8* g_heap; ///< Application heap (main memory) -extern u8* g_shared_mem; ///< Shared memory -extern u8* g_heap_linear; ///< Linear heap (main memory) -extern u8* g_vram; ///< Video memory (VRAM) -extern u8* g_dsp_mem; ///< DSP memory -extern u8* g_tls_mem; ///< TLS memory - void Init(); void Shutdown(); 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 @@ #include "core/hw/hw.h" #include "core/mem_map.h" #include "core/memory.h" +#include "core/memory_setup.h" namespace Memory { -const u32 PAGE_MASK = PAGE_SIZE - 1; -const int PAGE_BITS = 12; - enum class PageType { /// Page is unmapped and should cause an access error. Unmapped, @@ -64,7 +62,7 @@ static void MapPages(u32 base, u32 size, u8* memory, PageType type) { while (base != end) { ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at %08X", base); - if (current_page_table->attributes[base] != PageType::Unmapped) { + if (current_page_table->attributes[base] != PageType::Unmapped && type != PageType::Unmapped) { LOG_ERROR(HW_Memory, "overlapping memory ranges at %08X", base * PAGE_SIZE); } current_page_table->attributes[base] = type; @@ -92,6 +90,12 @@ void MapIoRegion(VAddr base, u32 size) { MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Special); } +void UnmapRegion(VAddr base, u32 size) { + ASSERT_MSG((size & PAGE_MASK) == 0, "non-page aligned size: %08X", size); + ASSERT_MSG((base & PAGE_MASK) == 0, "non-page aligned base: %08X", base); + MapPages(base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped); +} + template <typename T> T Read(const VAddr vaddr) { 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 { SHARED_PAGE_VADDR_END = SHARED_PAGE_VADDR + SHARED_PAGE_SIZE, // TODO(yuriks): The size of this area is dynamic, the kernel grows - // it as more and more threads are created. For now we'll just use a + // it as more and more threads are created. For now we'll just use a // hardcoded value. /// Area where TLS (Thread-Local Storage) buffers are allocated. 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 @@ #include "common/common_types.h" +#include "core/memory.h" + namespace Memory { +const u32 PAGE_MASK = PAGE_SIZE - 1; +const int PAGE_BITS = 12; + void InitMemoryMap(); /** @@ -26,4 +31,6 @@ void MapMemoryRegion(VAddr base, u32 size, u8* target); */ void MapIoRegion(VAddr base, u32 size); +void UnmapRegion(VAddr base, u32 size); + } diff --git a/src/core/settings.h b/src/core/settings.h index 54c1023b8..5a70d157a 100644 --- a/src/core/settings.h +++ b/src/core/settings.h @@ -35,7 +35,6 @@ struct Values { int pad_cright_key; // Core - int gpu_refresh_rate; int frame_skip; // Data Storage diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index 0258a3255..5c7f4ae18 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -29,11 +29,9 @@ set(HEADERS renderer_opengl/pica_to_gl.h renderer_opengl/renderer_opengl.h clipper.h - color.h command_processor.h gpu_debugger.h hwrasterizer_base.h - math.h pica.h primitive_assembly.h rasterizer.h 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) { // Trigger IRQ case PICA_REG_INDEX(trigger_irq): GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::P3D); - return; + break; + + case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[0], 0x23c): + case PICA_REG_INDEX_WORKAROUND(command_buffer.trigger[1], 0x23d): + { + unsigned index = id - PICA_REG_INDEX(command_buffer.trigger[0]); + u32* head_ptr = (u32*)Memory::GetPhysicalPointer(regs.command_buffer.GetPhysicalAddress(index)); + g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr; + g_state.cmd_list.length = regs.command_buffer.GetSize(index) / sizeof(u32); + break; + } // It seems like these trigger vertex rendering case PICA_REG_INDEX(trigger_draw): @@ -136,7 +146,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { input.attr[i][0].ToFloat32(), input.attr[i][1].ToFloat32(), input.attr[i][2].ToFloat32(), input.attr[i][3].ToFloat32()); } - + // Load per-vertex data from the loader arrays for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) { 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) { const Pica::VertexShader::OutputVertex& v2) { VideoCore::g_renderer->hw_rasterizer->AddTriangle(v0, v1, v2); }; - + primitive_assembler.SubmitVertex(output, AddHWTriangle); } else { // Send to triangle clipper @@ -282,7 +292,7 @@ static inline void WritePicaReg(u32 id, u32 value, u32 mask) { } break; } - + // Load default vertex input attributes case PICA_REG_INDEX_WORKAROUND(vs_default_attributes_setup.set_value[0], 0x233): 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) { } Math::Vec4<float24>& attribute = g_state.vs.default_attributes[setup.index]; - + // NOTE: The destination component order indeed is "backwards" attribute.w = float24::FromRawFloat24(default_attr_write_buffer[0] >> 8); 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) { g_debug_context->OnEvent(DebugContext::Event::CommandProcessed, reinterpret_cast<void*>(&id)); } -static std::ptrdiff_t ExecuteCommandBlock(const u32* first_command_word) { - const CommandHeader& header = *(const CommandHeader*)(&first_command_word[1]); - - u32* read_pointer = (u32*)first_command_word; - - const u32 write_mask = ((header.parameter_mask & 0x1) ? (0xFFu << 0) : 0u) | - ((header.parameter_mask & 0x2) ? (0xFFu << 8) : 0u) | - ((header.parameter_mask & 0x4) ? (0xFFu << 16) : 0u) | - ((header.parameter_mask & 0x8) ? (0xFFu << 24) : 0u); - - WritePicaReg(header.cmd_id, *read_pointer, write_mask); - read_pointer += 2; - - for (unsigned int i = 1; i < 1+header.extra_data_length; ++i) { - u32 cmd = header.cmd_id + ((header.group_commands) ? i : 0); - WritePicaReg(cmd, *read_pointer, write_mask); - ++read_pointer; - } - - // align read pointer to 8 bytes - if ((first_command_word - read_pointer) % 2) - ++read_pointer; - - return read_pointer - first_command_word; -} - void ProcessCommandList(const u32* list, u32 size) { - u32* read_pointer = (u32*)list; - u32 list_length = size / sizeof(u32); - - while (read_pointer < list + list_length) { - read_pointer += ExecuteCommandBlock(read_pointer); + g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = list; + g_state.cmd_list.length = size / sizeof(u32); + + while (g_state.cmd_list.current_ptr < g_state.cmd_list.head_ptr + g_state.cmd_list.length) { + // Expand a 4-bit mask to 4-byte mask, e.g. 0b0101 -> 0x00FF00FF + static const u32 expand_bits_to_bytes[] = { + 0x00000000, 0x000000ff, 0x0000ff00, 0x0000ffff, + 0x00ff0000, 0x00ff00ff, 0x00ffff00, 0x00ffffff, + 0xff000000, 0xff0000ff, 0xff00ff00, 0xff00ffff, + 0xffff0000, 0xffff00ff, 0xffffff00, 0xffffffff + }; + + // Align read pointer to 8 bytes + if ((g_state.cmd_list.head_ptr - g_state.cmd_list.current_ptr) % 2 != 0) + ++g_state.cmd_list.current_ptr; + + u32 value = *g_state.cmd_list.current_ptr++; + const CommandHeader header = { *g_state.cmd_list.current_ptr++ }; + const u32 write_mask = expand_bits_to_bytes[header.parameter_mask]; + u32 cmd = header.cmd_id; + + WritePicaReg(cmd, value, write_mask); + + for (unsigned i = 0; i < header.extra_data_length; ++i) { + u32 cmd = header.cmd_id + (header.group_commands ? i + 1 : 0); + WritePicaReg(cmd, *g_state.cmd_list.current_ptr++, write_mask); + } } } diff --git a/src/video_core/debug_utils/debug_utils.cpp b/src/video_core/debug_utils/debug_utils.cpp index 7987b922c..7b8ab72b6 100644 --- a/src/video_core/debug_utils/debug_utils.cpp +++ b/src/video_core/debug_utils/debug_utils.cpp @@ -17,11 +17,11 @@ #include <nihstro/shader_binary.h> #include "common/assert.h" +#include "common/color.h" #include "common/file_util.h" #include "common/math_util.h" +#include "common/vector_math.h" -#include "video_core/color.h" -#include "video_core/math.h" #include "video_core/pica.h" #include "video_core/utils.h" #include "video_core/video_core.h" @@ -319,7 +319,7 @@ const Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const Texture // TODO(neobrain): Fix code design to unify vertical block offsets! source += coarse_y * info.stride; } - + // TODO: Assert that width/height are multiples of block dimensions switch (info.format) { diff --git a/src/video_core/debug_utils/debug_utils.h b/src/video_core/debug_utils/debug_utils.h index f361a5385..7926d64ec 100644 --- a/src/video_core/debug_utils/debug_utils.h +++ b/src/video_core/debug_utils/debug_utils.h @@ -12,7 +12,8 @@ #include <mutex> #include <vector> -#include "video_core/math.h" +#include "common/vector_math.h" + #include "video_core/pica.h" namespace Pica { diff --git a/src/video_core/pica.h b/src/video_core/pica.h index b67dce1a9..9628a7589 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h @@ -15,8 +15,7 @@ #include "common/common_funcs.h" #include "common/common_types.h" #include "common/logging/log.h" - -#include "math.h" +#include "common/vector_math.h" namespace Pica { @@ -162,6 +161,25 @@ struct Regs { ETC1A4 = 13, // compressed }; + enum class LogicOp : u32 { + Clear = 0, + And = 1, + AndReverse = 2, + Copy = 3, + Set = 4, + CopyInverted = 5, + NoOp = 6, + Invert = 7, + Nand = 8, + Or = 9, + Nor = 10, + Xor = 11, + Equiv = 12, + AndInverted = 13, + OrReverse = 14, + OrInverted = 15, + }; + static unsigned NibblesPerPixel(TextureFormat format) { switch (format) { case TextureFormat::RGBA8: @@ -221,6 +239,7 @@ struct Regs { enum class Source : u32 { PrimaryColor = 0x0, PrimaryFragmentColor = 0x1, + SecondaryFragmentColor = 0x2, Texture0 = 0x3, Texture1 = 0x4, @@ -337,7 +356,7 @@ struct Regs { return (stage_index < 4) && (update_mask_a & (1 << stage_index)); } } tev_combiner_buffer_input; - + INSERT_PADDING_WORDS(0xf); TevStageConfig tev_stage4; INSERT_PADDING_WORDS(0x3); @@ -353,9 +372,9 @@ struct Regs { INSERT_PADDING_WORDS(0x2); const std::array<Regs::TevStageConfig,6> GetTevStages() const { - return { tev_stage0, tev_stage1, - tev_stage2, tev_stage3, - tev_stage4, tev_stage5 }; + return {{ tev_stage0, tev_stage1, + tev_stage2, tev_stage3, + tev_stage4, tev_stage5 }}; }; enum class BlendEquation : u32 { @@ -413,12 +432,8 @@ struct Regs { } alpha_blending; union { - enum Op { - Set = 4, - }; - - BitField<0, 4, Op> op; - } logic_op; + BitField<0, 4, LogicOp> logic_op; + }; union { BitField< 0, 8, u32> r; @@ -703,12 +718,38 @@ struct Regs { struct { // Index of the current default attribute u32 index; - + // Writing to these registers sets the "current" default attribute. u32 set_value[3]; } vs_default_attributes_setup; - - INSERT_PADDING_WORDS(0x28); + + INSERT_PADDING_WORDS(0x2); + + struct { + // There are two channels that can be used to configure the next command buffer, which + // can be then executed by writing to the "trigger" registers. There are two reasons why a + // game might use this feature: + // 1) With this, an arbitrary number of additional command buffers may be executed in + // sequence without requiring any intervention of the CPU after the initial one is + // kicked off. + // 2) Games can configure these registers to provide a command list subroutine mechanism. + + BitField< 0, 20, u32> size[2]; ///< Size (in bytes / 8) of each channel's command buffer + BitField< 0, 28, u32> addr[2]; ///< Physical address / 8 of each channel's command buffer + u32 trigger[2]; ///< Triggers execution of the channel's command buffer when written to + + unsigned GetSize(unsigned index) const { + ASSERT(index < 2); + return 8 * size[index]; + } + + PAddr GetPhysicalAddress(unsigned index) const { + ASSERT(index < 2); + return (PAddr)(8 * addr[index]); + } + } command_buffer; + + INSERT_PADDING_WORDS(0x20); enum class TriangleTopology : u32 { List = 0, @@ -861,6 +902,7 @@ struct Regs { ADD_FIELD(trigger_draw); ADD_FIELD(trigger_draw_indexed); ADD_FIELD(vs_default_attributes_setup); + ADD_FIELD(command_buffer); ADD_FIELD(triangle_topology); ADD_FIELD(vs_bool_uniforms); ADD_FIELD(vs_int_uniforms); @@ -938,6 +980,7 @@ ASSERT_REG_POSITION(num_vertices, 0x228); ASSERT_REG_POSITION(trigger_draw, 0x22e); ASSERT_REG_POSITION(trigger_draw_indexed, 0x22f); ASSERT_REG_POSITION(vs_default_attributes_setup, 0x232); +ASSERT_REG_POSITION(command_buffer, 0x238); ASSERT_REG_POSITION(triangle_topology, 0x25e); ASSERT_REG_POSITION(vs_bool_uniforms, 0x2b0); ASSERT_REG_POSITION(vs_int_uniforms, 0x2b1); @@ -1053,21 +1096,12 @@ private: float value; }; -union CommandHeader { - CommandHeader(u32 h) : hex(h) {} - - u32 hex; - - BitField< 0, 16, u32> cmd_id; - BitField<16, 4, u32> parameter_mask; - BitField<20, 11, u32> extra_data_length; - BitField<31, 1, u32> group_commands; -}; - /// Struct used to describe current Pica state struct State { + /// Pica registers Regs regs; + /// Vertex shader memory struct { struct { Math::Vec4<float24> f[96]; @@ -1080,6 +1114,13 @@ struct State { std::array<u32, 1024> program_code; std::array<u32, 1024> swizzle_data; } vs; + + /// Current Pica command list + struct { + const u32* head_ptr; + const u32* current_ptr; + u32 length; + } cmd_list; }; /// Initialize Pica state diff --git a/src/video_core/rasterizer.cpp b/src/video_core/rasterizer.cpp index 767ff4205..59d156ee7 100644 --- a/src/video_core/rasterizer.cpp +++ b/src/video_core/rasterizer.cpp @@ -4,6 +4,7 @@ #include <algorithm> +#include "common/color.h" #include "common/common_types.h" #include "common/math_util.h" #include "common/profiler.h" @@ -13,7 +14,6 @@ #include "debug_utils/debug_utils.h" #include "math.h" -#include "color.h" #include "pica.h" #include "rasterizer.h" #include "vertex_shader.h" @@ -104,7 +104,7 @@ static u32 GetDepth(int x, int y) { u8* depth_buffer = Memory::GetPhysicalPointer(addr); y = framebuffer.height - y; - + const u32 coarse_y = y & ~7; u32 bytes_per_pixel = Regs::BytesPerDepthPixel(framebuffer.depth_format); u32 stride = framebuffer.width * bytes_per_pixel; @@ -402,11 +402,16 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, auto GetSource = [&](Source source) -> Math::Vec4<u8> { switch (source) { - // TODO: What's the difference between these two? case Source::PrimaryColor: + + // HACK: Until we implement fragment lighting, use primary_color case Source::PrimaryFragmentColor: return primary_color; + // HACK: Until we implement fragment lighting, use zero + case Source::SecondaryFragmentColor: + return {0, 0, 0, 0}; + case Source::Texture0: return texture_color[0]; @@ -570,6 +575,13 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, case Operation::Add: return std::min(255, input[0] + input[1]); + case Operation::AddSigned: + { + // TODO(bunnei): Verify that the color conversion from (float) 0.5f to (byte) 128 is correct + auto result = static_cast<int>(input[0]) + static_cast<int>(input[1]) - 128; + return static_cast<u8>(MathUtil::Clamp<int>(result, 0, 255)); + } + case Operation::Lerp: return (input[0] * input[2] + input[1] * (255 - input[2])) / 255; @@ -808,10 +820,9 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, } }; - using BlendEquation = Regs::BlendEquation; static auto EvaluateBlendEquation = [](const Math::Vec4<u8>& src, const Math::Vec4<u8>& srcfactor, const Math::Vec4<u8>& dest, const Math::Vec4<u8>& destfactor, - BlendEquation equation) { + Regs::BlendEquation equation) { Math::Vec4<int> result; auto src_result = (src * srcfactor).Cast<int>(); @@ -866,8 +877,63 @@ static void ProcessTriangleInternal(const VertexShader::OutputVertex& v0, blend_output = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_rgb); blend_output.a() = EvaluateBlendEquation(combiner_output, srcfactor, dest, dstfactor, params.blend_equation_a).a(); } else { - LOG_CRITICAL(HW_GPU, "logic op: %x", output_merger.logic_op); - UNIMPLEMENTED(); + static auto LogicOp = [](u8 src, u8 dest, Regs::LogicOp op) -> u8 { + switch (op) { + case Regs::LogicOp::Clear: + return 0; + + case Regs::LogicOp::And: + return src & dest; + + case Regs::LogicOp::AndReverse: + return src & ~dest; + + case Regs::LogicOp::Copy: + return src; + + case Regs::LogicOp::Set: + return 255; + + case Regs::LogicOp::CopyInverted: + return ~src; + + case Regs::LogicOp::NoOp: + return dest; + + case Regs::LogicOp::Invert: + return ~dest; + + case Regs::LogicOp::Nand: + return ~(src & dest); + + case Regs::LogicOp::Or: + return src | dest; + + case Regs::LogicOp::Nor: + return ~(src | dest); + + case Regs::LogicOp::Xor: + return src ^ dest; + + case Regs::LogicOp::Equiv: + return ~(src ^ dest); + + case Regs::LogicOp::AndInverted: + return ~src & dest; + + case Regs::LogicOp::OrReverse: + return src | ~dest; + + case Regs::LogicOp::OrInverted: + return ~src | dest; + } + }; + + blend_output = Math::MakeVec( + LogicOp(combiner_output.r(), dest.r(), output_merger.logic_op), + LogicOp(combiner_output.g(), dest.g(), output_merger.logic_op), + LogicOp(combiner_output.b(), dest.b(), output_merger.logic_op), + LogicOp(combiner_output.a(), dest.a(), output_merger.logic_op)); } 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) ptrdiff_t iTest; if(!pTest) return 0; iTest = (ptrdiff_t)pTest; - + if(iTest == 1 || iTest == 2 || iTest == 3 || iTest == -1) return 0; - + return 1; } @@ -79,7 +79,7 @@ static PROC WinGetProcAddress(const char *name) glMod = GetModuleHandleA("OpenGL32.dll"); return (PROC)GetProcAddress(glMod, (LPCSTR)name); } - + #define IntGetProcAddress(name) WinGetProcAddress(name) #else #if defined(__APPLE__) @@ -1083,7 +1083,7 @@ static ogl_StrToExtMap *FindExtEntry(const char *extensionName) if(strcmp(extensionName, currLoc->extensionName) == 0) return currLoc; } - + return NULL; } @@ -1135,15 +1135,15 @@ int ogl_LoadFunctions() { int numFailed = 0; ClearExtensionVars(); - + _ptrc_glGetIntegerv = (void (CODEGEN_FUNCPTR *)(GLenum, GLint *))IntGetProcAddress("glGetIntegerv"); if(!_ptrc_glGetIntegerv) return ogl_LOAD_FAILED; _ptrc_glGetStringi = (const GLubyte * (CODEGEN_FUNCPTR *)(GLenum, GLuint))IntGetProcAddress("glGetStringi"); if(!_ptrc_glGetStringi) return ogl_LOAD_FAILED; - + ProcExtsFromExtList(); numFailed = Load_Version_3_2(); - + if(numFailed == 0) return ogl_LOAD_SUCCEEDED; else @@ -1177,7 +1177,7 @@ int ogl_IsVersionGEQ(int majorVersion, int minorVersion) { if(g_major_version == 0) GetGLVersion(); - + if(majorVersion > g_major_version) return 1; if(majorVersion < g_major_version) return 0; 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..518f79331 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp @@ -2,10 +2,11 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/color.h" + #include "core/settings.h" #include "core/hw/gpu.h" -#include "video_core/color.h" #include "video_core/pica.h" #include "video_core/utils.h" #include "video_core/renderer_opengl/gl_rasterizer.h" @@ -93,14 +94,27 @@ void RasterizerOpenGL::InitObjects() { // Create textures for OGL framebuffer that will be rendered to, initially 1x1 to succeed in framebuffer creation fb_color_texture.texture.Create(); ReconfigureColorTexture(fb_color_texture, Pica::Regs::ColorFormat::RGBA8, 1, 1); + + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = fb_color_texture.texture.handle; + state.Apply(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + state.texture_units[0].texture_2d = 0; + state.Apply(); + fb_depth_texture.texture.Create(); ReconfigureDepthTexture(fb_depth_texture, Pica::Regs::DepthFormat::D16, 1, 1); + + state.texture_units[0].enabled_2d = true; + state.texture_units[0].texture_2d = fb_depth_texture.texture.handle; + state.Apply(); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -109,14 +123,13 @@ void RasterizerOpenGL::InitObjects() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE); + state.texture_units[0].texture_2d = 0; + state.Apply(); + // Configure OpenGL framebuffer framebuffer.Create(); state.draw.framebuffer = framebuffer.handle; - - // Unbind texture to allow binding to framebuffer - state.texture_units[0].enabled_2d = true; - state.texture_units[0].texture_2d = 0; state.Apply(); glActiveTexture(GL_TEXTURE0); @@ -135,6 +148,7 @@ void RasterizerOpenGL::Reset() { SyncBlendFuncs(); SyncBlendColor(); SyncAlphaTest(); + SyncLogicOp(); SyncStencilTest(); SyncDepthTest(); @@ -203,7 +217,19 @@ void RasterizerOpenGL::DrawTriangles() { vertex_batch.clear(); - // TODO: Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture + // Flush the resource cache at the current depth and color framebuffer addresses for render-to-texture + const auto& regs = Pica::g_state.regs; + + PAddr cur_fb_color_addr = regs.framebuffer.GetColorBufferPhysicalAddress(); + u32 cur_fb_color_size = Pica::Regs::BytesPerColorPixel(regs.framebuffer.color_format) + * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); + + PAddr cur_fb_depth_addr = regs.framebuffer.GetDepthBufferPhysicalAddress(); + u32 cur_fb_depth_size = Pica::Regs::BytesPerDepthPixel(regs.framebuffer.depth_format) + * regs.framebuffer.GetWidth() * regs.framebuffer.GetHeight(); + + res_cache.NotifyFlush(cur_fb_color_addr, cur_fb_color_size); + res_cache.NotifyFlush(cur_fb_depth_addr, cur_fb_depth_size); } void RasterizerOpenGL::CommitFramebuffer() { @@ -249,6 +275,11 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { SyncDepthTest(); break; + // Logic op + case PICA_REG_INDEX(output_merger.logic_op): + SyncLogicOp(); + break; + // TEV stage 0 case PICA_REG_INDEX(tev_stage0.color_source1): SyncTevSources(0, regs.tev_stage0); @@ -350,7 +381,7 @@ void RasterizerOpenGL::NotifyPicaRegisterChanged(u32 id) { case PICA_REG_INDEX(tev_stage5.color_scale): SyncTevMultipliers(5, regs.tev_stage5); break; - + // TEV combiner buffer color case PICA_REG_INDEX(tev_combiner_buffer_color): SyncCombinerColor(); @@ -465,6 +496,9 @@ void RasterizerOpenGL::ReconfigureColorTexture(TextureInfo& texture, Pica::Regs: glActiveTexture(GL_TEXTURE0); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, texture.gl_format, texture.gl_type, nullptr); + + state.texture_units[0].texture_2d = 0; + state.Apply(); } void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica::Regs::DepthFormat format, u32 width, u32 height) { @@ -484,7 +518,7 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: case Pica::Regs::DepthFormat::D24: internal_format = GL_DEPTH_COMPONENT24; texture.gl_format = GL_DEPTH_COMPONENT; - texture.gl_type = GL_UNSIGNED_INT_24_8; + texture.gl_type = GL_UNSIGNED_INT; break; case Pica::Regs::DepthFormat::D24S8: @@ -506,6 +540,9 @@ void RasterizerOpenGL::ReconfigureDepthTexture(DepthTextureInfo& texture, Pica:: glActiveTexture(GL_TEXTURE0); glTexImage2D(GL_TEXTURE_2D, 0, internal_format, texture.width, texture.height, 0, texture.gl_format, texture.gl_type, nullptr); + + state.texture_units[0].texture_2d = 0; + state.Apply(); } void RasterizerOpenGL::SyncFramebuffer() { @@ -633,6 +670,10 @@ void RasterizerOpenGL::SyncAlphaTest() { glUniform1f(uniform_alphatest_ref, regs.output_merger.alpha_test.ref / 255.0f); } +void RasterizerOpenGL::SyncLogicOp() { + state.logic_op = PicaToGL::LogicOp(Pica::g_state.regs.output_merger.logic_op); +} + void RasterizerOpenGL::SyncStencilTest() { // TODO: Implement stencil test, mask, and op } @@ -641,6 +682,10 @@ void RasterizerOpenGL::SyncDepthTest() { const auto& regs = Pica::g_state.regs; state.depth.test_enabled = (regs.output_merger.depth_test_enable == 1); state.depth.test_func = PicaToGL::CompareFunc(regs.output_merger.depth_test_func); + state.color_mask.red_enabled = regs.output_merger.red_enable; + state.color_mask.green_enabled = regs.output_merger.green_enable; + state.color_mask.blue_enabled = regs.output_merger.blue_enable; + state.color_mask.alpha_enabled = regs.output_merger.alpha_enable; state.depth.write_mask = regs.output_merger.depth_write_enable ? GL_TRUE : GL_FALSE; } @@ -748,10 +793,10 @@ void RasterizerOpenGL::ReloadColorBuffer() { for (int x = 0; x < fb_color_texture.width; ++x) { const u32 coarse_y = y & ~7; u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; - u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; + u32 gl_pixel_index = (x + y * fb_color_texture.width) * bytes_per_pixel; u8* pixel = color_buffer + dst_offset; - memcpy(&temp_fb_color_buffer[gl_px_idx], pixel, bytes_per_pixel); + memcpy(&temp_fb_color_buffer[gl_pixel_index], pixel, bytes_per_pixel); } } @@ -762,6 +807,9 @@ void RasterizerOpenGL::ReloadColorBuffer() { glActiveTexture(GL_TEXTURE0); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_color_texture.width, fb_color_texture.height, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_fb_color_buffer.get()); + + state.texture_units[0].texture_2d = 0; + state.Apply(); } void RasterizerOpenGL::ReloadDepthBuffer() { @@ -779,29 +827,29 @@ void RasterizerOpenGL::ReloadDepthBuffer() { std::unique_ptr<u8[]> temp_fb_depth_buffer(new u8[fb_depth_texture.width * fb_depth_texture.height * gl_bpp]); - for (int y = 0; y < fb_depth_texture.height; ++y) { - for (int x = 0; x < fb_depth_texture.width; ++x) { - const u32 coarse_y = y & ~7; - u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; - u32 gl_px_idx = x + y * fb_depth_texture.width; - - switch (fb_depth_texture.format) { - case Pica::Regs::DepthFormat::D16: - ((u16*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD16(depth_buffer + dst_offset); - break; - case Pica::Regs::DepthFormat::D24: - ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = Color::DecodeD24(depth_buffer + dst_offset); - break; - case Pica::Regs::DepthFormat::D24S8: - { - Math::Vec2<u32> depth_stencil = Color::DecodeD24S8(depth_buffer + dst_offset); - ((u32*)temp_fb_depth_buffer.get())[gl_px_idx] = (depth_stencil.x << 8) | depth_stencil.y; - break; + u8* temp_fb_depth_data = bytes_per_pixel == 3 ? (temp_fb_depth_buffer.get() + 1) : temp_fb_depth_buffer.get(); + + if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) { + for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int x = 0; x < fb_depth_texture.width; ++x) { + const u32 coarse_y = y & ~7; + u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; + u32 gl_pixel_index = (x + y * fb_depth_texture.width); + + u8* pixel = depth_buffer + dst_offset; + u32 depth_stencil = *(u32*)pixel; + ((u32*)temp_fb_depth_data)[gl_pixel_index] = (depth_stencil << 8) | (depth_stencil >> 24); } - default: - LOG_CRITICAL(Render_OpenGL, "Unknown memory framebuffer depth format %x", fb_depth_texture.format); - UNIMPLEMENTED(); - break; + } + } else { + for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int x = 0; x < fb_depth_texture.width; ++x) { + const u32 coarse_y = y & ~7; + u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; + u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp; + + u8* pixel = depth_buffer + dst_offset; + memcpy(&temp_fb_depth_data[gl_pixel_index], pixel, bytes_per_pixel); } } } @@ -813,6 +861,9 @@ void RasterizerOpenGL::ReloadDepthBuffer() { glActiveTexture(GL_TEXTURE0); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_depth_texture.width, fb_depth_texture.height, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_fb_depth_buffer.get()); + + state.texture_units[0].texture_2d = 0; + state.Apply(); } void RasterizerOpenGL::CommitColorBuffer() { @@ -831,15 +882,18 @@ void RasterizerOpenGL::CommitColorBuffer() { glActiveTexture(GL_TEXTURE0); glGetTexImage(GL_TEXTURE_2D, 0, fb_color_texture.gl_format, fb_color_texture.gl_type, temp_gl_color_buffer.get()); + state.texture_units[0].texture_2d = 0; + state.Apply(); + // Directly copy pixels. Internal OpenGL color formats are consistent so no conversion is necessary. for (int y = 0; y < fb_color_texture.height; ++y) { for (int x = 0; x < fb_color_texture.width; ++x) { const u32 coarse_y = y & ~7; u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_color_texture.width * bytes_per_pixel; - u32 gl_px_idx = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; + u32 gl_pixel_index = x * bytes_per_pixel + y * fb_color_texture.width * bytes_per_pixel; u8* pixel = color_buffer + dst_offset; - memcpy(pixel, &temp_gl_color_buffer[gl_px_idx], bytes_per_pixel); + memcpy(pixel, &temp_gl_color_buffer[gl_pixel_index], bytes_per_pixel); } } } @@ -866,29 +920,32 @@ void RasterizerOpenGL::CommitDepthBuffer() { glActiveTexture(GL_TEXTURE0); glGetTexImage(GL_TEXTURE_2D, 0, fb_depth_texture.gl_format, fb_depth_texture.gl_type, temp_gl_depth_buffer.get()); - for (int y = 0; y < fb_depth_texture.height; ++y) { - for (int x = 0; x < fb_depth_texture.width; ++x) { - const u32 coarse_y = y & ~7; - u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; - u32 gl_px_idx = x + y * fb_depth_texture.width; - - switch (fb_depth_texture.format) { - case Pica::Regs::DepthFormat::D16: - Color::EncodeD16(((u16*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); - break; - case Pica::Regs::DepthFormat::D24: - Color::EncodeD24(((u32*)temp_gl_depth_buffer.get())[gl_px_idx], depth_buffer + dst_offset); - break; - case Pica::Regs::DepthFormat::D24S8: - { - u32 depth_stencil = ((u32*)temp_gl_depth_buffer.get())[gl_px_idx]; - Color::EncodeD24S8((depth_stencil >> 8), depth_stencil & 0xFF, depth_buffer + dst_offset); - break; + state.texture_units[0].texture_2d = 0; + state.Apply(); + + u8* temp_gl_depth_data = bytes_per_pixel == 3 ? (temp_gl_depth_buffer.get() + 1) : temp_gl_depth_buffer.get(); + + if (fb_depth_texture.format == Pica::Regs::DepthFormat::D24S8) { + for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int x = 0; x < fb_depth_texture.width; ++x) { + const u32 coarse_y = y & ~7; + u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; + u32 gl_pixel_index = (x + y * fb_depth_texture.width); + + u8* pixel = depth_buffer + dst_offset; + u32 depth_stencil = ((u32*)temp_gl_depth_data)[gl_pixel_index]; + *(u32*)pixel = (depth_stencil >> 8) | (depth_stencil << 24); } - default: - LOG_CRITICAL(Render_OpenGL, "Unknown framebuffer depth format %x", fb_depth_texture.format); - UNIMPLEMENTED(); - break; + } + } else { + for (int y = 0; y < fb_depth_texture.height; ++y) { + for (int x = 0; x < fb_depth_texture.width; ++x) { + const u32 coarse_y = y & ~7; + u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) + coarse_y * fb_depth_texture.width * bytes_per_pixel; + u32 gl_pixel_index = (x + y * fb_depth_texture.width) * gl_bpp; + + u8* pixel = depth_buffer + dst_offset; + memcpy(pixel, &temp_gl_depth_data[gl_pixel_index], bytes_per_pixel); } } } 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: /// Syncs the alpha test states to match the PICA register void SyncAlphaTest(); + /// Syncs the logic op states to match the PICA register + void SyncLogicOp(); + /// Syncs the stencil test states to match the PICA register void SyncStencilTest(); diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 6f88a8b21..2e4110a88 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp @@ -4,13 +4,13 @@ #include "common/make_unique.h" #include "common/math_util.h" +#include "common/vector_math.h" #include "core/memory.h" #include "video_core/renderer_opengl/gl_rasterizer_cache.h" #include "video_core/renderer_opengl/pica_to_gl.h" #include "video_core/debug_utils/debug_utils.h" -#include "video_core/math.h" RasterizerCacheOpenGL::~RasterizerCacheOpenGL() { FullFlush(); 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"( #define NUM_VTX_ATTR 7 #define NUM_TEV_STAGES 6 -#define SOURCE_PRIMARYCOLOR 0x0 -#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 -#define SOURCE_TEXTURE0 0x3 -#define SOURCE_TEXTURE1 0x4 -#define SOURCE_TEXTURE2 0x5 -#define SOURCE_TEXTURE3 0x6 -#define SOURCE_PREVIOUSBUFFER 0xd -#define SOURCE_CONSTANT 0xe -#define SOURCE_PREVIOUS 0xf +#define SOURCE_PRIMARYCOLOR 0x0 +#define SOURCE_PRIMARYFRAGMENTCOLOR 0x1 +#define SOURCE_SECONDARYFRAGMENTCOLOR 0x2 +#define SOURCE_TEXTURE0 0x3 +#define SOURCE_TEXTURE1 0x4 +#define SOURCE_TEXTURE2 0x5 +#define SOURCE_TEXTURE3 0x6 +#define SOURCE_PREVIOUSBUFFER 0xd +#define SOURCE_CONSTANT 0xe +#define SOURCE_PREVIOUS 0xf #define COLORMODIFIER_SOURCECOLOR 0x0 #define COLORMODIFIER_ONEMINUSSOURCECOLOR 0x1 @@ -151,8 +152,11 @@ vec4 GetSource(int source) { if (source == SOURCE_PRIMARYCOLOR) { return o[2]; } else if (source == SOURCE_PRIMARYFRAGMENTCOLOR) { - // HACK: Uses color value, but should really use fragment lighting output + // HACK: Until we implement fragment lighting, use primary_color return o[2]; + } else if (source == SOURCE_SECONDARYFRAGMENTCOLOR) { + // HACK: Until we implement fragment lighting, use zero + return vec4(0.0, 0.0, 0.0, 0.0); } else if (source == SOURCE_TEXTURE0) { return texture(tex[0], o[3].xy); } 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..3526e16d5 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp @@ -16,6 +16,11 @@ OpenGLState::OpenGLState() { depth.test_func = GL_LESS; depth.write_mask = GL_TRUE; + color_mask.red_enabled = GL_TRUE; + color_mask.green_enabled = GL_TRUE; + color_mask.blue_enabled = GL_TRUE; + color_mask.alpha_enabled = GL_TRUE; + stencil.test_enabled = false; stencil.test_func = GL_ALWAYS; stencil.test_ref = 0; @@ -32,6 +37,8 @@ OpenGLState::OpenGLState() { blend.color.blue = 0.0f; blend.color.alpha = 0.0f; + logic_op = GL_COPY; + for (auto& texture_unit : texture_units) { texture_unit.enabled_2d = false; texture_unit.texture_2d = 0; @@ -75,6 +82,15 @@ void OpenGLState::Apply() { glDepthMask(depth.write_mask); } + // Color mask + if (color_mask.red_enabled != cur_state.color_mask.red_enabled || + color_mask.green_enabled != cur_state.color_mask.green_enabled || + color_mask.blue_enabled != cur_state.color_mask.blue_enabled || + color_mask.alpha_enabled != cur_state.color_mask.alpha_enabled) { + glColorMask(color_mask.red_enabled, color_mask.green_enabled, + color_mask.blue_enabled, color_mask.alpha_enabled); + } + // Stencil test if (stencil.test_enabled != cur_state.stencil.test_enabled) { if (stencil.test_enabled) { @@ -82,11 +98,11 @@ void OpenGLState::Apply() { } else { glDisable(GL_STENCIL_TEST); } - } + } if (stencil.test_func != cur_state.stencil.test_func || - stencil.test_ref != cur_state.stencil.test_ref || - stencil.test_mask != cur_state.stencil.test_mask) { + stencil.test_ref != cur_state.stencil.test_ref || + stencil.test_mask != cur_state.stencil.test_mask) { glStencilFunc(stencil.test_func, stencil.test_ref, stencil.test_mask); } @@ -99,23 +115,34 @@ void OpenGLState::Apply() { if (blend.enabled != cur_state.blend.enabled) { if (blend.enabled) { glEnable(GL_BLEND); + + cur_state.logic_op = GL_COPY; + glLogicOp(cur_state.logic_op); + glDisable(GL_COLOR_LOGIC_OP); } else { glDisable(GL_BLEND); + glEnable(GL_COLOR_LOGIC_OP); } } if (blend.color.red != cur_state.blend.color.red || - blend.color.green != cur_state.blend.color.green || - blend.color.blue != cur_state.blend.color.blue || - blend.color.alpha != cur_state.blend.color.alpha) { - glBlendColor(blend.color.red, blend.color.green, blend.color.blue, blend.color.alpha); + blend.color.green != cur_state.blend.color.green || + blend.color.blue != cur_state.blend.color.blue || + blend.color.alpha != cur_state.blend.color.alpha) { + glBlendColor(blend.color.red, blend.color.green, + blend.color.blue, blend.color.alpha); } if (blend.src_rgb_func != cur_state.blend.src_rgb_func || - blend.dst_rgb_func != cur_state.blend.dst_rgb_func || - blend.src_a_func != cur_state.blend.src_a_func || - blend.dst_a_func != cur_state.blend.dst_a_func) { - glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, blend.src_a_func, blend.dst_a_func); + blend.dst_rgb_func != cur_state.blend.dst_rgb_func || + blend.src_a_func != cur_state.blend.src_a_func || + blend.dst_a_func != cur_state.blend.dst_a_func) { + glBlendFuncSeparate(blend.src_rgb_func, blend.dst_rgb_func, + blend.src_a_func, blend.dst_a_func); + } + + if (logic_op != cur_state.logic_op) { + glLogicOp(logic_op); } // Textures diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 281b7cad5..26b916360 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h @@ -20,6 +20,13 @@ public: } depth; struct { + GLboolean red_enabled; + GLboolean green_enabled; + GLboolean blue_enabled; + GLboolean alpha_enabled; + } color_mask; // GL_COLOR_WRITEMASK + + struct { bool test_enabled; // GL_STENCIL_TEST GLenum test_func; // GL_STENCIL_FUNC GLint test_ref; // GL_STENCIL_REF @@ -42,6 +49,8 @@ public: } color; // GL_BLEND_COLOR } blend; + GLenum logic_op; // GL_LOGIC_OP_MODE + // 3 texture units - one for each that is used in PICA fragment shader emulation struct { bool enabled_2d; // GL_TEXTURE_2D @@ -61,7 +70,7 @@ public: static const OpenGLState& GetCurState() { return cur_state; } - + /// Apply this state as the current OpenGL state void Apply(); 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) { return blend_func_table[(unsigned)factor]; } +inline GLenum LogicOp(Pica::Regs::LogicOp op) { + static const GLenum logic_op_table[] = { + GL_CLEAR, // Clear + GL_AND, // And + GL_AND_REVERSE, // AndReverse + GL_COPY, // Copy + GL_SET, // Set + GL_COPY_INVERTED, // CopyInverted + GL_NOOP, // NoOp + GL_INVERT, // Invert + GL_NAND, // Nand + GL_OR, // Or + GL_NOR, // Nor + GL_XOR, // Xor + GL_EQUIV, // Equiv + GL_AND_INVERTED, // AndInverted + GL_OR_REVERSE, // OrReverse + GL_OR_INVERTED, // OrInverted + }; + + // Range check table for input + if ((unsigned)op >= ARRAY_SIZE(logic_op_table)) { + LOG_CRITICAL(Render_OpenGL, "Unknown logic op %d", op); + UNREACHABLE(); + + return GL_COPY; + } + + return logic_op_table[(unsigned)op]; +} + inline GLenum CompareFunc(Pica::Regs::CompareFunc func) { static const GLenum compare_func_table[] = { 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..3399ca123 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& state.texture_units[0].enabled_2d = true; state.texture_units[0].texture_2d = texture.handle; state.Apply(); - + glActiveTexture(GL_TEXTURE0); glPixelStorei(GL_UNPACK_ROW_LENGTH, (GLint)pixel_stride); @@ -170,6 +170,9 @@ void RendererOpenGL::LoadFBToActiveGLTexture(const GPU::Regs::FramebufferConfig& texture.gl_format, texture.gl_type, framebuffer_data); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); + + state.texture_units[0].texture_2d = 0; + state.Apply(); } /** @@ -239,6 +242,9 @@ void RendererOpenGL::InitOpenGLObjects() { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } + state.texture_units[0].texture_2d = 0; + state.Apply(); + hw_rasterizer->InitObjects(); } @@ -370,6 +376,8 @@ void RendererOpenGL::Init() { } LOG_INFO(Render_OpenGL, "GL_VERSION: %s", glGetString(GL_VERSION)); + LOG_INFO(Render_OpenGL, "GL_VENDOR: %s", glGetString(GL_VENDOR)); + LOG_INFO(Render_OpenGL, "GL_RENDERER: %s", glGetString(GL_RENDERER)); InitOpenGLObjects(); } 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) { switch (instr.opcode.Value().GetInfo().type) { case OpCode::Type::Arithmetic: { - bool is_inverted = 0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed); - // TODO: We don't really support this properly: For instance, the address register - // offset needs to be applied to SRC2 instead, etc. - // For now, we just abort in this situation. - ASSERT_MSG(!is_inverted, "Bad condition..."); + const bool is_inverted = (0 != (instr.opcode.Value().GetInfo().subtype & OpCode::Info::SrcInversed)); const int address_offset = (instr.common.address_register_index == 0) ? 0 : state.address_registers[instr.common.address_register_index - 1]; - const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + address_offset); - const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted)); + const float24* src1_ = LookupSourceRegister(instr.common.GetSrc1(is_inverted) + (!is_inverted * address_offset)); + const float24* src2_ = LookupSourceRegister(instr.common.GetSrc2(is_inverted) + ( is_inverted * address_offset)); const bool negate_src1 = ((bool)swizzle.negate_src1 != false); const bool negate_src2 = ((bool)swizzle.negate_src2 != false); @@ -208,6 +204,15 @@ static void ProcessShaderCode(VertexShaderState& state) { } break; + case OpCode::Id::MIN: + for (int i = 0; i < 4; ++i) { + if (!swizzle.DestComponentEnabled(i)) + continue; + + dest[i] = std::min(src1[i], src2[i]); + } + break; + case OpCode::Id::DP3: case OpCode::Id::DP4: { @@ -279,6 +284,16 @@ static void ProcessShaderCode(VertexShaderState& state) { break; } + case OpCode::Id::SLT: + case OpCode::Id::SLTI: + for (int i = 0; i < 4; ++i) { + if (!swizzle.DestComponentEnabled(i)) + continue; + + dest[i] = (src1[i] < src2[i]) ? float24::FromFloat32(1.0f) : float24::FromFloat32(0.0f); + } + break; + case OpCode::Id::CMP: for (int i = 0; i < 2; ++i) { // TODO: Can you restrict to one compare via dest masking? @@ -330,7 +345,7 @@ static void ProcessShaderCode(VertexShaderState& state) { case OpCode::Type::MultiplyAdd: { - if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) || + if ((instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MAD) || (instr.opcode.Value().EffectiveOpCode() == OpCode::Id::MADI)) { const SwizzlePattern& swizzle = *(SwizzlePattern*)&swizzle_data[instr.mad.operand_desc_id]; @@ -547,7 +562,7 @@ OutputVertex RunShader(const InputVertex& input, int num_attributes) { const auto& attribute_register_map = regs.vs_input_register_map; float24 dummy_register; boost::fill(state.input_register_table, &dummy_register); - + if (num_attributes > 0) state.input_register_table[attribute_register_map.attribute0_register] = &input.attr[0].x; if (num_attributes > 1) state.input_register_table[attribute_register_map.attribute1_register] = &input.attr[1].x; if (num_attributes > 2) state.input_register_table[attribute_register_map.attribute2_register] = &input.attr[2].x; |