Remove libretro core - core will now be maintained by libretro

libretro have agreed to take over maintenance of the core.

Please see their fork at https://github.com/libretro/duckstation if you
wish to continue to use it.
This commit is contained in:
Connor McLaughlin 2021-01-08 01:11:19 +10:00
parent 573c8370d7
commit 419726f4cc
42 changed files with 108 additions and 8065 deletions

View file

@ -62,7 +62,6 @@ jobs:
del /Q bin\x64\*.iobj
del /Q bin\x64\*.ipdb
del /Q bin\x64\common-tests*
del /Q bin\x64\duckstation-libretro-*
rename bin\x64\updater-x64-ReleaseLTCG.exe updater.exe
- name: Create x64 release archive
@ -76,6 +75,35 @@ jobs:
name: "windows"
path: "duckstation-windows-x64-release.zip"
windows-arm64-build:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2.3.1
with:
fetch-depth: 0
submodules: true
- name: Tag as preview build
if: github.ref == 'refs/heads/master'
shell: cmd
run: |
echo #pragma once > src/scmversion/tag.h
echo #define SCM_RELEASE_ASSET "duckstation-windows-x64-release.zip" >> src/scmversion/tag.h
echo #define SCM_RELEASE_TAGS {"latest", "preview"} >> src/scmversion/tag.h
echo #define SCM_RELEASE_TAG "preview" >> src/scmversion/tag.h
- name: Tag as dev build
if: github.ref == 'refs/heads/dev'
shell: cmd
run: |
echo #pragma once > src/scmversion/tag.h
echo #define SCM_RELEASE_ASSET "duckstation-windows-x64-release.zip" >> src/scmversion/tag.h
echo #define SCM_RELEASE_TAGS {"latest", "preview"} >> src/scmversion/tag.h
echo #define SCM_RELEASE_TAG "latest" >> src/scmversion/tag.h
- name: Compile arm64 release build
shell: cmd
run: |
@ -91,7 +119,6 @@ jobs:
del /Q bin\ARM64\*.iobj
del /Q bin\ARM64\*.ipdb
del /Q bin\ARM64\common-tests*
del /Q bin\ARM64\duckstation-libretro-*
rename bin\ARM64\updater-ARM64-ReleaseLTCG.exe updater.exe
- name: Create arm64 release archive
@ -102,39 +129,10 @@ jobs:
- name: Upload arm64 release artifact
uses: actions/upload-artifact@v1
with:
name: "windows"
name: "windows-arm64"
path: "duckstation-windows-arm64-release.zip"
windows-libretro-build:
runs-on: windows-2019
steps:
- uses: actions/checkout@v2.3.1
with:
fetch-depth: 0
- name: Compile release build
shell: cmd
run: |
call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Enterprise\VC\Auxiliary\Build\vcvarsall.bat" x64
mkdir build
cd build
cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON -DCMAKE_C_COMPILER:FILEPATH="%VCToolsInstallDir%\bin\HostX64\x64\cl.exe" -DCMAKE_CXX_COMPILER:FILEPATH="%VCToolsInstallDir%\bin\HostX64\x64\cl.exe" ..
ninja
- name: Create libretro core archive
shell: cmd
run: |
cd build
"C:\Program Files\7-Zip\7z.exe" a -r duckstation_libretro.dll.zip ./duckstation_libretro.dll
- name: Upload release artifact
uses: actions/upload-artifact@v1
with:
name: "windows-libretro-x64"
path: "build/duckstation_libretro.dll.zip"
linux-build:
runs-on: ubuntu-18.04
steps:
@ -182,95 +180,6 @@ jobs:
path: "build/duckstation-qt-x64.AppImage.zsync"
linux-libretro-build:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2.3.1
with:
fetch-depth: 0
- name: Install packages
shell: bash
run: |
sudo apt-get update
sudo apt-get -y install gcc-aarch64-linux-gnu g++-aarch64-linux-gnu gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
- name: Compile and zip Linux x64 libretro core
shell: bash
run: |
mkdir build-libretro-linux-x64
cd build-libretro-linux-x64
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON ..
cmake --build . --parallel 2
zip -j duckstation_libretro_x64.so.zip duckstation_libretro.so
- name: Upload Linux x64 libretro core
uses: actions/upload-artifact@v1
with:
name: "linux-libretro"
path: "build-libretro-linux-x64/duckstation_libretro_x64.so.zip"
- name: Compile and zip Linux armv7 libretro core
shell: bash
run: |
mkdir build-libretro-linux-armv7
cd build-libretro-linux-armv7
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON -DCMAKE_TOOLCHAIN_FILE=../CMakeModules/armv7-cross-toolchain.cmake ..
cmake --build . --parallel 2
zip -j duckstation_libretro_linux_armv7.so.zip duckstation_libretro.so
- name: Upload Linux AArch64 libretro core
uses: actions/upload-artifact@v1
with:
name: "linux-libretro"
path: "build-libretro-linux-armv7/duckstation_libretro_linux_armv7.so.zip"
- name: Compile and zip Linux AArch64 libretro core
shell: bash
run: |
mkdir build-libretro-linux-aarch64
cd build-libretro-linux-aarch64
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON -DCMAKE_TOOLCHAIN_FILE=../CMakeModules/aarch64-cross-toolchain.cmake ..
cmake --build . --parallel 2
zip -j duckstation_libretro_linux_aarch64.so.zip duckstation_libretro.so
- name: Upload Linux AArch64 libretro core
uses: actions/upload-artifact@v1
with:
name: "linux-libretro"
path: "build-libretro-linux-aarch64/duckstation_libretro_linux_aarch64.so.zip"
- name: Compile and zip Android armv7 libretro core
shell: bash
run: |
mkdir build-libretro-android-armv7
cd build-libretro-android-armv7
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON -DANDROID_ABI=armeabi-v7a -DANDROID_ARM_NEON=ON -DCMAKE_TOOLCHAIN_FILE=${ANDROID_SDK_ROOT}/ndk-bundle/build/cmake/android.toolchain.cmake ..
cmake --build . --parallel 2
zip -j duckstation_libretro_android_armv7.so.zip duckstation_libretro_android.so
- name: Upload Android armv7 libretro core
uses: actions/upload-artifact@v1
with:
name: "linux-libretro"
path: "build-libretro-android-armv7/duckstation_libretro_android_armv7.so.zip"
- name: Compile and zip Android AArch64 libretro core
shell: bash
run: |
mkdir build-libretro-android-aarch64
cd build-libretro-android-aarch64
cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON -DANDROID_ABI=arm64-v8a -DCMAKE_TOOLCHAIN_FILE=${ANDROID_SDK_ROOT}/ndk-bundle/build/cmake/android.toolchain.cmake ..
cmake --build . --parallel 2
zip -j duckstation_libretro_android_aarch64.so.zip duckstation_libretro_android.so
- name: Upload Android AArch64 libretro core
uses: actions/upload-artifact@v1
with:
name: "linux-libretro"
path: "build-libretro-android-aarch64/duckstation_libretro_android_aarch64.so.zip"
android-build:
runs-on: ubuntu-20.04
steps:
@ -342,25 +251,9 @@ jobs:
name: "macos-x64"
path: "build/bin/duckstation-mac-release.zip"
- name: Compile libretro core and zip
shell: bash
run: |
mkdir build-libretro
cd build-libretro
export MACOSX_DEPLOYMENT_TARGET=10.14
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON ..
cmake --build . --parallel 2
zip -j duckstation_libretro_mac.dylib.zip duckstation_libretro.dylib
- name: Upload macOS libretro core
uses: actions/upload-artifact@v1
with:
name: "macos-x64"
path: "build-libretro/duckstation_libretro_mac.dylib.zip"
create-release:
needs: [windows-build, windows-libretro-build, linux-build, linux-libretro-build, android-build, macos-build]
needs: [windows-build, windows-arm64-build, linux-build, android-build, macos-build]
runs-on: "ubuntu-latest"
if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/dev'
steps:
@ -369,10 +262,10 @@ jobs:
with:
name: "windows"
- name: Download Windows libretro x64 Artifact
- name: Download Windows ARM64 Artifact
uses: actions/download-artifact@v1
with:
name: "windows-libretro-x64"
name: "windows-arm64"
- name: Download SDL AppImage Artifact
uses: actions/download-artifact@v1
@ -394,11 +287,6 @@ jobs:
with:
name: "linux-x64-appimage-qt-zsync"
- name: Download Linux libretro core
uses: actions/download-artifact@v1
with:
name: "linux-libretro"
- name: Download Android APK
uses: actions/download-artifact@v1
with:
@ -419,20 +307,12 @@ jobs:
title: "Latest Preview Build"
files: |
windows/duckstation-windows-x64-release.zip
windows/duckstation-windows-arm64-release.zip
windows-libretro-x64/duckstation_libretro.dll.zip
windows-arm64/duckstation-windows-arm64-release.zip
linux-x64-appimage-sdl/duckstation-sdl-x64.AppImage
linux-x64-appimage-sdl-zsync/duckstation-sdl-x64.AppImage.zsync
linux-x64-appimage-qt/duckstation-qt-x64.AppImage
linux-x64-appimage-qt-zsync/duckstation-qt-x64.AppImage.zsync
linux-libretro/duckstation_libretro_x64.so.zip
linux-libretro/duckstation_libretro_linux_armv7.so.zip
linux-libretro/duckstation_libretro_linux_aarch64.so.zip
linux-libretro/duckstation_libretro_android_armv7.so.zip
linux-libretro/duckstation_libretro_android_aarch64.so.zip
android/duckstation-android.apk
macos-x64/duckstation-mac-release.zip
macos-x64/duckstation_libretro_mac.dylib.zip
- name: Create dev release
if: github.ref == 'refs/heads/dev'
@ -444,18 +324,11 @@ jobs:
title: "Latest Development Build"
files: |
windows/duckstation-windows-x64-release.zip
windows/duckstation-windows-arm64-release.zip
windows-libretro-x64/duckstation_libretro.dll.zip
windows-arm64/duckstation-windows-arm64-release.zip
linux-x64-appimage-sdl/duckstation-sdl-x64.AppImage
linux-x64-appimage-sdl-zsync/duckstation-sdl-x64.AppImage.zsync
linux-x64-appimage-qt/duckstation-qt-x64.AppImage
linux-x64-appimage-qt-zsync/duckstation-qt-x64.AppImage.zsync
linux-libretro/duckstation_libretro_x64.so.zip
linux-libretro/duckstation_libretro_linux_armv7.so.zip
linux-libretro/duckstation_libretro_linux_aarch64.so.zip
linux-libretro/duckstation_libretro_android_armv7.so.zip
linux-libretro/duckstation_libretro_android_aarch64.so.zip
android/duckstation-android.apk
macos-x64/duckstation-mac-release.zip
macos-x64/duckstation_libretro_mac.dylib.zip

View file

@ -20,7 +20,6 @@ set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14.0" CACHE STRING "")
if(NOT ANDROID)
option(BUILD_SDL_FRONTEND "Build the SDL frontend" ON)
option(BUILD_QT_FRONTEND "Build the Qt frontend" ON)
option(BUILD_LIBRETRO_CORE "Build a libretro core" OFF)
option(ENABLE_DISCORD_PRESENCE "Build with Discord Rich Presence support" ON)
option(USE_SDL2 "Link with SDL2 for controller support" ON)
endif()
@ -42,8 +41,7 @@ if(USE_WAYLAND)
set(USE_EGL ON)
endif()
# When we're building for libretro, everything else is invalid because of PIC.
if(ANDROID OR BUILD_LIBRETRO_CORE)
if(ANDROID)
if(BUILD_SDL_FRONTEND)
message(WARNING "Building for Android or libretro core, disabling SDL frontend")
set(BUILD_SDL_FRONTEND OFF)
@ -66,14 +64,9 @@ if(ANDROID OR BUILD_LIBRETRO_CORE)
if(USE_WAYLAND)
set(USE_WAYLAND OFF)
endif()
if(BUILD_LIBRETRO_CORE AND USE_EGL)
if(USE_EGL)
set(USE_EGL OFF)
endif()
# Force PIC when compiling a libretro core.
if(BUILD_LIBRETRO_CORE)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
endif()
@ -211,7 +204,7 @@ endif()
# Write binaries to a seperate directory.
if(WIN32 AND NOT BUILD_LIBRETRO_CORE)
if(WIN32)
# For Windows, use the source directory, except for libretro.
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/bin/${CPU_ARCH}")
else()
@ -232,6 +225,6 @@ enable_testing()
add_subdirectory(dep)
add_subdirectory(src)
if(ANDROID AND NOT BUILD_LIBRETRO_CORE)
if(ANDROID)
add_subdirectory(android/app/src/cpp)
endif()

View file

