Validation Layer Filter + Fix `Texture`, GPU & `PresentationEngine` bugs

This commit implements a filter by type for any validation layer output, this allows filtering out any logs which may be unnecessary and additionally triggering a breakpoint as required. 

An issue concerning the `NDEBUG` flag never being set was fixed, it's now supplied as a release compiler flag. The issue can manifest itself by always relying on a validation layer even though it shouldn't on release, this is why the validation layer was mistakenly disabled entirely previously by using `#ifndef` rather than `#ifdef`.

An issue with the initial layout of a texture being supplied as neither `VK_IMAGE_LAYOUT_UNDEFINED` or `VK_IMAGE_LAYOUT_PREINITIALIZED` was fixed, these cases are now handled by transitioning to those layouts after creating the image rather than supplying it within `initialLayout`.

Another issue was fixed regarding not maintaining a transformation after a surface has been destroyed and recreated existed and manifested itself when the user would go out of the app and come back in, they would see the surface having an identity transformation rather than the desired one.
This commit is contained in:
PixelyIon 2021-09-14 21:13:16 +05:30
parent 54908afc44
commit bee28aaf0d
8 changed files with 102 additions and 22 deletions

View File

@ -60,7 +60,7 @@
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="JDK" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">

View File

@ -1,3 +1,3 @@
<component name="DependencyValidationManager">
<scope name="SkylineNative" pattern="file[skyline.app]:src/main/cpp//*.cpp||file[skyline.app]:src/main/cpp//*.h||file[skyline.app]:src/main/cpp//*.S" />
</component>
<scope name="SkylineNative" pattern="file[skyline.app]:src/main/cpp//*.cpp||file[skyline.app]:src/main/cpp//*.h||file[skyline.app]:src/main/cpp//*.S||file[skyline.app]:src/main/cpp//*.natvis" />
</component>

View File

@ -10,11 +10,8 @@ set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(source_DIR ${CMAKE_SOURCE_DIR}/src/main/cpp)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -fno-stack-protector -Wno-unused-command-line-argument")
if (uppercase_CMAKE_BUILD_TYPE STREQUAL "RELEASE")
add_compile_definitions(NDEBUG)
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE)
endif ()
set(CMAKE_CXX_FLAGS_RELEASE "-Ofast -flto=full -fno-stack-protector -Wno-unused-command-line-argument -DNDEBUG")
set(CMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE TRUE)
# {fmt}
add_subdirectory("libraries/fmt")

View File

@ -13,7 +13,7 @@ namespace skyline::gpu {
.apiVersion = VkApiVersion,
};
#ifndef NDEBUG
#ifdef NDEBUG
constexpr std::array<const char *, 0> requiredLayers{};
#else
constexpr std::array<const char *, 1> requiredLayers{
@ -82,7 +82,33 @@ namespace skyline::gpu {
Logger::LogLevel::Error, // VK_DEBUG_REPORT_ERROR_BIT_EXT
Logger::LogLevel::Debug, // VK_DEBUG_REPORT_DEBUG_BIT_EXT
};
#define IGNORE_VALIDATION(string) \
case util::Hash(string): \
if(string == type) \
return VK_FALSE; \
else \
break
#define DEBUG_VALIDATION(string) \
case util::Hash(string): \
if(string == type) \
__builtin_debugtrap(); \
break
std::string_view type(message);
auto first{type.find_first_of('[') + 2};
type = type.substr(first, type.find_first_of(']', first) - 4);
switch (util::Hash(type)) {
IGNORE_VALIDATION("UNASSIGNED-CoreValidation-SwapchainPreTransform"); // We handle transformation via Android APIs directly
IGNORE_VALIDATION("UNASSIGNED-GeneralParameterPerfWarn-SuboptimalSwapchain"); // Same as SwapchainPreTransform
}
#undef IGNORE_TYPE
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;
}

View File

