7size_t Graphics::uploadSkinPalette(Mesh*
mesh, Mesh3dFrameSlots& fslots) {
8 const bool skinned =
mesh &&
mesh->hasGpuSkinning() &&
mesh->getSkinPaletteCount() > 0;
9 const size_t slot = skinned ? fslots.drawIndex + 1 : 0;
10 const size_t bytes = skinned ?
mesh->skinPalette().size() *
sizeof(float) : sizeof(glm::mat4);
11 if (
bytes > device.physical_device.properties.limits.maxStorageBufferRange)
12 throw Exception(
"Skin palette exceeds device maxStorageBufferRange");
13 if (fslots.palettes.size() <= slot) fslots.palettes.resize(slot + 1);
14 auto&
buffer = fslots.palettes[slot];
16 buffer.allocate(frameToken(), device, vk::BufferUsageFlagBits::eStorageBuffer,
bytes, kHostVisibleCoherent);
20 fslots.skinSets.clear();
22 const glm::mat4 identity(1.f);
23 updateRingLocal(
buffer, 0, skinned ?
mesh->skinPalette().data() : &identity[0][0],
bytes);
24 fslots.activePalette = slot;
28vk::DescriptorSet Graphics::skinPassSetFor(GpuTexture*
albedo, Mesh3dFrameSlots& fslots) {
29 const auto key = std::make_pair(fslots.activePalette,
albedo);
30 auto it = fslots.skinSets.find(
key);
31 if (it != fslots.skinSets.end())
return it->second;
32 vk::DescriptorSetAllocateInfo alloc{};
33 alloc.descriptorPool = descriptorPool;
34 alloc.descriptorSetCount = 1;
35 alloc.pSetLayouts = &skinPassSetLayout;
36 vkb::UnboundSet unbound{device->allocateDescriptorSets(alloc).front()};
37 vkb::DescriptorSetUpdater updater(2, 1, 0);
38 updater.beginDescriptorSet(unbound)
39 .beginBuffers(0, 0, vk::DescriptorType::eUniformBufferDynamic)
40 .buffer(fslots.uboRing.buffer, 0,
sizeof(SkinPassUBO))
41 .beginBuffers(2, 0, vk::DescriptorType::eStorageBuffer)
42 .buffer(fslots.palettes[fslots.activePalette].buffer, 0, fslots.palettes[fslots.activePalette].capacity)
43 .beginImages(1, 0, vk::DescriptorType::eCombinedImageSampler)
44 .image(vkb::SampledImage::forLaterSample(
albedo->sampler,
albedo->imageView()))
45 .update(device.instance);
46 vkb::BoundSet bound = std::move(unbound).publish();
47 auto [inserted, ignored] = fslots.skinSets.emplace(
key, bound);
48 return inserted->second;
51bool Graphics::prepareSkinPass(Mesh*
mesh, Texture*
albedo,
const glm::mat4&
mvp,
const glm::mat4&
model,
52 const glm::vec4&
clip, vk::DescriptorSet& set, uint32_t& uboOffset) {
53 if (!
mesh || !
mesh->hasGpuSkinning())
return false;
54 auto& fslots = currentMesh3dFrameSlots();
60 if (!fslots.uboRing.buffer || fslots.capacity == 0) ensureMesh3dRing(fslots);
61 if (fslots.drawIndex >= fslots.capacity) {
62 std::fprintf(stderr,
"[vulkan] skin pass UBO ring exhausted (%zu draws); draw skipped\n", fslots.capacity);
69 ubo.skinInfo.x =
static_cast<float>(
mesh->getSkinPaletteCount());
70 ubo.skinInfo.y =
static_cast<float>(mesh3dSkinInfluenceLimit);
71 uploadSkinPalette(
mesh, fslots);
72 const size_t slot = fslots.drawIndex++;
73 ensureMesh3dStrides();
74 uboOffset = uint32_t(slot) * mesh3dUboStride;
75 updateRingLocal(fslots.uboRing, uboOffset, &ubo,
sizeof(ubo));
77 if (!texture || !texture->gpuHandle)
return false;
78 set = skinPassSetFor(
static_cast<GpuTexture*
>(texture->gpuHandle), fslots);
graphics::Texture * albedo
std::unique_ptr< gpgpu::GpuBuffer > buffer