mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-11-23 03:29:19 +01:00
Vulkan Instance + Validation Layer + Debug Report Initialization
The GPU class has been extended in this for Vulkan initialization, this is done to the point of initializing the instance alongside loading in `VK_LAYER_KHRONOS_validation` which is also now packed into all Debug APKs for Skyline. In addition, `VK_EXT_debug_report` is also initialized and it's output is piped directly into the Logger. A minor change regarding the type of the `Fps` and `Frametime` globals was changed to `skyline::i32`s which is a more suitable type due to those having a smaller chance of overflowing while being signed as Java doesn't have unsigned integral types.
This commit is contained in:
parent
5be7860cf7
commit
8b0d056c54
@ -11,5 +11,10 @@
|
|||||||
<mapping directory="$PROJECT_DIR$/app/libraries/tzcode" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/app/libraries/tzcode" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/app/libraries/vk-headers" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/app/libraries/vk-headers" vcs="Git" />
|
||||||
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp" vcs="Git" />
|
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp/Vulkan-Headers" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp/glfw" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp/glm" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp/glslang" vcs="Git" />
|
||||||
|
<mapping directory="$PROJECT_DIR$/app/libraries/vkhpp/tinyxml2" vcs="Git" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
@ -31,7 +31,7 @@ include_directories("libraries/lz4/lib")
|
|||||||
|
|
||||||
add_compile_definitions(VULKAN_HPP_NO_SPACESHIP_OPERATOR) # libcxx doesn't implement operator<=> for std::array which breaks this
|
add_compile_definitions(VULKAN_HPP_NO_SPACESHIP_OPERATOR) # libcxx doesn't implement operator<=> for std::array which breaks this
|
||||||
add_compile_definitions(VULKAN_HPP_NO_STRUCT_CONSTRUCTORS) # We want to use designated initializers in Vulkan-Hpp
|
add_compile_definitions(VULKAN_HPP_NO_STRUCT_CONSTRUCTORS) # We want to use designated initializers in Vulkan-Hpp
|
||||||
add_compile_definitions(VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1) # We use the dynamic loader rather than the static one
|
add_compile_definitions(VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1) # We use the dynamic loader rather than the static one to avoid an additional level of indirection
|
||||||
include_directories("libraries/vkhpp")
|
include_directories("libraries/vkhpp")
|
||||||
include_directories("libraries/vkhpp/Vulkan-Headers/include") # We use base Vulkan headers from this to ensure version parity with Vulkan-Hpp
|
include_directories("libraries/vkhpp/Vulkan-Headers/include") # We use base Vulkan headers from this to ensure version parity with Vulkan-Hpp
|
||||||
|
|
||||||
@ -72,6 +72,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/audio/track.cpp
|
${source_DIR}/skyline/audio/track.cpp
|
||||||
${source_DIR}/skyline/audio/resampler.cpp
|
${source_DIR}/skyline/audio/resampler.cpp
|
||||||
${source_DIR}/skyline/audio/adpcm_decoder.cpp
|
${source_DIR}/skyline/audio/adpcm_decoder.cpp
|
||||||
|
${source_DIR}/skyline/gpu.cpp
|
||||||
${source_DIR}/skyline/gpu/presentation_engine.cpp
|
${source_DIR}/skyline/gpu/presentation_engine.cpp
|
||||||
${source_DIR}/skyline/gpu/texture.cpp
|
${source_DIR}/skyline/gpu/texture.cpp
|
||||||
${source_DIR}/skyline/soc/gmmu.cpp
|
${source_DIR}/skyline/soc/gmmu.cpp
|
||||||
|
@ -71,11 +71,44 @@ android {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Vulkan Validation Layers */
|
||||||
|
sourceSets {
|
||||||
|
debug {
|
||||||
|
main {
|
||||||
|
jniLibs {
|
||||||
|
srcDir "$buildDir/generated/vulkan_layers"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Android Assets */
|
||||||
aaptOptions {
|
aaptOptions {
|
||||||
ignoreAssetsPattern "*.md"
|
ignoreAssetsPattern "*.md"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We just want VK_LAYER_KHRONOS_validation in the APK while NDK contains several other legacy layers
|
||||||
|
* This task copies shared objects associated with that layer into a folder from where JNI can use it
|
||||||
|
*/
|
||||||
|
task setupValidationLayer(type: Copy) {
|
||||||
|
doFirst {
|
||||||
|
def folder = new File("$buildDir/generated/vulkan_layers")
|
||||||
|
if (!folder.exists()) {
|
||||||
|
folder.mkdirs() // We need to recursively create all directories as the copy requires the output directory to exist
|
||||||
|
}
|
||||||
|
}
|
||||||
|
from("${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs") {
|
||||||
|
include "*/libVkLayer_khronos_validation.so"
|
||||||
|
}
|
||||||
|
into "$buildDir/generated/vulkan_layers"
|
||||||
|
}
|
||||||
|
|
||||||
|
afterEvaluate {
|
||||||
|
preDebugBuild.dependsOn setupValidationLayer
|
||||||
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
/* Filetrees */
|
/* Filetrees */
|
||||||
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar'])
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit de5ced3d4b76dd24bc43628127e26a9c7eb098d3
|
Subproject commit f638311337d6b0eaf63e84c6e9afe1227539e0d3
|
@ -19,8 +19,8 @@
|
|||||||
#include "skyline/input.h"
|
#include "skyline/input.h"
|
||||||
#include "skyline/kernel/types/KProcess.h"
|
#include "skyline/kernel/types/KProcess.h"
|
||||||
|
|
||||||
skyline::u16 Fps;
|
skyline::i32 Fps;
|
||||||
skyline::u32 FrameTime;
|
skyline::i32 FrameTime;
|
||||||
std::weak_ptr<skyline::kernel::OS> OsWeak;
|
std::weak_ptr<skyline::kernel::OS> OsWeak;
|
||||||
std::weak_ptr<skyline::gpu::GPU> GpuWeak;
|
std::weak_ptr<skyline::gpu::GPU> GpuWeak;
|
||||||
std::weak_ptr<skyline::input::Input> InputWeak;
|
std::weak_ptr<skyline::input::Input> InputWeak;
|
||||||
@ -85,11 +85,11 @@ extern "C" JNIEXPORT void Java_emu_skyline_EmulationActivity_executeApplication(
|
|||||||
|
|
||||||
os->Execute(romFd, static_cast<skyline::loader::RomFormat>(romType));
|
os->Execute(romFd, static_cast<skyline::loader::RomFormat>(romType));
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
logger->Error("An exception has occurred: {}", e.what());
|
logger->ErrorNoPrefix("An uncaught exception has occurred: {}", e.what());
|
||||||
} catch (const skyline::signal::SignalException &e) {
|
} catch (const skyline::signal::SignalException &e) {
|
||||||
logger->Error("An exception has occurred: {}", e.what());
|
logger->ErrorNoPrefix("An uncaught exception has occurred: {}", e.what());
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
logger->Error("An unknown exception has occurred");
|
logger->ErrorNoPrefix("An unknown uncaught exception has occurred");
|
||||||
}
|
}
|
||||||
|
|
||||||
perfetto::TrackEvent::Flush();
|
perfetto::TrackEvent::Flush();
|
||||||
|
98
app/src/main/cpp/skyline/gpu.cpp
Normal file
98
app/src/main/cpp/skyline/gpu.cpp
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
// SPDX-License-Identifier: LGPL-3.0-or-later
|
||||||
|
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||||
|
|
||||||
|
#include "gpu.h"
|
||||||
|
|
||||||
|
namespace skyline::gpu {
|
||||||
|
vk::raii::Instance GPU::CreateInstance(const DeviceState &state, const vk::raii::Context &context) {
|
||||||
|
vk::ApplicationInfo applicationInfo{
|
||||||
|
.pApplicationName = "Skyline",
|
||||||
|
.applicationVersion = VK_MAKE_VERSION('S', 'K', 'Y'), // "SKY" magic as the application version
|
||||||
|
.pEngineName = "GPU",
|
||||||
|
.engineVersion = VK_MAKE_VERSION('G', 'P', 'U'), // "GPU" magic as engine version
|
||||||
|
.apiVersion = VK_API_VERSION_1_1,
|
||||||
|
};
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
std::array<const char *, 0> requiredLayers{};
|
||||||
|
#else
|
||||||
|
std::array<const char *, 1> requiredLayers{
|
||||||
|
"VK_LAYER_KHRONOS_validation"
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto instanceLayers{context.enumerateInstanceLayerProperties()};
|
||||||
|
if (state.logger->configLevel >= Logger::LogLevel::Debug) {
|
||||||
|
std::string layers;
|
||||||
|
for (const auto &instanceLayer : instanceLayers)
|
||||||
|
layers += fmt::format("\n* {} (Sv{}.{}.{}, Iv{}.{}.{}) - {}", instanceLayer.layerName, VK_VERSION_MAJOR(instanceLayer.specVersion), VK_VERSION_MINOR(instanceLayer.specVersion), VK_VERSION_PATCH(instanceLayer.specVersion), VK_VERSION_MAJOR(instanceLayer.implementationVersion), VK_VERSION_MINOR(instanceLayer.implementationVersion), VK_VERSION_PATCH(instanceLayer.implementationVersion), instanceLayer.description);
|
||||||
|
state.logger->Debug("Vulkan Layers:{}", layers);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &requiredLayer : requiredLayers) {
|
||||||
|
if (![&] {
|
||||||
|
for (const auto &instanceLayer : instanceLayers)
|
||||||
|
if (std::string_view(instanceLayer.layerName) == std::string_view(requiredLayer))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}())
|
||||||
|
throw exception("Cannot find Vulkan layer: \"{}\"", requiredLayer);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef NDEBUG
|
||||||
|
std::array<const char*, 0> requiredInstanceExtensions{};
|
||||||
|
#else
|
||||||
|
std::array<const char *, 1> requiredInstanceExtensions{
|
||||||
|
VK_EXT_DEBUG_REPORT_EXTENSION_NAME
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
auto instanceExtensions{context.enumerateInstanceExtensionProperties()};
|
||||||
|
if (state.logger->configLevel >= Logger::LogLevel::Debug) {
|
||||||
|
std::string extensions;
|
||||||
|
for (const auto &instanceExtension : instanceExtensions)
|
||||||
|
extensions += fmt::format("\n* {} (v{}.{}.{})", instanceExtension.extensionName, VK_VERSION_MAJOR(instanceExtension.specVersion), VK_VERSION_MINOR(instanceExtension.specVersion), VK_VERSION_PATCH(instanceExtension.specVersion));
|
||||||
|
state.logger->Debug("Vulkan Instance Extensions:{}", extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &requiredExtension : requiredInstanceExtensions) {
|
||||||
|
if (![&] {
|
||||||
|
for (const auto &instanceExtension : instanceExtensions)
|
||||||
|
if (std::string_view(instanceExtension.extensionName) == std::string_view(requiredExtension))
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}())
|
||||||
|
throw exception("Cannot find Vulkan instance extension: \"{}\"", requiredExtension);
|
||||||
|
}
|
||||||
|
|
||||||
|
return vk::raii::Instance(context, vk::InstanceCreateInfo{
|
||||||
|
.pApplicationInfo = &applicationInfo,
|
||||||
|
.enabledLayerCount = requiredLayers.size(),
|
||||||
|
.ppEnabledLayerNames = requiredLayers.data(),
|
||||||
|
.enabledExtensionCount = requiredInstanceExtensions.size(),
|
||||||
|
.ppEnabledExtensionNames = requiredInstanceExtensions.data(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
vk::raii::DebugReportCallbackEXT GPU::CreateDebugReportCallback(const DeviceState &state, const vk::raii::Instance &instance) {
|
||||||
|
return vk::raii::DebugReportCallbackEXT(instance, vk::DebugReportCallbackCreateInfoEXT{
|
||||||
|
.flags = vk::DebugReportFlagBitsEXT::eError | vk::DebugReportFlagBitsEXT::eWarning | vk::DebugReportFlagBitsEXT::ePerformanceWarning | vk::DebugReportFlagBitsEXT::eInformation | vk::DebugReportFlagBitsEXT::eDebug,
|
||||||
|
.pfnCallback = reinterpret_cast<PFN_vkDebugReportCallbackEXT>(&DebugCallback),
|
||||||
|
.pUserData = state.logger.get(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
GPU::GPU(const DeviceState &state) : presentation(state), instance(CreateInstance(state, context)), debugReportCallback(CreateDebugReportCallback(state, instance)) {}
|
||||||
|
|
||||||
|
VkBool32 GPU::DebugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char *layerPrefix, const char *message, Logger *logger) {
|
||||||
|
constexpr std::array<Logger::LogLevel, 5> severityLookup{
|
||||||
|
Logger::LogLevel::Info, // VK_DEBUG_REPORT_INFORMATION_BIT_EXT
|
||||||
|
Logger::LogLevel::Warn, // VK_DEBUG_REPORT_WARNING_BIT_EXT
|
||||||
|
Logger::LogLevel::Warn, // VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT
|
||||||
|
Logger::LogLevel::Error, // VK_DEBUG_REPORT_ERROR_BIT_EXT
|
||||||
|
Logger::LogLevel::Debug, // VK_DEBUG_REPORT_DEBUG_BIT_EXT
|
||||||
|
};
|
||||||
|
logger->Write(severityLookup.at(std::countr_zero(static_cast<u32>(flags))), util::Format("Vk{}:{}[0x{:X}]:I{}:L{}: {}", layerPrefix, vk::to_string(vk::DebugReportObjectTypeEXT(objectType)), object, messageCode, location, message));
|
||||||
|
return VK_FALSE;
|
||||||
|
}
|
||||||
|
}
|
@ -10,9 +10,21 @@ namespace skyline::gpu {
|
|||||||
* @brief An interface to host GPU structures, anything concerning host GPU/Presentation APIs is encapsulated by this
|
* @brief An interface to host GPU structures, anything concerning host GPU/Presentation APIs is encapsulated by this
|
||||||
*/
|
*/
|
||||||
class GPU {
|
class GPU {
|
||||||
|
private:
|
||||||
|
vk::raii::Context context;
|
||||||
|
vk::raii::Instance instance;
|
||||||
|
vk::raii::DebugReportCallbackEXT debugReportCallback;
|
||||||
|
vk::Device device;
|
||||||
|
|
||||||
|
static vk::raii::Instance CreateInstance(const DeviceState &state, const vk::raii::Context &context);
|
||||||
|
|
||||||
|
static vk::raii::DebugReportCallbackEXT CreateDebugReportCallback(const DeviceState &state, const vk::raii::Instance &instance);
|
||||||
|
|
||||||
|
static VKAPI_ATTR VkBool32 VKAPI_CALL DebugCallback(VkDebugReportFlagsEXT flags, VkDebugReportObjectTypeEXT objectType, uint64_t object, size_t location, int32_t messageCode, const char *layerPrefix, const char *message, Logger *logger);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PresentationEngine presentation;
|
PresentationEngine presentation;
|
||||||
|
|
||||||
GPU(const DeviceState &state) : presentation(state) {}
|
GPU(const DeviceState &state);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -5,8 +5,8 @@
|
|||||||
#include "jvm.h"
|
#include "jvm.h"
|
||||||
#include "presentation_engine.h"
|
#include "presentation_engine.h"
|
||||||
|
|
||||||
extern skyline::u16 Fps;
|
extern skyline::i32 Fps;
|
||||||
extern skyline::u32 FrameTime;
|
extern skyline::i32 FrameTime;
|
||||||
|
|
||||||
namespace skyline::gpu {
|
namespace skyline::gpu {
|
||||||
PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)), presentationTrack(static_cast<u64>(trace::TrackIds::Presentation), perfetto::ProcessTrack::Current()) {
|
PresentationEngine::PresentationEngine(const DeviceState &state) : state(state), vsyncEvent(std::make_shared<kernel::type::KEvent>(state, true)), bufferEvent(std::make_shared<kernel::type::KEvent>(state, true)), presentationTrack(static_cast<u64>(trace::TrackIds::Presentation), perfetto::ProcessTrack::Current()) {
|
||||||
|
@ -70,7 +70,8 @@ namespace skyline {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief The linearity of a texture, refer to Chapter 20.1 of the Tegra X1 TRM for information
|
* @brief The layout of a texture in GPU memory
|
||||||
|
* @note Refer to Chapter 20.1 of the Tegra X1 TRM for information
|
||||||
*/
|
*/
|
||||||
enum class TileMode {
|
enum class TileMode {
|
||||||
Linear, //!< This is a purely linear texture
|
Linear, //!< This is a purely linear texture
|
||||||
|
Loading…
Reference in New Issue
Block a user