mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-27 15:25:38 +03: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
8ceed74371
5
.idea/vcs.xml
generated
5
.idea/vcs.xml
generated
@ -11,5 +11,10 @@
|
||||
<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/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>
|
||||
</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_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/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/resampler.cpp
|
||||
${source_DIR}/skyline/audio/adpcm_decoder.cpp
|
||||
${source_DIR}/skyline/gpu.cpp
|
||||
${source_DIR}/skyline/gpu/presentation_engine.cpp
|
||||
${source_DIR}/skyline/gpu/texture.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 {
|
||||
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 {
|
||||
/* Filetrees */
|
||||
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/kernel/types/KProcess.h"
|
||||
|
||||
skyline::u16 Fps;
|
||||
skyline::u32 FrameTime;
|
||||
skyline::i32 Fps;
|
||||
skyline::i32 FrameTime;
|
||||
std::weak_ptr<skyline::kernel::OS> OsWeak;
|
||||
std::weak_ptr<skyline::gpu::GPU> GpuWeak;
|
||||
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));
|
||||
} 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) {
|
||||
logger->Error("An exception has occurred: {}", e.what());
|
||||
logger->ErrorNoPrefix("An uncaught exception has occurred: {}", e.what());
|
||||
} catch (...) {
|
||||
logger->Error("An unknown exception has occurred");
|
||||
logger->ErrorNoPrefix("An unknown uncaught exception has occurred");
|
||||
}
|
||||
|
||||
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
|
||||
*/
|
||||
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:
|
||||
PresentationEngine presentation;
|
||||
|
||||
GPU(const DeviceState &state) : presentation(state) {}
|
||||
GPU(const DeviceState &state);
|
||||
};
|
||||
}
|
||||
|
@ -5,8 +5,8 @@
|
||||
#include "jvm.h"
|
||||
#include "presentation_engine.h"
|
||||
|
||||
extern skyline::u16 Fps;
|
||||
extern skyline::u32 FrameTime;
|
||||
extern skyline::i32 Fps;
|
||||
extern skyline::i32 FrameTime;
|
||||
|
||||
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()) {
|
||||
|
@ -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 {
|
||||
Linear, //!< This is a purely linear texture
|
||||
|
Loading…
Reference in New Issue
Block a user