@ -1,9 +1,9 @@
# DuckStation - PlayStation 1, aka. PSX Emulator
[Latest News](#latest-news) | [Features](#features) | [Screenshots](#screenshots) | [Downloading and Running](#downloading-and-running) | [Libretro Core](#libretro-core) | [Building](#building) | [Disclaimers](#disclaimers)
[Latest News](#latest-news) | [Features](#features) | [Screenshots](#screenshots) | [Downloading and Running](#downloading-and-running) | [Building](#building) | [Disclaimers](#disclaimers)
**Discord Server:** https://discord.gg/Buktv3t
**Latest Windows, Linux (AppImage), Mac, Android, and Libretro Builds:** https://github.com/stenzek/duckstation/releases/tag/latest
**Latest Windows, Linux (AppImage), Mac, Android** https://github.com/stenzek/duckstation/releases/tag/latest
**Available on Google Play:** https://play.google.com/store/apps/details?id=com.github.stenzek.duckstation&hl=en_AU&gl=US
@ -32,7 +32,6 @@ Older entries are available at https://github.com/stenzek/duckstation/blob/maste
- 2020/12/10: Translation support added for Android version. Currently Brazillian Portuguese, Italian, and Dutch are available.
- 2020/11/27: Cover support added for game list in Android version. Procedure is the same as the desktop version, except you should place cover images in `<storage>/duckstation/covers` (see [Adding Game Covers](https://github.com/stenzek/duckstation/wiki/Adding-Game-Covers)).
- 2020/11/27: Disc database is shipped with desktop and Android versions courtesy of redump.org. This will provide titles for games on Android, where it was not possible previously.
- 2020/11/27: Compatibility databases added to libretro core - broken enhancements will be automatically disabled. You can turn this off by disabling "Apply Compatibility Settings" in the core options.
- 2020/11/27: SDL game controller database is included with desktop versions courtesy of https://github.com/gabomdq/SDL_GameControllerDB.
- 2020/11/21: OpenGL ES 2.0 host display support added. You cannot use the hardware renderer with GLES2, it still requires GLES3, but GLES2 GPUs can now use the software renderer.
- 2020/11/21: Threaded renderer for software renderer added. Can result in a significant speed boost depending on the game.
@ -270,22 +269,6 @@ Hotkeys:
- **Page Up/Down:** Increase/decrease resolution scale in hardware renderers
- **End:** Toggle software renderer
## Libretro Core
DuckStation is available as a libretro core, supporting most of the features of the full frontend within the constraints and limitations of being a libretro core.
As of December 2020, the libretro core is no longer supported by the developer. The core will remain in the tree, but fixing any issues will not be a priority,
and any bugs must be tested in the standalone version prior to being reported.
To build on Windows, use cmake using the following commands from a `x64 Native Tools Command Prompt for VS 2019`:
- mkdir build
- cd build
- cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON ..
You should then have a file named `duckstation_libretro.dll` which can be loaded as a core.
To build on Linux, follow the same instructions as for a normal build, but for cmake use `cmake -DCMAKE_BUILD_TYPE=Release -DBUILD_LIBRETRO_CORE=ON ..`. The shared library will be named `duckstation_libretro.so` in the current directory.
## Tests
- Passes amidog's CPU and GTE tests in both interpreter and recompiler modes, partial passing of CPX tests

View file

@ -10,14 +10,11 @@ add_subdirectory(xxhash)
add_subdirectory(rapidjson)
add_subdirectory(glslang)
add_subdirectory(vulkan-loader)
if(NOT BUILD_LIBRETRO_CORE)
add_subdirectory(googletest)
add_subdirectory(cubeb)
add_subdirectory(imgui)
add_subdirectory(simpleini)
add_subdirectory(tinyxml2)
endif()
add_subdirectory(googletest)
add_subdirectory(cubeb)
add_subdirectory(imgui)
add_subdirectory(simpleini)
add_subdirectory(tinyxml2)
if(ENABLE_DISCORD_PRESENCE)
add_subdirectory(discord-rpc)
@ -27,10 +24,6 @@ if(BUILD_SDL_FRONTEND)
add_subdirectory(nativefiledialog)
endif()
if(BUILD_LIBRETRO_CORE)
add_subdirectory(libretro-common)
endif()
if(${CPU_ARCH} STREQUAL "aarch32" OR ${CPU_ARCH} STREQUAL "aarch64")
add_subdirectory(vixl)
endif()

View file

@ -1,2 +0,0 @@
add_library(libretro-common INTERFACE)
target_include_directories(libretro-common INTERFACE "${CMAKE_CURRENT_SOURCE_DIR}/include/")

File diff suppressed because it is too large Load diff

View file

@ -1,59 +0,0 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro_d3d.h)
* ---------------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the
* "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following
* conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or
* substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LIBRETRO_DIRECT3D_H__
#define LIBRETRO_DIRECT3D_H__
#include "libretro.h"
#ifdef HAVE_D3D11
#include <d3d11.h>
#include <d3dcompiler.h>
#define RETRO_HW_RENDER_INTERFACE_D3D11_VERSION 1
struct retro_hw_render_interface_d3d11
{
/* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11. */
enum retro_hw_render_interface_type interface_type;
/* Must be set to RETRO_HW_RENDER_INTERFACE_D3D11_VERSION. */
unsigned interface_version;
/* Opaque handle to the d3d11 backend in the frontend
* which must be passed along to all function pointers
* in this interface.
*/
void* handle;
ID3D11Device *device;
ID3D11DeviceContext *context;
D3D_FEATURE_LEVEL featureLevel;
pD3DCompile D3DCompile;
};
#endif
#endif /* LIBRETRO_DIRECT3D_H__ */

View file

@ -1,397 +0,0 @@
/* Copyright (C) 2010-2020 The RetroArch team
*
* ---------------------------------------------------------------------------------------------
* The following license statement only applies to this libretro API header (libretro_vulkan.h)
* ---------------------------------------------------------------------------------------------
*
* Permission is hereby granted, free of charge,
* to any person obtaining a copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
* and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef LIBRETRO_VULKAN_H__
#define LIBRETRO_VULKAN_H__
#include <libretro.h>
#include <vulkan/vulkan.h>
#define RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION 5
#define RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION 1
struct retro_vulkan_image
{
VkImageView image_view;
VkImageLayout image_layout;
VkImageViewCreateInfo create_info;
};
typedef void (*retro_vulkan_set_image_t)(void *handle,
const struct retro_vulkan_image *image,
uint32_t num_semaphores,
const VkSemaphore *semaphores,
uint32_t src_queue_family);
typedef uint32_t (*retro_vulkan_get_sync_index_t)(void *handle);
typedef uint32_t (*retro_vulkan_get_sync_index_mask_t)(void *handle);
typedef void (*retro_vulkan_set_command_buffers_t)(void *handle,
uint32_t num_cmd,
const VkCommandBuffer *cmd);
typedef void (*retro_vulkan_wait_sync_index_t)(void *handle);
typedef void (*retro_vulkan_lock_queue_t)(void *handle);
typedef void (*retro_vulkan_unlock_queue_t)(void *handle);
typedef void (*retro_vulkan_set_signal_semaphore_t)(void *handle, VkSemaphore semaphore);
typedef const VkApplicationInfo *(*retro_vulkan_get_application_info_t)(void);
struct retro_vulkan_context
{
VkPhysicalDevice gpu;
VkDevice device;
VkQueue queue;
uint32_t queue_family_index;
VkQueue presentation_queue;
uint32_t presentation_queue_family_index;
};
typedef bool (*retro_vulkan_create_device_t)(
struct retro_vulkan_context *context,
VkInstance instance,
VkPhysicalDevice gpu,
VkSurfaceKHR surface,
PFN_vkGetInstanceProcAddr get_instance_proc_addr,
const char **required_device_extensions,
unsigned num_required_device_extensions,
const char **required_device_layers,
unsigned num_required_device_layers,
const VkPhysicalDeviceFeatures *required_features);
typedef void (*retro_vulkan_destroy_device_t)(void);
/* Note on thread safety:
* The Vulkan API is heavily designed around multi-threading, and
* the libretro interface for it should also be threading friendly.
* A core should be able to build command buffers and submit
* command buffers to the GPU from any thread.
*/
struct retro_hw_render_context_negotiation_interface_vulkan
{
/* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN. */
enum retro_hw_render_context_negotiation_interface_type interface_type;
/* Must be set to RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION. */
unsigned interface_version;
/* If non-NULL, returns a VkApplicationInfo struct that the frontend can use instead of
* its "default" application info.
*/
retro_vulkan_get_application_info_t get_application_info;
/* If non-NULL, the libretro core will choose one or more physical devices,
* create one or more logical devices and create one or more queues.
* The core must prepare a designated PhysicalDevice, Device, Queue and queue family index
* which the frontend will use for its internal operation.
*
* If gpu is not VK_NULL_HANDLE, the physical device provided to the frontend must be this PhysicalDevice.
* The core is still free to use other physical devices.
*
* The frontend will request certain extensions and layers for a device which is created.
* The core must ensure that the queue and queue_family_index support GRAPHICS and COMPUTE.
*
* If surface is not VK_NULL_HANDLE, the core must consider presentation when creating the queues.
* If presentation to "surface" is supported on the queue, presentation_queue must be equal to queue.
* If not, a second queue must be provided in presentation_queue and presentation_queue_index.
* If surface is not VK_NULL_HANDLE, the instance from frontend will have been created with supported for
* VK_KHR_surface extension.
*
* The core is free to set its own queue priorities.
* Device provided to frontend is owned by the frontend, but any additional device resources must be freed by core
* in destroy_device callback.
*
* If this function returns true, a PhysicalDevice, Device and Queues are initialized.
* If false, none of the above have been initialized and the frontend will attempt
* to fallback to "default" device creation, as if this function was never called.
*/
retro_vulkan_create_device_t create_device;
/* If non-NULL, this callback is called similar to context_destroy for HW_RENDER_INTERFACE.
* However, it will be called even if context_reset was not called.
* This can happen if the context never succeeds in being created.
* destroy_device will always be called before the VkInstance
* of the frontend is destroyed if create_device was called successfully so that the core has a chance of
* tearing down its own device resources.
*
* Only auxillary resources should be freed here, i.e. resources which are not part of retro_vulkan_context.
*/
retro_vulkan_destroy_device_t destroy_device;
};
struct retro_hw_render_interface_vulkan
{
/* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN. */
enum retro_hw_render_interface_type interface_type;
/* Must be set to RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION. */
unsigned interface_version;
/* Opaque handle to the Vulkan backend in the frontend
* which must be passed along to all function pointers
* in this interface.
*
* The rationale for including a handle here (which libretro v1
* doesn't currently do in general) is:
*
* - Vulkan cores should be able to be freely threaded without lots of fuzz.
* This would break frontends which currently rely on TLS
* to deal with multiple cores loaded at the same time.
* - Fixing this in general is TODO for an eventual libretro v2.
*/
void *handle;
/* The Vulkan instance the context is using. */
VkInstance instance;
/* The physical device used. */
VkPhysicalDevice gpu;
/* The logical device used. */
VkDevice device;
/* Allows a core to fetch all its needed symbols without having to link
* against the loader itself. */
PFN_vkGetDeviceProcAddr get_device_proc_addr;
PFN_vkGetInstanceProcAddr get_instance_proc_addr;
/* The queue the core must use to submit data.
* This queue and index must remain constant throughout the lifetime
* of the context.
*
* This queue will be the queue that supports graphics and compute
* if the device supports compute.
*/
VkQueue queue;
unsigned queue_index;
/* Before calling retro_video_refresh_t with RETRO_HW_FRAME_BUFFER_VALID,
* set which image to use for this frame.
*
* If num_semaphores is non-zero, the frontend will wait for the
* semaphores provided to be signaled before using the results further
* in the pipeline.
*
* Semaphores provided by a single call to set_image will only be
* waited for once (waiting for a semaphore resets it).
* E.g. set_image, video_refresh, and then another
* video_refresh without set_image,
* but same image will only wait for semaphores once.
*
* For this reason, ownership transfer will only occur if semaphores
* are waited on for a particular frame in the frontend.
*
* Using semaphores is optional for synchronization purposes,
* but if not using
* semaphores, an image memory barrier in vkCmdPipelineBarrier
* should be used in the graphics_queue.
* Example:
*
* vkCmdPipelineBarrier(cmd,
* srcStageMask = VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT,
* dstStageMask = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT,
* image_memory_barrier = {
* srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT,
* dstAccessMask = VK_ACCESS_SHADER_READ_BIT,
* });
*
* The use of pipeline barriers instead of semaphores is encouraged
* as it is simpler and more fine-grained. A layout transition
* must generally happen anyways which requires a
* pipeline barrier.
*
* The image passed to set_image must have imageUsage flags set to at least
* VK_IMAGE_USAGE_TRANSFER_SRC_BIT and VK_IMAGE_USAGE_SAMPLED_BIT.
* The core will naturally want to use flags such as
* VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT and/or
* VK_IMAGE_USAGE_TRANSFER_DST_BIT depending
* on how the final image is created.
*
* The image must also have been created with MUTABLE_FORMAT bit set if
* 8-bit formats are used, so that the frontend can reinterpret sRGB
* formats as it sees fit.
*
* Images passed to set_image should be created with TILING_OPTIMAL.
* The image layout should be transitioned to either
* VK_IMAGE_LAYOUT_GENERIC or VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL.
* The actual image layout used must be set in image_layout.
*
* The image must be a 2D texture which may or not be layered
* and/or mipmapped.
*
* The image must be suitable for linear sampling.
* While the image_view is typically the only field used,
* the frontend may want to reinterpret the texture as sRGB vs.
* non-sRGB for example so the VkImageViewCreateInfo used to
* create the image view must also be passed in.
*
* The data in the pointer to the image struct will not be copied
* as the pNext field in create_info cannot be reliably deep-copied.
* The image pointer passed to set_image must be valid until
* retro_video_refresh_t has returned.
*
* If frame duping is used when passing NULL to retro_video_refresh_t,
* the frontend is free to either use the latest image passed to
* set_image or reuse the older pointer passed to set_image the
* frame RETRO_HW_FRAME_BUFFER_VALID was last used.
*
* Essentially, the lifetime of the pointer passed to
* retro_video_refresh_t should be extended if frame duping is used
* so that the frontend can reuse the older pointer.
*
* The image itself however, must not be touched by the core until
* wait_sync_index has been completed later. The frontend may perform
* layout transitions on the image, so even read-only access is not defined.
* The exception to read-only rule is if GENERAL layout is used for the image.
* In this case, the frontend is not allowed to perform any layout transitions,
* so concurrent reads from core and frontend are allowed.
*
* If frame duping is used, or if set_command_buffers is used,
* the frontend will not wait for any semaphores.
*
* The src_queue_family is used to specify which queue family
* the image is currently owned by. If using multiple queue families
* (e.g. async compute), the frontend will need to acquire ownership of the
* image before rendering with it and release the image afterwards.
*
* If src_queue_family is equal to the queue family (queue_index),
* no ownership transfer will occur.
* Similarly, if src_queue_family is VK_QUEUE_FAMILY_IGNORED,
* no ownership transfer will occur.
*
* The frontend will always release ownership back to src_queue_family.
* Waiting for frontend to complete with wait_sync_index() ensures that
* the frontend has released ownership back to the application.
* Note that in Vulkan, transfering ownership is a two-part process.
*
* Example frame:
* - core releases ownership from src_queue_index to queue_index with VkImageMemoryBarrier.
* - core calls set_image with src_queue_index.
* - Frontend will acquire the image with src_queue_index -> queue_index as well, completing the ownership transfer.
* - Frontend renders the frame.
* - Frontend releases ownership with queue_index -> src_queue_index.
* - Next time image is used, core must acquire ownership from queue_index ...
*
* Since the frontend releases ownership, we cannot necessarily dupe the frame because
* the core needs to make the roundtrip of ownership transfer.
*/
retro_vulkan_set_image_t set_image;
/* Get the current sync index for this frame which is obtained in
* frontend by calling e.g. vkAcquireNextImageKHR before calling
* retro_run().
*
* This index will correspond to which swapchain buffer is currently
* the active one.
*
* Knowing this index is very useful for maintaining safe asynchronous CPU
* and GPU operation without stalling.
*
* The common pattern for synchronization is to receive fences when
* submitting command buffers to Vulkan (vkQueueSubmit) and add this fence
* to a list of fences for frame number get_sync_index().
*
* Next time we receive the same get_sync_index(), we can wait for the
* fences from before, which will usually return immediately as the
* frontend will generally also avoid letting the GPU run ahead too much.
*
* After the fence has signaled, we know that the GPU has completed all
* GPU work related to work submitted in the frame we last saw get_sync_index().
*
* This means we can safely reuse or free resources allocated in this frame.
*
* In theory, even if we wait for the fences correctly, it is not technically
* safe to write to the image we earlier passed to the frontend since we're
* not waiting for the frontend GPU jobs to complete.
*
* The frontend will guarantee that the appropriate pipeline barrier
* in graphics_queue has been used such that
* VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT cannot
* start until the frontend is done with the image.
*/
retro_vulkan_get_sync_index_t get_sync_index;
/* Returns a bitmask of how many swapchain images we currently have
* in the frontend.
*
* If bit #N is set in the return value, get_sync_index can return N.
* Knowing this value is useful for preallocating per-frame management
* structures ahead of time.
*
* While this value will typically remain constant throughout the
* applications lifecycle, it may for example change if the frontend
* suddently changes fullscreen state and/or latency.
*
* If this value ever changes, it is safe to assume that the device
* is completely idle and all synchronization objects can be deleted
* right away as desired.
*/
retro_vulkan_get_sync_index_mask_t get_sync_index_mask;
/* Instead of submitting the command buffer to the queue first, the core
* can pass along its command buffer to the frontend, and the frontend
* will submit the command buffer together with the frontends command buffers.
*
* This has the advantage that the overhead of vkQueueSubmit can be
* amortized into a single call. For this mode, semaphores in set_image
* will be ignored, so vkCmdPipelineBarrier must be used to synchronize
* the core and frontend.
*
* The command buffers in set_command_buffers are only executed once,
* even if frame duping is used.
*
* If frame duping is used, set_image should be used for the frames
* which should be duped instead.
*
* Command buffers passed to the frontend with set_command_buffers
* must not actually be submitted to the GPU until retro_video_refresh_t
* is called.
*
* The frontend must submit the command buffer before submitting any
* other command buffers provided by set_command_buffers. */
retro_vulkan_set_command_buffers_t set_command_buffers;
/* Waits on CPU for device activity for the current sync index to complete.
* This is useful since the core will not have a relevant fence to sync with
* when the frontend is submitting the command buffers. */
retro_vulkan_wait_sync_index_t wait_sync_index;
/* If the core submits command buffers itself to any of the queues provided
* in this interface, the core must lock and unlock the frontend from
* racing on the VkQueue.
*
* Queue submission can happen on any thread.
* Even if queue submission happens on the same thread as retro_run(),
* the lock/unlock functions must still be called.
*
* NOTE: Queue submissions are heavy-weight. */
retro_vulkan_lock_queue_t lock_queue;
retro_vulkan_unlock_queue_t unlock_queue;
/* Sets a semaphore which is signaled when the image in set_image can safely be reused.
* The semaphore is consumed next call to retro_video_refresh_t.
* The semaphore will be signalled even for duped frames.
* The semaphore will be signalled only once, so set_signal_semaphore should be called every frame.
* The semaphore may be VK_NULL_HANDLE, which disables semaphore signalling for next call to retro_video_refresh_t.
*
* This is mostly useful to support use cases where you're rendering to a single image that
* is recycled in a ping-pong fashion with the frontend to save memory (but potentially less throughput).
*/
retro_vulkan_set_signal_semaphore_t set_signal_semaphore;
};
#endif

View file

@ -51,8 +51,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "scmversion", "src\scmversio
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "discord-rpc", "dep\discord-rpc\discord-rpc.vcxproj", "{4266505B-DBAF-484B-AB31-B53B9C8235B3}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duckstation-libretro", "src\duckstation-libretro\duckstation-libretro.vcxproj", "{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "glslang", "dep\glslang\glslang.vcxproj", "{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}"
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "vulkan-loader", "dep\vulkan-loader\vulkan-loader.vcxproj", "{9C8DDEB0-2B8F-4F5F-BA86-127CDF27F035}"
@ -629,18 +627,6 @@ Global
{4266505B-DBAF-484B-AB31-B53B9C8235B3}.ReleaseLTCG|x64.Build.0 = ReleaseLTCG|x64
{4266505B-DBAF-484B-AB31-B53B9C8235B3}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{4266505B-DBAF-484B-AB31-B53B9C8235B3}.ReleaseLTCG|x86.Build.0 = ReleaseLTCG|Win32
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|ARM64.ActiveCfg = Debug|ARM64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|x64.ActiveCfg = Debug|x64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Debug|x86.ActiveCfg = Debug|Win32
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|ARM64.ActiveCfg = DebugFast|ARM64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|x64.ActiveCfg = DebugFast|x64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.DebugFast|x86.ActiveCfg = DebugFast|Win32
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|ARM64.ActiveCfg = Release|ARM64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|x64.ActiveCfg = Release|x64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.Release|x86.ActiveCfg = Release|Win32
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|ARM64.ActiveCfg = ReleaseLTCG|ARM64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|x64.ActiveCfg = ReleaseLTCG|x64
{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}.ReleaseLTCG|x86.ActiveCfg = ReleaseLTCG|Win32
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.Debug|ARM64.ActiveCfg = Debug|ARM64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.Debug|ARM64.Build.0 = Debug|ARM64
{7F909E29-4808-4BD9-A60C-56C51A3AAEC2}.Debug|x64.ActiveCfg = Debug|x64

View file

@ -1,106 +0,0 @@
import sys
import configparser
def parse_ini(path):
config = configparser.ConfigParser()
config.read(path)
entries = {}
int_keys = {
"DisplayActiveStartOffset": "display_active_start_offset",
"DisplayActiveEndOffset": "display_active_end_offset",
"DMAMaxSliceTicks": "dma_max_slice_ticks",
"DMAHaltTicks": "dma_halt_ticks",
"GPUFIFOSize" : "gpu_fifo_size",
"GPUMaxRunAhead" : "gpu_max_run_ahead"
}
float_keys = {
"GPUPGXPTolerance" : "gpu_pgxp_tolerance"
}
traits = [
"ForceInterpreter",
"ForceSoftwareRenderer",
"ForceInterlacing",
"DisableTrueColor",
"DisableUpscaling",
"DisableScaledDithering",
"DisableForceNTSCTimings",
"DisableWidescreen",
"DisablePGXP",
"DisablePGXPCulling",
"DisablePGXPTextureCorrection",
"ForcePGXPVertexCache",
"ForcePGXPCPUMode",
"DisableAnalogModeForcing",
"ForceRecompilerMemoryExceptions",
"ForceRecompilerICache"
]
for gameid in config.sections():
entry = {}
for ini_key, cpp_key in int_keys.items():
try:
value = config.get(gameid, ini_key)
if value is not None:
entry[cpp_key] = str(value)
except configparser.NoOptionError:
pass
for ini_key, cpp_key in float_keys.items():
try:
value = config.getfloat(gameid, ini_key, fallback=None)
if value is not None:
entry[cpp_key] = str(value)
except configparser.NoOptionError:
pass
for trait in traits:
try:
value = config.getboolean(gameid, trait, fallback=None)
if value == True:
if "traits" not in entry:
entry["traits"] = []
entry["traits"].append(trait)
except configparser.NoOptionError:
pass
if len(entry) > 0:
entries[gameid] = entry
return entries
def write_cpp(entries, path):
print("Writing %u entries to '%s'" % (len(entries), path))
with open(path, "w") as f:
f.write('#include "libretro_game_settings.h"\n')
f.write('\n')
f.write('std::unique_ptr<GameSettings::Entry> GetSettingsForGame(const std::string& game_code)\n')
f.write('{\n')
f.write(' std::unique_ptr<GameSettings::Entry> gs = std::make_unique<GameSettings::Entry>();\n')
f.write('\n')
for gameid, entry in entries.items():
f.write(' if (game_code == "%s")\n' % gameid)
f.write(' {\n')
for key, value in entry.items():
if key == "traits":
for trait in value:
f.write(' gs->AddTrait(GameSettings::Trait::%s);\n' % trait)
else:
f.write(' gs->%s = %s;\n' % (key, value))
f.write(' return gs;\n')
f.write(' }\n')
f.write('\n')
f.write(' return {};\n')
f.write('}\n')
if __name__ == "__main__":
if len(sys.argv) < 3:
print("usage: %s <path to gamesettings.ini> <output cpp file>" % sys.argv[0])
sys.exit(1)
entries = parse_ini(sys.argv[1])
write_cpp(entries, sys.argv[2])

View file

@ -1,19 +1,13 @@
if(BUILD_LIBRETRO_CORE)
add_definitions("-DLIBRETRO=1")
endif()
add_subdirectory(common)
add_subdirectory(core)
add_subdirectory(scmversion)
if(NOT BUILD_LIBRETRO_CORE)
add_subdirectory(common-tests)
if(WIN32)
add_subdirectory(updater)
endif()
add_subdirectory(common-tests)
if(WIN32)
add_subdirectory(updater)
endif()
if(ANDROID OR BUILD_SDL_FRONTEND OR BUILD_QT_FRONTEND OR BUILD_LIBRETRO_CORE)
if(ANDROID OR BUILD_SDL_FRONTEND OR BUILD_QT_FRONTEND)
add_subdirectory(frontend-common)
endif()
@ -24,8 +18,3 @@ endif()
if(BUILD_QT_FRONTEND)
add_subdirectory(duckstation-qt)
endif()
if(BUILD_LIBRETRO_CORE)
add_subdirectory(duckstation-libretro)
endif()

View file

@ -179,9 +179,6 @@ endif()
if(APPLE)
# Needed for Vulkan Swap Chain.
target_link_libraries(common PRIVATE "objc")
endif()
if(APPLE AND NOT BUILD_LIBRETRO_CORE)
target_sources(common PRIVATE
gl/context_agl.mm
gl/context_agl.h

View file

@ -11,7 +11,7 @@ Log_SetChannel(GL::Context);
#if defined(WIN32) && !defined(_M_ARM64)
#include "context_wgl.h"
#elif defined(__APPLE__) && !defined(LIBERTRO)
#elif defined(__APPLE__)
#include "context_agl.h"
#endif
@ -77,7 +77,7 @@ std::unique_ptr<GL::Context> Context::Create(const WindowInfo& wi, const Version
std::unique_ptr<Context> context;
#if defined(WIN32) && !defined(_M_ARM64)
context = ContextWGL::Create(wi, versions_to_try, num_versions_to_try);
#elif defined(__APPLE__) && !defined(LIBRETRO)
#elif defined(__APPLE__)
context = ContextAGL::Create(wi, versions_to_try, num_versions_to_try);
#elif defined(ANDROID)
#ifdef USE_EGL

View file

@ -124,9 +124,7 @@ bool InitializeGlslang()
return false;
}
#ifndef LIBRETRO
std::atexit([]() { glslang::FinalizeProcess(); });
#endif
glslang_initialized = true;
return true;

View file

@ -12,7 +12,6 @@ struct WindowInfo
Wayland,
MacOS,
Android,
Libretro,
};
enum class SurfaceFormat

View file

@ -116,6 +116,9 @@ target_include_directories(core PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/..")
target_link_libraries(core PUBLIC Threads::Threads common zlib vulkan-loader)
target_link_libraries(core PRIVATE glad stb xxhash)
target_compile_definitions(core PRIVATE "WITH_IMGUI=1")
target_link_libraries(core PRIVATE imgui)
if(WIN32)
target_sources(core PRIVATE
gpu_hw_d3d11.cpp
@ -148,8 +151,3 @@ elseif(${CPU_ARCH} STREQUAL "aarch64")
else()
message("Not building recompiler")
endif()
if(NOT BUILD_LIBRETRO_CORE)
target_link_libraries(core PRIVATE imgui)
target_compile_definitions(core PRIVATE "WITH_IMGUI=1")
endif()

View file

@ -1,44 +0,0 @@
add_library(duckstation_libretro SHARED
libretro_audio_stream.cpp
libretro_audio_stream.h
libretro_game_settings.cpp
libretro_game_settings.h
libretro_host_display.cpp
libretro_host_display.h
libretro_host_interface.cpp
libretro_host_interface.h
libretro_opengl_host_display.cpp
libretro_opengl_host_display.h
libretro_settings_interface.cpp
libretro_settings_interface.h
libretro_vulkan_host_display.cpp
libretro_vulkan_host_display.h
main.cpp
)
if(WIN32)
target_sources(duckstation_libretro PRIVATE
libretro_d3d11_host_display.cpp
libretro_d3d11_host_display.h
)
endif()
target_link_libraries(duckstation_libretro PRIVATE core common glad scmversion frontend-common vulkan-loader libretro-common)
# no lib prefix
set_target_properties(duckstation_libretro PROPERTIES PREFIX "")
# drop in the build directory
set_target_properties(duckstation_libretro PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
set_target_properties(duckstation_libretro PROPERTIES LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}")
# work around .sln issue of hardcoded config directories
if(WIN32)
set_target_properties(duckstation_libretro PROPERTIES RUNTIME_OUTPUT_DIRECTORY_DEBUG "${CMAKE_BINARY_DIR}")
set_target_properties(duckstation_libretro PROPERTIES RUNTIME_OUTPUT_DIRECTORY_RELEASE "${CMAKE_BINARY_DIR}")
endif()
# for android, suffix _android
if(ANDROID)
set_target_properties(duckstation_libretro PROPERTIES OUTPUT_NAME "duckstation_libretro_android")
endif()

View file

@ -1,582 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="DebugFast|ARM64">
<Configuration>DebugFast</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugFast|Win32">
<Configuration>DebugFast</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="DebugFast|x64">
<Configuration>DebugFast</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|ARM64">
<Configuration>Debug</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|ARM64">
<Configuration>ReleaseLTCG</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|Win32">
<Configuration>ReleaseLTCG</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="ReleaseLTCG|x64">
<Configuration>ReleaseLTCG</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|ARM64">
<Configuration>Release</Configuration>
<Platform>ARM64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\dep\vulkan-loader\vulkan-loader.vcxproj">
<Project>{9c8ddeb0-2b8f-4f5f-ba86-127cdf27f035}</Project>
</ProjectReference>
<ProjectReference Include="..\common\common.vcxproj">
<Project>{ee054e08-3799-4a59-a422-18259c105ffd}</Project>
</ProjectReference>
<ProjectReference Include="..\core\core.vcxproj">
<Project>{868b98c8-65a1-494b-8346-250a73a48c0a}</Project>
</ProjectReference>
<ProjectReference Include="..\frontend-common\frontend-common.vcxproj">
<Project>{6245dec8-d2da-47ee-a373-cbd6fcf3ece6}</Project>
</ProjectReference>
<ProjectReference Include="..\scmversion\scmversion.vcxproj">
<Project>{075ced82-6a20-46df-94c7-9624ac9ddbeb}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ClCompile Include="libretro_d3d11_host_display.cpp" />
<ClCompile Include="libretro_audio_stream.cpp" />
<ClCompile Include="libretro_game_settings.cpp" />
<ClCompile Include="libretro_host_display.cpp" />
<ClCompile Include="libretro_host_interface.cpp" />
<ClCompile Include="libretro_settings_interface.cpp" />
<ClCompile Include="libretro_vulkan_host_display.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="libretro_opengl_host_display.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="libretro_d3d11_host_display.h" />
<ClInclude Include="libretro_audio_stream.h" />
<ClInclude Include="libretro_game_settings.h" />
<ClInclude Include="libretro_host_display.h" />
<ClInclude Include="libretro_host_interface.h" />
<ClInclude Include="libretro_settings_interface.h" />
<ClInclude Include="libretro_opengl_host_display.h" />
<ClInclude Include="libretro_vulkan_host_display.h" />
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{9D206548-DE8F-4D9D-A561-C7E5CD7A20DF}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>duckstation-libretro</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>NotSet</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="Configuration">
<ConfigurationType>DynamicLibrary</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>NotSet</CharacterSet>
<SpectreMitigation>false</SpectreMitigation>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'" Label="PropertySheets">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>true</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">
<IntDir>$(SolutionDir)build\$(ProjectName)-$(Platform)-$(Configuration)\</IntDir>
<TargetName>$(ProjectName)-$(Platform)-$(Configuration)</TargetName>
<LinkIncremental>false</LinkIncremental>
<OutDir>$(SolutionDir)bin\$(Platform)\</OutDir>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|x64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='DebugFast|ARM64'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level4</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>_ITERATOR_DEBUG_LEVEL=1;_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUGFAST;_DEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<SDLCheck>true</SDLCheck>
<DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<BasicRuntimeChecks>Default</BasicRuntimeChecks>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<MinimalRebuild>false</MinimalRebuild>
<LanguageStandard>stdcpp17</LanguageStandard>
<SupportJustMyCode>false</SupportJustMyCode>
<InlineFunctionExpansion>OnlyExplicitInline</InlineFunctionExpansion>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|Win32'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|ARM64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>false</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>Default</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|x64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='ReleaseLTCG|ARM64'">
<ClCompile>
<WarningLevel>Level4</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)dep\imgui\include;$(SolutionDir)dep\glad\include;$(SolutionDir)dep\vulkan-loader\include;$(SolutionDir)dep\libretro-common\include;$(SolutionDir)src;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
<MultiProcessorCompilation>true</MultiProcessorCompilation>
<WholeProgramOptimization>true</WholeProgramOptimization>
<LanguageStandard>stdcpp17</LanguageStandard>
<OmitFramePointers>true</OmitFramePointers>
<ConformanceMode>true</ConformanceMode>
<AdditionalOptions>/Zo /utf-8 %(AdditionalOptions)</AdditionalOptions>
</ClCompile>
<Link>
<SubSystem>Windows</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>d3d11.lib;dxgi.lib;%(AdditionalDependencies)</AdditionalDependencies>
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
</Link>
</ItemDefinitionGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ClCompile Include="libretro_host_interface.cpp" />
<ClCompile Include="libretro_audio_stream.cpp" />
<ClCompile Include="libretro_host_display.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="libretro_settings_interface.cpp" />
<ClCompile Include="libretro_opengl_host_display.cpp" />
<ClCompile Include="libretro_d3d11_host_display.cpp" />
<ClCompile Include="libretro_vulkan_host_display.cpp" />
<ClCompile Include="libretro_game_settings.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="libretro_host_interface.h" />
<ClInclude Include="libretro_audio_stream.h" />
<ClInclude Include="libretro_host_display.h" />
<ClInclude Include="libretro_settings_interface.h" />
<ClInclude Include="libretro_opengl_host_display.h" />
<ClInclude Include="libretro_d3d11_host_display.h" />
<ClInclude Include="libretro_vulkan_host_display.h" />
<ClInclude Include="libretro_game_settings.h" />
</ItemGroup>
</Project>

View file

@ -1,23 +0,0 @@
#include "libretro_audio_stream.h"
#include "libretro_host_interface.h"
LibretroAudioStream::LibretroAudioStream() = default;
LibretroAudioStream::~LibretroAudioStream() = default;
bool LibretroAudioStream::OpenDevice()
{
m_output_buffer.resize(m_buffer_size * m_channels);
return true;
}
void LibretroAudioStream::PauseDevice(bool paused) {}
void LibretroAudioStream::CloseDevice() {}
void LibretroAudioStream::FramesAvailable()
{
const u32 num_frames = GetSamplesAvailable();
ReadFrames(m_output_buffer.data(), num_frames, false);
g_retro_audio_sample_batch_callback(m_output_buffer.data(), num_frames);
}

View file

@ -1,21 +0,0 @@
#pragma once
#include "common/audio_stream.h"
#include <cstdint>
#include <vector>
class LibretroAudioStream final : public AudioStream
{
public:
LibretroAudioStream();
~LibretroAudioStream();
protected:
bool OpenDevice() override;
void PauseDevice(bool paused) override;
void CloseDevice() override;
void FramesAvailable() override;
private:
// TODO: Optimize this buffer away.
std::vector<SampleType> m_output_buffer;
};

View file

@ -1,144 +0,0 @@
#include "libretro_d3d11_host_display.h"
#include "common/align.h"
#include "common/assert.h"
#include "common/d3d11/shader_compiler.h"
#include "common/log.h"
#include "libretro_host_interface.h"
Log_SetChannel(LibretroD3D11HostDisplay);
#define HAVE_D3D11
#include "libretro_d3d.h"
LibretroD3D11HostDisplay::LibretroD3D11HostDisplay() = default;
LibretroD3D11HostDisplay::~LibretroD3D11HostDisplay() = default;
void LibretroD3D11HostDisplay::SetVSync(bool enabled)
{
// The libretro frontend controls this.
Log_DevPrintf("Ignoring SetVSync(%u)", BoolToUInt32(enabled));
}
bool LibretroD3D11HostDisplay::RequestHardwareRendererContext(retro_hw_render_callback* cb)
{
cb->cache_context = false;
cb->bottom_left_origin = false;
cb->context_type = RETRO_HW_CONTEXT_DIRECT3D;
cb->version_major = 11;
cb->version_minor = 0;
return g_retro_environment_callback(RETRO_ENVIRONMENT_SET_HW_RENDER, cb);
}
bool LibretroD3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name,
bool debug_device, bool threaded_presentation)
{
retro_hw_render_interface* ri = nullptr;
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, &ri))
{
Log_ErrorPrint("Failed to get HW render interface");
return false;
}
else if (ri->interface_type != RETRO_HW_RENDER_INTERFACE_D3D11 ||
ri->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION)
{
Log_ErrorPrintf("Unexpected HW interface - type %u version %u", static_cast<unsigned>(ri->interface_type),
static_cast<unsigned>(ri->interface_version));
return false;
}
const retro_hw_render_interface_d3d11* d3d11_ri = reinterpret_cast<const retro_hw_render_interface_d3d11*>(ri);
if (!d3d11_ri->device || !d3d11_ri->context)
{
Log_ErrorPrintf("Missing D3D device or context");
return false;
}
m_device = d3d11_ri->device;
m_context = d3d11_ri->context;
return true;
}
void LibretroD3D11HostDisplay::DestroyResources()
{
D3D11HostDisplay::DestroyResources();
m_framebuffer.Destroy();
}
void LibretroD3D11HostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
{
m_window_info.surface_width = static_cast<u32>(new_window_width);
m_window_info.surface_height = static_cast<u32>(new_window_height);
}
bool LibretroD3D11HostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
{
// Check that the device hasn't changed.
retro_hw_render_interface* ri = nullptr;
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, &ri))
{
Log_ErrorPrint("Failed to get HW render interface");
return false;
}
else if (ri->interface_type != RETRO_HW_RENDER_INTERFACE_D3D11 ||
ri->interface_version != RETRO_HW_RENDER_INTERFACE_D3D11_VERSION)
{
Log_ErrorPrintf("Unexpected HW interface - type %u version %u", static_cast<unsigned>(ri->interface_type),
static_cast<unsigned>(ri->interface_version));
return false;
}
const retro_hw_render_interface_d3d11* d3d11_ri = reinterpret_cast<const retro_hw_render_interface_d3d11*>(ri);
if (d3d11_ri->device != m_device.Get() || d3d11_ri->context != m_context.Get())
{
Log_ErrorPrintf("D3D device/context changed outside our control");
return false;
}
m_window_info = new_wi;
return true;
}
bool LibretroD3D11HostDisplay::Render()
{
const u32 resolution_scale = g_libretro_host_interface.GetResolutionScale();
const u32 display_width = static_cast<u32>(m_display_width) * resolution_scale;
const u32 display_height = static_cast<u32>(m_display_height) * resolution_scale;
if (!CheckFramebufferSize(display_width, display_height))
return false;
// Ensure we're not currently bound.
ID3D11ShaderResourceView* null_srv = nullptr;
m_context->PSSetShaderResources(0, 1, &null_srv);
m_context->OMSetRenderTargets(1u, m_framebuffer.GetD3DRTVArray(), nullptr);
if (HasDisplayTexture())
{
const auto [left, top, width, height] = CalculateDrawRect(display_width, display_height, 0, false);
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, m_display_linear_filtering);
}
if (HasSoftwareCursor())
{
// TODO: Scale mouse x/y
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect(m_mouse_position_x, m_mouse_position_y);
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
}
// NOTE: libretro frontend expects the data bound to PS SRV slot 0.
m_context->OMSetRenderTargets(0, nullptr, nullptr);
m_context->PSSetShaderResources(0, 1, m_framebuffer.GetD3DSRVArray());
g_retro_video_refresh_callback(RETRO_HW_FRAME_BUFFER_VALID, display_width, display_height, 0);
return true;
}
bool LibretroD3D11HostDisplay::CheckFramebufferSize(u32 width, u32 height)
{
if (m_framebuffer.GetWidth() == width && m_framebuffer.GetHeight() == height)
return true;
return m_framebuffer.Create(m_device.Get(), width, height, 1, 1, DXGI_FORMAT_R8G8B8A8_UNORM,
D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET);
}

