Address CR Comments

This commit is contained in:
PixelyIon 2021-10-22 15:29:38 +05:30
parent 595e53f7cf
commit ea2626bcc6
13 changed files with 304 additions and 269 deletions

View File

@ -102,6 +102,7 @@ add_library(skyline SHARED
${source_DIR}/skyline/gpu/texture/texture.cpp
${source_DIR}/skyline/gpu/presentation_engine.cpp
${source_DIR}/skyline/gpu/interconnect/command_executor.cpp
${source_DIR}/skyline/gpu/interconnect/command_nodes.cpp
${source_DIR}/skyline/soc/host1x/syncpoint.cpp
${source_DIR}/skyline/soc/gm20b/channel.cpp
${source_DIR}/skyline/soc/gm20b/gpfifo.cpp

View File

@ -24,8 +24,7 @@ namespace skyline {
public:
template<typename... Args>
ThreadLocal(Args &&... args) : constructor([args...]() { return new Type(args...); }) {
int result;
if ((result = pthread_key_create(&key, nullptr)))
if (int result = pthread_key_create(&key, nullptr))
throw exception("Cannot create pthread_key: {}", strerror(result));
}
@ -34,9 +33,8 @@ namespace skyline {
if (pointer)
return static_cast<Type *>(pointer);
int result;
Type *object{constructor(*this)};
if ((result = pthread_setspecific(key, object)))
if (int result = pthread_setspecific(key, object))
throw exception("Cannot set pthread_key to constructed type: {}", strerror(result));
return object;
@ -89,8 +87,7 @@ namespace skyline {
static_cast<IntrustiveTypeNode *>(object)->~IntrustiveTypeNode();
}};
int result;
if ((result = pthread_key_create(&key, destructor)))
if (int result = pthread_key_create(&key, destructor))
throw exception("Cannot create pthread_key: {}", strerror(result));
}
@ -99,9 +96,8 @@ namespace skyline {
if (pointer)
return &static_cast<IntrustiveTypeNode *>(pointer)->object;
int result;
IntrustiveTypeNode *node{constructor(*this)};
if ((result = pthread_setspecific(key, node)))
if (int result = pthread_setspecific(key, node))
throw exception("Cannot set pthread_key to constructed type: {}", strerror(result));
auto next{list.load(std::memory_order_acquire)};

View File

@ -85,13 +85,13 @@ namespace skyline::gpu {
#define IGNORE_VALIDATION(string) \
case util::Hash(string): \
if(string == type) \
if (string == type) \
return VK_FALSE; \
break
#define DEBUG_VALIDATION(string) \
case util::Hash(string): \
if(string == type) \
if (string == type) \
raise(SIGTRAP); \
break
// Using __builtin_debugtrap() as opposed to raise(SIGTRAP) will result in the inability to continue
@ -101,7 +101,6 @@ namespace skyline::gpu {
auto last{type.find(']', first)};
if (first != std::string_view::npos && last != std::string_view::npos) {
type = type.substr(first + 2, last != std::string_view::npos ? last - 4 : last);
std::string typeStr{type};
switch (util::Hash(type)) {
IGNORE_VALIDATION("UNASSIGNED-CoreValidation-SwapchainPreTransform"); // We handle transformation via Android APIs directly

View File

@ -5,6 +5,8 @@
#include "command_executor.h"
namespace skyline::gpu::interconnect {
CommandExecutor::CommandExecutor(const DeviceState &state) : gpu(*state.gpu) {}
bool CommandExecutor::CreateRenderpass(vk::Rect2D renderArea) {
if (renderpass && renderpass->renderArea != renderArea) {
nodes.emplace_back(std::in_place_type_t<node::RenderpassEndNode>());

View File

@ -25,7 +25,7 @@ namespace skyline::gpu::interconnect {
bool CreateRenderpass(vk::Rect2D renderArea);
public:
CommandExecutor(const DeviceState &state) : gpu(*state.gpu) {}
CommandExecutor(const DeviceState &state);
/**
* @brief Adds a command that needs to be executed inside a subpass configured with certain attachments

View File

@ -0,0 +1,219 @@
// SPDX-License-Identifier: MPL-2.0
// Copyright © 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
#include "command_nodes.h"
namespace skyline::gpu::interconnect::node {
RenderpassNode::Storage::~Storage() {
if (device) {
if (framebuffer)
(**device).destroy(framebuffer, nullptr, *device->getDispatcher());
if (renderpass)
(**device).destroy(renderpass, nullptr, *device->getDispatcher());
}
}
u32 RenderpassNode::AddAttachment(TextureView &view) {
auto &textures{storage->textures};
auto texture{std::find(textures.begin(), textures.end(), view.backing)};
if (texture == textures.end())
textures.push_back(view.backing);
auto vkView{view.GetView()};
auto attachment{std::find(attachments.begin(), attachments.end(), vkView)};
if (attachment == attachments.end()) {
// If we cannot find any matches for the specified attachment, we add it as a new one
attachments.push_back(vkView);
attachmentDescriptions.push_back(vk::AttachmentDescription{
.format = *view.format,
.initialLayout = view.backing->layout,
.finalLayout = view.backing->layout,
});
return attachments.size() - 1;
} else {
// If we've got a match from a previous subpass, we need to preserve the attachment till the current subpass
auto attachmentIndex{std::distance(attachments.begin(), attachment)};
auto it{subpassDescriptions.begin()};
for (; it != subpassDescriptions.end(); it++) {
// Find the bounds for the attachment references belonging to the current subpass
auto referenceBeginIt{attachmentReferences.begin()};
referenceBeginIt += reinterpret_cast<uintptr_t>(it->pInputAttachments) / sizeof(vk::AttachmentReference);
auto referenceEndIt{referenceBeginIt + it->inputAttachmentCount + it->colorAttachmentCount}; // We depend on all attachments being contiguous for a subpass, this will horribly break if that assumption is broken
if (reinterpret_cast<uintptr_t>(it->pDepthStencilAttachment) != NoDepthStencil)
referenceEndIt++;
// Iterate over all attachment references in the current subpass to see if they point to our target attachment
if (std::find_if(referenceBeginIt, referenceEndIt, [&](const vk::AttachmentReference &reference) {
return reference.attachment == attachmentIndex;
}) != referenceEndIt)
break; // The iterator should be set to the first subpass that utilizes the attachment we want to preserve
}
if (it == subpassDescriptions.end())
throw exception("Cannot find corresponding subpass for attachment #{}", attachmentIndex);
auto lastUsageIt{it}; //!< The last subpass that the attachment has been used in for creating a dependency
for (; it != subpassDescriptions.end(); it++) {
auto referenceBeginIt{attachmentReferences.begin()};
referenceBeginIt += reinterpret_cast<uintptr_t>(it->pInputAttachments) / sizeof(vk::AttachmentReference);
auto referenceEndIt{referenceBeginIt + it->inputAttachmentCount + it->colorAttachmentCount};
if (reinterpret_cast<uintptr_t>(it->pDepthStencilAttachment) != NoDepthStencil)
referenceEndIt++;
if (std::find_if(referenceBeginIt, referenceEndIt, [&](const vk::AttachmentReference &reference) {
return reference.attachment == attachmentIndex;
}) != referenceEndIt) {
lastUsageIt = it;
continue; // If a subpass uses an attachment then it doesn't need to be preserved
}
auto &subpassPreserveAttachments{preserveAttachmentReferences[std::distance(subpassDescriptions.begin(), it)]};
if (std::find(subpassPreserveAttachments.begin(), subpassPreserveAttachments.end(), attachmentIndex) != subpassPreserveAttachments.end())
subpassPreserveAttachments.push_back(attachmentIndex);
}
vk::SubpassDependency dependency{
.srcSubpass = static_cast<u32>(std::distance(subpassDescriptions.begin(), lastUsageIt)),
.dstSubpass = static_cast<uint32_t>(subpassDescriptions.size()), // We assume that the next subpass is using the attachment
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead,
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
};
if (std::find(subpassDependencies.begin(), subpassDependencies.end(), dependency) == subpassDependencies.end())
subpassDependencies.push_back(dependency);
return attachmentIndex;
}
}
void RenderpassNode::AddSubpass(span<TextureView> inputAttachments, span<TextureView> colorAttachments, TextureView *depthStencilAttachment) {
attachmentReferences.reserve(attachmentReferences.size() + inputAttachments.size() + colorAttachments.size() + (depthStencilAttachment ? 1 : 0));
auto inputAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)};
for (auto &attachment : inputAttachments) {
attachmentReferences.push_back(vk::AttachmentReference{
.attachment = AddAttachment(attachment),
.layout = attachment.backing->layout,
});
}
auto colorAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)}; // Calculate new base offset as it has changed since we pushed the input attachments
for (auto &attachment : colorAttachments) {
attachmentReferences.push_back(vk::AttachmentReference{
.attachment = AddAttachment(attachment),
.layout = attachment.backing->layout,
});
}
auto depthStencilAttachmentOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)};
if (depthStencilAttachment) {
attachmentReferences.push_back(vk::AttachmentReference{
.attachment = AddAttachment(*depthStencilAttachment),
.layout = depthStencilAttachment->backing->layout,
});
}
preserveAttachmentReferences.emplace_back(); // We need to create storage for any attachments that might need to preserved by this pass
// Note: We encode the offsets as the pointers due to vector pointer invalidation, RebasePointer(...) can be utilized to deduce the real pointer
subpassDescriptions.push_back(vk::SubpassDescription{
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = static_cast<u32>(inputAttachments.size()),
.pInputAttachments = reinterpret_cast<vk::AttachmentReference *>(inputAttachmentsOffset),
.colorAttachmentCount = static_cast<u32>(colorAttachments.size()),
.pColorAttachments = reinterpret_cast<vk::AttachmentReference *>(colorAttachmentsOffset),
.pDepthStencilAttachment = reinterpret_cast<vk::AttachmentReference *>(depthStencilAttachment ? depthStencilAttachmentOffset : NoDepthStencil),
});
}
bool RenderpassNode::ClearColorAttachment(u32 colorAttachment, const vk::ClearColorValue &value) {
auto attachmentReference{RebasePointer(attachmentReferences, subpassDescriptions.back().pColorAttachments) + colorAttachment};
auto attachmentIndex{attachmentReference->attachment};
for (const auto &reference : attachmentReferences)
if (reference.attachment == attachmentIndex && &reference != attachmentReference)
return false;
auto &attachmentDescription{attachmentDescriptions.at(attachmentIndex)};
if (attachmentDescription.loadOp == vk::AttachmentLoadOp::eLoad) {
attachmentDescription.loadOp = vk::AttachmentLoadOp::eClear;
clearValues.resize(attachmentIndex + 1);
clearValues[attachmentIndex].color = value;
return true;
} else if (attachmentDescription.loadOp == vk::AttachmentLoadOp::eClear && clearValues[attachmentIndex].color.uint32 == value.uint32) {
return true;
}
return false;
}
void RenderpassNode::operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu) {
storage->device = &gpu.vkDevice;
auto preserveAttachmentIt{preserveAttachmentReferences.begin()};
for (auto &subpassDescription : subpassDescriptions) {
subpassDescription.pInputAttachments = RebasePointer(attachmentReferences, subpassDescription.pInputAttachments);
subpassDescription.pColorAttachments = RebasePointer(attachmentReferences, subpassDescription.pColorAttachments);
auto depthStencilAttachmentOffset{reinterpret_cast<uintptr_t>(subpassDescription.pDepthStencilAttachment)};
if (depthStencilAttachmentOffset != NoDepthStencil)
subpassDescription.pDepthStencilAttachment = RebasePointer(attachmentReferences, subpassDescription.pDepthStencilAttachment);
else
subpassDescription.pDepthStencilAttachment = nullptr;
subpassDescription.preserveAttachmentCount = preserveAttachmentIt->size();
subpassDescription.pPreserveAttachments = preserveAttachmentIt->data();
preserveAttachmentIt++;
}
for (auto &texture : storage->textures) {
texture->lock();
texture->WaitOnBacking();
if (texture->cycle.lock() != cycle)
texture->WaitOnFence();
}
auto renderpass{(*gpu.vkDevice).createRenderPass(vk::RenderPassCreateInfo{
.attachmentCount = static_cast<u32>(attachmentDescriptions.size()),
.pAttachments = attachmentDescriptions.data(),
.subpassCount = static_cast<u32>(subpassDescriptions.size()),
.pSubpasses = subpassDescriptions.data(),
.dependencyCount = static_cast<u32>(subpassDependencies.size()),
.pDependencies = subpassDependencies.data(),
}, nullptr, *gpu.vkDevice.getDispatcher())};
storage->renderpass = renderpass;
auto framebuffer{(*gpu.vkDevice).createFramebuffer(vk::FramebufferCreateInfo{
.renderPass = renderpass,
.attachmentCount = static_cast<u32>(attachments.size()),
.pAttachments = attachments.data(),
.width = renderArea.extent.width,
.height = renderArea.extent.height,
.layers = 1,
}, nullptr, *gpu.vkDevice.getDispatcher())};
storage->framebuffer = framebuffer;
commandBuffer.beginRenderPass(vk::RenderPassBeginInfo{
.renderPass = renderpass,
.framebuffer = framebuffer,
.renderArea = renderArea,
.clearValueCount = static_cast<u32>(clearValues.size()),
.pClearValues = clearValues.data(),
}, vk::SubpassContents::eInline);
cycle->AttachObjects(storage);
for (auto &texture : storage->textures) {
texture->unlock();
texture->cycle = cycle;
}
}
}

View File

@ -24,25 +24,22 @@ namespace skyline::gpu::interconnect::node {
using FunctionNode = FunctionNodeBase<>;
/**
* @brief Creates and begins a VkRenderpass while tying lifetimes of all bound resources to a GPU fence
* @brief Creates and begins a VkRenderpass alongside managing all resources bound to it and to the subpasses inside it
*/
struct RenderpassNode {
private:
/**
* @brief Storage for all resources in the VkRenderPass that have their lifetimes bond to the completion fence
*/
struct Storage : public FenceCycleDependency {
vk::raii::Device *device{};
vk::Framebuffer framebuffer{};
vk::RenderPass renderpass{};
std::vector<std::shared_ptr<Texture>> textures;
~Storage() {
if (device) {
if (framebuffer)
(**device).destroy(framebuffer, nullptr, *device->getDispatcher());
if (renderpass)
(**device).destroy(renderpass, nullptr, *device->getDispatcher());
}
}
~Storage();
};
std::shared_ptr<Storage> storage;
std::vector<vk::ImageView> attachments;
@ -51,13 +48,13 @@ namespace skyline::gpu::interconnect::node {
std::vector<vk::AttachmentReference> attachmentReferences;
std::vector<std::vector<u32>> preserveAttachmentReferences; //!< Any attachment that must be preserved to be utilized by a future subpass, these are stored per-subpass to ensure contiguity
constexpr static uintptr_t DepthStencilNull{std::numeric_limits<uintptr_t>::max()}; //!< A sentinel value to denote the lack of a depth stencil attachment in a VkSubpassDescription
constexpr static uintptr_t NoDepthStencil{std::numeric_limits<uintptr_t>::max()}; //!< A sentinel value to denote the lack of a depth stencil attachment in a VkSubpassDescription
/**
* @brief Rebases a pointer containing an offset relative to the beginning of a container
*/
template<typename Container, typename T>
T *RebasePointer(const Container &container, const T *offset) {
constexpr T *RebasePointer(const Container &container, const T *offset) {
return reinterpret_cast<T *>(reinterpret_cast<uintptr_t>(container.data()) + reinterpret_cast<uintptr_t>(offset));
}
@ -74,125 +71,12 @@ namespace skyline::gpu::interconnect::node {
* @note Any preservation of attachments from previous subpasses is automatically handled by this
* @return The index of the attachment in the render pass which can be utilized with VkAttachmentReference
*/
u32 AddAttachment(TextureView &view) {
auto &textures{storage->textures};
auto texture{std::find(textures.begin(), textures.end(), view.backing)};
if (texture == textures.end())
textures.push_back(view.backing);
auto vkView{view.GetView()};
auto attachment{std::find(attachments.begin(), attachments.end(), vkView)};
if (attachment == attachments.end()) {
// If we cannot find any matches for the specified attachment, we add it as a new one
attachments.push_back(vkView);
attachmentDescriptions.push_back(vk::AttachmentDescription{
.format = *view.format,
.initialLayout = view.backing->layout,
.finalLayout = view.backing->layout,
});
return attachments.size() - 1;
} else {
// If we've got a match from a previous subpass, we need to preserve the attachment till the current subpass
auto attachmentIndex{std::distance(attachments.begin(), attachment)};
auto it{subpassDescriptions.begin()};
for (; it != subpassDescriptions.end(); it++) {
auto referenceBeginIt{attachmentReferences.begin()};
referenceBeginIt += reinterpret_cast<uintptr_t>(it->pInputAttachments) / sizeof(vk::AttachmentReference);
auto referenceEndIt{referenceBeginIt + it->inputAttachmentCount + it->colorAttachmentCount}; // We depend on all attachments being contiguous for a subpass, this will horribly break if that assumption is broken
if (reinterpret_cast<uintptr_t>(it->pDepthStencilAttachment) != DepthStencilNull)
referenceEndIt++;
if (std::find_if(referenceBeginIt, referenceEndIt, [&](const vk::AttachmentReference &reference) {
return reference.attachment == attachmentIndex;
}) != referenceEndIt)
break; // The first subpass that utilizes the attachment we want to preserve
}
if (it == subpassDescriptions.end())
throw exception("Cannot find corresponding subpass for attachment #{}", attachmentIndex);
auto lastUsageIt{it};
for (; it != subpassDescriptions.end(); it++) {
auto referenceBeginIt{attachmentReferences.begin()};
referenceBeginIt += reinterpret_cast<uintptr_t>(it->pInputAttachments) / sizeof(vk::AttachmentReference);
auto referenceEndIt{referenceBeginIt + it->inputAttachmentCount + it->colorAttachmentCount};
if (reinterpret_cast<uintptr_t>(it->pDepthStencilAttachment) != DepthStencilNull)
referenceEndIt++;
if (std::find_if(referenceBeginIt, referenceEndIt, [&](const vk::AttachmentReference &reference) {
return reference.attachment == attachmentIndex;
}) != referenceEndIt) {
lastUsageIt = it;
continue; // If a subpass uses an attachment then it doesn't need to be preserved
}
auto &subpassPreserveAttachments{preserveAttachmentReferences[std::distance(subpassDescriptions.begin(), it)]};
if (std::find(subpassPreserveAttachments.begin(), subpassPreserveAttachments.end(), attachmentIndex) != subpassPreserveAttachments.end())
subpassPreserveAttachments.push_back(attachmentIndex);
}
vk::SubpassDependency dependency{
.srcSubpass = static_cast<u32>(std::distance(subpassDescriptions.begin(), lastUsageIt)),
.dstSubpass = static_cast<uint32_t>(subpassDescriptions.size()), // We assume that the next subpass is using the attachment
.srcStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.dstStageMask = vk::PipelineStageFlagBits::eColorAttachmentOutput,
.srcAccessMask = vk::AccessFlagBits::eColorAttachmentWrite,
.dstAccessMask = vk::AccessFlagBits::eColorAttachmentRead,
.dependencyFlags = vk::DependencyFlagBits::eByRegion,
};
if (std::find(subpassDependencies.begin(), subpassDependencies.end(), dependency) == subpassDependencies.end())
subpassDependencies.push_back(dependency);
return attachmentIndex;
}
}
u32 AddAttachment(TextureView &view);
/**
* @brief Creates a subpass with the attachments bound in the specified order
*/
void AddSubpass(span <TextureView> inputAttachments, span <TextureView> colorAttachments, TextureView *depthStencilAttachment) {
attachmentReferences.reserve(attachmentReferences.size() + inputAttachments.size() + colorAttachments.size() + (depthStencilAttachment ? 1 : 0));
auto inputAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)};
for (auto &attachment : inputAttachments) {
attachmentReferences.push_back(vk::AttachmentReference{
.attachment = AddAttachment(attachment),
.layout = attachment.backing->layout,
});
}
auto colorAttachmentsOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)};
for (auto &attachment : colorAttachments) {
attachmentReferences.push_back(vk::AttachmentReference{
.attachment = AddAttachment(attachment),
.layout = attachment.backing->layout,
});
}
auto depthStencilAttachmentOffset{attachmentReferences.size() * sizeof(vk::AttachmentReference)};
if (depthStencilAttachment) {
attachmentReferences.push_back(vk::AttachmentReference{
.attachment = AddAttachment(*depthStencilAttachment),
.layout = depthStencilAttachment->backing->layout,
});
}
preserveAttachmentReferences.emplace_back(); // We need to create storage for any attachments that might need to preserved by this pass
// Note: We encode the offsets as the pointers due to vector pointer invalidation, RebasePointer(...) can be utilized to deduce the real pointer
subpassDescriptions.push_back(vk::SubpassDescription{
.pipelineBindPoint = vk::PipelineBindPoint::eGraphics,
.inputAttachmentCount = static_cast<u32>(inputAttachments.size()),
.pInputAttachments = reinterpret_cast<vk::AttachmentReference *>(inputAttachmentsOffset),
.colorAttachmentCount = static_cast<u32>(colorAttachments.size()),
.pColorAttachments = reinterpret_cast<vk::AttachmentReference *>(colorAttachmentsOffset),
.pDepthStencilAttachment = reinterpret_cast<vk::AttachmentReference *>(depthStencilAttachment ? depthStencilAttachmentOffset : DepthStencilNull),
});
}
void AddSubpass(span<TextureView> inputAttachments, span<TextureView> colorAttachments, TextureView *depthStencilAttachment);
/**
* @brief Clears a color attachment in the current subpass with VK_ATTACHMENT_LOAD_OP_LOAD
@ -200,90 +84,9 @@ namespace skyline::gpu::interconnect::node {
* @return If the attachment could be cleared or not due to conflicts with other operations
* @note We require a subpass to be attached during this as the clear will not take place unless it's referenced by a subpass
*/
bool ClearColorAttachment(u32 colorAttachment, const vk::ClearColorValue &value) {
auto attachmentReference{RebasePointer(attachmentReferences, subpassDescriptions.back().pColorAttachments) + colorAttachment};
auto attachmentIndex{attachmentReference->attachment};
bool ClearColorAttachment(u32 colorAttachment, const vk::ClearColorValue &value);
for (const auto &reference : attachmentReferences)
if (reference.attachment == attachmentIndex && &reference != attachmentReference)
return false;
auto &attachmentDescription{attachmentDescriptions.at(attachmentIndex)};
if (attachmentDescription.loadOp == vk::AttachmentLoadOp::eLoad) {
attachmentDescription.loadOp = vk::AttachmentLoadOp::eClear;
clearValues.resize(attachmentIndex + 1);
clearValues[attachmentIndex].color = value;
return true;
} else if (attachmentDescription.loadOp == vk::AttachmentLoadOp::eClear && clearValues[attachmentIndex].color.uint32 == value.uint32) {
return true;
}
return false;
}
void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu) {
storage->device = &gpu.vkDevice;
auto preserveAttachmentIt{preserveAttachmentReferences.begin()};
for (auto &subpassDescription : subpassDescriptions) {
subpassDescription.pInputAttachments = RebasePointer(attachmentReferences, subpassDescription.pInputAttachments);
subpassDescription.pColorAttachments = RebasePointer(attachmentReferences, subpassDescription.pColorAttachments);
auto depthStencilAttachmentOffset{reinterpret_cast<uintptr_t>(subpassDescription.pDepthStencilAttachment)};
if (depthStencilAttachmentOffset != DepthStencilNull)
subpassDescription.pDepthStencilAttachment = RebasePointer(attachmentReferences, subpassDescription.pDepthStencilAttachment);
else
subpassDescription.pDepthStencilAttachment = nullptr;
subpassDescription.preserveAttachmentCount = preserveAttachmentIt->size();
subpassDescription.pPreserveAttachments = preserveAttachmentIt->data();
preserveAttachmentIt++;
}
for (auto &texture : storage->textures) {
texture->lock();
texture->WaitOnBacking();
if (texture->cycle.lock() != cycle)
texture->WaitOnFence();
}
auto renderpass{(*gpu.vkDevice).createRenderPass(vk::RenderPassCreateInfo{
.attachmentCount = static_cast<u32>(attachmentDescriptions.size()),
.pAttachments = attachmentDescriptions.data(),
.subpassCount = static_cast<u32>(subpassDescriptions.size()),
.pSubpasses = subpassDescriptions.data(),
.dependencyCount = static_cast<u32>(subpassDependencies.size()),
.pDependencies = subpassDependencies.data(),
}, nullptr, *gpu.vkDevice.getDispatcher())};
storage->renderpass = renderpass;
auto framebuffer{(*gpu.vkDevice).createFramebuffer(vk::FramebufferCreateInfo{
.renderPass = renderpass,
.attachmentCount = static_cast<u32>(attachments.size()),
.pAttachments = attachments.data(),
.width = renderArea.extent.width,
.height = renderArea.extent.height,
.layers = 1,
}, nullptr, *gpu.vkDevice.getDispatcher())};
storage->framebuffer = framebuffer;
commandBuffer.beginRenderPass(vk::RenderPassBeginInfo{
.renderPass = renderpass,
.framebuffer = framebuffer,
.renderArea = renderArea,
.clearValueCount = static_cast<u32>(clearValues.size()),
.pClearValues = clearValues.data(),
}, vk::SubpassContents::eInline);
cycle->AttachObjects(storage);
for (auto &texture : storage->textures) {
texture->unlock();
texture->cycle = cycle;
}
}
void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu);
};
/**

View File

@ -9,21 +9,21 @@ namespace skyline::gpu {
/**
* @brief Copies the contents of a blocklinear guest texture to a linear output buffer
*/
void CopyBlockLinearToLinear(GuestTexture& guest, u8* guestInput, u8* linearOutput) {
void CopyBlockLinearToLinear(GuestTexture &guest, u8 *guestInput, u8 *linearOutput) {
// Reference on Block-linear tiling: https://gist.github.com/PixelyIon/d9c35050af0ef5690566ca9f0965bc32
constexpr u8 SectorWidth{16}; // The width of a sector in bytes
constexpr u8 SectorHeight{2}; // The height of a sector in lines
constexpr u8 GobWidth{64}; // The width of a GOB in bytes
constexpr u8 GobHeight{8}; // The height of a GOB in lines
auto blockHeight{guest.tileConfig.blockHeight}; //!< The height of the blocks in GOBs
auto robHeight{GobHeight * blockHeight}; //!< The height of a single ROB (Row of Blocks) in lines
auto surfaceHeight{guest.dimensions.height / guest.format->blockHeight}; //!< The height of the surface in lines
auto surfaceHeightRobs{util::AlignUp(surfaceHeight, robHeight) / robHeight}; //!< The height of the surface in ROBs (Row Of Blocks)
auto robWidthBytes{util::AlignUp((guest.dimensions.width / guest.format->blockWidth) * guest.format->bpb, GobWidth)}; //!< The width of a ROB in bytes
auto robWidthBlocks{robWidthBytes / GobWidth}; //!< The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
auto robBytes{robWidthBytes * robHeight}; //!< The size of a ROB in bytes
auto gobYOffset{robWidthBytes * GobHeight}; //!< The offset of the next Y-axis GOB from the current one in linear space
u32 blockHeight{guest.tileConfig.blockHeight}; //!< The height of the blocks in GOBs
u32 robHeight{GobHeight * blockHeight}; //!< The height of a single ROB (Row of Blocks) in lines
u32 surfaceHeight{guest.dimensions.height / guest.format->blockHeight}; //!< The height of the surface in lines
u32 surfaceHeightRobs{util::AlignUp(surfaceHeight, robHeight) / robHeight}; //!< The height of the surface in ROBs (Row Of Blocks)
u32 robWidthBytes{util::AlignUp((guest.dimensions.width / guest.format->blockWidth) * guest.format->bpb, GobWidth)}; //!< The width of a ROB in bytes
u32 robWidthBlocks{robWidthBytes / GobWidth}; //!< The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
u32 robBytes{robWidthBytes * robHeight}; //!< The size of a ROB in bytes
u32 gobYOffset{robWidthBytes * GobHeight}; //!< The offset of the next Y-axis GOB from the current one in linear space
auto inputSector{guestInput};
auto outputRob{linearOutput};
@ -51,24 +51,25 @@ namespace skyline::gpu {
paddingY = (guest.tileConfig.blockHeight - blockHeight) * (SectorWidth * SectorWidth * SectorHeight); // Calculate the amount of padding between contiguous sectors
}
}
/**
* @brief Copies the contents of a blocklinear guest texture to a linear output buffer
*/
void CopyLinearToBlockLinear(GuestTexture& guest, u8* linearInput, u8* guestOutput) {
void CopyLinearToBlockLinear(GuestTexture &guest, u8 *linearInput, u8 *guestOutput) {
// Reference on Block-linear tiling: https://gist.github.com/PixelyIon/d9c35050af0ef5690566ca9f0965bc32
constexpr u8 SectorWidth{16}; // The width of a sector in bytes
constexpr u8 SectorHeight{2}; // The height of a sector in lines
constexpr u8 GobWidth{64}; // The width of a GOB in bytes
constexpr u8 GobHeight{8}; // The height of a GOB in lines
auto blockHeight{guest.tileConfig.blockHeight}; //!< The height of the blocks in GOBs
auto robHeight{GobHeight * blockHeight}; //!< The height of a single ROB (Row of Blocks) in lines
auto surfaceHeight{guest.dimensions.height / guest.format->blockHeight}; //!< The height of the surface in lines
auto surfaceHeightRobs{util::AlignUp(surfaceHeight, robHeight) / robHeight}; //!< The height of the surface in ROBs (Row Of Blocks)
auto robWidthBytes{util::AlignUp((guest.dimensions.width / guest.format->blockWidth) * guest.format->bpb, GobWidth)}; //!< The width of a ROB in bytes
auto robWidthBlocks{robWidthBytes / GobWidth}; //!< The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
auto robBytes{robWidthBytes * robHeight}; //!< The size of a ROB in bytes
auto gobYOffset{robWidthBytes * GobHeight}; //!< The offset of the next Y-axis GOB from the current one in linear space
u32 blockHeight{guest.tileConfig.blockHeight}; //!< The height of the blocks in GOBs
u32 robHeight{GobHeight * blockHeight}; //!< The height of a single ROB (Row of Blocks) in lines
u32 surfaceHeight{guest.dimensions.height / guest.format->blockHeight}; //!< The height of the surface in lines
u32 surfaceHeightRobs{util::AlignUp(surfaceHeight, robHeight) / robHeight}; //!< The height of the surface in ROBs (Row Of Blocks)
u32 robWidthBytes{util::AlignUp((guest.dimensions.width / guest.format->blockWidth) * guest.format->bpb, GobWidth)}; //!< The width of a ROB in bytes
u32 robWidthBlocks{robWidthBytes / GobWidth}; //!< The width of a ROB in blocks (and GOBs because block width == 1 on the Tegra X1)
u32 robBytes{robWidthBytes * robHeight}; //!< The size of a ROB in bytes
u32 gobYOffset{robWidthBytes * GobHeight}; //!< The offset of the next Y-axis GOB from the current one in linear space
auto outputSector{guestOutput};
auto inputRob{linearInput};
@ -100,7 +101,7 @@ namespace skyline::gpu {
/**
* @brief Copies the contents of a pitch-linear guest texture to a linear output buffer
*/
void CopyPitchLinearToLinear(GuestTexture& guest, u8* guestInput, u8* linearOutput) {
void CopyPitchLinearToLinear(GuestTexture &guest, u8 *guestInput, u8 *linearOutput) {
auto sizeLine{guest.format->GetSize(guest.dimensions.width, 1)}; //!< The size of a single line of pixel data
auto sizeStride{guest.format->GetSize(guest.tileConfig.pitch, 1)}; //!< The size of a single stride of pixel data
@ -117,7 +118,7 @@ namespace skyline::gpu {
/**
* @brief Copies the contents of a linear buffer to a pitch-linear guest texture
*/
void CopyLinearToPitchLinear(GuestTexture& guest, u8* linearInput, u8* guestOutput) {
void CopyLinearToPitchLinear(GuestTexture &guest, u8 *linearInput, u8 *guestOutput) {
auto sizeLine{guest.format->GetSize(guest.dimensions.width, 1)}; //!< The size of a single line of pixel data
auto sizeStride{guest.format->GetSize(guest.tileConfig.pitch, 1)}; //!< The size of a single stride of pixel data

View File

@ -11,8 +11,6 @@ namespace skyline::gpu {
std::shared_ptr<memory::StagingBuffer> Texture::SynchronizeHostImpl(const std::shared_ptr<FenceCycle> &pCycle) {
if (!guest)
throw exception("Synchronization of host textures requires a valid guest texture to synchronize from");
else if (guest->mappings.size() != 1)
throw exception("Synchronization of non-contigious textures is not supported");
else if (guest->dimensions != dimensions)
throw exception("Guest and host dimensions being different is not supported currently");
else if (guest->mappings.size() > 1)
@ -334,8 +332,6 @@ namespace skyline::gpu {
void Texture::SynchronizeGuest() {
if (!guest)
throw exception("Synchronization of guest textures requires a valid guest texture to synchronize to");
else if (guest->mappings.size() != 1)
throw exception("Synchronization of non-contigious textures is not supported");
else if (layout == vk::ImageLayout::eUndefined)
return; // If the state of the host texture is undefined then so can the guest
else if (guest->mappings.size() > 1)
@ -366,8 +362,6 @@ namespace skyline::gpu {
void Texture::SynchronizeGuestWithBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &pCycle) {
if (!guest)
throw exception("Synchronization of guest textures requires a valid guest texture to synchronize to");
else if (guest->mappings.size() != 1)
throw exception("Synchronization of non-contigious textures is not supported");
else if (layout == vk::ImageLayout::eUndefined)
return; // If the state of the host texture is undefined then so can the guest
else if (guest->mappings.size() > 1)

View File

@ -214,13 +214,17 @@ namespace skyline::gpu {
};
constexpr bool operator==(const TileConfig &other) const {
if (mode == other.mode)
if (mode == TileMode::Linear)
return true;
else if (mode == TileMode::Pitch)
return pitch == other.pitch;
else if (mode == TileMode::Block)
return blockHeight == other.blockHeight && blockDepth == other.blockDepth;
if (mode == other.mode) {
switch (mode) {
case TileMode::Linear:
return true;
case TileMode::Pitch:
return pitch == other.pitch;
case TileMode::Block:
return blockHeight == other.blockHeight && blockDepth == other.blockDepth;
}
}
return false;
}
};
@ -248,7 +252,7 @@ namespace skyline::gpu {
* @brief A descriptor for a texture present in guest memory, it can be used to create a corresponding Texture object for usage on the host
*/
struct GuestTexture {
using Mappings = boost::container::small_vector<span<u8>, 3>;
using Mappings = boost::container::small_vector<span < u8>, 3>;
Mappings mappings; //!< Spans to CPU memory for the underlying data backing this texture
texture::Dimensions dimensions;
@ -261,9 +265,25 @@ namespace skyline::gpu {
GuestTexture() {}
GuestTexture(Mappings mappings, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, texture::TextureType type, u16 baseArrayLayer = 0, u16 layerCount = 1, u32 layerStride = 0) : mappings(mappings), dimensions(dimensions), format(format), tileConfig(tileConfig), type(type), baseArrayLayer(baseArrayLayer), layerCount(layerCount), layerStride(layerStride) {}
GuestTexture(Mappings mappings, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, texture::TextureType type, u16 baseArrayLayer = 0, u16 layerCount = 1, u32 layerStride = 0)
: mappings(mappings),
dimensions(dimensions),
format(format),
tileConfig(tileConfig),
type(type),
baseArrayLayer(baseArrayLayer),
layerCount(layerCount),
layerStride(layerStride) {}
GuestTexture(span<u8> mapping, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, texture::TextureType type, u16 baseArrayLayer = 0, u16 layerCount = 1, u32 layerStride = 0) : mappings(1, mapping), dimensions(dimensions), format(format), tileConfig(tileConfig), type(type), baseArrayLayer(baseArrayLayer), layerCount(layerCount), layerStride(layerStride) {}
GuestTexture(span <u8> mapping, texture::Dimensions dimensions, texture::Format format, texture::TileConfig tileConfig, texture::TextureType type, u16 baseArrayLayer = 0, u16 layerCount = 1, u32 layerStride = 0)
: mappings(1, mapping),
dimensions(dimensions),
format(format),
tileConfig(tileConfig),
type(type),
baseArrayLayer(baseArrayLayer),
layerCount(layerCount),
layerStride(layerStride) {}
};
class TextureManager;
@ -323,18 +343,18 @@ namespace skyline::gpu {
/**
* @brief Records commands for copying data from a staging buffer to the texture's backing into the supplied command buffer
*/
void CopyFromStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer>& stagingBuffer);
void CopyFromStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer);
/**
* @brief Records commands for copying data from the texture's backing to a staging buffer into the supplied command buffer
*/
void CopyIntoStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer>& stagingBuffer);
void CopyIntoStagingBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<memory::StagingBuffer> &stagingBuffer);
/**
* @brief Copies data from the supplied host buffer into the guest texture
* @note The host buffer must be contain the entire image
*/
void CopyToGuest(u8* hostBuffer);
void CopyToGuest(u8 *hostBuffer);
/**
* @brief A FenceCycleDependency that copies the contents of a staging buffer or mapped image backing the texture to the guest texture

View File

@ -51,9 +51,9 @@ namespace skyline::gpu {
.layerCount = texture->layerCount,
}, guestTexture.format);
}
} else if (mappingMatch) {
} /* else if (mappingMatch) {
// We've gotten a partial match with a certain subset of contiguous mappings matching, we need to check if this is a meaningful overlap
if (false) {
if (MeaningfulOverlap) {
// TODO: Layout Checks + Check match against Base Layer in TIC
auto &texture{hostMapping->texture};
return TextureView(texture, static_cast<vk::ImageViewType>(guestTexture.type), vk::ImageSubresourceRange{
@ -62,7 +62,7 @@ namespace skyline::gpu {
.layerCount = texture->layerCount,
}, guestTexture.format);
}
}
} */
}
// Create a texture as we cannot find one that matches

View File

@ -102,10 +102,11 @@ namespace skyline::nce {
*tls = nullptr;
} else { // If TLS wasn't restored then this occurred in host code
if (signal == SIGSEGV) {
static bool RunningUnderDebugger{[]() {
std::ifstream status("/proc/self/status");
constexpr std::string_view TracerPidTag = "TracerPid:";
bool runningUnderDebugger{[]() {
static std::ifstream status("/proc/self/status");
status.seekg(0);
constexpr std::string_view TracerPidTag = "TracerPid:";
for (std::string line; std::getline(status, line);) {
if (line.starts_with(TracerPidTag)) {
line = line.substr(TracerPidTag.size());
@ -123,7 +124,7 @@ namespace skyline::nce {
return false;
}()};
if (RunningUnderDebugger)
if (runningUnderDebugger)
raise(SIGTRAP); // Notify the debugger if we've got a SIGSEGV as the debugger doesn't catch them by default as they might be hooked
}

View File

@ -23,8 +23,7 @@ namespace skyline::service::codec {
// We utilize the guest-supplied work buffer for allocating the OpusDecoder object into
decoderState = reinterpret_cast<OpusDecoder *>(workBuffer->host.ptr);
int result{opus_decoder_init(decoderState, sampleRate, channelCount)};
if (result != OPUS_OK)
if (int result = opus_decoder_init(decoderState, sampleRate, channelCount) != OPUS_OK)
throw OpusException(result);
}