Implement support for GPU-side constant buffer updating

Previously constant buffer updates would be handled on the CPU and only the end result would be synced to the GPU before execute. This caused issues as if the constant buffer contents was changed between each draw in a renderpass (e.g. text rendering) the draws themselves would only see the final resulting constant buffer. Fix this by updating cbufs on the GPU/CPU seperately, only ever syncing them back at the start or after a guest side CPU write, at the moment only a single word is updated at a time however this can be optimised in the future to batch all consecutive updates into one large one.
This commit is contained in:
Billy Laws 2022-04-13 22:06:36 +01:00 committed by PixelyIon
parent 036faedabd
commit d79635772f
3 changed files with 19 additions and 7 deletions

View File

@ -145,10 +145,10 @@ namespace skyline::gpu {
std::memcpy(data.data(), backing.data() + offset, data.size());
}
void Buffer::Write(span<u8> data, vk::DeviceSize offset) {
void Buffer::Write(span<u8> data, vk::DeviceSize offset, bool skipCleanHostWrite) {
if (dirtyState == DirtyState::CpuDirty || dirtyState == DirtyState::Clean)
std::memcpy(mirror.data() + offset, data.data(), data.size());
if (dirtyState == DirtyState::GpuDirty || dirtyState == DirtyState::Clean)
if ((!skipCleanHostWrite && dirtyState == DirtyState::Clean) || dirtyState == DirtyState::GpuDirty)
std::memcpy(backing.data() + offset, data.data(), data.size());
}
@ -234,7 +234,7 @@ namespace skyline::gpu {
bufferDelegate->buffer->Read(data, offset + bufferDelegate->view->offset);
}
void BufferView::Write(span<u8> data, vk::DeviceSize offset) const {
bufferDelegate->buffer->Write(data, offset + bufferDelegate->view->offset);
void BufferView::Write(span<u8> data, vk::DeviceSize offset, bool skipCleanHostWrite) const {
bufferDelegate->buffer->Write(data, offset + bufferDelegate->view->offset, skipCleanHostWrite);
}
}

View File

@ -171,8 +171,9 @@ namespace skyline::gpu {
/**
* @brief Writes data at the specified offset in the buffer
* @param skipCleanHostWrite Skip writing to the host buffer if it's clean, assumes the buffer data will be synchronised externally
*/
void Write(span<u8> data, vk::DeviceSize offset);
void Write(span<u8> data, vk::DeviceSize offset, bool skipCleanHostWrite = false);
/**
* @return A cached or newly created view into this buffer with the supplied attributes
@ -250,7 +251,8 @@ namespace skyline::gpu {
/**
* @brief Writes data at the specified offset in the view
* @note The view **must** be locked prior to calling this
* @param skipCleanHostWrite Skip writing to the host buffer if it's clean, assumes the buffer data will be synchronised externally
*/
void Write(span<u8> data, vk::DeviceSize offset) const;
void Write(span<u8> data, vk::DeviceSize offset, bool skipCleanHostWrite = false) const;
};
}

View File

@ -629,7 +629,7 @@ namespace skyline::gpu::interconnect {
template<typename T>
void Write(T &object, size_t offset) {
std::scoped_lock lock{view};
view.Write(span<T>(object).template cast<u8>(), offset);
view.Write(span<T>(object).template cast<u8>(), offset, true);
}
};
ConstantBuffer constantBufferSelector; //!< The constant buffer selector is used to bind a constant buffer to a stage or update data in it
@ -698,6 +698,11 @@ namespace skyline::gpu::interconnect {
if (!view) {
auto mappings{channelCtx.asCtx->gmmu.TranslateRange(constantBufferSelector.iova, constantBufferSelector.size)};
view = gpu.buffer.FindOrCreate(mappings.front(), executor.cycle);
{
std::scoped_lock lock{*view};
view->bufferDelegate->buffer->SynchronizeHost(false);
}
constantBufferCache.Insert(constantBufferSelector.size, constantBufferSelector.iova, *view);
}
@ -708,6 +713,11 @@ namespace skyline::gpu::interconnect {
void ConstantBufferUpdate(u32 data, u32 offset) {
auto constantBuffer{GetConstantBufferSelector().value()};
constantBuffer.Write(data, offset);
executor.AddNonGraphicsPass([view = constantBuffer.view, data, offset](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &) {
std::scoped_lock lock{view};
commandBuffer.updateBuffer<u32>(view.bufferDelegate->buffer->GetBacking(), offset, vk::ArrayProxy(1, &data));
});
}
/* Shader Program */