View file

@ -1,31 +0,0 @@
#pragma once
#include "common/d3d11/texture.h"
#include "frontend-common/d3d11_host_display.h"
#include "libretro.h"
class LibretroD3D11HostDisplay final : public FrontendCommon::D3D11HostDisplay
{
public:
LibretroD3D11HostDisplay();
~LibretroD3D11HostDisplay();
static bool RequestHardwareRendererContext(retro_hw_render_callback* cb);
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
bool threaded_presentation) override;
void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
bool ChangeRenderWindow(const WindowInfo& new_wi) override;
void SetVSync(bool enabled) override;
bool Render() override;
protected:
void DestroyResources() override;
private:
bool CheckFramebufferSize(u32 width, u32 height);
D3D11::Texture m_framebuffer;
};

View file

@ -1,639 +0,0 @@
#include "libretro_game_settings.h"
std::unique_ptr<GameSettings::Entry> GetSettingsForGame(const std::string& game_code)
{
std::unique_ptr<GameSettings::Entry> gs = std::make_unique<GameSettings::Entry>();
if (game_code == "SLUS-00530")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SLUS-00634")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SLUS-00077")
{
gs->AddTrait(GameSettings::Trait::DisableUpscaling);
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLPM-87089")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLPS-03336")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-01260")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLES-01211")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-01261")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLES-02466")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLES-00259")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLES-00606")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00639")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-90039")
{
gs->AddTrait(GameSettings::Trait::ForceSoftwareRenderer);
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00337")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00606")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLPS-03553")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLPS-01211")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00656")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00952")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-01222")
{
gs->display_active_start_offset = 64;
gs->display_active_end_offset = 68;
return gs;
}
if (game_code == "SLUS-00297")
{
gs->AddTrait(GameSettings::Trait::DisableUpscaling);
gs->AddTrait(GameSettings::Trait::DisablePGXP);
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SCUS-94350")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SCUS-94900")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "PCPX-96085")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00590")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00403")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SCUS-94300")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00214")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00204")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00006")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00213")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SCES-00344")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00355")
{
gs->AddTrait(GameSettings::Trait::DisableUpscaling);
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00331")
{
gs->AddTrait(GameSettings::Trait::DisableUpscaling);
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00106")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00005")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-01265")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00601")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLPS-00435")
{
gs->AddTrait(GameSettings::Trait::ForceRecompilerICache);
return gs;
}
if (game_code == "SLUS-00388")
{
gs->AddTrait(GameSettings::Trait::ForceRecompilerICache);
return gs;
}
if (game_code == "SCES-02834")
{
gs->AddTrait(GameSettings::Trait::ForceRecompilerICache);
return gs;
}
if (game_code == "SLUS-00870")
{
gs->AddTrait(GameSettings::Trait::ForceInterpreter);
return gs;
}
if (game_code == "SLUS-00183")
{
gs->AddTrait(GameSettings::Trait::ForceRecompilerICache);
return gs;
}
if (game_code == "SLES-00483")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLPS-02361")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPVertexCache);
return gs;
}
if (game_code == "SLPM-86023")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00067")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLES-00524")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLPS-00712")
{
gs->AddTrait(GameSettings::Trait::ForceRecompilerICache);
return gs;
}
if (game_code == "SLPS-01434")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00684")
{
gs->AddTrait(GameSettings::Trait::ForceInterpreter);
return gs;
}
if (game_code == "SLPS-02459")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLPM-86750")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLPS-02120")
{
gs->AddTrait(GameSettings::Trait::ForceInterlacing);
return gs;
}
if (game_code == "SLUS-00102")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00152")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00603")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00348")
{
gs->AddTrait(GameSettings::Trait::DisableUpscaling);
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00042")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00561")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00035")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00057")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00014")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SCUS-94403")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00549")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00240")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00027")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00119")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00224")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00453")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00753")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00811")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00208")
{
gs->display_active_start_offset = -62;
gs->display_active_end_offset = 72;
return gs;
}
if (game_code == "SLPS-01762")
{
gs->AddTrait(GameSettings::Trait::DisablePGXPCulling);
return gs;
}
if (game_code == "SLPS-01567")
{
gs->display_active_start_offset = -62;
gs->display_active_end_offset = 51;
return gs;
}
if (game_code == "SLPS-00360")
{
gs->display_active_start_offset = -62;
gs->display_active_end_offset = 72;
return gs;
}
if (game_code == "SCES-02835")
{
gs->AddTrait(GameSettings::Trait::ForceInterpreter);
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCES-02104")
{
gs->AddTrait(GameSettings::Trait::ForceInterpreter);
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCES-01438")
{
gs->AddTrait(GameSettings::Trait::DisablePGXPCulling);
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCUS-94467")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCUS-94425")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCPS-10085")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCUS-94228")
{
gs->AddTrait(GameSettings::Trait::DisablePGXPCulling);
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SCUS-94290")
{
gs->AddTrait(GameSettings::Trait::ForcePGXPCPUMode);
return gs;
}
if (game_code == "SLUS-01138")
{
gs->dma_max_slice_ticks = 200;
gs->gpu_max_run_ahead = 1;
return gs;
}
if (game_code == "SLPS-02376")
{
gs->dma_max_slice_ticks = 100;
gs->gpu_max_run_ahead = 1;
return gs;
}
if (game_code == "SLUS-00282")
{
gs->dma_max_slice_ticks = 200;
gs->gpu_max_run_ahead = 1;
return gs;
}
if (game_code == "SLUS-00022")
{
gs->AddTrait(GameSettings::Trait::DisableUpscaling);
return gs;
}
if (game_code == "SLUS-00292")
{
gs->AddTrait(GameSettings::Trait::ForceRecompilerICache);
return gs;
}
if (game_code == "SLUS-00522")
{
gs->dma_max_slice_ticks = 200;
return gs;
}
if (game_code == "SLES-00469")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLPS-01163")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLUS-00498")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLPS-00433")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLUS-01029")
{
gs->AddTrait(GameSettings::Trait::DisableAnalogModeForcing);
return gs;
}
if (game_code == "SLUS-00506")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLES-00704")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLPS-01399")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLUS-00232")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLES-00526")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
if (game_code == "SLED-00570")
{
gs->dma_max_slice_ticks = 100;
return gs;
}
return {};
}

