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