Vulkan: Create a util WritebackTexture function (unused atm)
This commit is contained in:
parent
09c29bbdc5
commit
4809f3eb51
|
@ -116,6 +116,8 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file,
|
|||
trace_writer_(trace_writer),
|
||||
device_(device),
|
||||
staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
kStagingBufferSize),
|
||||
wb_staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
kStagingBufferSize) {
|
||||
VkResult err = VK_SUCCESS;
|
||||
|
||||
|
@ -127,6 +129,9 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file,
|
|||
*device_, 32768,
|
||||
std::vector<VkDescriptorPoolSize>(pool_sizes, std::end(pool_sizes)));
|
||||
|
||||
wb_command_pool_ = std::make_unique<ui::vulkan::CommandBufferPool>(
|
||||
*device_, VK_QUEUE_FAMILY_IGNORED);
|
||||
|
||||
// Check some device limits
|
||||
// On low sampler counts: Rarely would we experience over 16 unique samplers.
|
||||
// This code could be refactored to scale up/down to the # of samplers.
|
||||
|
@ -169,6 +174,10 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file,
|
|||
assert_always();
|
||||
}
|
||||
|
||||
if (!wb_staging_buffer_.Initialize()) {
|
||||
assert_always();
|
||||
}
|
||||
|
||||
invalidated_textures_sets_[0].reserve(64);
|
||||
invalidated_textures_sets_[1].reserve(64);
|
||||
invalidated_textures_ = &invalidated_textures_sets_[0];
|
||||
|
@ -424,21 +433,8 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
|||
trace_writer_->WriteMemoryRead(texture_info.guest_address,
|
||||
texture_info.input_length);
|
||||
|
||||
if (!UploadTexture(command_buffer, completion_fence, texture, texture_info)) {
|
||||
FreeTexture(texture);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Setup a debug name for the texture.
|
||||
device_->DbgSetObjectName(
|
||||
reinterpret_cast<uint64_t>(texture->image),
|
||||
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
|
||||
xe::format_string(
|
||||
"0x%.8X - 0x%.8X", texture_info.guest_address,
|
||||
texture_info.guest_address + texture_info.input_length));
|
||||
|
||||
// Okay. Now that the texture is uploaded from system memory, put a writewatch
|
||||
// on it to tell us if it's been modified from the guest.
|
||||
// Okay. Put a writewatch on it to tell us if it's been modified from the
|
||||
// guest.
|
||||
texture->access_watch_handle = memory_->AddPhysicalAccessWatch(
|
||||
texture_info.guest_address, texture_info.input_length,
|
||||
cpu::MMIOHandler::kWatchWrite,
|
||||
|
@ -457,6 +453,19 @@ TextureCache::Texture* TextureCache::Demand(const TextureInfo& texture_info,
|
|||
},
|
||||
this, texture);
|
||||
|
||||
if (!UploadTexture(command_buffer, completion_fence, texture, texture_info)) {
|
||||
FreeTexture(texture);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Setup a debug name for the texture.
|
||||
device_->DbgSetObjectName(
|
||||
reinterpret_cast<uint64_t>(texture->image),
|
||||
VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
|
||||
xe::format_string(
|
||||
"0x%.8X - 0x%.8X", texture_info.guest_address,
|
||||
texture_info.guest_address + texture_info.input_length));
|
||||
|
||||
textures_[texture_hash] = texture;
|
||||
return texture;
|
||||
}
|
||||
|
@ -1115,6 +1124,76 @@ bool TextureCache::ComputeTextureStorage(size_t* output_length,
|
|||
}
|
||||
}
|
||||
|
||||
void TextureCache::WritebackTexture(Texture* texture) {
|
||||
VkResult status = VK_SUCCESS;
|
||||
VkFence fence = wb_command_pool_->BeginBatch();
|
||||
auto alloc = wb_staging_buffer_.Acquire(texture->memory_size, fence);
|
||||
if (!alloc) {
|
||||
wb_command_pool_->EndBatch();
|
||||
return;
|
||||
}
|
||||
|
||||
auto command_buffer = wb_command_pool_->AcquireEntry();
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = {
|
||||
VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO, nullptr,
|
||||
VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT, nullptr,
|
||||
};
|
||||
vkBeginCommandBuffer(command_buffer, &begin_info);
|
||||
|
||||
// TODO: Transition the texture to a transfer source.
|
||||
|
||||
VkBufferImageCopy region = {
|
||||
alloc->offset,
|
||||
0,
|
||||
0,
|
||||
{VK_IMAGE_ASPECT_COLOR_BIT, 0, 0, 1},
|
||||
{0, 0, 0},
|
||||
{texture->texture_info.width + 1, texture->texture_info.height + 1, 1},
|
||||
};
|
||||
|
||||
vkCmdCopyImageToBuffer(command_buffer, texture->image,
|
||||
VK_IMAGE_LAYOUT_GENERAL,
|
||||
wb_staging_buffer_.gpu_buffer(), 1, ®ion);
|
||||
|
||||
// TODO: Transition the texture back to a shader resource.
|
||||
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
// Submit the command buffer.
|
||||
// Submit commands and wait.
|
||||
{
|
||||
std::lock_guard<std::mutex>(device_->primary_queue_mutex());
|
||||
VkSubmitInfo submit_info = {
|
||||
VK_STRUCTURE_TYPE_SUBMIT_INFO,
|
||||
nullptr,
|
||||
0,
|
||||
nullptr,
|
||||
nullptr,
|
||||
1,
|
||||
&command_buffer,
|
||||
0,
|
||||
nullptr,
|
||||
};
|
||||
status = vkQueueSubmit(device_->primary_queue(), 1, &submit_info, fence);
|
||||
CheckResult(status, "vkQueueSubmit");
|
||||
|
||||
if (status == VK_SUCCESS) {
|
||||
status = vkQueueWaitIdle(device_->primary_queue());
|
||||
CheckResult(status, "vkQueueWaitIdle");
|
||||
}
|
||||
}
|
||||
|
||||
wb_command_pool_->EndBatch();
|
||||
|
||||
auto dest = memory_->TranslatePhysical(texture->texture_info.guest_address);
|
||||
if (status == VK_SUCCESS) {
|
||||
std::memcpy(dest, alloc->host_ptr, texture->texture_info.input_length);
|
||||
}
|
||||
|
||||
wb_staging_buffer_.Scavenge();
|
||||
}
|
||||
|
||||
bool TextureCache::UploadTexture(VkCommandBuffer command_buffer,
|
||||
VkFence completion_fence, Texture* dest,
|
||||
const TextureInfo& src) {
|
||||
|
|
|
@ -148,6 +148,10 @@ class TextureCache {
|
|||
const TextureInfo& src);
|
||||
bool ComputeTextureStorage(size_t* output_length, const TextureInfo& src);
|
||||
|
||||
// Writes a texture back into guest memory. This call is (mostly) asynchronous
|
||||
// but the texture must not be flagged for destruction.
|
||||
void WritebackTexture(Texture* texture);
|
||||
|
||||
// Queues commands to upload a texture from system memory, applying any
|
||||
// conversions necessary. This may flush the command buffer to the GPU if we
|
||||
// run out of staging memory.
|
||||
|
@ -175,11 +179,13 @@ class TextureCache {
|
|||
ui::vulkan::VulkanDevice* device_ = nullptr;
|
||||
VkQueue device_queue_ = nullptr;
|
||||
|
||||
std::unique_ptr<xe::ui::vulkan::CommandBufferPool> wb_command_pool_ = nullptr;
|
||||
std::unique_ptr<xe::ui::vulkan::DescriptorPool> descriptor_pool_ = nullptr;
|
||||
std::unordered_map<uint64_t, VkDescriptorSet> texture_bindings_;
|
||||
VkDescriptorSetLayout texture_descriptor_set_layout_ = nullptr;
|
||||
|
||||
ui::vulkan::CircularBuffer staging_buffer_;
|
||||
ui::vulkan::CircularBuffer wb_staging_buffer_;
|
||||
std::unordered_map<uint64_t, Texture*> textures_;
|
||||
std::unordered_map<uint64_t, Sampler*> samplers_;
|
||||
std::list<Texture*> pending_delete_textures_;
|
||||
|
|
Loading…
Reference in New Issue