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
*/
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
/**
@ -114,7 +114,7 @@ namespace skyline::gpu {
* @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
*/
struct BufferView {
struct BufferView : public FenceCycleDependency, public std::enable_shared_from_this<BufferView> {
std::shared_ptr<Buffer> buffer;
vk::DeviceSize offset;
vk::DeviceSize range;

View File

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

View File

@ -1308,7 +1308,7 @@ namespace skyline::gpu::interconnect {
vertexBindingDivisorsDescriptions.push_back(vertexBuffer.bindingDivisorDescription);
vertexBufferLocks.emplace_back(*vertexBufferView);
executor.AttachBuffer(vertexBufferView->buffer);
executor.AttachBuffer(vertexBufferView);
vertexBufferHandles[index] = vertexBufferView->buffer->GetBacking();
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 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:
std::optional<vk::raii::ImageView> view;