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