@ -190,6 +190,9 @@ namespace skyline::gpu {
if (windowScalingMode != NativeWindowScalingMode::ScaleToWindow && (result = window->perform(window, NATIVE_WINDOW_SET_SCALING_MODE, static_cast<i32>(windowScalingMode))))
throw exception("Setting the layer scaling mode to '{}' failed with {}", ToString(windowScalingMode), result);
if (windowTransform != NativeWindowTransform::Identity && (result = window->perform(window, NATIVE_WINDOW_SET_BUFFERS_TRANSFORM, static_cast<i32>(windowTransform))))
throw exception("Setting the buffer transform to '{}' failed with {}", ToString(windowTransform), result);
if ((result = window->perform(window, NATIVE_WINDOW_ENABLE_FRAME_TIMESTAMPS, true)))
throw exception("Enabling frame timestamps failed with {}", result);
@ -226,6 +229,8 @@ namespace skyline::gpu {
windowTransform = transform;
}
gpu.vkDevice.resetFences(*acquireFence);
std::pair<vk::Result, u32> nextImage;
while (nextImage = vkSwapchain->acquireNextImage(std::numeric_limits<u64>::max(), {}, *acquireFence), nextImage.first != vk::Result::eSuccess) [[unlikely]] {
if (nextImage.first == vk::Result::eSuboptimalKHR)

View File

@ -7,19 +7,38 @@
#include "texture.h"
namespace skyline::gpu {
Texture::Texture(GPU &gpu, BackingType &&backing, GuestTexture guest, texture::Dimensions dimensions, texture::Format format, vk::ImageLayout layout, vk::ImageTiling tiling, u32 mipLevels, u32 layerCount, vk::SampleCountFlagBits sampleCount) : gpu(gpu), backing(std::move(backing)), layout(layout), guest(std::move(guest)), dimensions(dimensions), format(format), tiling(tiling), mipLevels(mipLevels), layerCount(layerCount), sampleCount(sampleCount) {
Texture::Texture(GPU &gpu, BackingType &&backing, GuestTexture guest, texture::Dimensions dimensions, texture::Format format, vk::ImageLayout layout, vk::ImageTiling tiling, u32 mipLevels, u32 layerCount, vk::SampleCountFlagBits sampleCount)
: gpu(gpu),
backing(std::move(backing)),
layout(layout),
guest(std::move(guest)),
dimensions(dimensions),
format(format),
tiling(tiling),
mipLevels(mipLevels),
layerCount(layerCount),
sampleCount(sampleCount) {
if (GetBacking())
SynchronizeHost();
}
Texture::Texture(GPU &gpu, BackingType &&backing, texture::Dimensions dimensions, texture::Format format, vk::ImageLayout layout, vk::ImageTiling tiling, u32 mipLevels, u32 layerCount, vk::SampleCountFlagBits sampleCount) : gpu(gpu), backing(std::move(backing)), dimensions(dimensions), format(format), layout(layout), tiling(tiling), mipLevels(mipLevels), layerCount(layerCount), sampleCount(sampleCount) {}
Texture::Texture(GPU &gpu, BackingType &&backing, texture::Dimensions dimensions, texture::Format format, vk::ImageLayout layout, vk::ImageTiling tiling, u32 mipLevels, u32 layerCount, vk::SampleCountFlagBits sampleCount)
: gpu(gpu),
backing(std::move(backing)),
dimensions(dimensions),
format(format),
layout(layout),
tiling(tiling),
mipLevels(mipLevels),
layerCount(layerCount),
sampleCount(sampleCount) {}
Texture::Texture(GPU &pGpu, GuestTexture pGuest)
: gpu(pGpu),
guest(std::move(pGuest)),
dimensions(guest->dimensions),
format(guest->format),
layout(vk::ImageLayout::eGeneral),
layout(vk::ImageLayout::eUndefined),
tiling((guest->tileConfig.mode == texture::TileMode::Block) ? vk::ImageTiling::eOptimal : vk::ImageTiling::eLinear),
mipLevels(1),
layerCount(guest->layerCount),
@ -39,9 +58,18 @@ namespace skyline::gpu {
.initialLayout = layout,
};
backing = tiling != vk::ImageTiling::eLinear ? gpu.memory.AllocateImage(imageCreateInfo) : gpu.memory.AllocateMappedImage(imageCreateInfo);
TransitionLayout(vk::ImageLayout::eGeneral);
}
Texture::Texture(GPU &gpu, texture::Dimensions dimensions, texture::Format format, vk::ImageLayout initialLayout, vk::ImageUsageFlags usage, vk::ImageTiling tiling, u32 mipLevels, u32 layerCount, vk::SampleCountFlagBits sampleCount) : gpu(gpu), dimensions(dimensions), format(format), layout(initialLayout), tiling(tiling), mipLevels(mipLevels), layerCount(layerCount), sampleCount(sampleCount) {
Texture::Texture(GPU &gpu, texture::Dimensions dimensions, texture::Format format, vk::ImageLayout initialLayout, vk::ImageUsageFlags usage, vk::ImageTiling tiling, u32 mipLevels, u32 layerCount, vk::SampleCountFlagBits sampleCount)
: gpu(gpu),
dimensions(dimensions),
format(format),
layout(initialLayout == vk::ImageLayout::ePreinitialized ? vk::ImageLayout::ePreinitialized : vk::ImageLayout::eUndefined),
tiling(tiling),
mipLevels(mipLevels),
layerCount(layerCount),
sampleCount(sampleCount) {
vk::ImageCreateInfo imageCreateInfo{
.imageType = dimensions.GetType(),
.format = *format,
@ -54,9 +82,11 @@ namespace skyline::gpu {
.sharingMode = vk::SharingMode::eExclusive,
.queueFamilyIndexCount = 1,
.pQueueFamilyIndices = &gpu.vkQueueFamilyIndex,
.initialLayout = initialLayout,
.initialLayout = layout,
};
backing = tiling != vk::ImageTiling::eLinear ? gpu.memory.AllocateImage(imageCreateInfo) : gpu.memory.AllocateMappedImage(imageCreateInfo);
if (initialLayout != layout)
TransitionLayout(initialLayout);
}
bool Texture::WaitOnBacking() {
@ -354,7 +384,6 @@ namespace skyline::gpu {
TextureView::TextureView(std::shared_ptr<Texture> backing, vk::ImageViewType type, vk::ImageSubresourceRange range, texture::Format format, vk::ComponentMapping mapping) : backing(std::move(backing)), type(type), format(format), mapping(mapping), range(range) {}
vk::ImageView TextureView::GetView() {
/*
if (view)
return **view;
@ -369,14 +398,21 @@ namespace skyline::gpu {
}
}()};
return *view.emplace(backing->gpu.vkDevice, vk::ImageViewCreateInfo{
vk::ImageViewCreateInfo createInfo{
.image = backing->GetBacking(),
.viewType = vk::ImageViewType::eCube,
.viewType = viewType,
.format = format ? *format : *backing->format,
.components = mapping,
.subresourceRange = range,
});
*/
throw exception("TODO: TextureView::GetView");
};
auto &views{backing->views};
auto iterator{std::find_if(views.begin(), views.end(), [&](const std::pair<vk::ImageViewCreateInfo, vk::raii::ImageView> &item) {
return item.first == createInfo;
})};
if (iterator != views.end())
return *iterator->second;
return *views.emplace_back(createInfo, vk::raii::ImageView(backing->gpu.vkDevice, createInfo)).second;
}
}

View File

@ -115,6 +115,7 @@ namespace skyline::gpu {
/**
* @brief A wrapper around a pointer to underlying format metadata to prevent redundant copies
* @note The equality operators **do not** compare equality for pointers but for the underlying formats while considering nullability
*/
class Format {
private:
@ -133,6 +134,14 @@ namespace skyline::gpu {
return *base;
}
constexpr bool operator==(const Format &format) const {
return base && format.base ? (*base) == (*format.base) : base == format.base;
}
constexpr bool operator!=(const Format &format) const {
return base && format.base ? (*base) != (*format.base) : base != format.base;
}
constexpr operator bool() const {
return base;
}
@ -281,6 +290,10 @@ namespace skyline::gpu {
* @return A Vulkan Image View that corresponds to the properties of this view
*/
vk::ImageView GetView();
bool operator==(const TextureView &rhs) {
return backing == rhs.backing && type == rhs.type && format == rhs.format && mapping == rhs.mapping && range == rhs.range;
}
};
/**
@ -294,11 +307,14 @@ namespace skyline::gpu {
std::condition_variable backingCondition; //!< Signalled when a valid backing has been swapped in
using BackingType = std::variant<vk::Image, vk::raii::Image, memory::Image>;
BackingType backing; //!< The Vulkan image that backs this texture, it is nullable
std::shared_ptr<FenceCycle> cycle; //!< A fence cycle for when any host operation mutating the texture has completed, it must be waited on prior to any mutations to the backing
std::vector<std::pair<vk::ImageViewCreateInfo, vk::raii::ImageView>> views; //!< VkImageView(s) that have been constructed from this Texture, utilized for caching
friend TextureManager;
friend TextureView;
public:
std::shared_ptr<FenceCycle> cycle; //!< A fence cycle for when any host operation mutating the texture has completed, it must be waited on prior to any mutations to the backing
std::optional<GuestTexture> guest;
texture::Dimensions dimensions;
texture::Format format;

View File

@ -171,9 +171,9 @@ namespace skyline::nce {
/* Replace Skyline TLS with host TLS */
*patch++ = 0xD53BD041; // MRS X1, TPIDR_EL0
*patch++ = 0xF9415022; // LDR X2, [X1, #0x2A0] (ThreadContext::hostTpidrEl0)
*patch++ = 0xD51BD042; // MSR TPIDR_EL0, X2
/* Replace guest stack with host stack */
*patch++ = 0xD51BD042; // MSR TPIDR_EL0, X2
*patch++ = 0x910003E2; // MOV X2, SP
*patch++ = 0xF9415423; // LDR X3, [X1, #0x2A8] (ThreadContext::hostSp)
*patch++ = 0x9100007F; // MOV SP, X3