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.
This commit is contained in:
PixelyIon 2022-01-06 00:50:55 +05:30
parent 08f29f7da4
commit bc29b23972
3 changed files with 58 additions and 0 deletions

View File

@ -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<typename T>
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<const u8 *>(&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 {

View File

@ -48,6 +48,7 @@ namespace skyline::soc::gm20b::engine::maxwell3d {
#define MAXWELL3D_OFFSET(field) (sizeof(typeof(Registers::field)) - sizeof(std::remove_reference_t<decltype(*Registers::field)>)) / sizeof(u32)
#define MAXWELL3D_STRUCT_OFFSET(field, member) MAXWELL3D_OFFSET(field) + U32_OFFSET(std::remove_reference_t<decltype(*Registers::field)>, member)
#define MAXWELL3D_STRUCT_STRUCT_OFFSET(field, member, submember) MAXWELL3D_STRUCT_OFFSET(field, member) + U32_OFFSET(std::remove_reference_t<decltype(Registers::field->member)>, submember)
#define MAXWELL3D_STRUCT_ARRAY_OFFSET(field, member, index) MAXWELL3D_STRUCT_OFFSET(field, member) + ((sizeof(std::remove_reference_t<decltype(Registers::field->member[0])>) / sizeof(u32)) * index)
#define MAXWELL3D_ARRAY_OFFSET(field, index) MAXWELL3D_OFFSET(field) + ((sizeof(std::remove_reference_t<decltype(Registers::field[0])>) / sizeof(u32)) * index)
#define MAXWELL3D_ARRAY_STRUCT_OFFSET(field, index, member) MAXWELL3D_ARRAY_OFFSET(field, index) + U32_OFFSET(std::remove_reference_t<decltype(Registers::field[0])>, 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

View File

@ -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<u32, 16> data;
};
Register<0x8E3, ConstantBufferUpdate> constantBufferUpdate;
Register<0x900, std::array<type::Bind, type::PipelineStageCount>> bind; //!< Binds constant buffers to pipeline stages
Register<0x982, u32> bindlessTextureConstantBufferIndex; //!< The index of the constant buffer containing bindless texture descriptors