From bc29b239723bdcf451b5c1909d246916c28a556e Mon Sep 17 00:00:00 2001 From: PixelyIon Date: Thu, 6 Jan 2022 00:50:55 +0530 Subject: [PATCH] Implement CPU-only Maxwell3D Inline Constant Buffer Updates Implements inline constant buffer updates that are written to the CPU copy of the buffer rather than generating an actual inline buffer write, this works for TIC/TSC index updates but won't work when the buffer is expected to actually be updated inline with regard to sequence rather than just as a buffer upload prior to rendering. GPU-sided constant buffer updates will be implemented later with optimizations for updating an entire range by handling GPFIFO `Inc`/`NonInc`directly and submitting it as a host inline buffer update. --- .../gpu/interconnect/graphics_context.h | 33 +++++++++++++++++++ .../skyline/soc/gm20b/engines/maxwell_3d.cpp | 16 +++++++++ .../skyline/soc/gm20b/engines/maxwell_3d.h | 9 +++++ 3 files changed, 58 insertions(+) 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 86fe5c2b..6647eedb 100644 --- a/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h +++ b/app/src/main/cpp/skyline/gpu/interconnect/graphics_context.h @@ -543,9 +543,33 @@ namespace skyline::gpu::interconnect { } throw exception("Object extent ({} + {} = {}) is larger than constant buffer size: {}", size + offset, sizeof(T), size + offset + sizeof(T), size); } + + /** + * @brief Writes an object to the supplied offset in the constant buffer + * @note This must only be called when the GuestBuffer is resolved correctly + */ + template + void Write(const T &object, size_t offset) { + size_t objectOffset{}; + for (auto &mapping: guest.mappings) { + if (offset < mapping.size_bytes()) { + auto copySize{std::min(mapping.size_bytes() - offset, sizeof(T))}; + std::memcpy(mapping.data() + offset, reinterpret_cast(&object) + objectOffset, copySize); + objectOffset += copySize; + if (objectOffset == sizeof(T)) + return; + offset = mapping.size_bytes(); + } else { + offset -= mapping.size_bytes(); + } + } + throw exception("Object extent ({} + {} = {}) is larger than constant buffer size: {}", size + offset, sizeof(T), size + offset + sizeof(T), size); + } }; ConstantBuffer constantBufferSelector; //!< The constant buffer selector is used to bind a constant buffer to a stage or update data in it + u32 constantBufferUpdateOffset{}; //!< The offset at which any inline constant buffer updata data is written + public: void SetConstantBufferSelectorSize(u32 size) { constantBufferSelector.size = size; @@ -575,6 +599,15 @@ namespace skyline::gpu::interconnect { return constantBufferSelector; } + void SetConstantBufferUpdateOffset(u32 offset) { + constantBufferUpdateOffset = offset; + } + + void ConstantBufferUpdate(u32 data) { + auto constantBuffer{GetConstantBufferSelector().value()}; + constantBuffer.Write(data, constantBufferUpdateOffset); + } + /* Shader Program */ private: struct Shader { 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 2ab1be7d..8b1c69e7 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 @@ -48,6 +48,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { #define MAXWELL3D_OFFSET(field) (sizeof(typeof(Registers::field)) - sizeof(std::remove_reference_t)) / sizeof(u32) #define MAXWELL3D_STRUCT_OFFSET(field, member) MAXWELL3D_OFFSET(field) + U32_OFFSET(std::remove_reference_t, member) #define MAXWELL3D_STRUCT_STRUCT_OFFSET(field, member, submember) MAXWELL3D_STRUCT_OFFSET(field, member) + U32_OFFSET(std::remove_reference_tmember)>, submember) + #define MAXWELL3D_STRUCT_ARRAY_OFFSET(field, member, index) MAXWELL3D_STRUCT_OFFSET(field, member) + ((sizeof(std::remove_reference_tmember[0])>) / sizeof(u32)) * index) #define MAXWELL3D_ARRAY_OFFSET(field, index) MAXWELL3D_OFFSET(field) + ((sizeof(std::remove_reference_t) / sizeof(u32)) * index) #define MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) MAXWELL3D_ARRAY_OFFSET(field, index) + U32_OFFSET(std::remove_reference_t, member) #define MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET(field, index, member, submember) MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) + U32_OFFSET(decltype(Registers::field[0].member), submember) @@ -64,6 +65,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { } #define MAXWELL3D_STRUCT_CASE(field, member, content) MAXWELL3D_CASE_BASE(member, field->member, MAXWELL3D_STRUCT_OFFSET(field, member), content) #define MAXWELL3D_STRUCT_STRUCT_CASE(field, member, submember, content) MAXWELL3D_CASE_BASE(submember, field->member.submember, MAXWELL3D_STRUCT_STRUCT_OFFSET(field, member, submember), content) + #define MAXWELL3D_STRUCT_ARRAY_CASE(field, member, index, content) MAXWELL3D_CASE_BASE(member, field->member[index], MAXWELL3D_STRUCT_ARRAY_OFFSET(field, member, index), content) #define MAXWELL3D_ARRAY_CASE(field, index, content) MAXWELL3D_CASE_BASE(field, field[index], MAXWELL3D_ARRAY_OFFSET(field, index), content) #define MAXWELL3D_ARRAY_STRUCT_CASE(field, index, member, content) MAXWELL3D_CASE_BASE(member, field[index].member, MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member), content) #define MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE(field, index, member, submember, content) MAXWELL3D_CASE_BASE(submember, field[index].member.submember, MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET(field, index, member, submember), content) @@ -487,6 +489,10 @@ namespace skyline::soc::gm20b::engine::maxwell3d { context.SetTexturePoolMaximumIndex(maximumIndex); }) + MAXWELL3D_STRUCT_CASE(constantBufferUpdate, offset, { + context.SetConstantBufferUpdateOffset(offset); + }) + default: break; } @@ -575,12 +581,21 @@ namespace skyline::soc::gm20b::engine::maxwell3d { registers.raw[0xD00] = 1; }) + #define CBUF_UPDATE_CALLBACKS(z, index, data_) \ + MAXWELL3D_STRUCT_ARRAY_CASE(constantBufferUpdate, data, index, { \ + context.ConstantBufferUpdate(data); \ + }) + + BOOST_PP_REPEAT(16, CBUF_UPDATE_CALLBACKS, 0) + #undef CBUF_UPDATE_CALLBACKS + default: break; } #undef MAXWELL3D_OFFSET #undef MAXWELL3D_STRUCT_OFFSET + #undef MAXWELL3D_STRUCT_ARRAY_OFFSET #undef MAXWELL3D_ARRAY_OFFSET #undef MAXWELL3D_ARRAY_STRUCT_OFFSET #undef MAXWELL3D_ARRAY_STRUCT_STRUCT_OFFSET @@ -588,6 +603,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d { #undef MAXWELL3D_CASE_BASE #undef MAXWELL3D_CASE #undef MAXWELL3D_STRUCT_CASE + #undef MAXWELL3D_STRUCT_ARRAY_CASE #undef MAXWELL3D_ARRAY_CASE #undef MAXWELL3D_ARRAY_STRUCT_CASE #undef MAXWELL3D_ARRAY_STRUCT_STRUCT_CASE 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 30eb723d..11f81e69 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 @@ -293,6 +293,15 @@ namespace skyline::soc::gm20b::engine::maxwell3d { }; Register<0x8E0, ConstantBufferSelector> constantBufferSelector; + /** + * @brief Allows updating the currently selected constant buffer inline with an offset and up to 16 words of data + */ + struct ConstantBufferUpdate { + u32 offset; + std::array data; + }; + Register<0x8E3, ConstantBufferUpdate> constantBufferUpdate; + Register<0x900, std::array> bind; //!< Binds constant buffers to pipeline stages Register<0x982, u32> bindlessTextureConstantBufferIndex; //!< The index of the constant buffer containing bindless texture descriptors