From 946373270960622603175e753bd50c382c74c817 Mon Sep 17 00:00:00 2001 From: DrChat Date: Sun, 18 Feb 2018 18:46:00 -0600 Subject: [PATCH] [Vulkan] BufferCache::PrepareVertexSet --- src/xenia/gpu/vulkan/buffer_cache.cc | 86 ++++++++++++++++++++++++++++ src/xenia/gpu/vulkan/buffer_cache.h | 11 ++++ 2 files changed, 97 insertions(+) diff --git a/src/xenia/gpu/vulkan/buffer_cache.cc b/src/xenia/gpu/vulkan/buffer_cache.cc index 7c8db8b8a..5c2fed5e4 100644 --- a/src/xenia/gpu/vulkan/buffer_cache.cc +++ b/src/xenia/gpu/vulkan/buffer_cache.cc @@ -18,6 +18,8 @@ #include "third_party/vulkan/vk_mem_alloc.h" +using namespace xe::gpu::xenos; + namespace xe { namespace gpu { namespace vulkan { @@ -532,6 +534,85 @@ std::pair BufferCache::UploadVertexBuffer( return {transient_buffer_->gpu_buffer(), offset + source_offset}; } +VkDescriptorSet BufferCache::PrepareVertexSet( + VkCommandBuffer setup_buffer, VkFence fence, + std::vector vertex_bindings) { + if (!vertex_descriptor_pool_->has_open_batch()) { + vertex_descriptor_pool_->BeginBatch(fence); + } + + VkDescriptorSet set = + vertex_descriptor_pool_->AcquireEntry(vertex_descriptor_set_layout_); + if (!set) { + return nullptr; + } + + // TODO(DrChat): Define magic number 32 as a constant somewhere. + VkDescriptorBufferInfo buffer_infos[32] = {}; + VkWriteDescriptorSet descriptor_write = { + VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET, + nullptr, + set, + 0, + 0, + 0, + VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER, + nullptr, + buffer_infos, + nullptr, + }; + + auto& regs = *register_file_; + for (const auto& vertex_binding : vertex_bindings) { + int r = XE_GPU_REG_SHADER_CONSTANT_FETCH_00_0 + + (vertex_binding.fetch_constant / 3) * 6; + const auto group = reinterpret_cast(®s.values[r]); + const xe_gpu_vertex_fetch_t* fetch = nullptr; + switch (vertex_binding.fetch_constant % 3) { + case 0: + fetch = &group->vertex_fetch_0; + break; + case 1: + fetch = &group->vertex_fetch_1; + break; + case 2: + fetch = &group->vertex_fetch_2; + break; + } + + if (fetch->type != 0x3) { + // TODO(DrChat): Some games use type 0x0 (with no data). + return false; + } + + // TODO(benvanik): compute based on indices or vertex count. + // THIS CAN BE MASSIVELY INCORRECT (too large). + // This may not be possible (with indexed vfetch). + uint32_t source_length = fetch->size * 4; + uint32_t physical_address = fetch->address << 2; + // trace_writer_.WriteMemoryRead(physical_address, source_length); + + // Upload (or get a cached copy of) the buffer. + auto buffer_ref = + UploadVertexBuffer(setup_buffer, physical_address, source_length, + static_cast(fetch->endian), fence); + if (buffer_ref.second == VK_WHOLE_SIZE) { + // Failed to upload buffer. + return false; + } + + // Stash the buffer reference for our bulk bind at the end. + buffer_infos[descriptor_write.descriptorCount++] = { + buffer_ref.first, + buffer_ref.second, + source_length, + }; + } + + vkUpdateDescriptorSets(*device_, 1, &descriptor_write, 0, nullptr); + return set; +} + VkDeviceSize BufferCache::AllocateTransientData(VkDeviceSize length, VkFence fence) { // Try fast path (if we have space). @@ -626,6 +707,11 @@ void BufferCache::ClearCache() { transient_cache_.clear(); } void BufferCache::Scavenge() { transient_cache_.clear(); transient_buffer_->Scavenge(); + if (vertex_descriptor_pool_->has_open_batch()) { + vertex_descriptor_pool_->EndBatch(); + } + + vertex_descriptor_pool_->Scavenge(); } } // namespace vulkan diff --git a/src/xenia/gpu/vulkan/buffer_cache.h b/src/xenia/gpu/vulkan/buffer_cache.h index 0e579c01f..b39a67b52 100644 --- a/src/xenia/gpu/vulkan/buffer_cache.h +++ b/src/xenia/gpu/vulkan/buffer_cache.h @@ -52,6 +52,12 @@ class BufferCache { return constant_descriptor_set_layout_; } + // Descriptor set containing vertex buffers stored in storage buffers. + // This set contains one binding with an array of 32 storage buffers. + VkDescriptorSetLayout vertex_descriptor_set_layout() const { + return vertex_descriptor_set_layout_; + } + // Uploads the constants specified in the register maps to the transient // uniform storage buffer. // The registers are tightly packed in order as [floats, ints, bools]. @@ -80,6 +86,11 @@ class BufferCache { VkCommandBuffer command_buffer, uint32_t source_addr, uint32_t source_length, Endian endian, VkFence fence); + // Prepares and returns a vertex descriptor set. + VkDescriptorSet PrepareVertexSet( + VkCommandBuffer setup_buffer, VkFence fence, + std::vector vertex_bindings); + // Flushes all pending data to the GPU. // Until this is called the GPU is not guaranteed to see any data. // The given command buffer will be used to queue up events so that the