View file

@ -1,4 +0,0 @@
#include "frontend-common/game_settings.h"
#include <memory>
std::unique_ptr<GameSettings::Entry> GetSettingsForGame(const std::string& game_code);

View file

@ -1,233 +0,0 @@
#include "libretro_host_display.h"
#include "common/align.h"
#include "common/assert.h"
#include "common/log.h"
#include "libretro.h"
#include "libretro_host_interface.h"
#include <array>
#include <tuple>
Log_SetChannel(LibretroHostDisplay);
static retro_pixel_format GetRetroPixelFormat(HostDisplayPixelFormat format)
{
switch (format)
{
case HostDisplayPixelFormat::BGRA8:
return RETRO_PIXEL_FORMAT_XRGB8888;
case HostDisplayPixelFormat::RGB565:
return RETRO_PIXEL_FORMAT_RGB565;
case HostDisplayPixelFormat::RGBA5551:
return RETRO_PIXEL_FORMAT_0RGB1555;
default:
return RETRO_PIXEL_FORMAT_UNKNOWN;
}
}
LibretroHostDisplay::LibretroHostDisplay()
{
retro_pixel_format pf = RETRO_PIXEL_FORMAT_RGB565;
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &pf))
Log_ErrorPrint("Failed to set pixel format to RGB565");
else
m_current_pixel_format = pf;
}
LibretroHostDisplay::~LibretroHostDisplay() = default;
bool LibretroHostDisplay::CheckPixelFormat(retro_pixel_format new_format)
{
if (new_format == RETRO_PIXEL_FORMAT_UNKNOWN || m_current_pixel_format == new_format)
return true;
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, &new_format))
{
Log_ErrorPrintf("g_retro_environment_callback(RETRO_ENVIRONMENT_SET_PIXEL_FORMAT, %u) failed",
static_cast<unsigned>(new_format));
return false;
}
if (!g_libretro_host_interface.UpdateSystemAVInfo(false))
return false;
m_current_pixel_format = new_format;
return true;
}
HostDisplay::RenderAPI LibretroHostDisplay::GetRenderAPI() const
{
return RenderAPI::None;
}
void* LibretroHostDisplay::GetRenderDevice() const
{
return nullptr;
}
void* LibretroHostDisplay::GetRenderContext() const
{
return nullptr;
}
bool LibretroHostDisplay::HasRenderDevice() const
{
return true;
}
bool LibretroHostDisplay::HasRenderSurface() const
{
return true;
}
bool LibretroHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
bool threaded_presentation)
{
m_window_info = wi;
return true;
}
bool LibretroHostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
bool threaded_presentation)
{
return true;
}
bool LibretroHostDisplay::MakeRenderContextCurrent()
{
return true;
}
bool LibretroHostDisplay::DoneRenderContextCurrent()
{
return true;
}
void LibretroHostDisplay::DestroyRenderDevice() {}
void LibretroHostDisplay::DestroyRenderSurface() {}
bool LibretroHostDisplay::CreateResources()
{
return true;
}
void LibretroHostDisplay::DestroyResources() {}
bool LibretroHostDisplay::ChangeRenderWindow(const WindowInfo& wi)
{
m_window_info = wi;
return true;
}
void LibretroHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
{
m_window_info.surface_width = new_window_width;
m_window_info.surface_height = new_window_height;
}
bool LibretroHostDisplay::SupportsFullscreen() const
{
return false;
}
bool LibretroHostDisplay::IsFullscreen()
{
return false;
}
bool LibretroHostDisplay::SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate)
{
return false;
}
bool LibretroHostDisplay::SetPostProcessingChain(const std::string_view& config)
{
return false;
}
std::unique_ptr<HostDisplayTexture> LibretroHostDisplay::CreateTexture(u32 width, u32 height, const void* data,
u32 data_stride, bool dynamic)
{
return nullptr;
}
void LibretroHostDisplay::UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height,
const void* data, u32 data_stride)
{
}
bool LibretroHostDisplay::DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x,
u32 y, u32 width, u32 height, void* out_data, u32 out_data_stride)
{
return false;
}
bool LibretroHostDisplay::SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const
{
// For when we can change the pixel format.
// return (GetRetroPixelFormat(format) != RETRO_PIXEL_FORMAT_UNKNOWN);
return (GetRetroPixelFormat(format) == m_current_pixel_format);
}
bool LibretroHostDisplay::BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
u32* out_pitch)
{
const retro_pixel_format retro_pf = GetRetroPixelFormat(format);
if (!CheckPixelFormat(retro_pf))
return false;
m_software_fb.data = nullptr;
m_software_fb.width = width;
m_software_fb.height = height;
m_software_fb.pitch = 0;
m_software_fb.format = RETRO_PIXEL_FORMAT_UNKNOWN;
m_software_fb.access_flags = RETRO_MEMORY_ACCESS_WRITE;
m_software_fb.memory_flags = 0;
if (g_retro_environment_callback(RETRO_ENVIRONMENT_GET_CURRENT_SOFTWARE_FRAMEBUFFER, &m_software_fb) &&
m_software_fb.format == retro_pf)
{
SetDisplayTexture(m_software_fb.data, format, m_software_fb.width, m_software_fb.height, 0, 0, m_software_fb.width,
m_software_fb.height);
*out_buffer = m_software_fb.data;
*out_pitch = static_cast<u32>(m_software_fb.pitch);
return true;
}
const u32 pitch = Common::AlignUpPow2(width * GetDisplayPixelFormatSize(format), 4);
const u32 required_size = height * pitch;
if (m_frame_buffer.size() < (required_size / 4))
m_frame_buffer.resize(required_size / 4);
m_frame_buffer_pitch = pitch;
SetDisplayTexture(m_frame_buffer.data(), format, width, height, 0, 0, width, height);
*out_buffer = m_frame_buffer.data();
*out_pitch = pitch;
return true;
}
void LibretroHostDisplay::EndSetDisplayPixels()
{
// noop
}
void LibretroHostDisplay::SetVSync(bool enabled)
{
// The libretro frontend controls this.
Log_DevPrintf("Ignoring SetVSync(%u)", BoolToUInt32(enabled));
}
bool LibretroHostDisplay::Render()
{
if (HasDisplayTexture())
{
g_retro_video_refresh_callback(m_display_texture_handle, m_display_texture_view_width,
m_display_texture_view_height, m_frame_buffer_pitch);
if (m_display_texture_handle == m_software_fb.data)
ClearDisplayTexture();
}
return true;
}

