vulkan_command_buffer.cc 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341
  1. // Copyright (c) 2016 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "gpu/vulkan/vulkan_command_buffer.h"
  5. #include "base/logging.h"
  6. #include "gpu/vulkan/vulkan_command_pool.h"
  7. #include "gpu/vulkan/vulkan_device_queue.h"
  8. #include "gpu/vulkan/vulkan_function_pointers.h"
  9. #include "gpu/vulkan/vulkan_util.h"
  10. namespace gpu {
  11. namespace {
  12. VkPipelineStageFlags GetPipelineStageFlags(
  13. const VulkanDeviceQueue* device_queue,
  14. const VkImageLayout layout) {
  15. switch (layout) {
  16. case VK_IMAGE_LAYOUT_UNDEFINED:
  17. return VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
  18. case VK_IMAGE_LAYOUT_GENERAL:
  19. return VK_PIPELINE_STAGE_ALL_COMMANDS_BIT;
  20. case VK_IMAGE_LAYOUT_PREINITIALIZED:
  21. return VK_PIPELINE_STAGE_HOST_BIT;
  22. case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
  23. case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
  24. return VK_PIPELINE_STAGE_TRANSFER_BIT;
  25. case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
  26. return VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
  27. case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL: {
  28. VkPipelineStageFlags flags = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT |
  29. VK_PIPELINE_STAGE_VERTEX_SHADER_BIT;
  30. if (device_queue->enabled_device_features().tessellationShader) {
  31. flags |= VK_PIPELINE_STAGE_TESSELLATION_CONTROL_SHADER_BIT |
  32. VK_PIPELINE_STAGE_TESSELLATION_EVALUATION_SHADER_BIT;
  33. }
  34. if (device_queue->enabled_device_features().geometryShader) {
  35. flags |= VK_PIPELINE_STAGE_GEOMETRY_SHADER_BIT;
  36. }
  37. return flags;
  38. }
  39. case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
  40. return VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
  41. default:
  42. NOTREACHED() << "layout=" << layout;
  43. }
  44. return 0;
  45. }
  46. VkAccessFlags GetAccessMask(const VkImageLayout layout) {
  47. switch (layout) {
  48. case VK_IMAGE_LAYOUT_UNDEFINED:
  49. return 0;
  50. case VK_IMAGE_LAYOUT_GENERAL:
  51. LOG(WARNING) << "VK_IMAGE_LAYOUT_GENERAL is used.";
  52. return VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
  53. VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT |
  54. VK_ACCESS_TRANSFER_WRITE_BIT | VK_ACCESS_TRANSFER_READ_BIT |
  55. VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_HOST_WRITE_BIT |
  56. VK_ACCESS_HOST_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT |
  57. VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
  58. VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
  59. VK_ACCESS_MEMORY_READ_BIT | VK_ACCESS_MEMORY_WRITE_BIT;
  60. case VK_IMAGE_LAYOUT_PREINITIALIZED:
  61. return VK_ACCESS_HOST_WRITE_BIT;
  62. case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
  63. return VK_ACCESS_COLOR_ATTACHMENT_READ_BIT |
  64. VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
  65. case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
  66. return VK_ACCESS_SHADER_READ_BIT | VK_ACCESS_INPUT_ATTACHMENT_READ_BIT;
  67. case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
  68. return VK_ACCESS_TRANSFER_READ_BIT;
  69. case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
  70. return VK_ACCESS_TRANSFER_WRITE_BIT;
  71. case VK_IMAGE_LAYOUT_PRESENT_SRC_KHR:
  72. return 0;
  73. default:
  74. NOTREACHED() << "layout=" << layout;
  75. }
  76. return 0;
  77. }
  78. } // namespace
  79. VulkanCommandBuffer::VulkanCommandBuffer(VulkanDeviceQueue* device_queue,
  80. VulkanCommandPool* command_pool,
  81. bool primary)
  82. : primary_(primary),
  83. device_queue_(device_queue),
  84. command_pool_(command_pool) {
  85. command_pool_->IncrementCommandBufferCount();
  86. }
  87. VulkanCommandBuffer::~VulkanCommandBuffer() {
  88. DCHECK(!submission_fence_.is_valid());
  89. DCHECK_EQ(static_cast<VkCommandBuffer>(VK_NULL_HANDLE), command_buffer_);
  90. DCHECK(!recording_);
  91. command_pool_->DecrementCommandBufferCount();
  92. }
  93. bool VulkanCommandBuffer::Initialize() {
  94. VkResult result = VK_SUCCESS;
  95. VkDevice device = device_queue_->GetVulkanDevice();
  96. VkCommandBufferAllocateInfo command_buffer_info = {
  97. .sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO,
  98. .pNext = nullptr,
  99. .commandPool = command_pool_->handle(),
  100. .level = primary_ ? VK_COMMAND_BUFFER_LEVEL_PRIMARY
  101. : VK_COMMAND_BUFFER_LEVEL_SECONDARY,
  102. .commandBufferCount = 1,
  103. };
  104. DCHECK_EQ(static_cast<VkCommandBuffer>(VK_NULL_HANDLE), command_buffer_);
  105. result =
  106. vkAllocateCommandBuffers(device, &command_buffer_info, &command_buffer_);
  107. if (VK_SUCCESS != result) {
  108. LOG(ERROR) << "vkAllocateCommandBuffers() failed: " << result;
  109. return false;
  110. }
  111. record_type_ = RECORD_TYPE_EMPTY;
  112. return true;
  113. }
  114. void VulkanCommandBuffer::Destroy() {
  115. VkDevice device = device_queue_->GetVulkanDevice();
  116. if (submission_fence_.is_valid()) {
  117. DCHECK(device_queue_->GetFenceHelper()->HasPassed(submission_fence_));
  118. submission_fence_ = VulkanFenceHelper::FenceHandle();
  119. }
  120. if (VK_NULL_HANDLE != command_buffer_) {
  121. vkFreeCommandBuffers(device, command_pool_->handle(), 1, &command_buffer_);
  122. command_buffer_ = VK_NULL_HANDLE;
  123. }
  124. }
  125. bool VulkanCommandBuffer::Submit(uint32_t num_wait_semaphores,
  126. VkSemaphore* wait_semaphores,
  127. uint32_t num_signal_semaphores,
  128. VkSemaphore* signal_semaphores) {
  129. DCHECK(primary_);
  130. std::vector<VkPipelineStageFlags> wait_dst_stage_mask(
  131. num_wait_semaphores, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT);
  132. VkSubmitInfo submit_info = {};
  133. submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
  134. submit_info.pNext = nullptr;
  135. submit_info.waitSemaphoreCount = num_wait_semaphores;
  136. submit_info.pWaitSemaphores = wait_semaphores;
  137. submit_info.pWaitDstStageMask = wait_dst_stage_mask.data();
  138. submit_info.commandBufferCount = 1;
  139. submit_info.pCommandBuffers = &command_buffer_;
  140. submit_info.signalSemaphoreCount = num_signal_semaphores;
  141. submit_info.pSignalSemaphores = signal_semaphores;
  142. VkResult result = VK_SUCCESS;
  143. VkFence fence;
  144. result = device_queue_->GetFenceHelper()->GetFence(&fence);
  145. if (VK_SUCCESS != result) {
  146. LOG(ERROR) << "Failed to create fence: " << result;
  147. return false;
  148. }
  149. result =
  150. vkQueueSubmit(device_queue_->GetVulkanQueue(), 1, &submit_info, fence);
  151. if (VK_SUCCESS != result) {
  152. vkDestroyFence(device_queue_->GetVulkanDevice(), fence, nullptr);
  153. submission_fence_ = VulkanFenceHelper::FenceHandle();
  154. } else {
  155. submission_fence_ = device_queue_->GetFenceHelper()->EnqueueFence(fence);
  156. }
  157. PostExecution();
  158. if (VK_SUCCESS != result) {
  159. LOG(ERROR) << "vkQueueSubmit() failed: " << result;
  160. return false;
  161. }
  162. return true;
  163. }
  164. void VulkanCommandBuffer::Enqueue(VkCommandBuffer primary_command_buffer) {
  165. DCHECK(!primary_);
  166. vkCmdExecuteCommands(primary_command_buffer, 1, &command_buffer_);
  167. PostExecution();
  168. }
  169. void VulkanCommandBuffer::Clear() {
  170. // Mark to reset upon next use.
  171. if (record_type_ != RECORD_TYPE_EMPTY)
  172. record_type_ = RECORD_TYPE_DIRTY;
  173. }
  174. void VulkanCommandBuffer::Wait(uint64_t timeout) {
  175. if (!submission_fence_.is_valid())
  176. return;
  177. device_queue_->GetFenceHelper()->Wait(submission_fence_, timeout);
  178. }
  179. bool VulkanCommandBuffer::SubmissionFinished() {
  180. if (!submission_fence_.is_valid())
  181. return true;
  182. return device_queue_->GetFenceHelper()->HasPassed(submission_fence_);
  183. }
  184. void VulkanCommandBuffer::TransitionImageLayout(
  185. VkImage image,
  186. VkImageLayout old_layout,
  187. VkImageLayout new_layout,
  188. uint32_t src_queue_family_index,
  189. uint32_t dst_queue_family_index) {
  190. VkImageMemoryBarrier barrier = {};
  191. barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
  192. barrier.srcAccessMask = GetAccessMask(old_layout);
  193. barrier.dstAccessMask = GetAccessMask(new_layout);
  194. barrier.oldLayout = old_layout;
  195. barrier.newLayout = new_layout;
  196. barrier.srcQueueFamilyIndex = src_queue_family_index;
  197. barrier.dstQueueFamilyIndex = dst_queue_family_index;
  198. barrier.image = image;
  199. barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  200. barrier.subresourceRange.baseMipLevel = 0;
  201. barrier.subresourceRange.levelCount = 1;
  202. barrier.subresourceRange.baseArrayLayer = 0;
  203. barrier.subresourceRange.layerCount = 1;
  204. vkCmdPipelineBarrier(command_buffer_,
  205. GetPipelineStageFlags(device_queue_, old_layout),
  206. GetPipelineStageFlags(device_queue_, new_layout), 0, 0,
  207. nullptr, 0, nullptr, 1, &barrier);
  208. }
  209. void VulkanCommandBuffer::CopyBufferToImage(VkBuffer buffer,
  210. VkImage image,
  211. uint32_t buffer_width,
  212. uint32_t buffer_height,
  213. uint32_t width,
  214. uint32_t height) {
  215. VkBufferImageCopy region = {};
  216. region.bufferOffset = 0;
  217. region.bufferRowLength = buffer_width;
  218. region.bufferImageHeight = buffer_height;
  219. region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  220. region.imageSubresource.mipLevel = 0;
  221. region.imageSubresource.baseArrayLayer = 0;
  222. region.imageSubresource.layerCount = 1;
  223. region.imageOffset = {0, 0, 0};
  224. region.imageExtent = {width, height, 1};
  225. vkCmdCopyBufferToImage(command_buffer_, buffer, image,
  226. VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &region);
  227. }
  228. void VulkanCommandBuffer::CopyImageToBuffer(VkBuffer buffer,
  229. VkImage image,
  230. uint32_t buffer_width,
  231. uint32_t buffer_height,
  232. uint32_t width,
  233. uint32_t height) {
  234. VkBufferImageCopy region = {};
  235. region.bufferOffset = 0;
  236. region.bufferRowLength = buffer_width;
  237. region.bufferImageHeight = buffer_height;
  238. region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
  239. region.imageSubresource.mipLevel = 0;
  240. region.imageSubresource.baseArrayLayer = 0;
  241. region.imageSubresource.layerCount = 1;
  242. region.imageOffset = {0, 0, 0};
  243. region.imageExtent = {width, height, 1};
  244. vkCmdCopyImageToBuffer(command_buffer_, image,
  245. VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, buffer, 1,
  246. &region);
  247. }
  248. void VulkanCommandBuffer::PostExecution() {
  249. if (record_type_ == RECORD_TYPE_SINGLE_USE) {
  250. // Clear upon next use.
  251. record_type_ = RECORD_TYPE_DIRTY;
  252. } else if (record_type_ == RECORD_TYPE_MULTI_USE) {
  253. // Can no longer record new items unless marked as clear.
  254. record_type_ = RECORD_TYPE_RECORDED;
  255. }
  256. }
  257. void VulkanCommandBuffer::ResetIfDirty() {
  258. DCHECK(!recording_);
  259. if (record_type_ == RECORD_TYPE_DIRTY) {
  260. // Block if command buffer is still in use. This can be externally avoided
  261. // using the asynchronous SubmissionFinished() function.
  262. Wait(UINT64_MAX);
  263. VkResult result = vkResetCommandBuffer(command_buffer_, 0);
  264. if (VK_SUCCESS != result) {
  265. LOG(ERROR) << "vkResetCommandBuffer() failed: " << result;
  266. } else {
  267. record_type_ = RECORD_TYPE_EMPTY;
  268. }
  269. }
  270. }
  271. CommandBufferRecorderBase::~CommandBufferRecorderBase() {
  272. VkResult result = vkEndCommandBuffer(handle_);
  273. if (VK_SUCCESS != result) {
  274. LOG(ERROR) << "vkEndCommandBuffer() failed: " << result;
  275. }
  276. }
  277. ScopedMultiUseCommandBufferRecorder::ScopedMultiUseCommandBufferRecorder(
  278. VulkanCommandBuffer& command_buffer)
  279. : CommandBufferRecorderBase(command_buffer) {
  280. ValidateMultiUse(command_buffer);
  281. VkCommandBufferBeginInfo begin_info = {};
  282. begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  283. VkResult result = vkBeginCommandBuffer(handle_, &begin_info);
  284. if (VK_SUCCESS != result) {
  285. LOG(ERROR) << "vkBeginCommandBuffer() failed: " << result;
  286. }
  287. }
  288. ScopedSingleUseCommandBufferRecorder::ScopedSingleUseCommandBufferRecorder(
  289. VulkanCommandBuffer& command_buffer)
  290. : CommandBufferRecorderBase(command_buffer) {
  291. ValidateSingleUse(command_buffer);
  292. VkCommandBufferBeginInfo begin_info = {};
  293. begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
  294. begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
  295. VkResult result = vkBeginCommandBuffer(handle_, &begin_info);
  296. if (VK_SUCCESS != result) {
  297. LOG(ERROR) << "vkBeginCommandBuffer() failed: " << result;
  298. }
  299. }
  300. } // namespace gpu