Implement batch constant buffer updates

Avoids spamming the driver with hundreds of cbuf updates per frame by batching all consecutive updates into one.
This commit is contained in:
Billy Laws 2022-04-17 00:35:00 +01:00
parent 02f99273ac
commit 32fe01e145
3 changed files with 44 additions and 7 deletions

View File

@ -698,7 +698,7 @@ namespace skyline::gpu::interconnect {
return constantBufferSelector; return constantBufferSelector;
} }
void ConstantBufferUpdate(u32 data, u32 offset) { void ConstantBufferUpdate(std::vector<u32> data, u32 offset) {
auto constantBuffer{GetConstantBufferSelector().value()}; auto constantBuffer{GetConstantBufferSelector().value()};
auto& constantBufferView{constantBuffer.view}; auto& constantBufferView{constantBuffer.view};
{ {
@ -708,9 +708,9 @@ namespace skyline::gpu::interconnect {
constantBufferView.Write(span<u32>(data).cast<u8>(), offset); constantBufferView.Write(span<u32>(data).cast<u8>(), offset);
} }
executor.AddOutsideRpCommand([constantBufferView, data, offset](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &) { executor.AddOutsideRpCommand([constantBufferView, data = std::move(data), offset](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr<FenceCycle> &cycle, GPU &) {
std::scoped_lock lock{constantBufferView}; std::scoped_lock lock{constantBufferView};
commandBuffer.updateBuffer<u32>(constantBufferView->buffer->GetBacking(), constantBufferView->view->offset + offset, vk::ArrayProxy(1, &data)); commandBuffer.updateBuffer<u32>(constantBufferView->buffer->GetBacking(), constantBufferView->view->offset + offset, vk::ArrayProxy(static_cast<u32>(data.size()), data.data()));
}); });
} }

View File

@ -41,6 +41,27 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
bool redundant{registers.raw[method] == argument}; bool redundant{registers.raw[method] == argument};
registers.raw[method] = argument; registers.raw[method] = argument;
if (batchConstantBufferUpdate.Active()) {
switch (method) {
// Add to the batch constant buffer update buffer
// Return early here so that any code below can rely on the fact that any cbuf updates will always be the first of a batch
#define CBUF_UPDATE_CALLBACKS(z, index, data_) \
ENGINE_STRUCT_ARRAY_CASE(constantBufferUpdate, data, index, { \
batchConstantBufferUpdate.buffer.push_back(data); \
registers.constantBufferUpdate->offset += 4; \
return; \
})
BOOST_PP_REPEAT(16, CBUF_UPDATE_CALLBACKS, 0)
#undef CBUF_UPDATE_CALLBACKS
default:
// When a method other than constant buffer update is called submit our submit the previously built-up update as a batch
context.ConstantBufferUpdate(std::move(batchConstantBufferUpdate.buffer), batchConstantBufferUpdate.startOffset);
batchConstantBufferUpdate.Reset();
break; // Continue on here to handle the actual method
}
}
if (!redundant) { if (!redundant) {
switch (method) { switch (method) {
ENGINE_STRUCT_CASE(mme, shadowRamControl, { ENGINE_STRUCT_CASE(mme, shadowRamControl, {
@ -651,10 +672,12 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
registers.raw[0xD00] = 1; registers.raw[0xD00] = 1;
}) })
#define CBUF_UPDATE_CALLBACKS(z, index, data_) \ // Begin a batch constant buffer update, this case will never be reached if a batch update is currently active
ENGINE_STRUCT_ARRAY_CASE(constantBufferUpdate, data, index, { \ #define CBUF_UPDATE_CALLBACKS(z, index, data_) \
context.ConstantBufferUpdate(data, registers.constantBufferUpdate->offset); \ ENGINE_STRUCT_ARRAY_CASE(constantBufferUpdate, data, index, { \
registers.constantBufferUpdate->offset += 4; \ batchConstantBufferUpdate.startOffset = registers.constantBufferUpdate->offset; \
batchConstantBufferUpdate.buffer.push_back(data); \
registers.constantBufferUpdate->offset += 4; \
}) })
BOOST_PP_REPEAT(16, CBUF_UPDATE_CALLBACKS, 0) BOOST_PP_REPEAT(16, CBUF_UPDATE_CALLBACKS, 0)

View File

@ -22,6 +22,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
gpu::interconnect::GraphicsContext context; gpu::interconnect::GraphicsContext context;
Inline2MemoryBackend i2m; Inline2MemoryBackend i2m;
struct BatchConstantBufferUpdateState {
std::vector<u32> buffer;
u32 startOffset{std::numeric_limits<u32>::max()};
bool Active() {
return startOffset != std::numeric_limits<u32>::max();
}
void Reset() {
buffer.clear();
startOffset = std::numeric_limits<u32>::max();
}
} batchConstantBufferUpdate; //!< Holds state for updating constant buffer data in a batch rather than word by word
/** /**
* @brief Calls the appropriate function corresponding to a certain method with the supplied argument * @brief Calls the appropriate function corresponding to a certain method with the supplied argument
*/ */