View file

@ -1,63 +0,0 @@
#pragma once
#include "core/host_display.h"
#include "libretro.h"
class LibretroHostDisplay final : public HostDisplay
{
public:
LibretroHostDisplay();
~LibretroHostDisplay();
RenderAPI GetRenderAPI() const override;
void* GetRenderDevice() const override;
void* GetRenderContext() const override;
bool HasRenderDevice() const override;
bool HasRenderSurface() const override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
bool threaded_presentation) override;
bool InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
bool threaded_presentation) override;
void DestroyRenderDevice() override;
bool MakeRenderContextCurrent() override;
bool DoneRenderContextCurrent() override;
bool ChangeRenderWindow(const WindowInfo& wi) override;
void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
bool SupportsFullscreen() const override;
bool IsFullscreen() override;
bool SetFullscreen(bool fullscreen, u32 width, u32 height, float refresh_rate) override;
void DestroyRenderSurface() override;
bool SetPostProcessingChain(const std::string_view& config) override;
bool CreateResources() override;
void DestroyResources() override;
std::unique_ptr<HostDisplayTexture> CreateTexture(u32 width, u32 height, const void* data, u32 data_stride,
bool dynamic) override;
void UpdateTexture(HostDisplayTexture* texture, u32 x, u32 y, u32 width, u32 height, const void* data,
u32 data_stride) override;
bool DownloadTexture(const void* texture_handle, HostDisplayPixelFormat texture_format, u32 x, u32 y, u32 width,
u32 height, void* out_data, u32 out_data_stride) override;
void SetVSync(bool enabled) override;
bool Render() override;
bool SupportsDisplayPixelFormat(HostDisplayPixelFormat format) const override;
bool BeginSetDisplayPixels(HostDisplayPixelFormat format, u32 width, u32 height, void** out_buffer,
u32* out_pitch) override;
void EndSetDisplayPixels() override;
private:
bool CheckPixelFormat(retro_pixel_format new_format);
std::vector<u32> m_frame_buffer;
u32 m_frame_buffer_pitch = 0;
retro_framebuffer m_software_fb = {};
retro_pixel_format m_current_pixel_format = RETRO_PIXEL_FORMAT_UNKNOWN;
};

