OLD | NEW |
---|---|
(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, ¤t_image_data->render_layout_semaphore, 1, | |
51 ¤t_image_data->render_semaphore)) { | |
52 return gfx::SwapResult::SWAP_FAILED; | |
53 } | |
54 | |
55 // Prepare the image layout to present. | |
56 { | |
57 ScopedSingleUseCommandBufferRecorder recorder( | |
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, ¤t_image_data->render_semaphore, 1, | |
76 ¤t_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 = ¤t_image_data->present_layout_semaphore; | |
85 present_info.swapchainCount = 1; | |
86 present_info.pSwapchains = &swap_chain_; | |
87 present_info.pImageIndices = ¤t_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. | |
100 result = vkAcquireNextImageKHR(GetVulkanDevice(), swap_chain_, 0, | |
101 current_image_data->present_semaphore, | |
David Yen
2016/03/10 02:19:38
Hmm... looking at this code again I'm unclear whic
David Yen
2016/03/11 00:59:46
Chatted separately. This semaphore and the followi
| |
102 VK_NULL_HANDLE, ¤t_image_); | |
103 if (VK_SUCCESS != result) { | |
104 return gfx::SwapResult::SWAP_FAILED; | |
105 } | |
106 | |
107 // Setup the previous layout back to the render layout after presentation. | |
108 { | |
109 ScopedSingleUseCommandBufferRecorder recorder( | |
110 *image_layout_command_buffer_); | |
111 | |
112 VkImageMemoryBarrier image_memory_barrier = {}; | |
113 image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | |
114 image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
115 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR; | |
116 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
117 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | |
118 image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | |
119 image_memory_barrier.subresourceRange = image_subresource_range; | |
120 image_memory_barrier.image = current_image_data->image; | |
121 | |
122 vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, | |
123 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, | |
124 nullptr, 1, &image_memory_barrier); | |
125 } | |
126 // TODO(dyen): This signals render_layout_semaphore which is waited upon | |
127 // above. When this submit is called it is possible the render layout | |
128 // semaphore is in an unsignalled state, however by the time the present | |
129 // semaphore is signalled it is guaranteed to be in an unsignalled state. | |
130 // We need to make sure this is ok, the spec doesn't specify any constraints | |
131 // here. | |
132 if (!image_layout_command_buffer_->Submit( | |
133 GetVulkanQueue(), 1, ¤t_image_data->present_semaphore, 1, | |
134 ¤t_image_data->render_layout_semaphore)) { | |
135 return gfx::SwapResult::SWAP_FAILED; | |
136 } | |
137 | |
138 return gfx::SwapResult::SWAP_ACK; | |
139 } | |
140 | |
141 bool VulkanSwapChain::InitializeSwapChain( | |
142 VkSurfaceKHR surface, | |
143 const VkSurfaceCapabilitiesKHR& surface_caps, | |
144 const VkSurfaceFormatKHR& surface_format) { | |
145 VkDevice device = GetVulkanDevice(); | |
146 VkResult result = VK_SUCCESS; | |
147 | |
148 VkSwapchainCreateInfoKHR swap_chain_create_info = {}; | |
149 swap_chain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR; | |
150 swap_chain_create_info.surface = surface; | |
151 swap_chain_create_info.minImageCount = | |
152 std::min(2u, surface_caps.maxImageCount); | |
153 swap_chain_create_info.imageFormat = surface_format.format; | |
154 swap_chain_create_info.imageColorSpace = surface_format.colorSpace; | |
155 swap_chain_create_info.imageExtent = surface_caps.currentExtent; | |
156 swap_chain_create_info.imageArrayLayers = 1; | |
157 swap_chain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; | |
158 swap_chain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE; | |
159 swap_chain_create_info.preTransform = surface_caps.currentTransform; | |
160 swap_chain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; | |
161 swap_chain_create_info.presentMode = VK_PRESENT_MODE_FIFO_KHR; | |
162 swap_chain_create_info.clipped = true; | |
163 swap_chain_create_info.oldSwapchain = swap_chain_; | |
164 | |
165 VkSwapchainKHR new_swap_chain = VK_NULL_HANDLE; | |
166 result = vkCreateSwapchainKHR(device, &swap_chain_create_info, nullptr, | |
167 &new_swap_chain); | |
168 if (VK_SUCCESS != result) { | |
169 DLOG(ERROR) << "vkCreateSwapchainKHR() failed: " << result; | |
170 return false; | |
171 } | |
172 | |
173 // Destroy the old swap chain and buffers. | |
174 // TODO(dyen): Look into how to do this safely while commands in flight. | |
175 Destroy(); | |
176 | |
177 swap_chain_ = new_swap_chain; | |
178 return true; | |
179 } | |
180 | |
181 void VulkanSwapChain::DestroySwapChain() { | |
182 VkDevice device = GetVulkanDevice(); | |
183 | |
184 if (swap_chain_ != VK_NULL_HANDLE) { | |
185 vkDestroySwapchainKHR(device, swap_chain_, nullptr); | |
186 swap_chain_ = VK_NULL_HANDLE; | |
187 } | |
188 } | |
189 | |
190 bool VulkanSwapChain::InitializeImageLayoutCommandBuffer() { | |
191 command_pool_ = CreateCommandPool(); | |
192 if (!command_pool_) | |
193 return false; | |
194 | |
195 image_layout_command_buffer_ = command_pool_->CreatePrimaryCommandBuffer(); | |
196 if (!image_layout_command_buffer_) | |
197 return false; | |
198 | |
199 return true; | |
200 } | |
201 | |
202 void VulkanSwapChain::DestroyImageLayoutCommandBuffer() { | |
203 if (image_layout_command_buffer_) { | |
204 image_layout_command_buffer_->Destroy(); | |
205 image_layout_command_buffer_.reset(); | |
206 } | |
207 | |
208 if (command_pool_) { | |
209 command_pool_->Destroy(); | |
210 command_pool_.reset(); | |
211 } | |
212 } | |
213 | |
214 bool VulkanSwapChain::InitializeSwapImages( | |
215 const VkSurfaceCapabilitiesKHR& surface_caps, | |
216 const VkSurfaceFormatKHR& surface_format) { | |
217 VkDevice device = GetVulkanDevice(); | |
218 VkResult result = VK_SUCCESS; | |
219 | |
220 uint32_t image_count = 0; | |
221 result = vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, nullptr); | |
222 if (VK_SUCCESS != result) { | |
223 DLOG(ERROR) << "vkGetSwapchainImagesKHR(NULL) failed: " << result; | |
224 return false; | |
225 } | |
226 | |
227 std::vector<VkImage> images(image_count); | |
228 result = | |
229 vkGetSwapchainImagesKHR(device, swap_chain_, &image_count, images.data()); | |
230 if (VK_SUCCESS != result) { | |
231 DLOG(ERROR) << "vkGetSwapchainImagesKHR(images) failed: " << result; | |
232 return false; | |
233 } | |
234 | |
235 // Generic semaphore creation structure. | |
236 VkSemaphoreCreateInfo semaphore_create_info = {}; | |
237 semaphore_create_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO; | |
238 | |
239 // Default image subresource range. | |
240 VkImageSubresourceRange image_subresource_range = {}; | |
241 image_subresource_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; | |
242 image_subresource_range.baseMipLevel = 0; | |
243 image_subresource_range.levelCount = 1; | |
244 image_subresource_range.baseArrayLayer = 0; | |
245 image_subresource_range.layerCount = 1; | |
246 | |
247 // The image memory barrier is used to setup the image layout. | |
248 VkImageMemoryBarrier image_memory_barrier = {}; | |
249 image_memory_barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; | |
250 image_memory_barrier.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; | |
251 image_memory_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; | |
252 image_memory_barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; | |
253 image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | |
254 image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; | |
255 image_memory_barrier.subresourceRange = image_subresource_range; | |
256 | |
257 // We must create an image view for each image. | |
258 VkImageViewCreateInfo image_view_create_info = {}; | |
259 image_view_create_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO; | |
260 image_view_create_info.viewType = VK_IMAGE_VIEW_TYPE_2D; | |
261 image_view_create_info.format = surface_format.format; | |
262 image_view_create_info.components = { | |
263 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY, | |
264 VK_COMPONENT_SWIZZLE_IDENTITY, VK_COMPONENT_SWIZZLE_IDENTITY}; | |
265 image_view_create_info.subresourceRange = image_subresource_range; | |
266 | |
267 { | |
268 ScopedSingleUseCommandBufferRecorder recorder( | |
269 *image_layout_command_buffer_); | |
270 images_.resize(image_count); | |
271 for (uint32_t i = 0; i < image_count; ++i) { | |
272 images_[i].reset(new ImageData); | |
273 scoped_ptr<ImageData>& image_data = images_[i]; | |
274 image_data->image = images[i]; | |
275 | |
276 // Setup semaphores. | |
277 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, | |
278 &image_data->render_layout_semaphore); | |
279 if (VK_SUCCESS != result) { | |
280 DLOG(ERROR) << "vkCreateSemaphore(render_layout) failed: " << result; | |
281 return false; | |
282 } | |
283 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, | |
284 &image_data->render_semaphore); | |
285 if (VK_SUCCESS != result) { | |
286 DLOG(ERROR) << "vkCreateSemaphore(render) failed: " << result; | |
287 return false; | |
288 } | |
289 | |
290 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, | |
291 &image_data->present_layout_semaphore); | |
292 if (VK_SUCCESS != result) { | |
293 DLOG(ERROR) << "vkCreateSemaphore(present_layout) failed: " << result; | |
294 return false; | |
295 } | |
296 | |
297 result = vkCreateSemaphore(device, &semaphore_create_info, nullptr, | |
298 &image_data->present_semaphore); | |
299 if (VK_SUCCESS != result) { | |
300 DLOG(ERROR) << "vkCreateSemaphore(present) failed: " << result; | |
301 return false; | |
302 } | |
303 | |
304 // Setup the Image Layout. | |
305 image_memory_barrier.image = images[i]; | |
306 vkCmdPipelineBarrier(recorder.handle(), VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, | |
307 VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT, 0, 0, nullptr, 0, | |
308 nullptr, 1, &image_memory_barrier); | |
309 | |
310 // Create the image view. | |
311 image_view_create_info.image = images[i]; | |
312 result = vkCreateImageView(device, &image_view_create_info, nullptr, | |
313 &image_data->image_view); | |
314 if (VK_SUCCESS != result) { | |
315 DLOG(ERROR) << "vkCreateImageView() failed: " << result; | |
316 return false; | |
317 } | |
318 | |
319 // Initialize the command buffer for this buffer data. | |
320 image_data->command_buffer = command_pool_->CreatePrimaryCommandBuffer(); | |
321 } | |
322 } | |
323 | |
324 // Submit the image layout commands, and tie them all to the render layout. | |
325 std::vector<VkSemaphore> initial_render_layout_semaphores(image_count); | |
326 for (uint32_t i = 0; i < image_count; ++i) { | |
327 initial_render_layout_semaphores[i] = images_[i]->render_layout_semaphore; | |
328 } | |
329 if (!image_layout_command_buffer_->Submit( | |
330 GetVulkanQueue(), 0, nullptr, image_count, | |
331 initial_render_layout_semaphores.data())) { | |
332 return false; | |
333 } | |
334 | |
335 return true; | |
336 } | |
337 | |
338 void VulkanSwapChain::DestroySwapImages() { | |
339 VkDevice device = GetVulkanDevice(); | |
340 | |
341 for (const scoped_ptr<ImageData>& image_data : images_) { | |
342 if (image_data->command_buffer) { | |
343 image_data->command_buffer->Destroy(); | |
344 image_data->command_buffer.reset(); | |
345 } | |
346 | |
347 // Destroy Image View. | |
348 if (VK_NULL_HANDLE != image_data->image_view) { | |
349 vkDestroyImageView(device, image_data->image_view, nullptr); | |
350 image_data->image_view = VK_NULL_HANDLE; | |
351 } | |
352 | |
353 // Destroy Semaphores. | |
354 if (VK_NULL_HANDLE != image_data->present_semaphore) { | |
355 vkDestroySemaphore(device, image_data->present_semaphore, nullptr); | |
356 image_data->present_semaphore = VK_NULL_HANDLE; | |
357 } | |
358 | |
359 if (VK_NULL_HANDLE != image_data->present_layout_semaphore) { | |
360 vkDestroySemaphore(device, image_data->present_layout_semaphore, nullptr); | |
361 image_data->present_layout_semaphore = VK_NULL_HANDLE; | |
362 } | |
363 | |
364 if (VK_NULL_HANDLE != image_data->render_semaphore) { | |
365 vkDestroySemaphore(device, image_data->render_semaphore, nullptr); | |
366 image_data->render_semaphore = VK_NULL_HANDLE; | |
367 } | |
368 | |
369 if (VK_NULL_HANDLE != image_data->render_layout_semaphore) { | |
370 vkDestroySemaphore(device, image_data->render_layout_semaphore, nullptr); | |
371 image_data->render_layout_semaphore = VK_NULL_HANDLE; | |
372 } | |
373 | |
374 image_data->image = VK_NULL_HANDLE; | |
375 } | |
376 images_.clear(); | |
377 } | |
378 | |
379 bool VulkanSwapChain::InitializeInitialBuffer() { | |
380 // Acquire the initial buffer, all the buffers have their initial render | |
381 // layout semaphore setup so this is a special case. | |
382 const VkResult result = | |
383 vkAcquireNextImageKHR(GetVulkanDevice(), swap_chain_, 0, VK_NULL_HANDLE, | |
384 VK_NULL_HANDLE, ¤t_image_); | |
385 if (VK_SUCCESS != result) { | |
386 DLOG(ERROR) << "vkAcquireNextImageKHR() failed: " << result; | |
387 return false; | |
388 } | |
389 | |
390 return true; | |
391 } | |
392 | |
393 VulkanSwapChain::ImageData::ImageData() {} | |
394 | |
395 VulkanSwapChain::ImageData::~ImageData() {} | |
396 | |
397 } // namespace gpu | |
OLD | NEW |