diff --git a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h index 483f24e7..fe7129b9 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -698,7 +698,7 @@ namespace skyline::gpu::interconnect { return constantBufferSelector; } - void ConstantBufferUpdate(u32 data, u32 offset) { + void ConstantBufferUpdate(std::vector data, u32 offset) { auto constantBuffer{GetConstantBufferSelector().value()}; auto& constantBufferView{constantBuffer.view}; { @@ -708,9 +708,9 @@ namespace skyline::gpu::interconnect { constantBufferView.Write(span(data).cast(), offset); } - executor.AddOutsideRpCommand([constantBufferView, data, offset](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &) { + executor.AddOutsideRpCommand([constantBufferView, data = std::move(data), offset](vk::raii::CommandBuffer &commandBuffer, const std::shared_ptr &cycle, GPU &) { std::scoped_lock lock{constantBufferView}; - commandBuffer.updateBuffer(constantBufferView->buffer->GetBacking(), constantBufferView->view->offset + offset, vk::ArrayProxy(1, &data)); + commandBuffer.updateBuffer(constantBufferView->buffer->GetBacking(), constantBufferView->view->offset + offset, vk::ArrayProxy(static_cast(data.size()), data.data())); }); } diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp index 5f37e3d6..5eecf20b 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.cpp @@ -41,6 +41,27 @@ namespace skyline::soc::gm20b::engine::maxwell3d { bool redundant{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) { switch (method) { ENGINE_STRUCT_CASE(mme, shadowRamControl, { @@ -651,10 +672,12 @@ namespace skyline::soc::gm20b::engine::maxwell3d { registers.raw[0xD00] = 1; }) - #define CBUF_UPDATE_CALLBACKS(z, index, data_) \ - ENGINE_STRUCT_ARRAY_CASE(constantBufferUpdate, data, index, { \ - context.ConstantBufferUpdate(data, registers.constantBufferUpdate->offset); \ - registers.constantBufferUpdate->offset += 4; \ + // Begin a batch constant buffer update, this case will never be reached if a batch update is currently active + #define CBUF_UPDATE_CALLBACKS(z, index, data_) \ + ENGINE_STRUCT_ARRAY_CASE(constantBufferUpdate, data, index, { \ + batchConstantBufferUpdate.startOffset = registers.constantBufferUpdate->offset; \ + batchConstantBufferUpdate.buffer.push_back(data); \ + registers.constantBufferUpdate->offset += 4; \ }) BOOST_PP_REPEAT(16, CBUF_UPDATE_CALLBACKS, 0) diff --git a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h index 77a8f774..eff5544d 100644 --- a/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h +++ b/app/src/main/cpp/skyline/soc/gm20b/engines/maxwell_3d.h @@ -22,6 +22,20 @@ namespace skyline::soc::gm20b::engine::maxwell3d { gpu::interconnect::GraphicsContext context; Inline2MemoryBackend i2m; + struct BatchConstantBufferUpdateState { + std::vector buffer; + u32 startOffset{std::numeric_limits::max()}; + + bool Active() { + return startOffset != std::numeric_limits::max(); + } + + void Reset() { + buffer.clear(); + startOffset = std::numeric_limits::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 */