File diff suppressed because it is too large Load diff

View file

@ -1,124 +0,0 @@
#pragma once
#include "core/host_interface.h"
#include "core/system.h"
#include "libretro.h"
#include <limits>
#include <optional>
#include <memory>
namespace GameSettings
{
struct Entry;
}
class LibretroHostInterface : public HostInterface
{
public:
LibretroHostInterface();
~LibretroHostInterface() override;
ALWAYS_INLINE u32 GetResolutionScale() const { return g_settings.gpu_resolution_scale; }
bool Initialize() override;
void Shutdown() override;
void ReportError(const char* message) override;
void ReportMessage(const char* message) override;
bool ConfirmMessage(const char* message) override;
void AddOSDMessage(std::string message, float duration = 2.0f) override;
void GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title) override;
std::string GetSharedMemoryCardPath(u32 slot) const override;
std::string GetGameMemoryCardPath(const char* game_code, u32 slot) const override;
std::string GetShaderCacheBasePath() const override;
std::string GetStringSettingValue(const char* section, const char* key, const char* default_value = "") override;
std::string GetBIOSDirectory() override;
std::unique_ptr<ByteStream> OpenPackageFile(const char* path, u32 flags) override;
bool UpdateSystemAVInfo(bool use_resolution_scale);
// Called by frontend
void retro_set_environment();
void retro_get_system_av_info(struct retro_system_av_info* info);
bool retro_load_game(const struct retro_game_info* game);
void retro_run_frame();
unsigned retro_get_region();
size_t retro_serialize_size();
bool retro_serialize(void* data, size_t size);
bool retro_unserialize(const void* data, size_t size);
void* retro_get_memory_data(unsigned id);
size_t retro_get_memory_size(unsigned id);
void retro_cheat_reset();
void retro_cheat_set(unsigned index, bool enabled, const char* code);
protected:
bool AcquireHostDisplay() override;
void ReleaseHostDisplay() override;
std::unique_ptr<AudioStream> CreateAudioStream(AudioBackend backend) override;
void OnSystemDestroyed() override;
void CheckForSettingsChanges(const Settings& old_settings) override;
void OnRunningGameChanged() override;
private:
bool SetCoreOptions();
bool HasCoreVariablesChanged();
void InitInterfaces();
void InitLogging();
void InitDiskControlInterface();
void InitRumbleInterface();
void LoadSettings() override;
void UpdateSettings();
void UpdateControllers();
void UpdateControllersDigitalController(u32 index);
void UpdateControllersAnalogController(u32 index);
void GetSystemAVInfo(struct retro_system_av_info* info, bool use_resolution_scale);
void UpdateGeometry();
void UpdateLogging();
bool UpdateGameSettings();
void ApplyGameSettings();
// Hardware renderer setup.
bool RequestHardwareRendererContext();
void SwitchToHardwareRenderer();
void SwitchToSoftwareRenderer();
static void HardwareRendererContextReset();
static void HardwareRendererContextDestroy();
// Disk control callbacks
static bool RETRO_CALLCONV DiskControlSetEjectState(bool ejected);
static bool RETRO_CALLCONV DiskControlGetEjectState();
static unsigned RETRO_CALLCONV DiskControlGetImageIndex();
static bool RETRO_CALLCONV DiskControlSetImageIndex(unsigned index);
static unsigned RETRO_CALLCONV DiskControlGetNumImages();
static bool RETRO_CALLCONV DiskControlReplaceImageIndex(unsigned index, const retro_game_info* info);
static bool RETRO_CALLCONV DiskControlAddImageIndex();
static bool RETRO_CALLCONV DiskControlSetInitialImage(unsigned index, const char* path);
static bool RETRO_CALLCONV DiskControlGetImagePath(unsigned index, char* path, size_t len);
static bool RETRO_CALLCONV DiskControlGetImageLabel(unsigned index, char* label, size_t len);
std::unique_ptr<GameSettings::Entry> m_game_settings;
float m_last_aspect_ratio = 4.0f / 3.0f;
retro_hw_render_callback m_hw_render_callback = {};
std::unique_ptr<HostDisplay> m_hw_render_display;
bool m_hw_render_callback_valid = false;
bool m_using_hardware_renderer = false;
std::optional<u32> m_next_disc_index;
retro_rumble_interface m_rumble_interface = {};
bool m_rumble_interface_valid = false;
bool m_supports_input_bitmasks = false;
};
extern LibretroHostInterface g_libretro_host_interface;
// libretro callbacks
extern retro_environment_t g_retro_environment_callback;
extern retro_video_refresh_t g_retro_video_refresh_callback;
extern retro_audio_sample_t g_retro_audio_sample_callback;
extern retro_audio_sample_batch_t g_retro_audio_sample_batch_callback;
extern retro_input_poll_t g_retro_input_poll_callback;
extern retro_input_state_t g_retro_input_state_callback;

View file

@ -1,177 +0,0 @@
#include "libretro_opengl_host_display.h"
#include "common/assert.h"
#include "common/log.h"
#include "core/gpu.h"
#include "libretro.h"
#include "libretro_host_interface.h"
#include <array>
#include <tuple>
Log_SetChannel(LibretroOpenGLHostDisplay);
LibretroOpenGLHostDisplay::LibretroOpenGLHostDisplay() = default;
LibretroOpenGLHostDisplay::~LibretroOpenGLHostDisplay() = default;
HostDisplay::RenderAPI LibretroOpenGLHostDisplay::GetRenderAPI() const
{
return m_is_gles ? HostDisplay::RenderAPI::OpenGLES : HostDisplay::RenderAPI::OpenGL;
}
void LibretroOpenGLHostDisplay::SetVSync(bool enabled)
{
// The libretro frontend controls this.
Log_DevPrintf("Ignoring SetVSync(%u)", BoolToUInt32(enabled));
}
static bool TryDesktopVersions(retro_hw_render_callback* cb)
{
static constexpr std::array<std::tuple<u32, u32>, 11> desktop_versions_to_try = {
{/*{4, 6}, {4, 5}, {4, 4}, {4, 3}, {4, 2}, {4, 1}, {4, 0}, */ {3, 3}, {3, 2}, {3, 1}, {3, 0}}};
for (const auto& [major, minor] : desktop_versions_to_try)
{
if (major > 3 || (major == 3 && minor >= 2))
{
cb->context_type = RETRO_HW_CONTEXT_OPENGL_CORE;
cb->version_major = major;
cb->version_minor = minor;
}
else
{
cb->context_type = RETRO_HW_CONTEXT_OPENGL;
cb->version_major = 0;
cb->version_minor = 0;
}
if (g_retro_environment_callback(RETRO_ENVIRONMENT_SET_HW_RENDER, cb))
return true;
}
return false;
}
static bool TryESVersions(retro_hw_render_callback* cb)
{
static constexpr std::array<std::tuple<u32, u32>, 4> es_versions_to_try = {{{3, 2}, {3, 1}, {3, 0}}};
for (const auto& [major, minor] : es_versions_to_try)
{
if (major >= 3 && minor > 0)
{
cb->context_type = RETRO_HW_CONTEXT_OPENGLES_VERSION;
cb->version_major = major;
cb->version_minor = minor;
}
else
{
cb->context_type = RETRO_HW_CONTEXT_OPENGLES3;
cb->version_major = 0;
cb->version_minor = 0;
}
if (g_retro_environment_callback(RETRO_ENVIRONMENT_SET_HW_RENDER, cb))
return true;
}
return false;
}
bool LibretroOpenGLHostDisplay::RequestHardwareRendererContext(retro_hw_render_callback* cb, bool prefer_gles)
{
// Prefer a desktop OpenGL context where possible. If we can't get this, try OpenGL ES.
cb->cache_context = false;
cb->bottom_left_origin = true;
if (!prefer_gles)
{
if (TryDesktopVersions(cb) || TryESVersions(cb))
return true;
}
else
{
if (TryESVersions(cb) || TryDesktopVersions(cb))
return true;
}
Log_ErrorPrint("Failed to set any GL HW renderer");
return false;
}
bool LibretroOpenGLHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name,
bool debug_device, bool threaded_presentation)
{
Assert(wi.type == WindowInfo::Type::Libretro);
// gross - but can't do much because of the GLADloadproc below.
static retro_hw_render_callback* cb;
cb = static_cast<retro_hw_render_callback*>(wi.display_connection);
m_window_info = wi;
m_is_gles = (cb->context_type == RETRO_HW_CONTEXT_OPENGLES3 || cb->context_type == RETRO_HW_CONTEXT_OPENGLES_VERSION);
const GLADloadproc get_proc_address = [](const char* sym) -> void* {
return reinterpret_cast<void*>(cb->get_proc_address(sym));
};
// Load GLAD.
const auto load_result = m_is_gles ? gladLoadGLES2Loader(get_proc_address) : gladLoadGLLoader(get_proc_address);
if (!load_result)
{
Log_ErrorPrintf("Failed to load GL functions");
return false;
}
return true;
}
void LibretroOpenGLHostDisplay::DestroyRenderDevice()
{
DestroyResources();
}
void LibretroOpenGLHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
{
m_window_info.surface_width = static_cast<u32>(new_window_width);
m_window_info.surface_height = static_cast<u32>(new_window_height);
}
bool LibretroOpenGLHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
{
m_window_info = new_wi;
return true;
}
bool LibretroOpenGLHostDisplay::Render()
{
const GLuint fbo = static_cast<GLuint>(
static_cast<retro_hw_render_callback*>(m_window_info.display_connection)->get_current_framebuffer());
const u32 resolution_scale = g_libretro_host_interface.GetResolutionScale();
const u32 display_width = static_cast<u32>(m_display_width) * resolution_scale;
const u32 display_height = static_cast<u32>(m_display_height) * resolution_scale;
glEnable(GL_SCISSOR_TEST);
glScissor(0, 0, display_width, display_height);
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, fbo);
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
if (HasDisplayTexture())
{
const auto [left, top, width, height] = CalculateDrawRect(display_width, display_height, 0, false);
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, m_display_linear_filtering);
}
if (HasSoftwareCursor())
{
// TODO: Scale mouse x/y
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect(m_mouse_position_x, m_mouse_position_y);
RenderSoftwareCursor(left, display_height - top - height, width, height, m_cursor_texture.get());
}
g_retro_video_refresh_callback(RETRO_HW_FRAME_BUFFER_VALID, display_width, display_height, 0);
GL::Program::ResetLastProgram();
return true;
}

View file

@ -1,33 +0,0 @@
#pragma once
#include "common/gl/program.h"
#include "common/gl/texture.h"
#include "core/host_display.h"
#include "frontend-common/opengl_host_display.h"
#include "libretro.h"
#include <memory>
#include <string>
class LibretroOpenGLHostDisplay final : public FrontendCommon::OpenGLHostDisplay
{
public:
LibretroOpenGLHostDisplay();
~LibretroOpenGLHostDisplay();
static bool RequestHardwareRendererContext(retro_hw_render_callback* cb, bool prefer_gles);
RenderAPI GetRenderAPI() const override;
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
bool threaded_presentation) override;
void DestroyRenderDevice() override;
void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
bool ChangeRenderWindow(const WindowInfo& new_wi) override;
void SetVSync(bool enabled) override;
bool Render() override;
private:
bool m_is_gles = false;
};

View file

@ -1,122 +0,0 @@
#include "libretro_settings_interface.h"
#include "common/log.h"
#include "common/string_util.h"
#include "libretro_host_interface.h"
#include <type_traits>
Log_SetChannel(LibretroSettingsInterface);
template<typename T, typename DefaultValueType>
static T GetVariable(const char* section, const char* key, DefaultValueType default_value)
{
TinyString full_key;
full_key.Format("duckstation_%s.%s", section, key);
retro_variable rv = {full_key.GetCharArray(), nullptr};
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_GET_VARIABLE, &rv) || !rv.value)
return T(default_value);
if constexpr (std::is_same_v<T, std::string>)
{
return T(rv.value);
}
else if constexpr (std::is_same_v<T, bool>)
{
return (StringUtil::Strcasecmp(rv.value, "true") == 0 || StringUtil::Strcasecmp(rv.value, "1") == 0);
}
else if constexpr (std::is_same_v<T, float>)
{
return std::strtof(rv.value, nullptr);
}
else
{
std::optional<T> parsed = StringUtil::FromChars<T>(rv.value);
if (!parsed.has_value())
return T(default_value);
return parsed.value();
}
}
void LibretroSettingsInterface::Clear()
{
Log_WarningPrintf("Clear not implemented");
}
int LibretroSettingsInterface::GetIntValue(const char* section, const char* key, int default_value /*= 0*/)
{
return GetVariable<int>(section, key, default_value);
}
float LibretroSettingsInterface::GetFloatValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{
return GetVariable<float>(section, key, default_value);
}
bool LibretroSettingsInterface::GetBoolValue(const char* section, const char* key, bool default_value /*= false*/)
{
return GetVariable<bool>(section, key, default_value);
}
std::string LibretroSettingsInterface::GetStringValue(const char* section, const char* key,
const char* default_value /*= ""*/)
{
return GetVariable<std::string>(section, key, default_value);
}
void LibretroSettingsInterface::SetIntValue(const char* section, const char* key, int value)
{
Log_ErrorPrintf("SetIntValue(\"%s\", \"%s\", %d) not implemented", section, key, value);
}
void LibretroSettingsInterface::SetFloatValue(const char* section, const char* key, float value)
{
Log_ErrorPrintf("SetFloatValue(\"%s\", \"%s\", %f) not implemented", section, key, value);
}
void LibretroSettingsInterface::SetBoolValue(const char* section, const char* key, bool value)
{
Log_ErrorPrintf("SetBoolValue(\"%s\", \"%s\", %u) not implemented", section, key, static_cast<unsigned>(value));
}
void LibretroSettingsInterface::SetStringValue(const char* section, const char* key, const char* value)
{
Log_ErrorPrintf("SetStringValue(\"%s\", \"%s\", \"%s\") not implemented", section, key, value);
}
std::vector<std::string> LibretroSettingsInterface::GetStringList(const char* section, const char* key)
{
std::string value = GetVariable<std::string>(section, key, "");
if (value.empty())
return {};
return std::vector<std::string>({std::move(value)});
}
void LibretroSettingsInterface::SetStringList(const char* section, const char* key,
const std::vector<std::string>& items)
{
Log_ErrorPrintf("SetStringList(\"%s\", \"%s\") not implemented", section, key);
}
bool LibretroSettingsInterface::RemoveFromStringList(const char* section, const char* key, const char* item)
{
Log_ErrorPrintf("RemoveFromStringList(\"%s\", \"%s\", \"%s\") not implemented", section, key, item);
return false;
}
bool LibretroSettingsInterface::AddToStringList(const char* section, const char* key, const char* item)
{
Log_ErrorPrintf("AddToStringList(\"%s\", \"%s\", \"%s\") not implemented", section, key, item);
return false;
}
void LibretroSettingsInterface::DeleteValue(const char* section, const char* key)
{
Log_ErrorPrintf("DeleteValue(\"%s\", \"%s\") not implemented", section, key);
}
void LibretroSettingsInterface::ClearSection(const char* section)
{
Log_ErrorPrintf("ClearSection(\"%s\") not implemented", section);
}

