mirror of
https://github.com/skyline-emu/skyline.git
synced 2024-12-28 23:55:29 +03:00
Address CR Comments
This commit is contained in:
parent
595e53f7cf
commit
ea2626bcc6
@ -102,6 +102,7 @@ add_library(skyline SHARED
|
|||||||
${source_DIR}/skyline/gpu/texture/texture.cpp
|
${source_DIR}/skyline/gpu/texture/texture.cpp
|
||||||
${source_DIR}/skyline/gpu/presentation_engine.cpp
|
${source_DIR}/skyline/gpu/presentation_engine.cpp
|
||||||
${source_DIR}/skyline/gpu/interconnect/command_executor.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/host1x/syncpoint.cpp
|
||||||
${source_DIR}/skyline/soc/gm20b/channel.cpp
|
${source_DIR}/skyline/soc/gm20b/channel.cpp
|
||||||
${source_DIR}/skyline/soc/gm20b/gpfifo.cpp
|
${source_DIR}/skyline/soc/gm20b/gpfifo.cpp
|
||||||
|
@ -24,8 +24,7 @@ namespace skyline {
|
|||||||
public:
|
public:
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ThreadLocal(Args &&... args) : constructor([args...]() { return new Type(args...); }) {
|
ThreadLocal(Args &&... args) : constructor([args...]() { return new Type(args...); }) {
|
||||||
int result;
|
if (int result = pthread_key_create(&key, nullptr))
|
||||||
if ((result = pthread_key_create(&key, nullptr)))
|
|
||||||
throw exception("Cannot create pthread_key: {}", strerror(result));
|
throw exception("Cannot create pthread_key: {}", strerror(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -34,9 +33,8 @@ namespace skyline {
|
|||||||
if (pointer)
|
if (pointer)
|
||||||
return static_cast<Type *>(pointer);
|
return static_cast<Type *>(pointer);
|
||||||
|
|
||||||
int result;
|
|
||||||
Type *object{constructor(*this)};
|
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));
|
throw exception("Cannot set pthread_key to constructed type: {}", strerror(result));
|
||||||
|
|
||||||
return object;
|
return object;
|
||||||
@ -89,8 +87,7 @@ namespace skyline {
|
|||||||
static_cast<IntrustiveTypeNode *>(object)->~IntrustiveTypeNode();
|
static_cast<IntrustiveTypeNode *>(object)->~IntrustiveTypeNode();
|
||||||
}};
|
}};
|
||||||
|
|
||||||
int result;
|
if (int result = pthread_key_create(&key, destructor))
|
||||||
if ((result = pthread_key_create(&key, destructor)))
|
|
||||||
throw exception("Cannot create pthread_key: {}", strerror(result));
|
throw exception("Cannot create pthread_key: {}", strerror(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -99,9 +96,8 @@ namespace skyline {
|
|||||||
if (pointer)
|
if (pointer)
|
||||||
return &static_cast<IntrustiveTypeNode *>(pointer)->object;
|
return &static_cast<IntrustiveTypeNode *>(pointer)->object;
|
||||||
|
|
||||||
int result;
|
|
||||||
IntrustiveTypeNode *node{constructor(*this)};
|
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));
|
throw exception("Cannot set pthread_key to constructed type: {}", strerror(result));
|
||||||
|
|
||||||
auto next{list.load(std::memory_order_acquire)};
|
auto next{list.load(std::memory_order_acquire)};
|
||||||
|
@ -85,13 +85,13 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
#define IGNORE_VALIDATION(string) \
|
#define IGNORE_VALIDATION(string) \
|
||||||
case util::Hash(string): \
|
case util::Hash(string): \
|
||||||
if(string == type) \
|
if (string == type) \
|
||||||
return VK_FALSE; \
|
return VK_FALSE; \
|
||||||
break
|
break
|
||||||
|
|
||||||
#define DEBUG_VALIDATION(string) \
|
#define DEBUG_VALIDATION(string) \
|
||||||
case util::Hash(string): \
|
case util::Hash(string): \
|
||||||
if(string == type) \
|
if (string == type) \
|
||||||
raise(SIGTRAP); \
|
raise(SIGTRAP); \
|
||||||
break
|
break
|
||||||
// Using __builtin_debugtrap() as opposed to raise(SIGTRAP) will result in the inability to continue
|
// 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)};
|
auto last{type.find(']', first)};
|
||||||
if (first != std::string_view::npos && last != std::string_view::npos) {
|
if (first != std::string_view::npos && last != std::string_view::npos) {
|
||||||
type = type.substr(first + 2, last != std::string_view::npos ? last - 4 : last);
|
type = type.substr(first + 2, last != std::string_view::npos ? last - 4 : last);
|
||||||
std::string typeStr{type};
|
|
||||||
|
|
||||||
switch (util::Hash(type)) {
|
switch (util::Hash(type)) {
|
||||||
IGNORE_VALIDATION("UNASSIGNED-CoreValidation-SwapchainPreTransform"); // We handle transformation via Android APIs directly
|
IGNORE_VALIDATION("UNASSIGNED-CoreValidation-SwapchainPreTransform"); // We handle transformation via Android APIs directly
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include "command_executor.h"
|
#include "command_executor.h"
|
||||||
|
|
||||||
namespace skyline::gpu::interconnect {
|
namespace skyline::gpu::interconnect {
|
||||||
|
CommandExecutor::CommandExecutor(const DeviceState &state) : gpu(*state.gpu) {}
|
||||||
|
|
||||||
bool CommandExecutor::CreateRenderpass(vk::Rect2D renderArea) {
|
bool CommandExecutor::CreateRenderpass(vk::Rect2D renderArea) {
|
||||||
if (renderpass && renderpass->renderArea != renderArea) {
|
if (renderpass && renderpass->renderArea != renderArea) {
|
||||||
nodes.emplace_back(std::in_place_type_t<node::RenderpassEndNode>());
|
nodes.emplace_back(std::in_place_type_t<node::RenderpassEndNode>());
|
||||||
|
@ -25,7 +25,7 @@ namespace skyline::gpu::interconnect {
|
|||||||
bool CreateRenderpass(vk::Rect2D renderArea);
|
bool CreateRenderpass(vk::Rect2D renderArea);
|
||||||
|
|
||||||
public:
|
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
|
* @brief Adds a command that needs to be executed inside a subpass configured with certain attachments
|
||||||
|
219
app/src/main/cpp/skyline/gpu/interconnect/command_nodes.cpp
Normal file
219
app/src/main/cpp/skyline/gpu/interconnect/command_nodes.cpp
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -24,25 +24,22 @@ namespace skyline::gpu::interconnect::node {
|
|||||||
using FunctionNode = FunctionNodeBase<>;
|
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 {
|
struct RenderpassNode {
|
||||||
private:
|
private:
|
||||||
|
/**
|
||||||
|
* @brief Storage for all resources in the VkRenderPass that have their lifetimes bond to the completion fence
|
||||||
|
*/
|
||||||
struct Storage : public FenceCycleDependency {
|
struct Storage : public FenceCycleDependency {
|
||||||
vk::raii::Device *device{};
|
vk::raii::Device *device{};
|
||||||
vk::Framebuffer framebuffer{};
|
vk::Framebuffer framebuffer{};
|
||||||
vk::RenderPass renderpass{};
|
vk::RenderPass renderpass{};
|
||||||
std::vector<std::shared_ptr<Texture>> textures;
|
std::vector<std::shared_ptr<Texture>> textures;
|
||||||
|
|
||||||
~Storage() {
|
~Storage();
|
||||||
if (device) {
|
|
||||||
if (framebuffer)
|
|
||||||
(**device).destroy(framebuffer, nullptr, *device->getDispatcher());
|
|
||||||
if (renderpass)
|
|
||||||
(**device).destroy(renderpass, nullptr, *device->getDispatcher());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
std::shared_ptr<Storage> storage;
|
std::shared_ptr<Storage> storage;
|
||||||
|
|
||||||
std::vector<vk::ImageView> attachments;
|
std::vector<vk::ImageView> attachments;
|
||||||
@ -51,13 +48,13 @@ namespace skyline::gpu::interconnect::node {
|
|||||||
std::vector<vk::AttachmentReference> attachmentReferences;
|
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
|
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
|
* @brief Rebases a pointer containing an offset relative to the beginning of a container
|
||||||
*/
|
*/
|
||||||
template<typename Container, typename T>
|
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));
|
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
|
* @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
|
* @return The index of the attachment in the render pass which can be utilized with VkAttachmentReference
|
||||||
*/
|
*/
|
||||||
u32 AddAttachment(TextureView &view) {
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Creates a subpass with the attachments bound in the specified order
|
* @brief Creates a subpass with the attachments bound in the specified order
|
||||||
*/
|
*/
|
||||||
void AddSubpass(span <TextureView> inputAttachments, span <TextureView> colorAttachments, TextureView *depthStencilAttachment) {
|
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),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Clears a color attachment in the current subpass with VK_ATTACHMENT_LOAD_OP_LOAD
|
* @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
|
* @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
|
* @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) {
|
bool ClearColorAttachment(u32 colorAttachment, const vk::ClearColorValue &value);
|
||||||
auto attachmentReference{RebasePointer(attachmentReferences, subpassDescriptions.back().pColorAttachments) + colorAttachment};
|
|
||||||
auto attachmentIndex{attachmentReference->attachment};
|
|
||||||
|
|
||||||
for (const auto &reference : attachmentReferences)
|
void operator()(vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &gpu);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -9,21 +9,21 @@ namespace skyline::gpu {
|
|||||||
/**
|
/**
|
||||||
* @brief Copies the contents of a blocklinear guest texture to a linear output buffer
|
* @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
|
// Reference on Block-linear tiling: https://gist.github.com/PixelyIon/d9c35050af0ef5690566ca9f0965bc32
|
||||||
constexpr u8 SectorWidth{16}; // The width of a sector in bytes
|
constexpr u8 SectorWidth{16}; // The width of a sector in bytes
|
||||||
constexpr u8 SectorHeight{2}; // The height of a sector in lines
|
constexpr u8 SectorHeight{2}; // The height of a sector in lines
|
||||||
constexpr u8 GobWidth{64}; // The width of a GOB in bytes
|
constexpr u8 GobWidth{64}; // The width of a GOB in bytes
|
||||||
constexpr u8 GobHeight{8}; // The height of a GOB in lines
|
constexpr u8 GobHeight{8}; // The height of a GOB in lines
|
||||||
|
|
||||||
auto blockHeight{guest.tileConfig.blockHeight}; //!< The height of the blocks in GOBs
|
u32 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
|
u32 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
|
u32 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)
|
u32 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
|
u32 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)
|
u32 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
|
u32 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 gobYOffset{robWidthBytes * GobHeight}; //!< The offset of the next Y-axis GOB from the current one in linear space
|
||||||
|
|
||||||
auto inputSector{guestInput};
|
auto inputSector{guestInput};
|
||||||
auto outputRob{linearOutput};
|
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
|
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
|
* @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
|
// Reference on Block-linear tiling: https://gist.github.com/PixelyIon/d9c35050af0ef5690566ca9f0965bc32
|
||||||
constexpr u8 SectorWidth{16}; // The width of a sector in bytes
|
constexpr u8 SectorWidth{16}; // The width of a sector in bytes
|
||||||
constexpr u8 SectorHeight{2}; // The height of a sector in lines
|
constexpr u8 SectorHeight{2}; // The height of a sector in lines
|
||||||
constexpr u8 GobWidth{64}; // The width of a GOB in bytes
|
constexpr u8 GobWidth{64}; // The width of a GOB in bytes
|
||||||
constexpr u8 GobHeight{8}; // The height of a GOB in lines
|
constexpr u8 GobHeight{8}; // The height of a GOB in lines
|
||||||
|
|
||||||
auto blockHeight{guest.tileConfig.blockHeight}; //!< The height of the blocks in GOBs
|
u32 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
|
u32 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
|
u32 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)
|
u32 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
|
u32 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)
|
u32 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
|
u32 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 gobYOffset{robWidthBytes * GobHeight}; //!< The offset of the next Y-axis GOB from the current one in linear space
|
||||||
|
|
||||||
auto outputSector{guestOutput};
|
auto outputSector{guestOutput};
|
||||||
auto inputRob{linearInput};
|
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
|
* @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 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
|
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
|
* @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 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
|
auto sizeStride{guest.format->GetSize(guest.tileConfig.pitch, 1)}; //!< The size of a single stride of pixel data
|
||||||
|
|
||||||
|
@ -11,8 +11,6 @@ namespace skyline::gpu {
|
|||||||
std::shared_ptr<memory::StagingBuffer> Texture::SynchronizeHostImpl(const std::shared_ptr<FenceCycle> &pCycle) {
|
std::shared_ptr<memory::StagingBuffer> Texture::SynchronizeHostImpl(const std::shared_ptr<FenceCycle> &pCycle) {
|
||||||
if (!guest)
|
if (!guest)
|
||||||
throw exception("Synchronization of host textures requires a valid guest texture to synchronize from");
|
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)
|
else if (guest->dimensions != dimensions)
|
||||||
throw exception("Guest and host dimensions being different is not supported currently");
|
throw exception("Guest and host dimensions being different is not supported currently");
|
||||||
else if (guest->mappings.size() > 1)
|
else if (guest->mappings.size() > 1)
|
||||||
@ -334,8 +332,6 @@ namespace skyline::gpu {
|
|||||||
void Texture::SynchronizeGuest() {
|
void Texture::SynchronizeGuest() {
|
||||||
if (!guest)
|
if (!guest)
|
||||||
throw exception("Synchronization of guest textures requires a valid guest texture to synchronize to");
|
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)
|
else if (layout == vk::ImageLayout::eUndefined)
|
||||||
return; // If the state of the host texture is undefined then so can the guest
|
return; // If the state of the host texture is undefined then so can the guest
|
||||||
else if (guest->mappings.size() > 1)
|
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) {
|
void Texture::SynchronizeGuestWithBuffer(const vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &pCycle) {
|
||||||
if (!guest)
|
if (!guest)
|
||||||
throw exception("Synchronization of guest textures requires a valid guest texture to synchronize to");
|
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)
|
else if (layout == vk::ImageLayout::eUndefined)
|
||||||
return; // If the state of the host texture is undefined then so can the guest
|
return; // If the state of the host texture is undefined then so can the guest
|
||||||
else if (guest->mappings.size() > 1)
|
else if (guest->mappings.size() > 1)
|
||||||
|
@ -214,13 +214,17 @@ namespace skyline::gpu {
|
|||||||
};
|
};
|
||||||
|
|
||||||
constexpr bool operator==(const TileConfig &other) const {
|
constexpr bool operator==(const TileConfig &other) const {
|
||||||
if (mode == other.mode)
|
if (mode == other.mode) {
|
||||||
if (mode == TileMode::Linear)
|
switch (mode) {
|
||||||
return true;
|
case TileMode::Linear:
|
||||||
else if (mode == TileMode::Pitch)
|
return true;
|
||||||
return pitch == other.pitch;
|
case TileMode::Pitch:
|
||||||
else if (mode == TileMode::Block)
|
return pitch == other.pitch;
|
||||||
return blockHeight == other.blockHeight && blockDepth == other.blockDepth;
|
case TileMode::Block:
|
||||||
|
return blockHeight == other.blockHeight && blockDepth == other.blockDepth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
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
|
* @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 {
|
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
|
Mappings mappings; //!< Spans to CPU memory for the underlying data backing this texture
|
||||||
texture::Dimensions dimensions;
|
texture::Dimensions dimensions;
|
||||||
@ -261,9 +265,25 @@ namespace skyline::gpu {
|
|||||||
|
|
||||||
GuestTexture() {}
|
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;
|
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
|
* @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
|
* @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
|
* @brief Copies data from the supplied host buffer into the guest texture
|
||||||
* @note The host buffer must be contain the entire image
|
* @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
|
* @brief A FenceCycleDependency that copies the contents of a staging buffer or mapped image backing the texture to the guest texture
|
||||||
|
@ -51,9 +51,9 @@ namespace skyline::gpu {
|
|||||||
.layerCount = texture->layerCount,
|
.layerCount = texture->layerCount,
|
||||||
}, guestTexture.format);
|
}, 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
|
// 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
|
// TODO: Layout Checks + Check match against Base Layer in TIC
|
||||||
auto &texture{hostMapping->texture};
|
auto &texture{hostMapping->texture};
|
||||||
return TextureView(texture, static_cast<vk::ImageViewType>(guestTexture.type), vk::ImageSubresourceRange{
|
return TextureView(texture, static_cast<vk::ImageViewType>(guestTexture.type), vk::ImageSubresourceRange{
|
||||||
@ -62,7 +62,7 @@ namespace skyline::gpu {
|
|||||||
.layerCount = texture->layerCount,
|
.layerCount = texture->layerCount,
|
||||||
}, guestTexture.format);
|
}, guestTexture.format);
|
||||||
}
|
}
|
||||||
}
|
} */
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a texture as we cannot find one that matches
|
// Create a texture as we cannot find one that matches
|
||||||
|
@ -102,10 +102,11 @@ namespace skyline::nce {
|
|||||||
*tls = nullptr;
|
*tls = nullptr;
|
||||||
} else { // If TLS wasn't restored then this occurred in host code
|
} else { // If TLS wasn't restored then this occurred in host code
|
||||||
if (signal == SIGSEGV) {
|
if (signal == SIGSEGV) {
|
||||||
static bool RunningUnderDebugger{[]() {
|
bool runningUnderDebugger{[]() {
|
||||||
std::ifstream status("/proc/self/status");
|
static std::ifstream status("/proc/self/status");
|
||||||
constexpr std::string_view TracerPidTag = "TracerPid:";
|
status.seekg(0);
|
||||||
|
|
||||||
|
constexpr std::string_view TracerPidTag = "TracerPid:";
|
||||||
for (std::string line; std::getline(status, line);) {
|
for (std::string line; std::getline(status, line);) {
|
||||||
if (line.starts_with(TracerPidTag)) {
|
if (line.starts_with(TracerPidTag)) {
|
||||||
line = line.substr(TracerPidTag.size());
|
line = line.substr(TracerPidTag.size());
|
||||||
@ -123,7 +124,7 @@ namespace skyline::nce {
|
|||||||
return false;
|
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
|
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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,8 +23,7 @@ namespace skyline::service::codec {
|
|||||||
// We utilize the guest-supplied work buffer for allocating the OpusDecoder object into
|
// We utilize the guest-supplied work buffer for allocating the OpusDecoder object into
|
||||||
decoderState = reinterpret_cast<OpusDecoder *>(workBuffer->host.ptr);
|
decoderState = reinterpret_cast<OpusDecoder *>(workBuffer->host.ptr);
|
||||||
|
|
||||||
int result{opus_decoder_init(decoderState, sampleRate, channelCount)};
|
if (int result = opus_decoder_init(decoderState, sampleRate, channelCount) != OPUS_OK)
|
||||||
if (result != OPUS_OK)
|
|
||||||
throw OpusException(result);
|
throw OpusException(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user