Vulkan SDK for Android 1.1.1 Mali Developer Center
display.cpp
1 /* Copyright (c) 2016-2017, ARM Limited and Contributors
2  *
3  * SPDX-License-Identifier: MIT
4  *
5  * Permission is hereby granted, free of charge,
6  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
9  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
14  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
16  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
17  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
19  */
20 
21 #include "display.hpp"
22 #include <algorithm>
23 
24 using namespace std;
25 
26 namespace MaliSDK
27 {
28 Platform &Platform::get()
29 {
30  // Not initialized until first call to Platform::get().
31  // Initialization is thread-safe.
32  static DisplayPlatform singleton;
33  return singleton;
34 }
35 
36 VkSurfaceKHR DisplayPlatform::createSurface()
37 {
38  VkSurfaceKHR surface;
39 
40  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceDisplayPropertiesKHR);
41  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetPhysicalDeviceDisplayPlanePropertiesKHR);
42  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetDisplayModePropertiesKHR);
43  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetDisplayPlaneSupportedDisplaysKHR);
44  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkGetDisplayPlaneCapabilitiesKHR);
45  VULKAN_SYMBOL_WRAPPER_LOAD_INSTANCE_EXTENSION_SYMBOL(instance, vkCreateDisplayPlaneSurfaceKHR);
46 
47  // First, find all displays connected to this platform.
48  uint32_t displayPropertyCount;
49  VK_CHECK(vkGetPhysicalDeviceDisplayPropertiesKHR(gpu, &displayPropertyCount, nullptr));
50 
51  if (displayPropertyCount < 1)
52  {
53  LOGE("No displays available.\n");
54  return VK_NULL_HANDLE;
55  }
56 
57  vector<VkDisplayPropertiesKHR> displayProperties(displayPropertyCount);
58  VK_CHECK(vkGetPhysicalDeviceDisplayPropertiesKHR(gpu, &displayPropertyCount, displayProperties.data()));
59 
60  // Find all supported planes.
61  uint32_t planeCount;
62  VK_CHECK(vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &planeCount, nullptr));
63 
64  if (planeCount < 1)
65  {
66  LOGE("No display planes available.\n");
67  return VK_NULL_HANDLE;
68  }
69 
70  vector<VkDisplayPlanePropertiesKHR> planeProperties(planeCount);
71  VK_CHECK(vkGetPhysicalDeviceDisplayPlanePropertiesKHR(gpu, &planeCount, planeProperties.data()));
72 
73  struct Candidate
74  {
75  VkDisplayKHR display;
76  VkDisplayModeKHR mode;
77  uint32_t plane;
78  uint32_t planeStack;
79  uint32_t width;
80  uint32_t height;
81  };
82  vector<Candidate> candidates;
83 
84  // Try to find a good combination of display mode, plane and display for use
85  // with our application.
86  for (uint32_t plane = 0; plane < planeCount; plane++)
87  {
88  uint32_t supportedCount;
89  VK_CHECK(vkGetDisplayPlaneSupportedDisplaysKHR(gpu, plane, &supportedCount, nullptr));
90 
91  if (supportedCount < 1)
92  continue;
93 
94  // For a given plane, find all displays which are supported.
95  vector<VkDisplayKHR> supportedDisplays(supportedCount);
96  VK_CHECK(vkGetDisplayPlaneSupportedDisplaysKHR(gpu, plane, &supportedCount, supportedDisplays.data()));
97 
98  for (auto display : supportedDisplays)
99  {
100  // Find the display properties belonging to this display.
101  auto itr = find_if(begin(displayProperties), end(displayProperties),
102  [display](const VkDisplayPropertiesKHR &props) { return props.display == display; });
103 
104  // This really shouldn't happen, since a plane cannot support a display
105  // which doesn't exist.
106  if (itr == end(displayProperties))
107  continue;
108 
109  // Display should support identity transform.
110  if ((itr->supportedTransforms & VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR) == 0)
111  continue;
112 
113  // If the plane is associated with another display already, skip.
114  if (planeProperties[plane].currentDisplay != display &&
115  planeProperties[plane].currentDisplay != VK_NULL_HANDLE)
116  continue;
117 
118  // For the display, find all display modes.
119  uint32_t modeCount;
120  VK_CHECK(vkGetDisplayModePropertiesKHR(gpu, display, &modeCount, nullptr));
121 
122  if (modeCount < 1)
123  continue;
124 
125  vector<VkDisplayModePropertiesKHR> modes(modeCount);
126  VK_CHECK(vkGetDisplayModePropertiesKHR(gpu, display, &modeCount, modes.data()));
127 
128  for (auto mode : modes)
129  {
130  // Check that the mode we're trying to use supports what we need.
131  VkDisplayPlaneCapabilitiesKHR caps;
132  VK_CHECK(vkGetDisplayPlaneCapabilitiesKHR(gpu, mode.displayMode, plane, &caps));
133 
134  // We don't want alpha since we're not going to composite.
135  if ((caps.supportedAlpha & VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR) == 0)
136  continue;
137 
138  // Check that our preferred swapchain fits into the plane.
139  if (caps.minSrcExtent.width > preferredWidth)
140  continue;
141  if (caps.minSrcExtent.height > preferredHeight)
142  continue;
143  if (caps.maxSrcExtent.width < preferredWidth)
144  continue;
145  if (caps.maxSrcExtent.height < preferredHeight)
146  continue;
147 
148  if (mode.parameters.visibleRegion.width >= preferredWidth &&
149  mode.parameters.visibleRegion.height >= preferredHeight)
150  {
151  // We found a candidate.
152  candidates.push_back(
153  { display, mode.displayMode, plane, planeProperties[plane].currentStackIndex,
154  mode.parameters.visibleRegion.width, mode.parameters.visibleRegion.height });
155  }
156  }
157  }
158  }
159 
160  if (candidates.empty())
161  {
162  LOGE("Could not find a suitable display mode.\n");
163  return VK_NULL_HANDLE;
164  }
165 
166  // We could go though the list of candidates here to find the optimal match,
167  // but we can pick the first one here.
168  VkDisplaySurfaceCreateInfoKHR info = { VK_STRUCTURE_TYPE_DISPLAY_SURFACE_CREATE_INFO_KHR };
169  info.displayMode = candidates.front().mode;
170  info.planeIndex = candidates.front().plane;
171  info.planeStackIndex = candidates.front().planeStack;
172  info.transform = VK_SURFACE_TRANSFORM_IDENTITY_BIT_KHR;
173  info.alphaMode = VK_DISPLAY_PLANE_ALPHA_OPAQUE_BIT_KHR;
174  info.imageExtent.width = candidates.front().width;
175  info.imageExtent.height = candidates.front().height;
176 
177  LOGI("Using display mode: %u x %u.\n", info.imageExtent.width, info.imageExtent.height);
178 
179  VK_CHECK(vkCreateDisplayPlaneSurfaceKHR(instance, &info, nullptr, &surface));
180  return surface;
181 }
182 
183 Platform::Status DisplayPlatform::getWindowStatus()
184 {
185  return status;
186 }
187 
188 Platform::SwapchainDimensions DisplayPlatform::getPreferredSwapchain()
189 {
190  SwapchainDimensions chain = { 1280, 720, VK_FORMAT_B8G8R8A8_UNORM };
191  return chain;
192 }
193 
194 Result DisplayPlatform::createWindow(const SwapchainDimensions &swapchain)
195 {
196  preferredWidth = swapchain.width;
197  preferredHeight = swapchain.height;
198  return initVulkan(swapchain, { "VK_KHR_surface", "VK_KHR_display" }, { "VK_KHR_swapchain" });
199 }
200 }
unsigned height
Height of the swapchain.
Definition: platform.hpp:59
Describes the size and format of the swapchain.
Definition: platform.hpp:54
unsigned width
Width of the swapchain.
Definition: platform.hpp:57
Status
Describes the status of the application lifecycle.
Definition: platform.hpp:65