View file

@ -1,26 +0,0 @@
#pragma once
#include "core/settings.h"
class LibretroSettingsInterface : public SettingsInterface
{
public:
void Clear() override;
int GetIntValue(const char* section, const char* key, int default_value = 0) override;
float GetFloatValue(const char* section, const char* key, float default_value = 0.0f) override;
bool GetBoolValue(const char* section, const char* key, bool default_value = false) override;
std::string GetStringValue(const char* section, const char* key, const char* default_value = "") override;
void SetIntValue(const char* section, const char* key, int value) override;
void SetFloatValue(const char* section, const char* key, float value) override;
void SetBoolValue(const char* section, const char* key, bool value) override;
void SetStringValue(const char* section, const char* key, const char* value) override;
std::vector<std::string> GetStringList(const char* section, const char* key) override;
void SetStringList(const char* section, const char* key, const std::vector<std::string>& items) override;
bool RemoveFromStringList(const char* section, const char* key, const char* item) override;
bool AddToStringList(const char* section, const char* key, const char* item) override;
void DeleteValue(const char* section, const char* key) override;
void ClearSection(const char* section) override;
};

View file

@ -1,268 +0,0 @@
#include "libretro_vulkan_host_display.h"
#include "common/align.h"
#include "common/assert.h"
#include "common/log.h"
#include "common/vulkan/builders.h"
#include "common/vulkan/context.h"
#include "common/vulkan/shader_cache.h"
#include "common/vulkan/util.h"
#include "libretro_host_interface.h"
#include "vulkan_loader.h"
Log_SetChannel(LibretroVulkanHostDisplay);
LibretroVulkanHostDisplay::LibretroVulkanHostDisplay() = default;
LibretroVulkanHostDisplay::~LibretroVulkanHostDisplay() = default;
void LibretroVulkanHostDisplay::SetVSync(bool enabled)
{
// The libretro frontend controls this.
Log_DevPrintf("Ignoring SetVSync(%u)", BoolToUInt32(enabled));
}
static bool RetroCreateVulkanDevice(struct retro_vulkan_context* context, VkInstance instance, VkPhysicalDevice gpu,
VkSurfaceKHR surface, PFN_vkGetInstanceProcAddr get_instance_proc_addr,
const char** required_device_extensions, unsigned num_required_device_extensions,
const char** required_device_layers, unsigned num_required_device_layers,
const VkPhysicalDeviceFeatures* required_features)
{
// We need some module functions.
vkGetInstanceProcAddr = get_instance_proc_addr;
if (!Vulkan::LoadVulkanInstanceFunctions(instance))
{
Log_ErrorPrintf("Failed to load Vulkan instance functions");
Vulkan::ResetVulkanLibraryFunctionPointers();
return false;
}
if (gpu == VK_NULL_HANDLE)
{
Vulkan::Context::GPUList gpus = Vulkan::Context::EnumerateGPUs(instance);
if (gpus.empty())
{
g_libretro_host_interface.ReportError("No GPU provided and none available, cannot create device");
Vulkan::ResetVulkanLibraryFunctionPointers();
return false;
}
Log_InfoPrintf("No GPU provided, using first/default");
gpu = gpus[0];
}
if (!Vulkan::Context::CreateFromExistingInstance(
instance, gpu, surface, false, false, false, required_device_extensions, num_required_device_extensions,
required_device_layers, num_required_device_layers, required_features))
{
Vulkan::ResetVulkanLibraryFunctionPointers();
return false;
}
context->gpu = g_vulkan_context->GetPhysicalDevice();
context->device = g_vulkan_context->GetDevice();
context->queue = g_vulkan_context->GetGraphicsQueue();
context->queue_family_index = g_vulkan_context->GetGraphicsQueueFamilyIndex();
context->presentation_queue = g_vulkan_context->GetPresentQueue();
context->presentation_queue_family_index = g_vulkan_context->GetPresentQueueFamilyIndex();
return true;
}
static retro_hw_render_context_negotiation_interface_vulkan s_vulkan_context_negotiation_interface = {
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN, // interface_type
RETRO_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE_VULKAN_VERSION, // interface_version
nullptr, // get_application_info
RetroCreateVulkanDevice, // create_device
nullptr // destroy_device
};
bool LibretroVulkanHostDisplay::RequestHardwareRendererContext(retro_hw_render_callback* cb)
{
cb->cache_context = false;
cb->bottom_left_origin = false;
cb->context_type = RETRO_HW_CONTEXT_VULKAN;
return g_retro_environment_callback(RETRO_ENVIRONMENT_SET_HW_RENDER, cb) &&
g_retro_environment_callback(RETRO_ENVIRONMENT_SET_HW_RENDER_CONTEXT_NEGOTIATION_INTERFACE,
&s_vulkan_context_negotiation_interface);
}
bool LibretroVulkanHostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name,
bool debug_device, bool threaded_presentation)
{
retro_hw_render_interface* ri = nullptr;
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, &ri))
{
Log_ErrorPrint("Failed to get HW render interface");
return false;
}
else if (ri->interface_type != RETRO_HW_RENDER_INTERFACE_VULKAN ||
ri->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION)
{
Log_ErrorPrintf("Unexpected HW interface - type %u version %u", static_cast<unsigned>(ri->interface_type),
static_cast<unsigned>(ri->interface_version));
return false;
}
if (!g_vulkan_context)
{
Log_ErrorPrintf("Vulkan context was not negotiated/created");
return false;
}
// TODO: Grab queue? it should be the same
m_ri = reinterpret_cast<retro_hw_render_interface_vulkan*>(ri);
return true;
}
void LibretroVulkanHostDisplay::DestroyRenderDevice()
{
VulkanHostDisplay::DestroyRenderDevice();
Vulkan::ResetVulkanLibraryFunctionPointers();
}
bool LibretroVulkanHostDisplay::CreateResources()
{
m_frame_render_pass = g_vulkan_context->GetRenderPass(FRAMEBUFFER_FORMAT, VK_FORMAT_UNDEFINED, VK_SAMPLE_COUNT_1_BIT,
VK_ATTACHMENT_LOAD_OP_CLEAR);
if (m_frame_render_pass == VK_NULL_HANDLE)
return false;
return VulkanHostDisplay::CreateResources();
}
void LibretroVulkanHostDisplay::DestroyResources()
{
VulkanHostDisplay::DestroyResources();
Vulkan::Util::SafeDestroyFramebuffer(m_frame_framebuffer);
m_frame_texture.Destroy();
Vulkan::ShaderCompiler::DeinitializeGlslang();
}
VkRenderPass LibretroVulkanHostDisplay::GetRenderPassForDisplay() const
{
return m_frame_render_pass;
}
void LibretroVulkanHostDisplay::ResizeRenderWindow(s32 new_window_width, s32 new_window_height)
{
m_window_info.surface_width = static_cast<u32>(new_window_width);
m_window_info.surface_height = static_cast<u32>(new_window_height);
}
bool LibretroVulkanHostDisplay::ChangeRenderWindow(const WindowInfo& new_wi)
{
// re-query hardware render interface - in vulkan, things get recreated without us being notified
retro_hw_render_interface* ri = nullptr;
if (!g_retro_environment_callback(RETRO_ENVIRONMENT_GET_HW_RENDER_INTERFACE, &ri))
{
Log_ErrorPrint("Failed to get HW render interface");
return false;
}
else if (ri->interface_type != RETRO_HW_RENDER_INTERFACE_VULKAN ||
ri->interface_version != RETRO_HW_RENDER_INTERFACE_VULKAN_VERSION)
{
Log_ErrorPrintf("Unexpected HW interface - type %u version %u", static_cast<unsigned>(ri->interface_type),
static_cast<unsigned>(ri->interface_version));
return false;
}
retro_hw_render_interface_vulkan* vri = reinterpret_cast<retro_hw_render_interface_vulkan*>(ri);
if (vri != m_ri)
{
Log_WarningPrintf("HW render interface pointer changed without us being notified, this might cause issues?");
m_ri = vri;
}
return true;
}
bool LibretroVulkanHostDisplay::Render()
{
const u32 resolution_scale = g_libretro_host_interface.GetResolutionScale();
const u32 display_width = static_cast<u32>(m_display_width) * resolution_scale;
const u32 display_height = static_cast<u32>(m_display_height) * resolution_scale;
if (display_width == 0 || display_height == 0 || !CheckFramebufferSize(display_width, display_height))
return false;
VkCommandBuffer cmdbuffer = g_vulkan_context->GetCurrentCommandBuffer();
m_frame_texture.OverrideImageLayout(m_frame_view.image_layout);
m_frame_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL);
const VkClearValue clear_value = {};
const VkRenderPassBeginInfo rp = {
VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO, nullptr, m_frame_render_pass, m_frame_framebuffer,
{{0, 0}, {display_width, display_height}}, 1u, &clear_value};
vkCmdBeginRenderPass(cmdbuffer, &rp, VK_SUBPASS_CONTENTS_INLINE);
if (HasDisplayTexture())
{
const auto [left, top, width, height] = CalculateDrawRect(display_width, display_height, 0, false);
RenderDisplay(left, top, width, height, m_display_texture_handle, m_display_texture_width, m_display_texture_height,
m_display_texture_view_x, m_display_texture_view_y, m_display_texture_view_width,
m_display_texture_view_height, m_display_linear_filtering);
}
if (HasSoftwareCursor())
{
// TODO: Scale mouse x/y
const auto [left, top, width, height] = CalculateSoftwareCursorDrawRect(m_mouse_position_x, m_mouse_position_y);
RenderSoftwareCursor(left, top, width, height, m_cursor_texture.get());
}
vkCmdEndRenderPass(cmdbuffer);
m_frame_texture.TransitionToLayout(cmdbuffer, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
m_frame_view.image_layout = m_frame_texture.GetLayout();
m_ri->set_image(m_ri->handle, &m_frame_view, 0, nullptr, VK_QUEUE_FAMILY_IGNORED);
// TODO: We can't use this because it doesn't support passing fences...
// m_ri.set_command_buffers(m_ri.handle, 1, &cmdbuffer);
m_ri->lock_queue(m_ri->handle);
g_vulkan_context->SubmitCommandBuffer();
m_ri->unlock_queue(m_ri->handle);
g_vulkan_context->MoveToNextCommandBuffer();
g_retro_video_refresh_callback(RETRO_HW_FRAME_BUFFER_VALID, display_width, display_height, 0);
return true;
}
bool LibretroVulkanHostDisplay::CheckFramebufferSize(u32 width, u32 height)
{
static constexpr VkImageUsageFlags usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT |
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT;
static constexpr VkImageViewType view_type = VK_IMAGE_VIEW_TYPE_2D;
static constexpr VkImageTiling tiling = VK_IMAGE_TILING_OPTIMAL;
if (m_frame_texture.GetWidth() == width && m_frame_texture.GetHeight() == height)
return true;
g_vulkan_context->DeferFramebufferDestruction(m_frame_framebuffer);
m_frame_texture.Destroy(true);
if (!m_frame_texture.Create(width, height, 1, 1, FRAMEBUFFER_FORMAT, VK_SAMPLE_COUNT_1_BIT, view_type, tiling, usage))
return false;
VkCommandBuffer cmdbuf = g_vulkan_context->GetCurrentCommandBuffer();
m_frame_texture.TransitionToLayout(cmdbuf, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
static constexpr VkClearColorValue cc = {};
static constexpr VkImageSubresourceRange range = {VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1};
vkCmdClearColorImage(cmdbuf, m_frame_texture.GetImage(), m_frame_texture.GetLayout(), &cc, 1, &range);
Vulkan::FramebufferBuilder fbb;
fbb.SetRenderPass(m_frame_render_pass);
fbb.AddAttachment(m_frame_texture.GetView());
fbb.SetSize(width, height, 1);
m_frame_framebuffer = fbb.Create(g_vulkan_context->GetDevice(), false);
if (m_frame_framebuffer == VK_NULL_HANDLE)
return false;
m_frame_view = {};
m_frame_view.image_view = m_frame_texture.GetView();
m_frame_view.image_layout = m_frame_texture.GetLayout();
m_frame_view.create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
m_frame_view.create_info.image = m_frame_texture.GetImage();
m_frame_view.create_info.viewType = view_type;
m_frame_view.create_info.format = FRAMEBUFFER_FORMAT;
m_frame_view.create_info.components = {VK_COMPONENT_SWIZZLE_R, VK_COMPONENT_SWIZZLE_G, VK_COMPONENT_SWIZZLE_B,
VK_COMPONENT_SWIZZLE_A};
m_frame_view.create_info.subresourceRange = range;
return true;
}

View file

@ -1,44 +0,0 @@
#pragma once
#include "common/vulkan/texture.h"
#include "frontend-common/vulkan_host_display.h"
#include "libretro.h"
#define HAVE_VULKAN
#include "libretro_vulkan.h"
class LibretroVulkanHostDisplay final : public FrontendCommon::VulkanHostDisplay
{
public:
LibretroVulkanHostDisplay();
~LibretroVulkanHostDisplay();
static bool RequestHardwareRendererContext(retro_hw_render_callback* cb);
bool CreateRenderDevice(const WindowInfo& wi, std::string_view adapter_name, bool debug_device,
bool threaded_presentation) override;
void DestroyRenderDevice() override;
void ResizeRenderWindow(s32 new_window_width, s32 new_window_height) override;
bool ChangeRenderWindow(const WindowInfo& new_wi) override;
void SetVSync(bool enabled) override;
bool Render() override;
protected:
bool CreateResources() override;
void DestroyResources() override;
VkRenderPass GetRenderPassForDisplay() const override;
private:
static constexpr VkFormat FRAMEBUFFER_FORMAT = VK_FORMAT_R8G8B8A8_UNORM;
bool CheckFramebufferSize(u32 width, u32 height);
retro_hw_render_interface_vulkan* m_ri = nullptr;
Vulkan::Texture m_frame_texture;
retro_vulkan_image m_frame_view = {};
VkFramebuffer m_frame_framebuffer = VK_NULL_HANDLE;
VkRenderPass m_frame_render_pass = VK_NULL_HANDLE;
};

View file

@ -1,153 +0,0 @@
#include "common/assert.h"
#include "common/log.h"
#include "libretro_host_interface.h"
#include "scmversion/scmversion.h"
Log_SetChannel(Main);
RETRO_API unsigned retro_api_version(void)
{
return RETRO_API_VERSION;
}
RETRO_API void retro_init(void)
{
// default log to stdout until we get an interface
Log::SetConsoleOutputParams(true, nullptr, LOGLEVEL_INFO);
if (!g_libretro_host_interface.Initialize())
Panic("Host interface initialization failed");
}
RETRO_API void retro_deinit(void)
{
g_libretro_host_interface.Shutdown();
}
RETRO_API void retro_get_system_info(struct retro_system_info* info)
{
std::memset(info, 0, sizeof(*info));
#if defined(_DEBUGFAST)
info->library_name = "DuckStation DebugFast";
#elif defined(_DEBUG)
info->library_name = "DuckStation Debug";
#else
info->library_name = "DuckStation";
#endif
info->library_version = g_scm_tag_str;
info->valid_extensions = "exe|cue|bin|chd|psf|m3u";
info->need_fullpath = true;
info->block_extract = false;
}
RETRO_API void retro_get_system_av_info(struct retro_system_av_info* info)
{
g_libretro_host_interface.retro_get_system_av_info(info);
}
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device)
{
Log_ErrorPrintf("retro_set_controller_port_device(%u, %u)", port, device);
}
RETRO_API void retro_reset(void)
{
Log_InfoPrint("retro_reset()");
g_libretro_host_interface.ResetSystem();
}
RETRO_API void retro_run(void)
{
g_libretro_host_interface.retro_run_frame();
}
RETRO_API size_t retro_serialize_size(void)
{
return g_libretro_host_interface.retro_serialize_size();
}
RETRO_API bool retro_serialize(void* data, size_t size)
{
return g_libretro_host_interface.retro_serialize(data, size);
}
RETRO_API bool retro_unserialize(const void* data, size_t size)
{
return g_libretro_host_interface.retro_unserialize(data, size);
}
RETRO_API void retro_cheat_reset(void)
{
Log_InfoPrint("retro_cheat_reset()");
g_libretro_host_interface.retro_cheat_reset();
}
RETRO_API void retro_cheat_set(unsigned index, bool enabled, const char* code)
{
Log_InfoPrintf("retro_cheat_set(%u, %u, %s)", index, enabled, code);
g_libretro_host_interface.retro_cheat_set(index, enabled, code);
}
RETRO_API bool retro_load_game(const struct retro_game_info* game)
{
Log_InfoPrintf("retro_load_game(%s)", game->path);
return g_libretro_host_interface.retro_load_game(game);
}
RETRO_API bool retro_load_game_special(unsigned game_type, const struct retro_game_info* info, size_t num_info)
{
Log_ErrorPrintf("retro_load_game_special()");
return false;
}
RETRO_API void retro_unload_game(void)
{
g_libretro_host_interface.DestroySystem();
}
RETRO_API unsigned retro_get_region(void)
{
return g_libretro_host_interface.retro_get_region();
}
RETRO_API void* retro_get_memory_data(unsigned id)
{
return g_libretro_host_interface.retro_get_memory_data(id);
}
RETRO_API size_t retro_get_memory_size(unsigned id)
{
return g_libretro_host_interface.retro_get_memory_size(id);
}
RETRO_API void retro_set_environment(retro_environment_t f)
{
g_retro_environment_callback = f;
g_libretro_host_interface.retro_set_environment();
}
RETRO_API void retro_set_video_refresh(retro_video_refresh_t f)
{
g_retro_video_refresh_callback = f;
}
RETRO_API void retro_set_audio_sample(retro_audio_sample_t f)
{
g_retro_audio_sample_callback = f;
}
RETRO_API void retro_set_audio_sample_batch(retro_audio_sample_batch_t f)
{
g_retro_audio_sample_batch_callback = f;
}
RETRO_API void retro_set_input_poll(retro_input_poll_t f)
{
g_retro_input_poll_callback = f;
}
RETRO_API void retro_set_input_state(retro_input_state_t f)
{
g_retro_input_state_callback = f;
}

