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_surface.h"
6 
7 #include <vulkan/vulkan.h>
8 
9 #include <algorithm>
10 
11 #include "base/macros.h"
12 #include "base/stl_util.h"
13 #include "gpu/vulkan/vulkan_device_queue.h"
14 #include "gpu/vulkan/vulkan_function_pointers.h"
15 #include "gpu/vulkan/vulkan_swap_chain.h"
16 
17 namespace gpu {
18 
19 namespace {
20 const VkFormat kPreferredVkFormats32[] = {
21     VK_FORMAT_B8G8R8A8_UNORM,  // FORMAT_BGRA8888,
22     VK_FORMAT_R8G8B8A8_UNORM,  // FORMAT_RGBA8888,
23 };
24 
25 const VkFormat kPreferredVkFormats16[] = {
26     VK_FORMAT_R5G6B5_UNORM_PACK16,  // FORMAT_RGB565,
27 };
28 
ToVkSurfaceTransformFlag(gfx::OverlayTransform transform)29 VkSurfaceTransformFlagBitsKHR ToVkSurfaceTransformFlag(
30     gfx::OverlayTransform transform) {
31   switch (transform) {
32     case gfx::OVERLAY_TRANSFORM_NONE:
33       return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
34     case gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL:
35       return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR;
36     case gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL:
37       return VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR;
38     case gfx::OVERLAY_TRANSFORM_ROTATE_90:
39       return VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR;
40     case gfx::OVERLAY_TRANSFORM_ROTATE_180:
41       return VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR;
42     case gfx::OVERLAY_TRANSFORM_ROTATE_270:
43       return VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR;
44     default:
45       NOTREACHED() << "transform:" << transform;
46       return VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
47   };
48 }
49 
FromVkSurfaceTransformFlag(VkSurfaceTransformFlagBitsKHR transform)50 gfx::OverlayTransform FromVkSurfaceTransformFlag(
51     VkSurfaceTransformFlagBitsKHR transform) {
52   switch (transform) {
53     case VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR:
54       return gfx::OVERLAY_TRANSFORM_NONE;
55     case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_BIT_KHR:
56       return gfx::OVERLAY_TRANSFORM_FLIP_HORIZONTAL;
57     case VK_SURFACE_TRANSFORM_HORIZONTAL_MIRROR_ROTATE_180_BIT_KHR:
58       return gfx::OVERLAY_TRANSFORM_FLIP_VERTICAL;
59     case VK_SURFACE_TRANSFORM_ROTATE_90_BIT_KHR:
60       return gfx::OVERLAY_TRANSFORM_ROTATE_90;
61     case VK_SURFACE_TRANSFORM_ROTATE_180_BIT_KHR:
62       return gfx::OVERLAY_TRANSFORM_ROTATE_180;
63     case VK_SURFACE_TRANSFORM_ROTATE_270_BIT_KHR:
64       return gfx::OVERLAY_TRANSFORM_ROTATE_270;
65     default:
66       NOTREACHED() << "transform:" << transform;
67       return gfx::OVERLAY_TRANSFORM_INVALID;
68   }
69 }
70 
71 }  // namespace
72 
~VulkanSurface()73 VulkanSurface::~VulkanSurface() {
74   DCHECK_EQ(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_);
75 }
76 
VulkanSurface(VkInstance vk_instance,VkSurfaceKHR surface,bool enforce_protected_memory)77 VulkanSurface::VulkanSurface(VkInstance vk_instance,
78                              VkSurfaceKHR surface,
79                              bool enforce_protected_memory)
80     : vk_instance_(vk_instance),
81       surface_(surface),
82       enforce_protected_memory_(enforce_protected_memory) {
83   DCHECK_NE(static_cast<VkSurfaceKHR>(VK_NULL_HANDLE), surface_);
84 }
85 
Initialize(VulkanDeviceQueue * device_queue,VulkanSurface::Format format)86 bool VulkanSurface::Initialize(VulkanDeviceQueue* device_queue,
87                                VulkanSurface::Format format) {
88   DCHECK(format >= 0 && format < NUM_SURFACE_FORMATS);
89   DCHECK(device_queue);
90 
91   device_queue_ = device_queue;
92 
93 
94   VkBool32 present_support;
95   VkResult result = vkGetPhysicalDeviceSurfaceSupportKHR(
96       device_queue_->GetVulkanPhysicalDevice(),
97       device_queue_->GetVulkanQueueIndex(), surface_, &present_support);
98   if (result != VK_SUCCESS) {
99     DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceSupportKHR() failed: " << result;
100     return false;
101   }
102   if (!present_support) {
103     DLOG(ERROR) << "Surface not supported by present queue.";
104     return false;
105   }
106 
107   // Get list of supported formats.
108   uint32_t format_count = 0;
109   result = vkGetPhysicalDeviceSurfaceFormatsKHR(
110       device_queue_->GetVulkanPhysicalDevice(), surface_, &format_count,
111       nullptr);
112   if (VK_SUCCESS != result) {
113     DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceFormatsKHR() failed: " << result;
114     return false;
115   }
116 
117   std::vector<VkSurfaceFormatKHR> formats(format_count);
118   result = vkGetPhysicalDeviceSurfaceFormatsKHR(
119       device_queue_->GetVulkanPhysicalDevice(), surface_, &format_count,
120       formats.data());
121   if (VK_SUCCESS != result) {
122     DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceFormatsKHR() failed: " << result;
123     return false;
124   }
125 
126   const VkFormat* preferred_formats = (format == FORMAT_RGBA_32)
127                                           ? kPreferredVkFormats32
128                                           : kPreferredVkFormats16;
129   unsigned int size = (format == FORMAT_RGBA_32)
130                           ? base::size(kPreferredVkFormats32)
131                           : base::size(kPreferredVkFormats16);
132 
133   if (formats.size() == 1 && VK_FORMAT_UNDEFINED == formats[0].format) {
134     surface_format_.format = preferred_formats[0];
135     surface_format_.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
136   } else {
137     bool format_set = false;
138     for (VkSurfaceFormatKHR supported_format : formats) {
139       unsigned int counter = 0;
140       while (counter < size && format_set == false) {
141         if (supported_format.format == preferred_formats[counter]) {
142           surface_format_ = supported_format;
143           surface_format_.colorSpace = VK_COLOR_SPACE_SRGB_NONLINEAR_KHR;
144           format_set = true;
145         }
146         counter++;
147       }
148       if (format_set)
149         break;
150     }
151     if (!format_set) {
152       DLOG(ERROR) << "Format not supported.";
153       return false;
154     }
155   }
156 
157   VkSurfaceCapabilitiesKHR surface_caps;
158   result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
159       device_queue_->GetVulkanPhysicalDevice(), surface_, &surface_caps);
160   if (VK_SUCCESS != result) {
161     DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed: "
162                 << result;
163     return false;
164   }
165 
166   image_count_ = std::max(surface_caps.minImageCount, 3u);
167 
168   return true;
169 }
170 
Destroy()171 void VulkanSurface::Destroy() {
172   if (swap_chain_) {
173     swap_chain_->Destroy();
174     swap_chain_ = nullptr;
175   }
176   vkDestroySurfaceKHR(vk_instance_, surface_, nullptr);
177   surface_ = VK_NULL_HANDLE;
178 }
179 
SwapBuffers()180 gfx::SwapResult VulkanSurface::SwapBuffers() {
181   return PostSubBuffer(gfx::Rect(image_size_));
182 }
183 
PostSubBuffer(const gfx::Rect & rect)184 gfx::SwapResult VulkanSurface::PostSubBuffer(const gfx::Rect& rect) {
185   return swap_chain_->PresentBuffer(rect);
186 }
187 
Finish()188 void VulkanSurface::Finish() {
189   vkQueueWaitIdle(device_queue_->GetVulkanQueue());
190 }
191 
Reshape(const gfx::Size & size,gfx::OverlayTransform transform)192 bool VulkanSurface::Reshape(const gfx::Size& size,
193                             gfx::OverlayTransform transform) {
194   return CreateSwapChain(size, transform);
195 }
196 
CreateSwapChain(const gfx::Size & size,gfx::OverlayTransform transform)197 bool VulkanSurface::CreateSwapChain(const gfx::Size& size,
198                                     gfx::OverlayTransform transform) {
199   // Get Surface Information.
200   VkSurfaceCapabilitiesKHR surface_caps;
201   VkResult result = vkGetPhysicalDeviceSurfaceCapabilitiesKHR(
202       device_queue_->GetVulkanPhysicalDevice(), surface_, &surface_caps);
203   if (VK_SUCCESS != result) {
204     DLOG(ERROR) << "vkGetPhysicalDeviceSurfaceCapabilitiesKHR() failed: "
205                 << result;
206     return false;
207   }
208 
209   auto vk_transform = transform != gfx::OVERLAY_TRANSFORM_INVALID
210                           ? ToVkSurfaceTransformFlag(transform)
211                           : surface_caps.currentTransform;
212   DCHECK(vk_transform == (vk_transform & surface_caps.supportedTransforms));
213   if (transform == gfx::OVERLAY_TRANSFORM_INVALID)
214     transform = FromVkSurfaceTransformFlag(surface_caps.currentTransform);
215 
216   // For Android, the current vulkan surface size may not match the new size
217   // (the current window size), in that case, we will create a swap chain with
218   // the requested new size, and vulkan surface size should match the swapchain
219   // images size soon.
220   gfx::Size image_size = size;
221   if (image_size.IsEmpty()) {
222     // If width and height of the surface are 0xFFFFFFFF, it means the surface
223     // size will be determined by the extent of a swapchain targeting the
224     // surface. In that case, we will use the minImageExtent for the swapchain.
225     const uint32_t kUndefinedExtent = 0xFFFFFFFF;
226     if (surface_caps.currentExtent.width == kUndefinedExtent &&
227         surface_caps.currentExtent.height == kUndefinedExtent) {
228       image_size.SetSize(surface_caps.minImageExtent.width,
229                          surface_caps.minImageExtent.height);
230     } else {
231       image_size.SetSize(surface_caps.currentExtent.width,
232                          surface_caps.currentExtent.height);
233     }
234     if (transform == gfx::OVERLAY_TRANSFORM_ROTATE_90 ||
235         transform == gfx::OVERLAY_TRANSFORM_ROTATE_270) {
236       image_size.SetSize(image_size.height(), image_size.width());
237     }
238   }
239 
240   DCHECK_GE(static_cast<uint32_t>(image_size.width()),
241             surface_caps.minImageExtent.width);
242   DCHECK_GE(static_cast<uint32_t>(image_size.height()),
243             surface_caps.minImageExtent.height);
244   DCHECK_LE(static_cast<uint32_t>(image_size.width()),
245             surface_caps.maxImageExtent.width);
246   DCHECK_LE(static_cast<uint32_t>(image_size.height()),
247             surface_caps.maxImageExtent.height);
248   DCHECK_GT(static_cast<uint32_t>(image_size.width()), 0u);
249   DCHECK_GT(static_cast<uint32_t>(image_size.height()), 0u);
250 
251   if (image_size_ == image_size && transform_ == transform)
252     return true;
253 
254   image_size_ = image_size;
255   transform_ = transform;
256 
257   auto swap_chain = std::make_unique<VulkanSwapChain>();
258 
259   // Create swap chain.
260   DCHECK_EQ(image_count_, std::max(surface_caps.minImageCount, 3u));
261   if (!swap_chain->Initialize(
262           device_queue_, surface_, surface_format_, image_size_, image_count_,
263           vk_transform, enforce_protected_memory_, std::move(swap_chain_))) {
264     return false;
265   }
266 
267   swap_chain_ = std::move(swap_chain);
268   ++swap_chain_generation_;
269   return true;
270 }
271 
272 }  // namespace gpu
273