Attach TextureView/BufferView Lifetime to FenceCycle

The lifetime of a texture and buffer view is now bound by the `FenceCycle` in `CommandExecutor`, this ensures that a `VkImageView` isn't destroyed prior to usage leading to UB.
This commit is contained in:
PixelyIon 2021-12-08 14:13:10 +05:30
parent 34fc1e32b8
commit cfeb8098db
5 changed files with 22 additions and 18 deletions

View File

@ -10,7 +10,7 @@ namespace skyline::gpu {
* @brief A descriptor for a GPU buffer on the guest * @brief A descriptor for a GPU buffer on the guest
*/ */
struct GuestBuffer { struct GuestBuffer {
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 buffer Mappings mappings; //!< Spans to CPU memory for the underlying data backing this buffer
/** /**
@ -114,7 +114,7 @@ namespace skyline::gpu {
* @note The object **must** be locked prior to accessing any members as values will be mutated * @note The object **must** be locked prior to accessing any members as values will be mutated
* @note This class conforms to the Lockable and BasicLockable C++ named requirements * @note This class conforms to the Lockable and BasicLockable C++ named requirements
*/ */
struct BufferView { struct BufferView : public FenceCycleDependency, public std::enable_shared_from_this<BufferView> {
std::shared_ptr<Buffer> buffer; std::shared_ptr<Buffer> buffer;
vk::DeviceSize offset; vk::DeviceSize offset;
vk::DeviceSize range; vk::DeviceSize range;

View File

@ -25,30 +25,32 @@ namespace skyline::gpu::interconnect {
return newRenderPass; return newRenderPass;
} }
void CommandExecutor::AttachTexture(const std::shared_ptr<Texture> &texture) { void CommandExecutor::AttachTexture(TextureView *view) {
if (!syncTextures.contains(texture.get())) { auto texture{view->texture.get()};
if (!syncTextures.contains(texture)) {
texture->WaitOnFence(); texture->WaitOnFence();
texture->cycle = cycle; texture->cycle = cycle;
cycle->AttachObject(texture); cycle->AttachObject(view->shared_from_this());
syncTextures.emplace(texture.get()); syncTextures.emplace(texture);
} }
} }
void CommandExecutor::AttachBuffer(const std::shared_ptr<Buffer> &buffer) { void CommandExecutor::AttachBuffer(BufferView *view) {
if (!syncBuffers.contains(buffer.get())) { auto buffer{view->buffer.get()};
if (!syncBuffers.contains(buffer)) {
buffer->WaitOnFence(); buffer->WaitOnFence();
buffer->cycle = cycle; buffer->cycle = cycle;
cycle->AttachObject(buffer); cycle->AttachObject(view->shared_from_this());
syncBuffers.emplace(buffer.get()); syncBuffers.emplace(buffer);
} }
} }
void CommandExecutor::AddSubpass(std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &, vk::RenderPass, u32)> &&function, vk::Rect2D renderArea, span<TextureView *> inputAttachments, span<TextureView *> colorAttachments, TextureView *depthStencilAttachment) { void CommandExecutor::AddSubpass(std::function<void(vk::raii::CommandBuffer &, const std::shared_ptr<FenceCycle> &, GPU &, vk::RenderPass, u32)> &&function, vk::Rect2D renderArea, span<TextureView *> inputAttachments, span<TextureView *> colorAttachments, TextureView *depthStencilAttachment) {
for (const auto &attachments : {inputAttachments, colorAttachments}) for (const auto &attachments : {inputAttachments, colorAttachments})
for (const auto &attachment : attachments) for (const auto &attachment : attachments)
AttachTexture(attachment->texture); AttachTexture(attachment);
if (depthStencilAttachment) if (depthStencilAttachment)
AttachTexture(depthStencilAttachment->texture); AttachTexture(depthStencilAttachment);
bool newRenderPass{CreateRenderPass(renderArea)}; bool newRenderPass{CreateRenderPass(renderArea)};
renderPass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment ? &*depthStencilAttachment : nullptr); renderPass->AddSubpass(inputAttachments, colorAttachments, depthStencilAttachment ? &*depthStencilAttachment : nullptr);
@ -59,7 +61,7 @@ namespace skyline::gpu::interconnect {
} }
void CommandExecutor::AddClearColorSubpass(TextureView *attachment, const vk::ClearColorValue &value) { void CommandExecutor::AddClearColorSubpass(TextureView *attachment, const vk::ClearColorValue &value) {
AttachTexture(attachment->texture); AttachTexture(attachment);
bool newRenderPass{CreateRenderPass(vk::Rect2D{ bool newRenderPass{CreateRenderPass(vk::Rect2D{
.extent = attachment->texture->dimensions, .extent = attachment->texture->dimensions,
@ -90,7 +92,7 @@ namespace skyline::gpu::interconnect {
} }
void CommandExecutor::AddClearDepthStencilSubpass(TextureView *attachment, const vk::ClearDepthStencilValue &value) { void CommandExecutor::AddClearDepthStencilSubpass(TextureView *attachment, const vk::ClearDepthStencilValue &value) {
AttachTexture(attachment->texture); AttachTexture(attachment);
bool newRenderPass{CreateRenderPass(vk::Rect2D{ bool newRenderPass{CreateRenderPass(vk::Rect2D{
.extent = attachment->texture->dimensions, .extent = attachment->texture->dimensions,

View File

@ -34,15 +34,17 @@ namespace skyline::gpu::interconnect {
/** /**
* @brief Attach the lifetime of the texture to the command buffer * @brief Attach the lifetime of the texture to the command buffer
* @note The supplied texture **must** be locked by the calling thread
* @note This'll automatically handle syncing of the texture in the most optimal way possible * @note This'll automatically handle syncing of the texture in the most optimal way possible
*/ */
void AttachTexture(const std::shared_ptr<Texture> &texture); void AttachTexture(TextureView *view);
/** /**
* @brief Attach the lifetime of a buffer to the command buffer * @brief Attach the lifetime of a buffer to the command buffer
* @note The supplied buffer **must** be locked by the calling thread
* @note This'll automatically handle syncing of the buffer in the most optimal way possible * @note This'll automatically handle syncing of the buffer in the most optimal way possible
*/ */
void AttachBuffer(const std::shared_ptr<Buffer> &buffer); void AttachBuffer(BufferView *view);
/** /**
* @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

View File

@ -1308,7 +1308,7 @@ namespace skyline::gpu::interconnect {
vertexBindingDivisorsDescriptions.push_back(vertexBuffer.bindingDivisorDescription); vertexBindingDivisorsDescriptions.push_back(vertexBuffer.bindingDivisorDescription);
vertexBufferLocks.emplace_back(*vertexBufferView); vertexBufferLocks.emplace_back(*vertexBufferView);
executor.AttachBuffer(vertexBufferView->buffer); executor.AttachBuffer(vertexBufferView);
vertexBufferHandles[index] = vertexBufferView->buffer->GetBacking(); vertexBufferHandles[index] = vertexBufferView->buffer->GetBacking();
vertexBufferOffsets[index] = vertexBufferView->offset; vertexBufferOffsets[index] = vertexBufferView->offset;
} }

View File

@ -293,7 +293,7 @@ namespace skyline::gpu {
* @note The object **must** be locked prior to accessing any members as values will be mutated * @note The object **must** be locked prior to accessing any members as values will be mutated
* @note This class conforms to the Lockable and BasicLockable C++ named requirements * @note This class conforms to the Lockable and BasicLockable C++ named requirements
*/ */
class TextureView { class TextureView : public FenceCycleDependency, public std::enable_shared_from_this<TextureView> {
private: private:
std::optional<vk::raii::ImageView> view; std::optional<vk::raii::ImageView> view;