View file

@ -1,6 +1,24 @@
add_library(frontend-common
common_host_interface.cpp
common_host_interface.h
controller_interface.cpp
controller_interface.h
cubeb_audio_stream.cpp
cubeb_audio_stream.h
game_list.cpp
game_list.h
game_settings.cpp
game_settings.h
icon.cpp
icon.h
ini_settings_interface.cpp
ini_settings_interface.h
imgui_impl_opengl3.cpp
imgui_impl_opengl3.h
imgui_impl_vulkan.cpp
imgui_impl_vulkan.h
imgui_styles.cpp
imgui_styles.h
opengl_host_display.cpp
opengl_host_display.h
postprocessing_chain.cpp
@ -9,97 +27,55 @@ add_library(frontend-common
postprocessing_shader.h
postprocessing_shadergen.cpp
postprocessing_shadergen.h
save_state_selector_ui.cpp
save_state_selector_ui.h
vulkan_host_display.cpp
vulkan_host_display.h
)
target_link_libraries(frontend-common PUBLIC core common glad vulkan-loader)
target_compile_definitions(frontend-common PRIVATE "WITH_IMGUI=1")
target_link_libraries(frontend-common PUBLIC core common glad vulkan-loader cubeb imgui simpleini tinyxml2 scmversion)
if(WIN32)
target_sources(frontend-common PRIVATE
d3d11_host_display.cpp
d3d11_host_display.h
dinput_controller_interface.cpp
dinput_controller_interface.h
imgui_impl_dx11.cpp
imgui_impl_dx11.h
xinput_controller_interface.cpp
xinput_controller_interface.h
)
target_link_libraries(frontend-common PRIVATE d3d11.lib dxgi.lib)
endif()
if(NOT BUILD_LIBRETRO_CORE)
target_sources(frontend-common PRIVATE
imgui_impl_opengl3.h
imgui_impl_opengl3.cpp
)
target_sources(frontend-common PRIVATE
imgui_impl_vulkan.h
imgui_impl_vulkan.cpp
if(SDL2_FOUND)
target_sources(frontend-common PRIVATE
sdl_audio_stream.cpp
sdl_audio_stream.h
sdl_controller_interface.cpp
sdl_controller_interface.h
sdl_initializer.cpp
sdl_initializer.h
)
target_compile_definitions(frontend-common PUBLIC "WITH_SDL2=1")
target_include_directories(frontend-common PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(frontend-common PRIVATE ${SDL2_LIBRARIES})
# Copy bundled SDL2 to output on Windows.
if(WIN32)
target_sources(frontend-common PRIVATE
imgui_impl_dx11.h
imgui_impl_dx11.cpp
)
add_custom_command(TARGET frontend-common POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_DLL_PATH}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/SDL2.dll")
endif()
target_sources(frontend-common PRIVATE
common_host_interface.cpp
common_host_interface.h
controller_interface.cpp
controller_interface.h
cubeb_audio_stream.cpp
cubeb_audio_stream.h
game_list.cpp
game_list.h
icon.cpp
icon.h
imgui_styles.cpp
imgui_styles.h
ini_settings_interface.cpp
ini_settings_interface.h
save_state_selector_ui.cpp
save_state_selector_ui.h
)
if(WIN32)
target_sources(frontend-common PRIVATE
dinput_controller_interface.cpp
dinput_controller_interface.h
xinput_controller_interface.cpp
xinput_controller_interface.h
)
endif()
target_compile_definitions(frontend-common PRIVATE "WITH_IMGUI=1")
target_link_libraries(frontend-common PUBLIC cubeb imgui simpleini tinyxml2 scmversion)
if(SDL2_FOUND)
target_sources(frontend-common PRIVATE
sdl_audio_stream.cpp
sdl_audio_stream.h
sdl_controller_interface.cpp
sdl_controller_interface.h
sdl_initializer.cpp
sdl_initializer.h
)
target_compile_definitions(frontend-common PUBLIC "WITH_SDL2=1")
target_include_directories(frontend-common PRIVATE ${SDL2_INCLUDE_DIRS})
target_link_libraries(frontend-common PRIVATE ${SDL2_LIBRARIES})
# Copy bundled SDL2 to output on Windows.
if(WIN32)
add_custom_command(TARGET frontend-common POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${SDL2_DLL_PATH}" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/SDL2.dll")
endif()
endif()
if(ENABLE_DISCORD_PRESENCE AND NOT BUILD_LIBRETRO_CORE)
target_compile_definitions(frontend-common PUBLIC -DWITH_DISCORD_PRESENCE=1)
target_link_libraries(frontend-common PRIVATE discord-rpc)
endif()
# Copy the provided data directory to the output directory.
add_custom_command(TARGET frontend-common POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
)
endif()
if(ENABLE_DISCORD_PRESENCE)
target_compile_definitions(frontend-common PUBLIC -DWITH_DISCORD_PRESENCE=1)
target_link_libraries(frontend-common PRIVATE discord-rpc)
endif()
# Copy the provided data directory to the output directory.
add_custom_command(TARGET frontend-common POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory "${CMAKE_SOURCE_DIR}/data" "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}"
)

View file

@ -344,11 +344,8 @@ bool D3D11HostDisplay::CreateRenderDevice(const WindowInfo& wi, std::string_view
bool D3D11HostDisplay::InitializeRenderDevice(std::string_view shader_cache_directory, bool debug_device,
bool threaded_presentation)
{
if (m_window_info.type != WindowInfo::Type::Surfaceless && m_window_info.type != WindowInfo::Type::Libretro &&
!CreateSwapChain(nullptr))
{
if (m_window_info.type != WindowInfo::Type::Surfaceless && !CreateSwapChain(nullptr))
return false;
}
if (!CreateResources())
return false;

View file

@ -11,12 +11,10 @@
#include <utility>
Log_SetChannel(GameSettings);
#ifndef LIBRETRO
#ifdef WIN32
#include "common/windows_headers.h"
#endif
#include "SimpleIni.h"
#endif
namespace GameSettings {
@ -183,8 +181,6 @@ bool Entry::SaveToStream(ByteStream* stream) const
WriteStringToStream(stream, memory_card_2_shared_path) && WriteStringToStream(stream, input_profile_name);
}
#ifndef LIBRETRO
static void ParseIniSection(Entry* entry, const char* section, const CSimpleIniA& ini)
{
for (u32 trait = 0; trait < static_cast<u32>(Trait::Count); trait++)
@ -897,8 +893,6 @@ void Entry::SetValueForKey(const std::string_view& key, const std::optional<std:
SetEntryValueForKey(*this, key, value);
}
#endif
void Entry::ApplySettings(bool display_osd_messages) const
{
constexpr float osd_duration = 10.0f;

View file

@ -93,8 +93,6 @@ struct Entry
void SetValueForKey(const std::string_view& key, const std::optional<std::string>& value);
};
#ifndef LIBRETRO
class Database
{
public:
@ -110,6 +108,4 @@ private:
std::unordered_map<std::string, Entry> m_entries;
};
#endif
}; // namespace GameSettings

View file

@ -9,7 +9,7 @@
#include "imgui_impl_opengl3.h"
#endif
#include "postprocessing_shadergen.h"
Log_SetChannel(LibretroOpenGLHostDisplay);
Log_SetChannel(OpenGLHostDisplay);
namespace FrontendCommon {

View file

@ -499,7 +499,6 @@ void main()
void VulkanHostDisplay::DestroyResources()
{
#ifndef LIBRETRO
Vulkan::Util::SafeDestroyPipelineLayout(m_post_process_pipeline_layout);
Vulkan::Util::SafeDestroyPipelineLayout(m_post_process_ubo_pipeline_layout);
Vulkan::Util::SafeDestroyDescriptorSetLayout(m_post_process_descriptor_set_layout);
@ -509,7 +508,6 @@ void VulkanHostDisplay::DestroyResources()
m_post_processing_stages.clear();
m_post_processing_ubo.Destroy(true);
m_post_processing_chain.ClearStages();
#endif
m_display_pixels_texture.Destroy(false);
m_readback_staging_texture.Destroy(false);