Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Side by Side Diff: gpu/vulkan/vulkan_swap_chain.cc

Issue 1776453003: Added initial implementation of Vulkan Render Passes. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@gn_vulkan
Patch Set: Fix SwapBuffers() present layout, test in unittests instead of injections Created 4 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« gpu/vulkan/vulkan_surface.h ('K') | « gpu/vulkan/vulkan_swap_chain.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
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
5 #include "gpu/vulkan/vulkan_swap_chain.h"
6
7 #include "gpu/vulkan/vulkan_command_buffer.h"
8 #include "gpu/vulkan/vulkan_command_pool.h"
9 #include "gpu/vulkan/vulkan_implementation.h"
10
11 namespace gpu {
12
13 VulkanSwapChain::VulkanSwapChain() {}
14
15 VulkanSwapChain::~VulkanSwapChain() {
16 DCHECK(images_.empty());
17 DCHECK_EQ(static_cast<VkSwapchainKHR>(VK_NULL_HANDLE), swap_chain_);
18 }
19
20 bool VulkanSwapChain::Initialize(VkSurfaceKHR surface,
21 const VkSurfaceCapabilitiesKHR& surface_caps,
22 const VkSurfaceFormatKHR& surface_format) {
23 return InitializeSwapChain(surface, surface_caps, surface_format) &&
24 InitializeImageLayoutCommandBuffer() &&
25 InitializeSwapImages(surface_caps, surface_format) &&
26 InitializeInitialBuffer();
27 }
28
29 void VulkanSwapChain::Destroy() {
30 DestroySwapImages();
31 DestroyImageLayoutCommandBuffer();
32 DestroySwapChain();
33 }
34
35 gfx::SwapResult VulkanSwapChain::SwapBuffers() {
36 VkResult result = VK_SUCCESS;
37
38 scoped_ptr<ImageData>& current_image_data = images_[current_image_];
39
40 // Default image subresource range.
41 VkImageSubresourceRange image_subresource_range = {};
42 image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
43 image_subresource_range.baseMipLevel = 0;
44 image_subresource_range.levelCount = 1;
45 image_subresource_range.baseArrayLayer = 0;
46 image_subresource_range.layerCount = 1;
47
48 // Submit our command buffer for the current buffer.
49 if (!current_image_data->command_buffer->Submit(
50 GetVulkanQueue(), 1, &current_image_data->render_layout_semaphore, 1,
51 &current_image_data->render_semaphore)) {
piman 2016/03/11 03:07:52 You don't need a semaphore to order command buffer
David Yen 2016/03/21 18:26:31 That would make things easier. I wasn't sure becau
52 return gfx::SwapResult::SWAP_FAILED;
53 }
54
55 // Prepare the image layout to present.
56 {
57 ScopedSingleUseCommandBufferRecorder recorder(
piman 2016/03/11 03:07:53 2 things: 1- you can't reuse the command buffer un
David Yen 2016/03/21 18:26:31 Done. To make how this is suppose to be done clear
58 *image_layout_command_buffer_);
59
60 VkImageMemoryBarrier image_memory_barrier = {};
61 image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
62 image_memory_barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
63 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
64 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
65 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
66 image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
67 image_memory_barrier.subresourceRange = image_subresource_range;
68 image_memory_barrier.image = current_image_data->image;
69
70 vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
71 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
72 nullptr, 1, &image_memory_barrier);
73 }
74 if (!image_layout_command_buffer_->Submit(
75 GetVulkanQueue(), 1, &current_image_data->render_semaphore, 1,
76 &current_image_data->present_layout_semaphore)) {
77 return gfx::SwapResult::SWAP_FAILED;
78 }
79
80 // Queue the present.
81 VkPresentInfoKHR present_info = {};
82 present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
83 present_info.waitSemaphoreCount = 1;
84 present_info.pWaitSemaphores = &current_image_data->present_layout_semaphore;
85 present_info.swapchainCount = 1;
86 present_info.pSwapchains = &swap_chain_;
87 present_info.pImageIndices = &current_image_;
88
89 result = vkQueuePresentKHR(GetVulkanQueue(), &present_info);
90 if (VK_SUCCESS != result) {
91 return gfx::SwapResult::SWAP_FAILED;
92 }
93
94 // Setup for the next available buffer.
95 // TODO(dyen): Look into if this does what I'm expecting. More studying of
96 // the spec is required here. It doesn't seem clear if "success" when timeout
97 // is 0 means it will give you a buffer even before it's done presenting. That
98 // is probably what we want and the present/render_layout semaphore will
99 // do the synchronization for us.
piman 2016/03/11 03:07:53 vkAcquireNextImageKHR needs to be able to block, r
David Yen 2016/03/21 18:26:31 Done.
100 result = vkAcquireNextImageKHR(GetVulkanDevice(), swap_chain_, 0,
101 current_image_data->present_semaphore,
102 VK_NULL_HANDLE, &current_image_);
103 if (VK_SUCCESS != result) {
104 return gfx::SwapResult::SWAP_FAILED;
105 }
106
107 scoped_ptr<ImageData>& next_image_data = images_[current_image_];
108
109 // The present semaphore actually is associated with the new image data, but
110 // the previous one is guaranteed to be unused to swap it to the correct one.
111 std::swap(next_image_data->present_semaphore,
112 current_image_data->present_semaphore);
113
114 // Setup the previous layout back to the render layout after presentation.
115 {
116 ScopedSingleUseCommandBufferRecorder recorder(
piman 2016/03/11 03:07:52 Same points as above.
David Yen 2016/03/21 18:26:31 Done.
117 *image_layout_command_buffer_);
118
119 VkImageMemoryBarrier image_memory_barrier = {};
120 image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
121 image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
122 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
123 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
124 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
125 image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
126 image_memory_barrier.subresourceRange = image_subresource_range;
127 image_memory_barrier.image = next_image_data->image;
128
129 vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
130 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
131 nullptr, 1, &image_memory_barrier);
132 }
133 // TODO(dyen): This signals render_layout_semaphore which is waited upon
134 // above. When this submit is called it is possible the render layout
135 // semaphore is in an unsignalled state, however by the time the present
136 // semaphore is signalled it is guaranteed to be in an unsignalled state.
137 // We need to make sure this is ok, the spec doesn't specify any constraints
138 // here.
piman 2016/03/11 03:07:53 This should be ok (note that I don't think you nee
David Yen 2016/03/21 18:26:31 Acknowledged.
139 if (!image_layout_command_buffer_->Submit(
140 GetVulkanQueue(), 1, &next_image_data->present_semaphore, 1,
141 &next_image_data->render_layout_semaphore)) {
142 return gfx::SwapResult::SWAP_FAILED;
143 }
144
145 return gfx::SwapResult::SWAP_ACK;
146 }
147
148 bool VulkanSwapChain::InitializeSwapChain(
149 VkSurfaceKHR surface,
150 const VkSurfaceCapabilitiesKHR& surface_caps,
151 const VkSurfaceFormatKHR& surface_format) {
152 VkDevice device = GetVulkanDevice();
153 VkResult result = VK_SUCCESS;
154
155 VkSwapchainCreateInfoKHR swap_chain_create_info = {};
156 swap_chain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
157 swap_chain_create_info.surface = surface;
158 swap_chain_create_info.minImageCount =
159 std::min(2u, surface_caps.maxImageCount);
piman 2016/03/11 03:07:53 It does have to be more than surface_caps.minImage
David Yen 2016/03/21 18:26:31 Done.
160 swap_chain_create_info.imageFormat = surface_format.format;
161 swap_chain_create_info.imageColorSpace = surface_format.colorSpace;
162 swap_chain_create_info.imageExtent = surface_caps.currentExtent;
163 swap_chain_create_info.imageArrayLayers = 1;
164 swap_chain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
165 swap_chain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
166 swap_chain_create_info.preTransform = surface_caps.currentTransform;
167 swap_chain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
168 swap_chain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR;
169 swap_chain_create_info.clipped = true;
170 swap_chain_create_info.oldSwapchain = swap_chain_;
171
172 VkSwapchainKHR new_swap_chain = VK_NULL_HANDLE;
173 result = vkCreateSwapchainKHR(device, &swap_chain_create_info, nullptr,
174 &new_swap_chain);
175 if (VK_SUCCESS != result) {
176 DLOG(ERROR) << "vkCreateSwapchainKHR() failed: " << result;
177 return false;
178 }
179
180 // Destroy the old swap chain and buffers.
181 // TODO(dyen): Look into how to do this safely while commands in flight.
182 Destroy();
183
184 swap_chain_ = new_swap_chain;
185 return true;
186 }
187
188 void VulkanSwapChain::DestroySwapChain() {
189 VkDevice device = GetVulkanDevice();
190
191 if (swap_chain_ != VK_NULL_HANDLE) {
192 vkDestroySwapchainKHR(device, swap_chain_, nullptr);
193 swap_chain_ = VK_NULL_HANDLE;
194 }
195 }
196
197 bool VulkanSwapChain::InitializeImageLayoutCommandBuffer() {
198 command_pool_ = CreateCommandPool();
199 if (!command_pool_)
200 return false;
201
202 image_layout_command_buffer_ = command_pool_->CreatePrimaryCommandBuffer();
203 if (!image_layout_command_buffer_)
204 return false;
205
206 return true;
207 }
208
209 void VulkanSwapChain::DestroyImageLayoutCommandBuffer() {
210 if (image_layout_command_buffer_) {
211 image_layout_command_buffer_->Destroy();
212 image_layout_command_buffer_.reset();
213 }
214
215 if (command_pool_) {
216 command_pool_->Destroy();
217 command_pool_.reset();
218 }
219 }
220
221 bool VulkanSwapChain::InitializeSwapImages(
222 const VkSurfaceCapabilitiesKHR& surface_caps,
223 const VkSurfaceFormatKHR& surface_format) {
224 VkDevice device = GetVulkanDevice();
225 VkResult result = VK_SUCCESS;
226
227 uint32_t image_count = 0;
228 result = vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, nullptr);
229 if (VK_SUCCESS != result) {
230 DLOG(ERROR) << "vkGetSwapchainImagesKHR(NULL) failed: " << result;
231 return false;
232 }
233
234 std::vector<VkImage> images(image_count);
235 result =
236 vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, images.data());
237 if (VK_SUCCESS != result) {
238 DLOG(ERROR) << "vkGetSwapchainImagesKHR(images) failed: " << result;
239 return false;
240 }
241
242 // Generic semaphore creation structure.
243 VkSemaphoreCreateInfo semaphore_create_info = {};
244 semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
245
246 // Default image subresource range.
247 VkImageSubresourceRange image_subresource_range = {};
248 image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
249 image_subresource_range.baseMipLevel = 0;
250 image_subresource_range.levelCount = 1;
251 image_subresource_range.baseArrayLayer = 0;
252 image_subresource_range.layerCount = 1;
253
254 // The image memory barrier is used to setup the image layout.
255 VkImageMemoryBarrier image_memory_barrier = {};
256 image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
257 image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
258 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED;
259 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
260 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
261 image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
262 image_memory_barrier.subresourceRange = image_subresource_range;
263
264 // We must create an image view for each image.
265 VkImageViewCreateInfo image_view_create_info = {};
266 image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
267 image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
268 image_view_create_info.format = surface_format.format;
269 image_view_create_info.components = {
270 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY,
271 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY};
272 image_view_create_info.subresourceRange = image_subresource_range;
273
274 {
275 ScopedSingleUseCommandBufferRecorder recorder(
276 *image_layout_command_buffer_);
277 images_.resize(image_count);
278 for (uint32_t i = 0; i < image_count; ++i) {
279 images_[i].reset(new ImageData);
280 scoped_ptr<ImageData>& image_data = images_[i];
281 image_data->image = images[i];
282
283 // Setup semaphores.
284 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
285 &image_data->render_layout_semaphore);
286 if (VK_SUCCESS != result) {
287 DLOG(ERROR) << "vkCreateSemaphore(render_layout) failed: " << result;
288 return false;
289 }
290 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
291 &image_data->render_semaphore);
292 if (VK_SUCCESS != result) {
293 DLOG(ERROR) << "vkCreateSemaphore(render) failed: " << result;
294 return false;
295 }
296
297 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
298 &image_data->present_layout_semaphore);
299 if (VK_SUCCESS != result) {
300 DLOG(ERROR) << "vkCreateSemaphore(present_layout) failed: " << result;
301 return false;
302 }
303
304 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr,
305 &image_data->present_semaphore);
306 if (VK_SUCCESS != result) {
307 DLOG(ERROR) << "vkCreateSemaphore(present) failed: " << result;
308 return false;
309 }
310
311 // Setup the Image Layout.
312 image_memory_barrier.image = images[i];
313 vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT,
314 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0,
315 nullptr, 1, &image_memory_barrier);
316
317 // Create the image view.
318 image_view_create_info.image = images[i];
319 result = vkCreateImageView(device, &image_view_create_info, nullptr,
320 &image_data->image_view);
321 if (VK_SUCCESS != result) {
322 DLOG(ERROR) << "vkCreateImageView() failed: " << result;
323 return false;
324 }
325
326 // Initialize the command buffer for this buffer data.
327 image_data->command_buffer = command_pool_->CreatePrimaryCommandBuffer();
328 }
329 }
330
331 // Submit the image layout commands, and tie them all to the render layout.
332 std::vector<VkSemaphore> initial_render_layout_semaphores(image_count);
333 for (uint32_t i = 0; i < image_count; ++i) {
334 initial_render_layout_semaphores[i] = images_[i]->render_layout_semaphore;
335 }
336 if (!image_layout_command_buffer_->Submit(
337 GetVulkanQueue(), 0, nullptr, image_count,
338 initial_render_layout_semaphores.data())) {
339 return false;
340 }
341
342 return true;
343 }
344
345 void VulkanSwapChain::DestroySwapImages() {
346 VkDevice device = GetVulkanDevice();
347
348 for (const scoped_ptr<ImageData>& image_data : images_) {
349 if (image_data->command_buffer) {
350 image_data->command_buffer->Destroy();
351 image_data->command_buffer.reset();
352 }
353
354 // Destroy Image View.
355 if (VK_NULL_HANDLE != image_data->image_view) {
356 vkDestroyImageView(device, image_data->image_view, nullptr);
357 image_data->image_view = VK_NULL_HANDLE;
358 }
359
360 // Destroy Semaphores.
361 if (VK_NULL_HANDLE != image_data->present_semaphore) {
362 vkDestroySemaphore(device, image_data->present_semaphore, nullptr);
363 image_data->present_semaphore = VK_NULL_HANDLE;
364 }
365
366 if (VK_NULL_HANDLE != image_data->present_layout_semaphore) {
367 vkDestroySemaphore(device, image_data->present_layout_semaphore, nullptr);
368 image_data->present_layout_semaphore = VK_NULL_HANDLE;
369 }
370
371 if (VK_NULL_HANDLE != image_data->render_semaphore) {
372 vkDestroySemaphore(device, image_data->render_semaphore, nullptr);
373 image_data->render_semaphore = VK_NULL_HANDLE;
374 }
375
376 if (VK_NULL_HANDLE != image_data->render_layout_semaphore) {
377 vkDestroySemaphore(device, image_data->render_layout_semaphore, nullptr);
378 image_data->render_layout_semaphore = VK_NULL_HANDLE;
379 }
380
381 image_data->image = VK_NULL_HANDLE;
382 }
383 images_.clear();
384 }
385
386 bool VulkanSwapChain::InitializeInitialBuffer() {
387 // Acquire the initial buffer, all the buffers have their initial render
388 // layout semaphore setup so this is a special case.
389 const VkResult result =
390 vkAcquireNextImageKHR(GetVulkanDevice(), swap_chain_, 0, VK_NULL_HANDLE,
391 VK_NULL_HANDLE, &current_image_);
392 if (VK_SUCCESS != result) {
393 DLOG(ERROR) << "vkAcquireNextImageKHR() failed: " << result;
394 return false;
395 }
396
397 return true;
398 }
399
400 VulkanSwapChain::ImageData::ImageData() {}
401
402 VulkanSwapChain::ImageData::~ImageData() {}
403
404 } // namespace gpu
OLDNEW
« gpu/vulkan/vulkan_surface.h ('K') | « gpu/vulkan/vulkan_swap_chain.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698