Merge commit 'f2fabfdf0' into canary_experimental

Sync changes from master up to before the recent GPU changes, those will be
merged later
This commit is contained in:
Herman S.
2026-02-17 15:46:27 +09:00
294 changed files with 165264 additions and 173899 deletions

View File

@@ -69,6 +69,9 @@ constexpr VkDescriptorPoolSize
VulkanCommandProcessor::VulkanCommandProcessor(
VulkanGraphicsSystem* graphics_system, kernel::KernelState* kernel_state)
: CommandProcessor(graphics_system, kernel_state),
completion_timeline_(static_cast<const ui::vulkan::VulkanProvider*>(
graphics_system->provider())
->vulkan_device()),
deferred_command_buffer_(*this),
transient_descriptor_allocator_uniform_buffer_(
static_cast<const ui::vulkan::VulkanProvider*>(
@@ -229,11 +232,11 @@ bool VulkanCommandProcessor::SetupContext() {
"constant buffers");
return false;
}
// Transient: uniform buffer for compute shaders.
// Transient: storage buffer for compute shaders.
VkDescriptorSetLayoutBinding descriptor_set_layout_binding_transient;
descriptor_set_layout_binding_transient.binding = 0;
descriptor_set_layout_binding_transient.descriptorType =
VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_set_layout_binding_transient.descriptorCount = 1;
descriptor_set_layout_binding_transient.stageFlags =
VK_SHADER_STAGE_COMPUTE_BIT;
@@ -241,21 +244,6 @@ bool VulkanCommandProcessor::SetupContext() {
descriptor_set_layout_create_info.bindingCount = 1;
descriptor_set_layout_create_info.pBindings =
&descriptor_set_layout_binding_transient;
if (dfn.vkCreateDescriptorSetLayout(
device, &descriptor_set_layout_create_info, nullptr,
&descriptor_set_layouts_single_transient_[size_t(
SingleTransientDescriptorLayout::kUniformBufferCompute)]) !=
VK_SUCCESS) {
XELOGE(
"Failed to create a Vulkan descriptor set layout for a uniform buffer "
"bound to the compute shader");
return false;
}
// Transient: storage buffer for compute shaders.
descriptor_set_layout_binding_transient.descriptorType =
VK_DESCRIPTOR_TYPE_STORAGE_BUFFER;
descriptor_set_layout_binding_transient.stageFlags =
VK_SHADER_STAGE_COMPUTE_BIT;
if (dfn.vkCreateDescriptorSetLayout(
device, &descriptor_set_layout_create_info, nullptr,
&descriptor_set_layouts_single_transient_[size_t(
@@ -1187,26 +1175,17 @@ void VulkanCommandProcessor::ShutdownContext() {
dfn.vkDestroySemaphore(device, semaphore.second, nullptr);
}
submissions_in_flight_semaphores_.clear();
for (VkFence& fence : submissions_in_flight_fences_) {
dfn.vkDestroyFence(device, fence, nullptr);
}
submissions_in_flight_fences_.clear();
current_submission_wait_stage_masks_.clear();
for (VkSemaphore semaphore : current_submission_wait_semaphores_) {
dfn.vkDestroySemaphore(device, semaphore, nullptr);
}
current_submission_wait_semaphores_.clear();
submission_completed_ = 0;
submission_open_ = false;
for (VkSemaphore semaphore : semaphores_free_) {
dfn.vkDestroySemaphore(device, semaphore, nullptr);
}
semaphores_free_.clear();
for (VkFence fence : fences_free_) {
dfn.vkDestroyFence(device, fence, nullptr);
}
fences_free_.clear();
device_lost_ = false;
@@ -1465,7 +1444,8 @@ void VulkanCommandProcessor::IssueSwap(uint32_t frontbuffer_ptr,
SwapFramebuffer& new_swap_framebuffer =
swap_framebuffers_[swap_framebuffer_new_index];
if (new_swap_framebuffer.framebuffer != VK_NULL_HANDLE) {
if (submission_completed_ >= new_swap_framebuffer.last_submission) {
if (GetCompletedSubmission() >=
new_swap_framebuffer.last_submission) {
dfn.vkDestroyFramebuffer(device, new_swap_framebuffer.framebuffer,
nullptr);
} else {
@@ -2073,7 +2053,7 @@ VulkanCommandProcessor::AcquireScratchGpuBuffer(
return ScratchBufferAcquisition();
}
if (submission_completed_ >= scratch_buffer_last_usage_submission_) {
if (GetCompletedSubmission() >= scratch_buffer_last_usage_submission_) {
const ui::vulkan::VulkanDevice::Functions& dfn = vulkan_device->functions();
const VkDevice device = vulkan_device->device();
if (scratch_buffer_ != VK_NULL_HANDLE) {
@@ -2388,7 +2368,7 @@ bool VulkanCommandProcessor::IssueDraw(xenos::PrimitiveType prim_type,
texture_cache_->GetSubmissionToAwaitOnSamplerOverflow(
samplers_overflowed_count);
assert_true(sampler_overflow_await_submission <= GetCurrentSubmission());
CheckSubmissionFenceAndDeviceLoss(sampler_overflow_await_submission);
CheckSubmissionCompletionAndDeviceLoss(sampler_overflow_await_submission);
}
// Set up the render targets - this may perform dispatches and draws.
@@ -3038,7 +3018,7 @@ void VulkanCommandProcessor::InitializeTrace() {
}
}
void VulkanCommandProcessor::CheckSubmissionFenceAndDeviceLoss(
void VulkanCommandProcessor::CheckSubmissionCompletionAndDeviceLoss(
uint64_t await_submission) {
// Only report once, no need to retry a wait that won't succeed anyway.
if (device_lost_) {
@@ -3054,69 +3034,23 @@ void VulkanCommandProcessor::CheckSubmissionFenceAndDeviceLoss(
await_submission = GetCurrentSubmission() - 1;
}
const ui::vulkan::VulkanDevice* const vulkan_device = GetVulkanDevice();
const ui::vulkan::VulkanDevice::Functions& dfn = vulkan_device->functions();
const VkDevice device = vulkan_device->device();
completion_timeline_.AwaitSubmissionAndUpdateCompleted(await_submission);
size_t fences_total = submissions_in_flight_fences_.size();
size_t fences_awaited = 0;
if (await_submission > submission_completed_) {
// Await in a blocking way if requested.
// TODO(Triang3l): Await only one fence. "Fence signal operations that are
// defined by vkQueueSubmit additionally include in the first
// synchronization scope all commands that occur earlier in submission
// order."
VkResult wait_result = dfn.vkWaitForFences(
device, uint32_t(await_submission - submission_completed_),
submissions_in_flight_fences_.data(), VK_TRUE, UINT64_MAX);
if (wait_result == VK_SUCCESS) {
fences_awaited += await_submission - submission_completed_;
} else {
XELOGE("Failed to await submission completion Vulkan fences");
if (wait_result == VK_ERROR_DEVICE_LOST) {
device_lost_ = true;
}
}
}
// Check how far into the submissions the GPU currently is, in order because
// submission themselves can be executed out of order, but Xenia serializes
// that for simplicity.
while (fences_awaited < fences_total) {
VkResult fence_status = dfn.vkWaitForFences(
device, 1, &submissions_in_flight_fences_[fences_awaited], VK_TRUE, 0);
if (fence_status != VK_SUCCESS) {
if (fence_status == VK_ERROR_DEVICE_LOST) {
device_lost_ = true;
}
break;
}
++fences_awaited;
}
if (device_lost_) {
const ui::vulkan::VulkanDevice* const vulkan_device = GetVulkanDevice();
if (vulkan_device->IsLost()) {
device_lost_ = true;
graphics_system_->OnHostGpuLossFromAnyThread(true);
return;
}
if (!fences_awaited) {
// Not updated - no need to reclaim or download things.
return;
}
// Reclaim fences.
fences_free_.reserve(fences_free_.size() + fences_awaited);
auto submissions_in_flight_fences_awaited_end =
submissions_in_flight_fences_.cbegin();
std::advance(submissions_in_flight_fences_awaited_end, fences_awaited);
fences_free_.insert(fences_free_.cend(),
submissions_in_flight_fences_.cbegin(),
submissions_in_flight_fences_awaited_end);
submissions_in_flight_fences_.erase(submissions_in_flight_fences_.cbegin(),
submissions_in_flight_fences_awaited_end);
submission_completed_ += fences_awaited;
const uint64_t completed_submission = GetCompletedSubmission();
// Reclaim semaphores.
while (!submissions_in_flight_semaphores_.empty()) {
const auto& semaphore_submission =
submissions_in_flight_semaphores_.front();
if (semaphore_submission.first > submission_completed_) {
if (semaphore_submission.first > completed_submission) {
break;
}
semaphores_free_.push_back(semaphore_submission.second);
@@ -3126,7 +3060,7 @@ void VulkanCommandProcessor::CheckSubmissionFenceAndDeviceLoss(
// Reclaim command pools.
while (!command_buffers_submitted_.empty()) {
const auto& command_buffer_pair = command_buffers_submitted_.front();
if (command_buffer_pair.first > submission_completed_) {
if (command_buffer_pair.first > completed_submission) {
break;
}
command_buffers_writable_.push_back(command_buffer_pair.second);
@@ -3139,12 +3073,14 @@ void VulkanCommandProcessor::CheckSubmissionFenceAndDeviceLoss(
render_target_cache_->CompletedSubmissionUpdated();
texture_cache_->CompletedSubmissionUpdated(submission_completed_);
texture_cache_->CompletedSubmissionUpdated(completed_submission);
// Destroy objects scheduled for destruction.
const ui::vulkan::VulkanDevice::Functions& dfn = vulkan_device->functions();
const VkDevice device = vulkan_device->device();
while (!destroy_framebuffers_.empty()) {
const auto& destroy_pair = destroy_framebuffers_.front();
if (destroy_pair.first > submission_completed_) {
if (destroy_pair.first > completed_submission) {
break;
}
dfn.vkDestroyFramebuffer(device, destroy_pair.second, nullptr);
@@ -3152,7 +3088,7 @@ void VulkanCommandProcessor::CheckSubmissionFenceAndDeviceLoss(
}
while (!destroy_buffers_.empty()) {
const auto& destroy_pair = destroy_buffers_.front();
if (destroy_pair.first > submission_completed_) {
if (destroy_pair.first > completed_submission) {
break;
}
dfn.vkDestroyBuffer(device, destroy_pair.second, nullptr);
@@ -3160,7 +3096,7 @@ void VulkanCommandProcessor::CheckSubmissionFenceAndDeviceLoss(
}
while (!destroy_memory_.empty()) {
const auto& destroy_pair = destroy_memory_.front();
if (destroy_pair.first > submission_completed_) {
if (destroy_pair.first > completed_submission) {
break;
}
dfn.vkFreeMemory(device, destroy_pair.second, nullptr);
@@ -3190,8 +3126,9 @@ bool VulkanCommandProcessor::BeginSubmission(bool is_guest_command) {
is_opening_frame
? closed_frame_submissions_[frame_current_ % kMaxFramesInFlight]
: 0;
CheckSubmissionFenceAndDeviceLoss(await_submission);
if (device_lost_ || submission_completed_ < await_submission) {
CheckSubmissionCompletionAndDeviceLoss(await_submission);
const uint64_t completed_submission = GetCompletedSubmission();
if (device_lost_ || completed_submission < await_submission) {
return false;
}
@@ -3204,7 +3141,7 @@ bool VulkanCommandProcessor::BeginSubmission(bool is_guest_command) {
for (uint64_t frame = frame_completed_ + 1; frame < frame_current_;
++frame) {
if (closed_frame_submissions_[frame % kMaxFramesInFlight] >
submission_completed_) {
completed_submission) {
break;
}
frame_completed_ = frame;
@@ -3352,27 +3289,12 @@ bool VulkanCommandProcessor::BeginSubmission(bool is_guest_command) {
}
bool VulkanCommandProcessor::EndSubmission(bool is_swap) {
const ui::vulkan::VulkanDevice* const vulkan_device = GetVulkanDevice();
ui::vulkan::VulkanDevice* const vulkan_device = GetVulkanDevice();
const ui::vulkan::VulkanDevice::Functions& dfn = vulkan_device->functions();
const VkDevice device = vulkan_device->device();
// Make sure everything needed for submitting exist.
if (submission_open_) {
if (fences_free_.empty()) {
VkFenceCreateInfo fence_create_info;
fence_create_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
fence_create_info.pNext = nullptr;
fence_create_info.flags = 0;
VkFence fence;
if (dfn.vkCreateFence(device, &fence_create_info, nullptr, &fence) !=
VK_SUCCESS) {
XELOGE("Failed to create a Vulkan fence");
// Try to submit later. Completely dropping the submission is not
// permitted because resources would be left in an undefined state.
return false;
}
fences_free_.push_back(fence);
}
if (!sparse_memory_binds_.empty() && semaphores_free_.empty()) {
VkSemaphoreCreateInfo semaphore_create_info;
semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
@@ -3515,58 +3437,37 @@ bool VulkanCommandProcessor::EndSubmission(bool is_swap) {
return false;
}
VkSubmitInfo submit_info;
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
submit_info.pNext = nullptr;
const uint64_t submission_index = GetCurrentSubmission();
VkSubmitInfo submit_info = {VK_STRUCTURE_TYPE_SUBMIT_INFO};
if (!current_submission_wait_semaphores_.empty()) {
submit_info.waitSemaphoreCount =
uint32_t(current_submission_wait_semaphores_.size());
submit_info.pWaitSemaphores = current_submission_wait_semaphores_.data();
submit_info.pWaitDstStageMask =
current_submission_wait_stage_masks_.data();
} else {
submit_info.waitSemaphoreCount = 0;
submit_info.pWaitSemaphores = nullptr;
submit_info.pWaitDstStageMask = nullptr;
}
submit_info.commandBufferCount = 1;
submit_info.pCommandBuffers = &command_buffer.buffer;
submit_info.signalSemaphoreCount = 0;
submit_info.pSignalSemaphores = nullptr;
assert_false(fences_free_.empty());
VkFence fence = fences_free_.back();
if (dfn.vkResetFences(device, 1, &fence) != VK_SUCCESS) {
XELOGE("Failed to reset a Vulkan submission fence");
return false;
}
VkResult submit_result;
{
ui::vulkan::VulkanDevice::Queue::Acquisition queue_acquisition =
vulkan_device->AcquireQueue(
vulkan_device->queue_family_graphics_compute(), 0);
submit_result =
dfn.vkQueueSubmit(queue_acquisition.queue(), 1, &submit_info, fence);
}
const VkResult submit_result = completion_timeline_.AcquireFenceAndSubmit(
vulkan_device->queue_family_graphics_compute(), 0, 1, &submit_info);
if (submit_result != VK_SUCCESS) {
XELOGE("Failed to submit a Vulkan command buffer");
if (submit_result == VK_ERROR_DEVICE_LOST && !device_lost_) {
XELOGE("Failed to submit a GPU emulation Vulkan command buffer: {}",
vk::to_string(vk::Result(submit_result)));
if (vulkan_device->IsLost() && !device_lost_) {
device_lost_ = true;
graphics_system_->OnHostGpuLossFromAnyThread(true);
}
return false;
}
uint64_t submission_current = GetCurrentSubmission();
current_submission_wait_stage_masks_.clear();
for (VkSemaphore semaphore : current_submission_wait_semaphores_) {
submissions_in_flight_semaphores_.emplace_back(submission_current,
submissions_in_flight_semaphores_.emplace_back(submission_index,
semaphore);
}
current_submission_wait_semaphores_.clear();
command_buffers_submitted_.emplace_back(submission_current, command_buffer);
command_buffers_submitted_.emplace_back(submission_index, command_buffer);
command_buffers_writable_.pop_back();
// Increments the current submission number, going to the next submission.
submissions_in_flight_fences_.push_back(fence);
fences_free_.pop_back();
submission_open_ = false;
}
@@ -4795,56 +4696,6 @@ bool VulkanCommandProcessor::UpdateBindings(const VulkanShader* vertex_shader,
return true;
}
uint8_t* VulkanCommandProcessor::WriteTransientUniformBufferBinding(
size_t size, SingleTransientDescriptorLayout transient_descriptor_layout,
VkDescriptorBufferInfo& descriptor_buffer_info_out,
VkWriteDescriptorSet& write_descriptor_set_out) {
assert_true(frame_open_);
VkDescriptorSet descriptor_set =
AllocateSingleTransientDescriptor(transient_descriptor_layout);
if (descriptor_set == VK_NULL_HANDLE) {
return nullptr;
}
uint8_t* mapping = uniform_buffer_pool_->Request(
frame_current_, size,
size_t(GetVulkanDevice()->properties().minUniformBufferOffsetAlignment),
descriptor_buffer_info_out.buffer, descriptor_buffer_info_out.offset);
if (!mapping) {
return nullptr;
}
descriptor_buffer_info_out.range = VkDeviceSize(size);
write_descriptor_set_out.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
write_descriptor_set_out.pNext = nullptr;
write_descriptor_set_out.dstSet = descriptor_set;
write_descriptor_set_out.dstBinding = 0;
write_descriptor_set_out.dstArrayElement = 0;
write_descriptor_set_out.descriptorCount = 1;
write_descriptor_set_out.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
write_descriptor_set_out.pImageInfo = nullptr;
write_descriptor_set_out.pBufferInfo = &descriptor_buffer_info_out;
write_descriptor_set_out.pTexelBufferView = nullptr;
return mapping;
}
uint8_t* VulkanCommandProcessor::WriteTransientUniformBufferBinding(
size_t size, SingleTransientDescriptorLayout transient_descriptor_layout,
VkDescriptorSet& descriptor_set_out) {
VkDescriptorBufferInfo write_descriptor_buffer_info;
VkWriteDescriptorSet write_descriptor_set;
uint8_t* mapping = WriteTransientUniformBufferBinding(
size, transient_descriptor_layout, write_descriptor_buffer_info,
write_descriptor_set);
if (!mapping) {
return nullptr;
}
const ui::vulkan::VulkanDevice* const vulkan_device = GetVulkanDevice();
const ui::vulkan::VulkanDevice::Functions& dfn = vulkan_device->functions();
const VkDevice device = vulkan_device->device();
dfn.vkUpdateDescriptorSets(device, 1, &write_descriptor_set, 0, nullptr);
descriptor_set_out = write_descriptor_set.dstSet;
return mapping;
}
uint32_t VulkanCommandProcessor::WriteTransientTextureBindings(
bool is_vertex, uint32_t texture_count, uint32_t sampler_count,
VkDescriptorSetLayout descriptor_set_layout,

View File

@@ -38,6 +38,7 @@
#include "xenia/gpu/xenos.h"
#include "xenia/kernel/kernel_state.h"
#include "xenia/ui/vulkan/linked_type_descriptor_set_allocator.h"
#include "xenia/ui/vulkan/vulkan_gpu_completion_timeline.h"
#include "xenia/ui/vulkan/vulkan_presenter.h"
#include "xenia/ui/vulkan/vulkan_provider.h"
#include "xenia/ui/vulkan/vulkan_upload_buffer_pool.h"
@@ -54,7 +55,6 @@ class VulkanCommandProcessor final : public CommandProcessor {
public:
// Single-descriptor layouts for use within a single frame.
enum class SingleTransientDescriptorLayout {
kUniformBufferCompute,
kStorageBufferCompute,
kCount,
};
@@ -162,10 +162,11 @@ class VulkanCommandProcessor final : public CommandProcessor {
bool submission_open() const { return submission_open_; }
uint64_t GetCurrentSubmission() const {
return submission_completed_ +
uint64_t(submissions_in_flight_fences_.size()) + 1;
return completion_timeline_.GetUpcomingSubmission();
}
uint64_t GetCompletedSubmission() const {
return completion_timeline_.GetCompletedSubmissionFromLastUpdate();
}
uint64_t GetCompletedSubmission() const { return submission_completed_; }
// Sparse binds are:
// - In a single submission, all submitted in one vkQueueBindSparse.
@@ -221,16 +222,6 @@ class VulkanCommandProcessor final : public CommandProcessor {
// A frame must be open.
VkDescriptorSet AllocateSingleTransientDescriptor(
SingleTransientDescriptorLayout transient_descriptor_layout);
// Allocates a descriptor, space in the uniform buffer pool, and fills the
// VkWriteDescriptorSet structure and VkDescriptorBufferInfo referenced by it.
// Returns null in case of failure.
uint8_t* WriteTransientUniformBufferBinding(
size_t size, SingleTransientDescriptorLayout transient_descriptor_layout,
VkDescriptorBufferInfo& descriptor_buffer_info_out,
VkWriteDescriptorSet& write_descriptor_set_out);
uint8_t* WriteTransientUniformBufferBinding(
size_t size, SingleTransientDescriptorLayout transient_descriptor_layout,
VkDescriptorSet& descriptor_set_out);
// The returned reference is valid until a cache clear.
VkDescriptorSetLayout GetTextureDescriptorSetLayout(bool is_vertex,
@@ -421,7 +412,7 @@ class VulkanCommandProcessor final : public CommandProcessor {
// Rechecks submission number and reclaims per-submission resources. Pass 0 as
// the submission to await to simply check status, or pass
// GetCurrentSubmission() to wait for all queue operations to be completed.
void CheckSubmissionFenceAndDeviceLoss(uint64_t await_submission);
void CheckSubmissionCompletionAndDeviceLoss(uint64_t await_submission);
// If is_guest_command is true, a new full frame - with full cleanup of
// resources and, if needed, starting capturing - is opened if pending (as
// opposed to simply resuming after mid-frame synchronization). Returns
@@ -432,8 +423,9 @@ class VulkanCommandProcessor final : public CommandProcessor {
// successfully, if it has failed, leaves it open.
bool EndSubmission(bool is_swap);
bool AwaitAllQueueOperationsCompletion() {
CheckSubmissionFenceAndDeviceLoss(GetCurrentSubmission());
return !submission_open_ && submissions_in_flight_fences_.empty();
CheckSubmissionCompletionAndDeviceLoss(GetCurrentSubmission());
return !submission_open_ &&
GetCompletedSubmission() + 1u >= GetCurrentSubmission();
}
// Requests a readback buffer for CPU access to GPU data.
@@ -483,16 +475,14 @@ class VulkanCommandProcessor final : public CommandProcessor {
VkPipelineStageFlags guest_shader_pipeline_stages_ = 0;
VkShaderStageFlags guest_shader_vertex_stages_ = 0;
std::vector<VkFence> fences_free_;
std::vector<VkSemaphore> semaphores_free_;
ui::vulkan::VulkanGPUCompletionTimeline completion_timeline_;
bool submission_open_ = false;
uint64_t submission_completed_ = 0;
// In case vkQueueSubmit fails after something like a successful
// vkQueueBindSparse, to wait correctly on the next attempt.
std::vector<VkSemaphore> current_submission_wait_semaphores_;
std::vector<VkPipelineStageFlags> current_submission_wait_stage_masks_;
std::vector<VkFence> submissions_in_flight_fences_;
std::deque<std::pair<uint64_t, VkSemaphore>>
submissions_in_flight_semaphores_;

View File

@@ -9,6 +9,11 @@
#include "xenia/gpu/vulkan/vulkan_texture_cache.h"
#include <algorithm>
#include <array>
#include <cstddef>
#include <utility>
#include "xenia/base/assert.h"
#include "xenia/base/logging.h"
#include "xenia/base/math.h"
@@ -1468,13 +1473,8 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
}
const texture_util::TextureGuestLayout::Level& level_guest_layout =
is_base ? guest_layout.base : guest_layout.mips[level];
uint32_t level_guest_pitch = level_guest_layout.row_pitch_bytes;
if (texture_key.tiled) {
// Shaders expect pitch in blocks for tiled textures.
level_guest_pitch /= bytes_per_block;
assert_zero(level_guest_pitch & (xenos::kTextureTileWidthHeight - 1));
}
load_constants.guest_pitch_aligned = level_guest_pitch;
load_constants.guest_pitch_aligned =
level_guest_layout.row_pitch_bytes / bytes_per_block;
load_constants.guest_z_stride_block_rows_aligned =
level_guest_layout.z_slice_stride_block_rows;
assert_true(dimension != xenos::DataDimension::k3D ||
@@ -1517,25 +1517,24 @@ bool VulkanTextureCache::LoadTextureDataFromResidentMemoryImpl(Texture& texture,
load_constants.host_pitch = load_shader_info.bytes_per_host_block *
level_host_layout.x_pitch_blocks;
command_buffer.CmdVkPushConstants(load_pipeline_layout_,
VK_SHADER_STAGE_COMPUTE_BIT, 0,
sizeof(load_constants), &load_constants);
uint32_t level_array_slice_stride_bytes_scaled =
level_guest_layout.array_slice_stride_bytes *
(texture_resolution_scale_x * texture_resolution_scale_y);
for (uint32_t slice = 0; slice < array_size; ++slice) {
VkDescriptorSet descriptor_set_constants;
void* constants_mapping =
command_processor_.WriteTransientUniformBufferBinding(
sizeof(load_constants),
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
kUniformBufferCompute,
descriptor_set_constants);
if (!constants_mapping) {
return false;
if (slice != 0) {
command_buffer.CmdVkPushConstants(
load_pipeline_layout_, VK_SHADER_STAGE_COMPUTE_BIT,
offsetof(LoadConstants, guest_offset),
sizeof(load_constants.guest_offset), &load_constants.guest_offset);
command_buffer.CmdVkPushConstants(
load_pipeline_layout_, VK_SHADER_STAGE_COMPUTE_BIT,
offsetof(LoadConstants, host_offset),
sizeof(load_constants.host_offset), &load_constants.host_offset);
}
std::memcpy(constants_mapping, &load_constants, sizeof(load_constants));
command_buffer.CmdVkBindDescriptorSets(
VK_PIPELINE_BIND_POINT_COMPUTE, load_pipeline_layout_,
kLoadDescriptorSetIndexConstants, 1, &descriptor_set_constants, 0,
nullptr);
command_processor_.SubmitBarriers(true);
command_buffer.CmdVkDispatch(group_count_x, group_count_y,
load_constants.size_blocks[2]);
@@ -2183,12 +2182,11 @@ bool VulkanTextureCache::Initialize() {
load_descriptor_set_layout_storage_buffer;
load_descriptor_set_layouts[kLoadDescriptorSetIndexSource] =
load_descriptor_set_layout_storage_buffer;
load_descriptor_set_layouts[kLoadDescriptorSetIndexConstants] =
command_processor_.GetSingleTransientDescriptorLayout(
VulkanCommandProcessor::SingleTransientDescriptorLayout ::
kUniformBufferCompute);
assert_true(load_descriptor_set_layouts[kLoadDescriptorSetIndexConstants] !=
VK_NULL_HANDLE);
VkPushConstantRange load_pipeline_layout_push_constant_range;
load_pipeline_layout_push_constant_range.stageFlags =
VK_SHADER_STAGE_COMPUTE_BIT;
load_pipeline_layout_push_constant_range.offset = 0;
load_pipeline_layout_push_constant_range.size = sizeof(LoadConstants);
VkPipelineLayoutCreateInfo load_pipeline_layout_create_info;
load_pipeline_layout_create_info.sType =
VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
@@ -2196,8 +2194,9 @@ bool VulkanTextureCache::Initialize() {
load_pipeline_layout_create_info.flags = 0;
load_pipeline_layout_create_info.setLayoutCount = kLoadDescriptorSetCount;
load_pipeline_layout_create_info.pSetLayouts = load_descriptor_set_layouts;
load_pipeline_layout_create_info.pushConstantRangeCount = 0;
load_pipeline_layout_create_info.pPushConstantRanges = nullptr;
load_pipeline_layout_create_info.pushConstantRangeCount = 1;
load_pipeline_layout_create_info.pPushConstantRanges =
&load_pipeline_layout_push_constant_range;
if (dfn.vkCreatePipelineLayout(device, &load_pipeline_layout_create_info,
nullptr, &load_pipeline_layout_)) {
XELOGE("VulkanTexture: Failed to create the texture load pipeline layout");

View File

@@ -180,7 +180,6 @@ class VulkanTextureCache final : public TextureCache {
enum LoadDescriptorSetIndex {
kLoadDescriptorSetIndexDestination,
kLoadDescriptorSetIndexSource,
kLoadDescriptorSetIndexConstants,
kLoadDescriptorSetCount,
};