1///////////////////////////////////////////////////////////////////////////////
2//
3// Copyright (c) 2015-2016 The Khronos Group Inc.
4// Copyright (c) 2015-2016 Valve Corporation
5// Copyright (c) 2015-2016 LunarG, Inc.
6// Copyright (c) 2015-2016 Google, Inc.
7//
8// Licensed under the Apache License, Version 2.0 (the "License");
9// you may not use this file except in compliance with the License.
10// You may obtain a copy of the License at
11//
12//     http://www.apache.org/licenses/LICENSE-2.0
13//
14// Unless required by applicable law or agreed to in writing, software
15// distributed under the License is distributed on an "AS IS" BASIS,
16// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17// See the License for the specific language governing permissions and
18// limitations under the License.
19///////////////////////////////////////////////////////////////////////////////
20
21#ifndef VK_PROTOTYPES
22#define VK_PROTOTYPES
23#endif
24
25#include "vkjson.h"
26
27#include <algorithm>
28#include <utility>
29
30namespace {
31const char* kSupportedInstanceExtensions[] = {
32    "VK_KHR_get_physical_device_properties2"};
33
34bool EnumerateExtensions(const char* layer_name,
35                         std::vector<VkExtensionProperties>* extensions) {
36  VkResult result;
37  uint32_t count = 0;
38  result = vkEnumerateInstanceExtensionProperties(layer_name, &count, nullptr);
39  if (result != VK_SUCCESS)
40    return false;
41  extensions->resize(count);
42  result = vkEnumerateInstanceExtensionProperties(layer_name, &count,
43                                                  extensions->data());
44  if (result != VK_SUCCESS)
45    return false;
46  return true;
47}
48
49bool HasExtension(const char* extension_name,
50                  uint32_t count,
51                  const char* const* extensions) {
52  return std::find_if(extensions, extensions + count,
53                      [extension_name](const char* extension) {
54                        return strcmp(extension, extension_name) == 0;
55                      }) != extensions + count;
56}
57
58bool HasExtension(const char* extension_name,
59                  const std::vector<VkExtensionProperties>& extensions) {
60  return std::find_if(extensions.cbegin(), extensions.cend(),
61                      [extension_name](const VkExtensionProperties& extension) {
62                        return strcmp(extension.extensionName,
63                                      extension_name) == 0;
64                      }) != extensions.cend();
65}
66}  // anonymous namespace
67
68VkJsonDevice VkJsonGetDevice(VkInstance instance,
69                             VkPhysicalDevice physical_device,
70                             uint32_t instance_extension_count,
71                             const char* const* instance_extensions) {
72  VkJsonDevice device;
73
74  PFN_vkGetPhysicalDeviceFeatures2KHR vkpGetPhysicalDeviceFeatures2KHR =
75      nullptr;
76  if (instance != VK_NULL_HANDLE &&
77      HasExtension("VK_KHR_get_physical_device_properties2",
78                   instance_extension_count, instance_extensions)) {
79    vkpGetPhysicalDeviceFeatures2KHR =
80        reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
81            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2KHR"));
82  }
83
84  uint32_t extension_count = 0;
85  vkEnumerateDeviceExtensionProperties(physical_device, nullptr,
86                                       &extension_count, nullptr);
87  if (extension_count > 0) {
88    device.extensions.resize(extension_count);
89    vkEnumerateDeviceExtensionProperties(
90        physical_device, nullptr, &extension_count, device.extensions.data());
91  }
92
93  uint32_t layer_count = 0;
94  vkEnumerateDeviceLayerProperties(physical_device, &layer_count, nullptr);
95  if (layer_count > 0) {
96    device.layers.resize(layer_count);
97    vkEnumerateDeviceLayerProperties(physical_device, &layer_count,
98                                     device.layers.data());
99  }
100
101  vkGetPhysicalDeviceProperties(physical_device, &device.properties);
102  if (HasExtension("VK_KHR_get_physical_device_properties2",
103                   instance_extension_count, instance_extensions)) {
104    VkPhysicalDeviceFeatures2KHR features = {
105        VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR,
106        nullptr,
107        {}  // features
108    };
109    if (HasExtension("VK_KHR_variable_pointers", device.extensions)) {
110      device.ext_variable_pointer_features.variable_pointer_features_khr.sType =
111          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
112      device.ext_variable_pointer_features.variable_pointer_features_khr.pNext =
113          features.pNext;
114      features.pNext =
115          &device.ext_variable_pointer_features.variable_pointer_features_khr;
116    }
117    vkpGetPhysicalDeviceFeatures2KHR(physical_device, &features);
118    device.features = features.features;
119  } else {
120    vkGetPhysicalDeviceFeatures(physical_device, &device.features);
121  }
122  vkGetPhysicalDeviceMemoryProperties(physical_device, &device.memory);
123
124  uint32_t queue_family_count = 0;
125  vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queue_family_count,
126                                           nullptr);
127  if (queue_family_count > 0) {
128    device.queues.resize(queue_family_count);
129    vkGetPhysicalDeviceQueueFamilyProperties(
130        physical_device, &queue_family_count, device.queues.data());
131  }
132
133  VkFormatProperties format_properties = {};
134  for (VkFormat format = VK_FORMAT_R4G4_UNORM_PACK8;
135       format <= VK_FORMAT_END_RANGE;
136       format = static_cast<VkFormat>(format + 1)) {
137    vkGetPhysicalDeviceFormatProperties(physical_device, format,
138                                        &format_properties);
139    if (format_properties.linearTilingFeatures ||
140        format_properties.optimalTilingFeatures ||
141        format_properties.bufferFeatures) {
142      device.formats.insert(std::make_pair(format, format_properties));
143    }
144  }
145
146  if (device.properties.apiVersion >= VK_API_VERSION_1_1) {
147    for (VkFormat format = VK_FORMAT_G8B8G8R8_422_UNORM;
148         format <= VK_FORMAT_G16_B16_R16_3PLANE_444_UNORM;
149         format = static_cast<VkFormat>(format + 1)) {
150      vkGetPhysicalDeviceFormatProperties(physical_device, format,
151                                          &format_properties);
152      if (format_properties.linearTilingFeatures ||
153          format_properties.optimalTilingFeatures ||
154          format_properties.bufferFeatures) {
155        device.formats.insert(std::make_pair(format, format_properties));
156      }
157    }
158
159    PFN_vkGetPhysicalDeviceProperties2 vkpGetPhysicalDeviceProperties2 =
160        reinterpret_cast<PFN_vkGetPhysicalDeviceProperties2>(
161            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceProperties2"));
162    if (vkpGetPhysicalDeviceProperties2) {
163      VkPhysicalDeviceProperties2 properties2 = {
164          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2, nullptr, {}};
165
166      device.subgroup_properties.sType =
167          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SUBGROUP_PROPERTIES;
168      device.subgroup_properties.pNext = properties2.pNext;
169      properties2.pNext = &device.subgroup_properties;
170
171      device.point_clipping_properties.sType =
172          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_POINT_CLIPPING_PROPERTIES;
173      device.point_clipping_properties.pNext = properties2.pNext;
174      properties2.pNext = &device.point_clipping_properties;
175
176      device.multiview_properties.sType =
177          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_PROPERTIES;
178      device.multiview_properties.pNext = properties2.pNext;
179      properties2.pNext = &device.multiview_properties;
180
181      device.id_properties.sType =
182          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_ID_PROPERTIES;
183      device.id_properties.pNext = properties2.pNext;
184      properties2.pNext = &device.id_properties;
185
186      device.maintenance3_properties.sType =
187          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MAINTENANCE_3_PROPERTIES;
188      device.maintenance3_properties.pNext = properties2.pNext;
189      properties2.pNext = &device.maintenance3_properties;
190
191      (*vkpGetPhysicalDeviceProperties2)(physical_device, &properties2);
192    }
193
194    PFN_vkGetPhysicalDeviceFeatures2 vkpGetPhysicalDeviceFeatures2 =
195        reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2>(
196            vkGetInstanceProcAddr(instance, "vkGetPhysicalDeviceFeatures2"));
197    if (vkpGetPhysicalDeviceFeatures2) {
198      VkPhysicalDeviceFeatures2 features2 = {
199          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, nullptr, {}};
200
201      device.bit16_storage_features.sType =
202          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_16BIT_STORAGE_FEATURES;
203      device.bit16_storage_features.pNext = features2.pNext;
204      features2.pNext = &device.bit16_storage_features;
205
206      device.multiview_features.sType =
207          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MULTIVIEW_FEATURES;
208      device.multiview_features.pNext = features2.pNext;
209      features2.pNext = &device.multiview_features;
210
211      device.variable_pointer_features.sType =
212          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES;
213      device.variable_pointer_features.pNext = features2.pNext;
214      features2.pNext = &device.variable_pointer_features;
215
216      device.protected_memory_features.sType =
217          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROTECTED_MEMORY_FEATURES;
218      device.protected_memory_features.pNext = features2.pNext;
219      features2.pNext = &device.protected_memory_features;
220
221      device.sampler_ycbcr_conversion_features.sType =
222          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES;
223      device.sampler_ycbcr_conversion_features.pNext = features2.pNext;
224      features2.pNext = &device.sampler_ycbcr_conversion_features;
225
226      device.shader_draw_parameter_features.sType =
227          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SHADER_DRAW_PARAMETER_FEATURES;
228      device.shader_draw_parameter_features.pNext = features2.pNext;
229      features2.pNext = &device.shader_draw_parameter_features;
230
231      (*vkpGetPhysicalDeviceFeatures2)(physical_device, &features2);
232    }
233
234    PFN_vkGetPhysicalDeviceExternalFenceProperties
235        vkpGetPhysicalDeviceExternalFenceProperties =
236            reinterpret_cast<PFN_vkGetPhysicalDeviceExternalFenceProperties>(
237                vkGetInstanceProcAddr(
238                    instance, "vkGetPhysicalDeviceExternalFenceProperties"));
239    if (vkpGetPhysicalDeviceExternalFenceProperties) {
240      VkPhysicalDeviceExternalFenceInfo external_fence_info = {
241          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_FENCE_INFO, nullptr,
242          VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT};
243      VkExternalFenceProperties external_fence_properties = {};
244
245      for (VkExternalFenceHandleTypeFlagBits handle_type =
246               VK_EXTERNAL_FENCE_HANDLE_TYPE_OPAQUE_FD_BIT;
247           handle_type <= VK_EXTERNAL_FENCE_HANDLE_TYPE_SYNC_FD_BIT;
248           handle_type = static_cast<VkExternalFenceHandleTypeFlagBits>(
249               handle_type << 1)) {
250        external_fence_info.handleType = handle_type;
251        (*vkpGetPhysicalDeviceExternalFenceProperties)(
252            physical_device, &external_fence_info, &external_fence_properties);
253        if (external_fence_properties.exportFromImportedHandleTypes ||
254            external_fence_properties.compatibleHandleTypes ||
255            external_fence_properties.externalFenceFeatures) {
256          device.external_fence_properties.insert(
257              std::make_pair(handle_type, external_fence_properties));
258        }
259      }
260    }
261
262    PFN_vkGetPhysicalDeviceExternalSemaphoreProperties
263        vkpGetPhysicalDeviceExternalSemaphoreProperties = reinterpret_cast<
264            PFN_vkGetPhysicalDeviceExternalSemaphoreProperties>(
265            vkGetInstanceProcAddr(
266                instance, "vkGetPhysicalDeviceExternalSemaphoreProperties"));
267    if (vkpGetPhysicalDeviceExternalSemaphoreProperties) {
268      VkPhysicalDeviceExternalSemaphoreInfo external_semaphore_info = {
269          VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_EXTERNAL_SEMAPHORE_INFO, nullptr,
270          VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT};
271      VkExternalSemaphoreProperties external_semaphore_properties = {};
272
273      for (VkExternalSemaphoreHandleTypeFlagBits handle_type =
274               VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_OPAQUE_FD_BIT;
275           handle_type <= VK_EXTERNAL_SEMAPHORE_HANDLE_TYPE_SYNC_FD_BIT;
276           handle_type = static_cast<VkExternalSemaphoreHandleTypeFlagBits>(
277               handle_type << 1)) {
278        external_semaphore_info.handleType = handle_type;
279        (*vkpGetPhysicalDeviceExternalSemaphoreProperties)(
280            physical_device, &external_semaphore_info,
281            &external_semaphore_properties);
282        if (external_semaphore_properties.exportFromImportedHandleTypes ||
283            external_semaphore_properties.compatibleHandleTypes ||
284            external_semaphore_properties.externalSemaphoreFeatures) {
285          device.external_semaphore_properties.insert(
286              std::make_pair(handle_type, external_semaphore_properties));
287        }
288      }
289    }
290  }
291
292  return device;
293}
294
295VkJsonInstance VkJsonGetInstance() {
296  VkJsonInstance instance;
297  VkResult result;
298  uint32_t count;
299
300  count = 0;
301  result = vkEnumerateInstanceLayerProperties(&count, nullptr);
302  if (result != VK_SUCCESS)
303    return VkJsonInstance();
304  if (count > 0) {
305    std::vector<VkLayerProperties> layers(count);
306    result = vkEnumerateInstanceLayerProperties(&count, layers.data());
307    if (result != VK_SUCCESS)
308      return VkJsonInstance();
309    instance.layers.reserve(count);
310    for (auto& layer : layers) {
311      instance.layers.push_back(VkJsonLayer{layer, std::vector<VkExtensionProperties>()});
312      if (!EnumerateExtensions(layer.layerName,
313                               &instance.layers.back().extensions))
314        return VkJsonInstance();
315    }
316  }
317
318  if (!EnumerateExtensions(nullptr, &instance.extensions))
319    return VkJsonInstance();
320
321  std::vector<const char*> instance_extensions;
322  for (const auto extension : kSupportedInstanceExtensions) {
323    if (HasExtension(extension, instance.extensions))
324      instance_extensions.push_back(extension);
325  }
326
327  const VkApplicationInfo app_info = {VK_STRUCTURE_TYPE_APPLICATION_INFO,
328                                      nullptr,
329                                      "vkjson_info",
330                                      1,
331                                      "",
332                                      0,
333                                      VK_API_VERSION_1_0};
334  VkInstanceCreateInfo instance_info = {
335      VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
336      nullptr,
337      0,
338      &app_info,
339      0,
340      nullptr,
341      static_cast<uint32_t>(instance_extensions.size()),
342      instance_extensions.data()};
343  VkInstance vkinstance;
344  result = vkCreateInstance(&instance_info, nullptr, &vkinstance);
345  if (result != VK_SUCCESS)
346    return VkJsonInstance();
347
348  count = 0;
349  result = vkEnumeratePhysicalDevices(vkinstance, &count, nullptr);
350  if (result != VK_SUCCESS) {
351    vkDestroyInstance(vkinstance, nullptr);
352    return VkJsonInstance();
353  }
354
355  std::vector<VkPhysicalDevice> devices(count, VK_NULL_HANDLE);
356  result = vkEnumeratePhysicalDevices(vkinstance, &count, devices.data());
357  if (result != VK_SUCCESS) {
358    vkDestroyInstance(vkinstance, nullptr);
359    return VkJsonInstance();
360  }
361
362  std::map<VkPhysicalDevice, uint32_t> device_map;
363  const uint32_t sz = devices.size();
364  instance.devices.reserve(sz);
365  for (uint32_t i = 0; i < sz; ++i) {
366    device_map.insert(std::make_pair(devices[i], i));
367    instance.devices.emplace_back(VkJsonGetDevice(vkinstance, devices[i],
368                                                  instance_extensions.size(),
369                                                  instance_extensions.data()));
370  }
371
372  PFN_vkEnumerateInstanceVersion vkpEnumerateInstanceVersion =
373      reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
374          vkGetInstanceProcAddr(nullptr, "vkEnumerateInstanceVersion"));
375  if (!vkpEnumerateInstanceVersion) {
376    instance.api_version = VK_API_VERSION_1_0;
377  } else {
378    result = (*vkpEnumerateInstanceVersion)(&instance.api_version);
379    if (result != VK_SUCCESS) {
380      vkDestroyInstance(vkinstance, nullptr);
381      return VkJsonInstance();
382    }
383  }
384
385  PFN_vkEnumeratePhysicalDeviceGroups vkpEnumeratePhysicalDeviceGroups =
386      reinterpret_cast<PFN_vkEnumeratePhysicalDeviceGroups>(
387          vkGetInstanceProcAddr(vkinstance, "vkEnumeratePhysicalDeviceGroups"));
388  if (vkpEnumeratePhysicalDeviceGroups) {
389    count = 0;
390    result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count, nullptr);
391    if (result != VK_SUCCESS) {
392      vkDestroyInstance(vkinstance, nullptr);
393      return VkJsonInstance();
394    }
395
396    VkJsonDeviceGroup device_group;
397    std::vector<VkPhysicalDeviceGroupProperties> group_properties;
398    group_properties.resize(count);
399    result = (*vkpEnumeratePhysicalDeviceGroups)(vkinstance, &count,
400                                                 group_properties.data());
401    if (result != VK_SUCCESS) {
402      vkDestroyInstance(vkinstance, nullptr);
403      return VkJsonInstance();
404    }
405    for (auto properties : group_properties) {
406      device_group.properties = properties;
407      for (uint32_t i = 0; i < properties.physicalDeviceCount; ++i) {
408        device_group.device_inds.push_back(
409            device_map[properties.physicalDevices[i]]);
410      }
411      instance.device_groups.push_back(device_group);
412    }
413  }
414
415  vkDestroyInstance(vkinstance, nullptr);
416  return instance;
417}
418