mirror of
https://github.com/par274/sharpemu.git
synced 2026-09-01 06:13:38 +08:00
Make external Vulkan backend optional
This commit is contained in:
@@ -1,93 +0,0 @@
|
|||||||
# Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
name: Test Windows Native Vulkan Backend
|
|
||||||
|
|
||||||
on:
|
|
||||||
workflow_dispatch:
|
|
||||||
|
|
||||||
permissions:
|
|
||||||
contents: read
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
test-windows-native-vulkan:
|
|
||||||
name: Build and test win-x64 native backend
|
|
||||||
runs-on: windows-latest
|
|
||||||
env:
|
|
||||||
DOTNET_NOLOGO: true
|
|
||||||
NUGET_PACKAGES: ${{ github.workspace }}\.nuget\packages
|
|
||||||
NATIVE_BUILD_DIR: ${{ github.workspace }}\artifacts\native\gpu-vulkan
|
|
||||||
PUBLISH_DIR: ${{ github.workspace }}\artifacts\publish\win-x64-native-test
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- name: Checkout repository
|
|
||||||
uses: actions/checkout@v6
|
|
||||||
|
|
||||||
- name: Setup .NET SDK
|
|
||||||
uses: actions/setup-dotnet@v5
|
|
||||||
with:
|
|
||||||
dotnet-version: 10.0.103
|
|
||||||
cache: true
|
|
||||||
cache-dependency-path: |
|
|
||||||
Directory.Packages.props
|
|
||||||
src/**/packages.lock.json
|
|
||||||
|
|
||||||
- name: Install native dependencies
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
& "$env:VCPKG_INSTALLATION_ROOT\vcpkg.exe" install sdl3[vulkan]:x64-windows vulkan:x64-windows
|
|
||||||
|
|
||||||
- name: Configure native backend
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
cmake `
|
|
||||||
-S src/SharpEmu.Gpu.Vulkan.Native `
|
|
||||||
-B "$env:NATIVE_BUILD_DIR" `
|
|
||||||
-A x64 `
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
|
|
||||||
-DVCPKG_TARGET_TRIPLET=x64-windows `
|
|
||||||
-DBUILD_TESTING=ON
|
|
||||||
|
|
||||||
- name: Build native backend and Windows-safe ABI test
|
|
||||||
run: cmake --build "$env:NATIVE_BUILD_DIR" --config Release --target sharpemu_gpu_vulkan_exports_test
|
|
||||||
|
|
||||||
- name: Run native DLL load and ABI test
|
|
||||||
run: ctest --test-dir "$env:NATIVE_BUILD_DIR" -C Release -R sharpemu_gpu_vulkan_exports_test --output-on-failure
|
|
||||||
|
|
||||||
- name: Restore solution
|
|
||||||
run: dotnet restore SharpEmu.slnx --locked-mode
|
|
||||||
|
|
||||||
- name: Build solution
|
|
||||||
run: dotnet build SharpEmu.slnx -c Release --no-restore
|
|
||||||
|
|
||||||
- name: Publish win-x64 emulator
|
|
||||||
run: dotnet publish src/SharpEmu.CLI/SharpEmu.CLI.csproj -c Release -r win-x64 --self-contained true --no-restore -p:PublishDir="${env:PUBLISH_DIR}"
|
|
||||||
|
|
||||||
- name: Verify published native runtime
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$required = @(
|
|
||||||
(Join-Path $env:PUBLISH_DIR 'SharpEmu.exe'),
|
|
||||||
(Join-Path $env:PUBLISH_DIR 'sharpemu_gpu_vulkan.dll'),
|
|
||||||
(Join-Path $env:PUBLISH_DIR 'SDL3.dll')
|
|
||||||
)
|
|
||||||
foreach ($path in $required) {
|
|
||||||
if (-not (Test-Path $path)) {
|
|
||||||
throw "Missing published runtime file: $path"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$exports = & dumpbin.exe /nologo /exports (Join-Path $env:PUBLISH_DIR 'sharpemu_gpu_vulkan.dll')
|
|
||||||
foreach ($name in @('se_gpu_abi_version', 'se_gpu_create', 'se_gpu_submit_draw', 'se_gpu_present_bgra')) {
|
|
||||||
if ($exports -notmatch "\b$name\b") {
|
|
||||||
throw "Missing native GPU export: $name"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Upload tested Windows package
|
|
||||||
uses: actions/upload-artifact@v7
|
|
||||||
with:
|
|
||||||
name: sharpemu-win-x64-native-backend-test-${{ github.sha }}
|
|
||||||
path: ${{ env.PUBLISH_DIR }}
|
|
||||||
if-no-files-found: error
|
|
||||||
retention-days: 7
|
|
||||||
@@ -96,19 +96,6 @@ jobs:
|
|||||||
Directory.Packages.props
|
Directory.Packages.props
|
||||||
Directory.Build.props
|
Directory.Build.props
|
||||||
|
|
||||||
- name: Install Windows native GPU dependencies
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
& "$env:VCPKG_INSTALLATION_ROOT\vcpkg.exe" install sdl3[vulkan]:x64-windows vulkan:x64-windows
|
|
||||||
|
|
||||||
cmake `
|
|
||||||
-S src/SharpEmu.Gpu.Vulkan.Native `
|
|
||||||
-B artifacts/native/gpu-vulkan `
|
|
||||||
-A x64 `
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE="$env:VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" `
|
|
||||||
-DVCPKG_TARGET_TRIPLET=x64-windows `
|
|
||||||
-DBUILD_TESTING=OFF
|
|
||||||
|
|
||||||
- name: Restore solution
|
- name: Restore solution
|
||||||
run: dotnet restore SharpEmu.slnx
|
run: dotnet restore SharpEmu.slnx
|
||||||
|
|
||||||
@@ -127,19 +114,6 @@ jobs:
|
|||||||
- name: Publish win-x64 CLI
|
- name: Publish win-x64 CLI
|
||||||
run: dotnet publish src/SharpEmu.CLI/SharpEmu.CLI.csproj -c Release -r win-x64 --self-contained true --no-restore -p:PublishDir="${env:PUBLISH_DIR}"
|
run: dotnet publish src/SharpEmu.CLI/SharpEmu.CLI.csproj -c Release -r win-x64 --self-contained true --no-restore -p:PublishDir="${env:PUBLISH_DIR}"
|
||||||
|
|
||||||
- name: Verify Windows native GPU runtime
|
|
||||||
shell: pwsh
|
|
||||||
run: |
|
|
||||||
$required = @(
|
|
||||||
(Join-Path $env:PUBLISH_DIR 'sharpemu_gpu_vulkan.dll'),
|
|
||||||
(Join-Path $env:PUBLISH_DIR 'SDL3.dll')
|
|
||||||
)
|
|
||||||
foreach ($path in $required) {
|
|
||||||
if (-not (Test-Path $path)) {
|
|
||||||
throw "Missing native GPU runtime: $path"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
- name: Create release archive
|
- name: Create release archive
|
||||||
run: |
|
run: |
|
||||||
New-Item -ItemType Directory -Path $env:RELEASE_DIR -Force | Out-Null
|
New-Item -ItemType Directory -Path $env:RELEASE_DIR -Force | Out-Null
|
||||||
@@ -191,42 +165,6 @@ jobs:
|
|||||||
Directory.Packages.props
|
Directory.Packages.props
|
||||||
Directory.Build.props
|
Directory.Build.props
|
||||||
|
|
||||||
- name: Install Linux native GPU dependencies
|
|
||||||
if: matrix.rid == 'linux-x64'
|
|
||||||
run: |
|
|
||||||
sudo apt-get update
|
|
||||||
sudo apt-get install --yes \
|
|
||||||
autoconf \
|
|
||||||
autoconf-archive \
|
|
||||||
automake \
|
|
||||||
libegl1-mesa-dev \
|
|
||||||
libibus-1.0-dev \
|
|
||||||
libtool \
|
|
||||||
libltdl-dev \
|
|
||||||
libvulkan-dev \
|
|
||||||
libwayland-dev \
|
|
||||||
libxkbcommon-dev \
|
|
||||||
pkg-config
|
|
||||||
"$VCPKG_INSTALLATION_ROOT/vcpkg" install sdl3[vulkan]:x64-linux
|
|
||||||
cmake \
|
|
||||||
-S src/SharpEmu.Gpu.Vulkan.Native \
|
|
||||||
-B artifacts/native/gpu-vulkan \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_TOOLCHAIN_FILE="$VCPKG_INSTALLATION_ROOT/scripts/buildsystems/vcpkg.cmake" \
|
|
||||||
-DVCPKG_TARGET_TRIPLET=x64-linux \
|
|
||||||
-DBUILD_TESTING=OFF
|
|
||||||
|
|
||||||
- name: Install macOS native GPU dependencies
|
|
||||||
if: matrix.rid == 'osx-x64'
|
|
||||||
run: |
|
|
||||||
brew install sdl3 vulkan-loader vulkan-headers
|
|
||||||
cmake \
|
|
||||||
-S src/SharpEmu.Gpu.Vulkan.Native \
|
|
||||||
-B artifacts/native/gpu-vulkan \
|
|
||||||
-DCMAKE_BUILD_TYPE=Release \
|
|
||||||
-DCMAKE_PREFIX_PATH="$(brew --prefix)" \
|
|
||||||
-DBUILD_TESTING=OFF
|
|
||||||
|
|
||||||
- name: Restore solution
|
- name: Restore solution
|
||||||
run: dotnet restore SharpEmu.slnx
|
run: dotnet restore SharpEmu.slnx
|
||||||
|
|
||||||
|
|||||||
@@ -58,21 +58,6 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<NoWarn>$(NoWarn);1591</NoWarn>
|
<NoWarn>$(NoWarn);1591</NoWarn>
|
||||||
<NativeGpuBuildDir>$(RepoRoot)artifacts\native\gpu-vulkan\bin</NativeGpuBuildDir>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
|
|
||||||
<NativeGpuHostLibrary>$(NativeGpuBuildDir)\sharpemu_gpu_vulkan.dll</NativeGpuHostLibrary>
|
|
||||||
<NativeGpuHostFileName>sharpemu_gpu_vulkan.dll</NativeGpuHostFileName>
|
|
||||||
<NativeGpuHostSdlLibrary>$(NativeGpuBuildDir)\SDL3.dll</NativeGpuHostSdlLibrary>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Linux'))">
|
|
||||||
<NativeGpuHostLibrary>$(NativeGpuBuildDir)\libsharpemu_gpu_vulkan.so</NativeGpuHostLibrary>
|
|
||||||
<NativeGpuHostFileName>libsharpemu_gpu_vulkan.so</NativeGpuHostFileName>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
|
||||||
<NativeGpuHostLibrary>$(NativeGpuBuildDir)\libsharpemu_gpu_vulkan.dylib</NativeGpuHostLibrary>
|
|
||||||
<NativeGpuHostFileName>libsharpemu_gpu_vulkan.dylib</NativeGpuHostFileName>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@@ -101,18 +86,4 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Target>
|
</Target>
|
||||||
|
|
||||||
<!-- Project-reference content does not reliably flow through a single-file
|
|
||||||
publish. Copy the optional native GPU runtime at the executable boundary
|
|
||||||
after bundling so NativeLibrary can resolve it by ABI name. -->
|
|
||||||
<Target Name="StageNativeGpuRuntime" AfterTargets="Publish"
|
|
||||||
Condition="Exists('$(NativeGpuHostLibrary)')">
|
|
||||||
<Copy SourceFiles="$(NativeGpuHostLibrary)"
|
|
||||||
DestinationFiles="$(PublishDir)$(NativeGpuHostFileName)"
|
|
||||||
SkipUnchangedFiles="true" />
|
|
||||||
<Copy SourceFiles="$(NativeGpuHostSdlLibrary)"
|
|
||||||
DestinationFiles="$(PublishDir)SDL3.dll"
|
|
||||||
SkipUnchangedFiles="true"
|
|
||||||
Condition="'$(NativeGpuHostSdlLibrary)' != '' And Exists('$(NativeGpuHostSdlLibrary)')" />
|
|
||||||
</Target>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
@@ -44,9 +44,10 @@
|
|||||||
"Options.CpuEngine.Native": "Native",
|
"Options.CpuEngine.Native": "Native",
|
||||||
|
|
||||||
"Options.RenderingBackend.Label": "Rendering backend",
|
"Options.RenderingBackend.Label": "Rendering backend",
|
||||||
"Options.RenderingBackend.Desc": "Graphics implementation used for newly launched games.",
|
"Options.RenderingBackend.Desc": "Graphics implementation used for newly launched games. Native Vulkan requires a separate library.",
|
||||||
"Options.RenderingBackend.Native": "Native Vulkan",
|
"Options.RenderingBackend.Native": "Native Vulkan (Experimental)",
|
||||||
"Options.RenderingBackend.Legacy": "Silk.NET Vulkan (Legacy)",
|
"Options.RenderingBackend.Legacy": "Silk.NET Vulkan (Default)",
|
||||||
|
"Launch.NativeBackendMissing": "WARNING: Native Vulkan is selected, but {0} was not found next to SharpEmu. Download it from https://github.com/sharpemu/sharpemu.vulkan or select Silk.NET Vulkan in Options.",
|
||||||
|
|
||||||
"Options.Strict.Label": "Strict dynlib resolution",
|
"Options.Strict.Label": "Strict dynlib resolution",
|
||||||
"Options.Strict.Desc": "Fail the launch when an imported symbol cannot be resolved.",
|
"Options.Strict.Desc": "Fail the launch when an imported symbol cannot be resolved.",
|
||||||
|
|||||||
@@ -211,8 +211,8 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
<ComboBox Grid.Column="1" x:Name="RenderingBackendBox" Width="200" SelectedIndex="0"
|
<ComboBox Grid.Column="1" x:Name="RenderingBackendBox" Width="200" SelectedIndex="0"
|
||||||
VerticalAlignment="Center" CornerRadius="8">
|
VerticalAlignment="Center" CornerRadius="8">
|
||||||
<ComboBoxItem x:Name="RenderingBackendLegacyItem" Content="Silk.NET Vulkan (Legacy)" />
|
<ComboBoxItem x:Name="RenderingBackendLegacyItem" Content="Silk.NET Vulkan (Default)" />
|
||||||
<ComboBoxItem x:Name="RenderingBackendNativeItem" Content="Native Vulkan" />
|
<ComboBoxItem x:Name="RenderingBackendNativeItem" Content="Native Vulkan (Experimental)" />
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|||||||
@@ -1496,6 +1496,22 @@ public partial class MainWindow : Window
|
|||||||
? "legacy"
|
? "legacy"
|
||||||
: "native");
|
: "native");
|
||||||
|
|
||||||
|
if (string.Equals(_settings.RenderingBackend, "Native", StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
var nativeLibraryName = OperatingSystem.IsWindows()
|
||||||
|
? "sharpemu_gpu_vulkan.dll"
|
||||||
|
: OperatingSystem.IsMacOS()
|
||||||
|
? "libsharpemu_gpu_vulkan.dylib"
|
||||||
|
: "libsharpemu_gpu_vulkan.so";
|
||||||
|
var emulatorDirectory = Path.GetDirectoryName(_emulatorExePath) ?? AppContext.BaseDirectory;
|
||||||
|
if (!File.Exists(Path.Combine(emulatorDirectory, nativeLibraryName)))
|
||||||
|
{
|
||||||
|
AppendConsoleLine(
|
||||||
|
Localization.Instance.Format("Launch.NativeBackendMissing", nativeLibraryName),
|
||||||
|
WarningLineBrush);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var emulator = new EmulatorProcess();
|
var emulator = new EmulatorProcess();
|
||||||
emulator.OutputReceived += (line, isError) => _pendingLines.Enqueue((line, isError));
|
emulator.OutputReceived += (line, isError) => _pendingLines.Enqueue((line, isError));
|
||||||
emulator.Exited += code => Dispatcher.UIThread.Post(() => OnEmulatorExited(code));
|
emulator.Exited += code => Dispatcher.UIThread.Post(() => OnEmulatorExited(code));
|
||||||
|
|||||||
@@ -1,88 +0,0 @@
|
|||||||
# Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
# SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.25)
|
|
||||||
project(SharpEmuGpuVulkan VERSION 0.1.0 LANGUAGES CXX)
|
|
||||||
|
|
||||||
find_package(Vulkan REQUIRED)
|
|
||||||
find_package(SDL3 CONFIG QUIET)
|
|
||||||
if(TARGET SDL3::SDL3)
|
|
||||||
set(SE_GPU_SDL_TARGET SDL3::SDL3)
|
|
||||||
elseif(TARGET SDL3::SDL3-shared)
|
|
||||||
set(SE_GPU_SDL_TARGET SDL3::SDL3-shared)
|
|
||||||
else()
|
|
||||||
find_package(PkgConfig REQUIRED)
|
|
||||||
pkg_check_modules(SDL3 REQUIRED IMPORTED_TARGET sdl3>=3.2)
|
|
||||||
set(SE_GPU_SDL_TARGET PkgConfig::SDL3)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
add_library(sharpemu_gpu_vulkan SHARED src/backend.cpp)
|
|
||||||
target_compile_features(sharpemu_gpu_vulkan PRIVATE cxx_std_20)
|
|
||||||
target_compile_definitions(sharpemu_gpu_vulkan PRIVATE SE_GPU_BUILD)
|
|
||||||
target_include_directories(sharpemu_gpu_vulkan PUBLIC include)
|
|
||||||
target_link_libraries(sharpemu_gpu_vulkan PRIVATE Vulkan::Vulkan ${SE_GPU_SDL_TARGET})
|
|
||||||
if(MSVC)
|
|
||||||
target_compile_options(sharpemu_gpu_vulkan PRIVATE /W4 /permissive- /EHsc)
|
|
||||||
else()
|
|
||||||
target_compile_options(sharpemu_gpu_vulkan PRIVATE -Wall -Wextra -Wpedantic -Wconversion -Werror)
|
|
||||||
endif()
|
|
||||||
set_target_properties(sharpemu_gpu_vulkan PROPERTIES
|
|
||||||
CXX_VISIBILITY_PRESET hidden
|
|
||||||
VISIBILITY_INLINES_HIDDEN YES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin"
|
|
||||||
LIBRARY_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
||||||
|
|
||||||
# Visual Studio is a multi-config generator and otherwise inserts an extra
|
|
||||||
# Debug/Release directory. Keep the ABI library at the path consumed by the
|
|
||||||
# managed project on every generator.
|
|
||||||
foreach(SE_GPU_CONFIG Debug Release RelWithDebInfo MinSizeRel)
|
|
||||||
string(TOUPPER "${SE_GPU_CONFIG}" SE_GPU_CONFIG_UPPER)
|
|
||||||
set_target_properties(sharpemu_gpu_vulkan PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY_${SE_GPU_CONFIG_UPPER} "${CMAKE_BINARY_DIR}/bin"
|
|
||||||
LIBRARY_OUTPUT_DIRECTORY_${SE_GPU_CONFIG_UPPER} "${CMAKE_BINARY_DIR}/bin")
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
add_custom_command(TARGET sharpemu_gpu_vulkan POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
|
||||||
$<TARGET_RUNTIME_DLLS:sharpemu_gpu_vulkan>
|
|
||||||
$<TARGET_FILE_DIR:sharpemu_gpu_vulkan>
|
|
||||||
COMMAND_EXPAND_LISTS)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
include(CTest)
|
|
||||||
if(BUILD_TESTING)
|
|
||||||
add_executable(sharpemu_gpu_vulkan_exports_test tests/exports_test.cpp)
|
|
||||||
target_link_libraries(sharpemu_gpu_vulkan_exports_test PRIVATE sharpemu_gpu_vulkan)
|
|
||||||
set_target_properties(sharpemu_gpu_vulkan_exports_test PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin")
|
|
||||||
foreach(SE_GPU_CONFIG Debug Release RelWithDebInfo MinSizeRel)
|
|
||||||
string(TOUPPER "${SE_GPU_CONFIG}" SE_GPU_CONFIG_UPPER)
|
|
||||||
set_target_properties(sharpemu_gpu_vulkan_exports_test PROPERTIES
|
|
||||||
RUNTIME_OUTPUT_DIRECTORY_${SE_GPU_CONFIG_UPPER} "${CMAKE_BINARY_DIR}/bin")
|
|
||||||
endforeach()
|
|
||||||
add_test(NAME sharpemu_gpu_vulkan_exports_test COMMAND sharpemu_gpu_vulkan_exports_test)
|
|
||||||
|
|
||||||
if(TARGET Vulkan::glslc)
|
|
||||||
set(SMOKE_COMPUTE_SPV "${CMAKE_CURRENT_BINARY_DIR}/smoke.comp.spv")
|
|
||||||
set(SMOKE_VERTEX_SPV "${CMAKE_CURRENT_BINARY_DIR}/smoke.vert.spv")
|
|
||||||
set(SMOKE_FRAGMENT_SPV "${CMAKE_CURRENT_BINARY_DIR}/smoke.frag.spv")
|
|
||||||
add_custom_command(OUTPUT "${SMOKE_COMPUTE_SPV}"
|
|
||||||
COMMAND Vulkan::glslc "${CMAKE_CURRENT_SOURCE_DIR}/tests/smoke.comp" -o "${SMOKE_COMPUTE_SPV}"
|
|
||||||
DEPENDS tests/smoke.comp VERBATIM)
|
|
||||||
add_custom_command(OUTPUT "${SMOKE_VERTEX_SPV}"
|
|
||||||
COMMAND Vulkan::glslc "${CMAKE_CURRENT_SOURCE_DIR}/tests/smoke.vert" -o "${SMOKE_VERTEX_SPV}"
|
|
||||||
DEPENDS tests/smoke.vert VERBATIM)
|
|
||||||
add_custom_command(OUTPUT "${SMOKE_FRAGMENT_SPV}"
|
|
||||||
COMMAND Vulkan::glslc "${CMAKE_CURRENT_SOURCE_DIR}/tests/smoke.frag" -o "${SMOKE_FRAGMENT_SPV}"
|
|
||||||
DEPENDS tests/smoke.frag VERBATIM)
|
|
||||||
add_custom_target(sharpemu_gpu_vulkan_test_shaders
|
|
||||||
DEPENDS "${SMOKE_COMPUTE_SPV}" "${SMOKE_VERTEX_SPV}" "${SMOKE_FRAGMENT_SPV}")
|
|
||||||
add_executable(sharpemu_gpu_vulkan_abi_test tests/abi_test.cpp)
|
|
||||||
target_link_libraries(sharpemu_gpu_vulkan_abi_test PRIVATE sharpemu_gpu_vulkan)
|
|
||||||
add_dependencies(sharpemu_gpu_vulkan_abi_test sharpemu_gpu_vulkan_test_shaders)
|
|
||||||
add_test(NAME sharpemu_gpu_vulkan_abi_test
|
|
||||||
COMMAND sharpemu_gpu_vulkan_abi_test
|
|
||||||
"${SMOKE_COMPUTE_SPV}" "${SMOKE_VERTEX_SPV}" "${SMOKE_FRAGMENT_SPV}")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
/* Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
#pragma once
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
|
||||||
# define SE_GPU_CALL __cdecl
|
|
||||||
# if defined(SE_GPU_BUILD)
|
|
||||||
# define SE_GPU_API __declspec(dllexport)
|
|
||||||
# else
|
|
||||||
# define SE_GPU_API __declspec(dllimport)
|
|
||||||
# endif
|
|
||||||
#else
|
|
||||||
# define SE_GPU_CALL
|
|
||||||
# define SE_GPU_API __attribute__((visibility("default")))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define SE_GPU_ABI_VERSION 1u
|
|
||||||
typedef struct se_gpu_backend se_gpu_backend;
|
|
||||||
typedef enum se_gpu_result {
|
|
||||||
SE_GPU_OK = 0, SE_GPU_NOT_FOUND = 1, SE_GPU_NOT_READY = 2,
|
|
||||||
SE_GPU_INVALID_ARGUMENT = -1, SE_GPU_INCOMPATIBLE_ABI = -2,
|
|
||||||
SE_GPU_PLATFORM_ERROR = -3, SE_GPU_VULKAN_ERROR = -4,
|
|
||||||
SE_GPU_OUT_OF_MEMORY = -5, SE_GPU_INTERNAL_ERROR = -6
|
|
||||||
} se_gpu_result;
|
|
||||||
typedef struct se_gpu_bytes { const void* data; size_t size; } se_gpu_bytes;
|
|
||||||
typedef void (SE_GPU_CALL *se_gpu_log_fn)(int32_t level, const char* message, void* user);
|
|
||||||
typedef struct se_gpu_create_info {
|
|
||||||
uint32_t struct_size, abi_version, width, height, enable_validation;
|
|
||||||
const char* title_utf8;
|
|
||||||
se_gpu_log_fn log; void* log_user;
|
|
||||||
} se_gpu_create_info;
|
|
||||||
typedef struct se_gpu_sampler { uint32_t words[4]; } se_gpu_sampler;
|
|
||||||
typedef struct se_gpu_texture {
|
|
||||||
uint32_t struct_size; uint64_t address; uint32_t width, height, format, number_type;
|
|
||||||
se_gpu_bytes rgba_pixels; uint32_t is_fallback, is_storage, mip_levels, mip_level;
|
|
||||||
uint32_t pitch, tile_mode, dst_select; se_gpu_sampler sampler;
|
|
||||||
} se_gpu_texture;
|
|
||||||
typedef struct se_gpu_memory_buffer { uint64_t address; se_gpu_bytes data; } se_gpu_memory_buffer;
|
|
||||||
typedef struct se_gpu_vertex_buffer {
|
|
||||||
uint32_t struct_size, location, component_count, data_format, number_format;
|
|
||||||
uint64_t address; uint32_t stride, offset_bytes; se_gpu_bytes data;
|
|
||||||
} se_gpu_vertex_buffer;
|
|
||||||
typedef struct se_gpu_index_buffer { se_gpu_bytes data; uint32_t is_32_bit; } se_gpu_index_buffer;
|
|
||||||
typedef struct se_gpu_rect { int32_t x, y; uint32_t width, height; } se_gpu_rect;
|
|
||||||
typedef struct se_gpu_viewport { float x, y, width, height, min_depth, max_depth; } se_gpu_viewport;
|
|
||||||
typedef struct se_gpu_blend {
|
|
||||||
uint32_t enable, color_src, color_dst, color_func, alpha_src, alpha_dst, alpha_func;
|
|
||||||
uint32_t separate_alpha, write_mask;
|
|
||||||
} se_gpu_blend;
|
|
||||||
typedef struct se_gpu_render_target {
|
|
||||||
uint32_t struct_size; uint64_t address; uint32_t width, height, format, number_type, mip_levels;
|
|
||||||
} se_gpu_render_target;
|
|
||||||
typedef struct se_gpu_draw {
|
|
||||||
uint32_t struct_size, width, height; se_gpu_bytes vertex_spirv, pixel_spirv;
|
|
||||||
const se_gpu_texture* textures; uint32_t texture_count;
|
|
||||||
const se_gpu_memory_buffer* memory_buffers; uint32_t memory_buffer_count;
|
|
||||||
const se_gpu_vertex_buffer* vertex_buffers; uint32_t vertex_buffer_count;
|
|
||||||
const se_gpu_render_target* targets; uint32_t target_count;
|
|
||||||
const se_gpu_blend* blends; uint32_t blend_count;
|
|
||||||
const se_gpu_index_buffer* index_buffer; const se_gpu_rect* scissor;
|
|
||||||
const se_gpu_viewport* viewport; uint32_t attribute_count, vertex_count, instance_count;
|
|
||||||
uint32_t primitive_type, publish_targets;
|
|
||||||
} se_gpu_draw;
|
|
||||||
typedef struct se_gpu_compute {
|
|
||||||
uint32_t struct_size; uint64_t shader_address; se_gpu_bytes spirv;
|
|
||||||
const se_gpu_texture* textures; uint32_t texture_count;
|
|
||||||
const se_gpu_memory_buffer* memory_buffers; uint32_t memory_buffer_count;
|
|
||||||
uint32_t groups_x, groups_y, groups_z;
|
|
||||||
} se_gpu_compute;
|
|
||||||
typedef struct se_gpu_input {
|
|
||||||
uint32_t struct_size, keyboard_focused, virtual_keys[8], gamepad_connected, gamepad_buttons;
|
|
||||||
uint8_t left_x, left_y, right_x, right_y, left_trigger, right_trigger, reserved[2];
|
|
||||||
char gamepad_name_utf8[128];
|
|
||||||
} se_gpu_input;
|
|
||||||
|
|
||||||
SE_GPU_API uint32_t SE_GPU_CALL se_gpu_abi_version(void);
|
|
||||||
SE_GPU_API const char* SE_GPU_CALL se_gpu_last_error(const se_gpu_backend* backend);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_create(const se_gpu_create_info*, se_gpu_backend**);
|
|
||||||
SE_GPU_API void SE_GPU_CALL se_gpu_destroy(se_gpu_backend*);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_poll(se_gpu_backend*, uint32_t* should_close);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_input_snapshot(se_gpu_backend*, se_gpu_input*);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_present_bgra(
|
|
||||||
se_gpu_backend*, const void* pixels, size_t size, uint32_t width, uint32_t height, uint32_t pitch);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_submit_draw(se_gpu_backend*, const se_gpu_draw*);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_submit_compute(se_gpu_backend*, const se_gpu_compute*);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_register_display_buffer(se_gpu_backend*, uint64_t, uint32_t);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_present_guest_image(
|
|
||||||
se_gpu_backend*, uint64_t, uint32_t, uint32_t, uint32_t);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_has_guest_image(
|
|
||||||
se_gpu_backend*, uint64_t, uint32_t, uint32_t);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_blit_guest_image(
|
|
||||||
se_gpu_backend*, uint64_t, uint32_t, uint32_t, uint32_t,
|
|
||||||
uint64_t, uint32_t, uint32_t, uint32_t);
|
|
||||||
SE_GPU_API se_gpu_result SE_GPU_CALL se_gpu_render_target_output_kind(
|
|
||||||
uint32_t format, uint32_t number_type, uint32_t* output_kind);
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,58 +0,0 @@
|
|||||||
/* Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
|
|
||||||
#include "sharpemu_gpu_vulkan.h"
|
|
||||||
#include <algorithm>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <fstream>
|
|
||||||
#include <iterator>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
std::vector<char> read_file(const char* path) {
|
|
||||||
std::ifstream file(path, std::ios::binary);
|
|
||||||
return {std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>()};
|
|
||||||
}
|
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
|
||||||
if (se_gpu_abi_version() != SE_GPU_ABI_VERSION) return 1;
|
|
||||||
uint32_t output_kind{};
|
|
||||||
if (se_gpu_render_target_output_kind(10, 4, &output_kind) != SE_GPU_OK || output_kind != 1) return 5;
|
|
||||||
if (se_gpu_render_target_output_kind(0xffffffffu, 0, &output_kind) != SE_GPU_NOT_FOUND) return 6;
|
|
||||||
se_gpu_create_info info{}; info.struct_size = sizeof(info); info.abi_version = SE_GPU_ABI_VERSION;
|
|
||||||
info.width = 64; info.height = 64; info.title_utf8 = "SharpEmu native GPU test";
|
|
||||||
se_gpu_backend* backend{};
|
|
||||||
if (se_gpu_create(&info, &backend) != SE_GPU_OK) return 2;
|
|
||||||
if (argc != 4) { se_gpu_destroy(backend); return 8; }
|
|
||||||
std::vector<char> shader = read_file(argv[1]);
|
|
||||||
se_gpu_compute compute{}; compute.struct_size = sizeof(compute);
|
|
||||||
compute.spirv = {shader.data(), shader.size()}; compute.groups_x = 1; compute.groups_y = 1; compute.groups_z = 1;
|
|
||||||
if (shader.empty() || se_gpu_submit_compute(backend, &compute) != SE_GPU_OK) {
|
|
||||||
se_gpu_destroy(backend); return 9;
|
|
||||||
}
|
|
||||||
std::vector<char> vertex = read_file(argv[2]);
|
|
||||||
std::vector<char> fragment = read_file(argv[3]);
|
|
||||||
se_gpu_draw draw{}; draw.struct_size = sizeof(draw); draw.width = 64; draw.height = 64;
|
|
||||||
draw.vertex_spirv = {vertex.data(), vertex.size()}; draw.pixel_spirv = {fragment.data(), fragment.size()};
|
|
||||||
std::vector<uint32_t> padded_texture(8, 0xff804020u);
|
|
||||||
se_gpu_texture texture{}; texture.struct_size = sizeof(texture); texture.width = 2; texture.height = 2;
|
|
||||||
texture.format = 10; texture.pitch = 4; texture.dst_select = 0x324;
|
|
||||||
texture.rgba_pixels = {padded_texture.data(), padded_texture.size() * sizeof(uint32_t)};
|
|
||||||
draw.textures = &texture; draw.texture_count = 1;
|
|
||||||
draw.vertex_count = 3; draw.instance_count = 1; draw.primitive_type = 4;
|
|
||||||
if (vertex.empty() || fragment.empty() || se_gpu_submit_draw(backend, &draw) != SE_GPU_OK) {
|
|
||||||
se_gpu_destroy(backend); return 10;
|
|
||||||
}
|
|
||||||
std::vector<uint32_t> pixels(64 * 64);
|
|
||||||
for (uint32_t frame = 0; frame < 3; ++frame) {
|
|
||||||
std::fill(pixels.begin(), pixels.end(), 0xff000000u | frame * 0x00303030u);
|
|
||||||
if (se_gpu_present_bgra(backend, pixels.data(), pixels.size() * sizeof(uint32_t), 64, 64, 256) != SE_GPU_OK) {
|
|
||||||
se_gpu_destroy(backend); return 3;
|
|
||||||
}
|
|
||||||
uint32_t close{}; if (se_gpu_poll(backend, &close) != SE_GPU_OK || close) {
|
|
||||||
se_gpu_destroy(backend); return 4;
|
|
||||||
}
|
|
||||||
se_gpu_input input{}; input.struct_size = sizeof(input);
|
|
||||||
if (se_gpu_input_snapshot(backend, &input) != SE_GPU_OK) { se_gpu_destroy(backend); return 7; }
|
|
||||||
}
|
|
||||||
se_gpu_destroy(backend); return 0;
|
|
||||||
}
|
|
||||||
@@ -1,14 +0,0 @@
|
|||||||
/* Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
||||||
#include "sharpemu_gpu_vulkan.h"
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
if (se_gpu_abi_version() != SE_GPU_ABI_VERSION) return 1;
|
|
||||||
|
|
||||||
uint32_t output_kind{};
|
|
||||||
if (se_gpu_render_target_output_kind(10, 4, &output_kind) != SE_GPU_OK || output_kind != 1) return 2;
|
|
||||||
if (se_gpu_render_target_output_kind(10, 5, &output_kind) != SE_GPU_OK || output_kind != 2) return 3;
|
|
||||||
if (se_gpu_render_target_output_kind(0xffffffffu, 0, &output_kind) != SE_GPU_NOT_FOUND) return 4;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
|
|
||||||
void main() {}
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
layout(location = 0) out vec4 color;
|
|
||||||
layout(set = 0, binding = 1) uniform sampler2D sourceTexture;
|
|
||||||
void main() { color = texture(sourceTexture, gl_FragCoord.xy / vec2(64.0)); }
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
// Copyright (C) 2026 SharpEmu Emulator Project
|
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
||||||
|
|
||||||
#version 450
|
|
||||||
vec2 positions[3] = vec2[](vec2(-1.0, -1.0), vec2(3.0, -1.0), vec2(-1.0, 3.0));
|
|
||||||
void main() { gl_Position = vec4(positions[gl_VertexIndex], 0.0, 1.0); }
|
|
||||||
@@ -13,13 +13,25 @@ namespace SharpEmu.Libs.Gpu;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class GuestGpu
|
internal static class GuestGpu
|
||||||
{
|
{
|
||||||
private static readonly Lazy<IGuestGpuBackend> Instance = new(static () =>
|
private static readonly Lazy<IGuestGpuBackend> Instance = new(CreateBackend);
|
||||||
string.Equals(
|
|
||||||
Environment.GetEnvironmentVariable("SHARPEMU_GPU_BACKEND"),
|
|
||||||
"native",
|
|
||||||
StringComparison.OrdinalIgnoreCase)
|
|
||||||
? new NativeVulkanGuestGpuBackend()
|
|
||||||
: new VulkanGuestGpuBackend());
|
|
||||||
|
|
||||||
public static IGuestGpuBackend Current => Instance.Value;
|
public static IGuestGpuBackend Current => Instance.Value;
|
||||||
|
|
||||||
|
private static IGuestGpuBackend CreateBackend()
|
||||||
|
{
|
||||||
|
if (!string.Equals(
|
||||||
|
Environment.GetEnvironmentVariable("SHARPEMU_GPU_BACKEND"),
|
||||||
|
"native",
|
||||||
|
StringComparison.OrdinalIgnoreCase))
|
||||||
|
{
|
||||||
|
return new VulkanGuestGpuBackend();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NativeVulkanApi.IsAvailable(out var error))
|
||||||
|
{
|
||||||
|
Console.Error.WriteLine($"[LOADER][WARN] {error}");
|
||||||
|
}
|
||||||
|
|
||||||
|
return new NativeVulkanGuestGpuBackend();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,31 @@ internal static unsafe partial class NativeVulkanApi
|
|||||||
internal const uint AbiVersion = 1;
|
internal const uint AbiVersion = 1;
|
||||||
private const string Library = "sharpemu_gpu_vulkan";
|
private const string Library = "sharpemu_gpu_vulkan";
|
||||||
|
|
||||||
|
internal static string LibraryFileName =>
|
||||||
|
OperatingSystem.IsWindows() ? "sharpemu_gpu_vulkan.dll" :
|
||||||
|
OperatingSystem.IsMacOS() ? "libsharpemu_gpu_vulkan.dylib" :
|
||||||
|
"libsharpemu_gpu_vulkan.so";
|
||||||
|
|
||||||
|
internal static bool IsAvailable(out string error)
|
||||||
|
{
|
||||||
|
if (NativeLibrary.TryLoad(
|
||||||
|
Library,
|
||||||
|
typeof(NativeVulkanApi).Assembly,
|
||||||
|
DllImportSearchPath.SafeDirectories | DllImportSearchPath.AssemblyDirectory,
|
||||||
|
out var handle))
|
||||||
|
{
|
||||||
|
NativeLibrary.Free(handle);
|
||||||
|
error = string.Empty;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
error =
|
||||||
|
$"The optional native Vulkan backend was selected, but {LibraryFileName} could not be loaded. " +
|
||||||
|
"Place the library from https://github.com/sharpemu/sharpemu.vulkan next to the SharpEmu executable " +
|
||||||
|
"and ensure its SDL3 and Vulkan runtime dependencies are installed.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal struct CreateInfo
|
internal struct CreateInfo
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -34,7 +34,16 @@ internal sealed unsafe class NativeVulkanGuestGpuBackend : IGuestGpuBackend
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ready.Wait();
|
_ready.Wait();
|
||||||
if (_startError is not null) throw new InvalidOperationException("Native Vulkan startup failed", _startError);
|
if (_startError is not null)
|
||||||
|
{
|
||||||
|
if (_startError is DllNotFoundException)
|
||||||
|
{
|
||||||
|
_ = NativeVulkanApi.IsAvailable(out var error);
|
||||||
|
throw new InvalidOperationException(error, _startError);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new InvalidOperationException("Native Vulkan startup failed", _startError);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryCompileVertexShader(Gen5ShaderState state, Gen5ShaderEvaluation evaluation,
|
public bool TryCompileVertexShader(Gen5ShaderState state, Gen5ShaderEvaluation evaluation,
|
||||||
|
|||||||
@@ -37,46 +37,5 @@ SPDX-License-Identifier: GPL-2.0-or-later
|
|||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
<NativeGpuProjectDir>$(MSBuildThisFileDirectory)..\SharpEmu.Gpu.Vulkan.Native</NativeGpuProjectDir>
|
|
||||||
<NativeGpuBuildDir>$(RepoRoot)artifacts\native\gpu-vulkan</NativeGpuBuildDir>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Windows'))">
|
|
||||||
<NativeGpuLibrary>$(NativeGpuBuildDir)\bin\sharpemu_gpu_vulkan.dll</NativeGpuLibrary>
|
|
||||||
<NativeGpuFileName>sharpemu_gpu_vulkan.dll</NativeGpuFileName>
|
|
||||||
<NativeGpuSdlLibrary>$(NativeGpuBuildDir)\bin\SDL3.dll</NativeGpuSdlLibrary>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('Linux'))">
|
|
||||||
<NativeGpuLibrary>$(NativeGpuBuildDir)\bin\libsharpemu_gpu_vulkan.so</NativeGpuLibrary>
|
|
||||||
<NativeGpuFileName>libsharpemu_gpu_vulkan.so</NativeGpuFileName>
|
|
||||||
</PropertyGroup>
|
|
||||||
<PropertyGroup Condition="$([MSBuild]::IsOSPlatform('OSX'))">
|
|
||||||
<NativeGpuLibrary>$(NativeGpuBuildDir)\bin\libsharpemu_gpu_vulkan.dylib</NativeGpuLibrary>
|
|
||||||
<NativeGpuFileName>libsharpemu_gpu_vulkan.dylib</NativeGpuFileName>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup Condition="'$(NativeGpuLibrary)' != ''">
|
|
||||||
<None Include="$(NativeGpuLibrary)"
|
|
||||||
Link="$(NativeGpuFileName)"
|
|
||||||
CopyToOutputDirectory="PreserveNewest"
|
|
||||||
CopyToPublishDirectory="PreserveNewest" />
|
|
||||||
<None Include="$(NativeGpuSdlLibrary)"
|
|
||||||
Condition="'$(NativeGpuSdlLibrary)' != ''"
|
|
||||||
Link="SDL3.dll"
|
|
||||||
CopyToOutputDirectory="PreserveNewest"
|
|
||||||
CopyToPublishDirectory="PreserveNewest" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
<!-- Native outputs must exist before MSBuild evaluates/copies Content items.
|
|
||||||
Hooking Build is too late on a clean checkout: CopyFilesToOutputDirectory
|
|
||||||
runs first and fails because the library has not been produced yet. -->
|
|
||||||
<Target Name="BuildNativeGuestGpu" BeforeTargets="PrepareForBuild" Condition="'$(NativeGpuLibrary)' != ''">
|
|
||||||
<Exec Command="cmake -S "$(NativeGpuProjectDir)" -B "$(NativeGpuBuildDir)" -DCMAKE_BUILD_TYPE=$(Configuration) -DBUILD_TESTING=OFF" />
|
|
||||||
<Exec Command="cmake --build "$(NativeGpuBuildDir)" --config $(Configuration)" />
|
|
||||||
<Copy SourceFiles="$(NativeGpuLibrary)" DestinationFolder="$(TargetDir)" SkipUnchangedFiles="true" />
|
|
||||||
<Copy SourceFiles="$(NativeGpuSdlLibrary)"
|
|
||||||
DestinationFolder="$(TargetDir)"
|
|
||||||
SkipUnchangedFiles="true"
|
|
||||||
Condition="'$(NativeGpuSdlLibrary)' != ''" />
|
|
||||||
</Target>
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|||||||
Reference in New Issue
Block a user