summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDrChat <arkolbed@gmail.com>2017-08-10 15:01:12 -0500
committerDrChat <arkolbed@gmail.com>2017-08-10 15:01:12 -0500
commit4809f3eb51bc275e359d9476d19b4b7ba6b6e4a5 (patch)
tree00e80dc8f98820dd066c04ed4c6344f545795a0e
parent09c29bbdc5167347268f6a78163f30a09032ef1a (diff)
Vulkan: Create a util WritebackTexture function (unused atm)
-rw-r--r--src/xenia/gpu/vulkan/texture_cache.cc111
-rw-r--r--src/xenia/gpu/vulkan/texture_cache.h6
2 files changed, 101 insertions, 16 deletions
diff --git a/src/xenia/gpu/vulkan/texture_cache.cc b/src/xenia/gpu/vulkan/texture_cache.cc
index 018f78693..d3b1182e1 100644
--- a/src/xenia/gpu/vulkan/texture_cache.cc
+++ b/src/xenia/gpu/vulkan/texture_cache.cc
@@ -116,7 +116,9 @@ TextureCache::TextureCache(Memory* memory, RegisterFile* register_file,
trace_writer_(trace_writer),
device_(device),
staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
- kStagingBufferSize) {
+ kStagingBufferSize),
+ wb_staging_buffer_(device, VK_BUFFER_USAGE_TRANSFER_DST_BIT,
+ kStagingBufferSize) {
VkResult err = VK_SUCCESS;
// Descriptor pool used for all of our cached descriptors.
@@ -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, &region);
+
+ // 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) {
diff --git a/src/xenia/gpu/vulkan/texture_cache.h b/src/xenia/gpu/vulkan/texture_cache.h
index 241faed88..75ce5cb74 100644
--- a/src/xenia/gpu/vulkan/texture_cache.h
+++ b/src/xenia/gpu/vulkan/texture_cache.h
@@ -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_;