blob: fdb0698e5d05b1ace614725a7ccb42518ea3b143 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "target_requirements.h"
#include <stdio.h>
#include <string.h>
#include "common/macros.h"
#include "radix_sort/platforms/vk/radix_sort_vk.h"
#include "spinel/platforms/vk/spinel_vk.h"
#include "target.h"
#include "target_archive/target_archive.h"
//
//
//
struct spinel_vk_target
{
struct target_archive_header ar_header;
};
//
// SPINEL TARGET REQUIREMENTS: VULKAN
//
bool
spinel_vk_target_get_requirements(struct spinel_vk_target const * target,
struct spinel_vk_target_requirements * requirements)
{
//
// Must not be NULL
//
if ((target == NULL) || (requirements == NULL))
{
return false;
}
//
// Unmarshalling assumes dword alignment.
//
assert(alignof(struct spinel_target_header) == 4);
//
// Verify target archive is valid archive
//
#ifndef SPN_VK_TARGET_DISABLE_VERIFY
if (target->ar_header.magic != TARGET_ARCHIVE_MAGIC)
{
#ifndef NDEBUG
fprintf(stderr, "Error: Invalid target -- missing magic.");
#endif
return NULL;
}
#endif
//
// Get the target archive header
//
struct target_archive_header const * const ar_header = &target->ar_header;
struct target_archive_entry const * const ar_entries = ar_header->entries;
uint32_t const * const ar_data = ar_entries[ar_header->count - 1].data;
//
// Get the spinel_vk_target header
//
struct spinel_target_header const * spinel_header;
// We assert `alignof(spinel_target_header) == 4` (see above) so we can
// memcpy() pointers.
memcpy(&spinel_header, &ar_data, sizeof(spinel_header));
//
// Get the embedded radix_vk_target
//
// clang-format off
uint32_t const * rs_target_data = ar_data + (ar_entries[ar_header->count - 1].offset >> 2);
struct radix_sort_vk_target const * rs_target;
// clang-format on
// We assert `alignof(radix_sort_vk_target_header) == 4` in the radix sort
// sources so we can memcpy() pointers.
memcpy(&rs_target, &rs_target_data, sizeof(rs_target_data));
//
// Verify target is compatible with the library.
//
#ifndef SPN_VK_TARGET_DISABLE_VERIFY
if (spinel_header->magic != SPN_HEADER_MAGIC)
{
#ifndef NDEBUG
fprintf(stderr, "Error: Target is not compatible with library.");
#endif
return NULL;
}
#endif
//
//
//
bool is_ok = true;
uint32_t ext_name_count = 0;
//
// EXTENSIONS
//
// Compute number of required extensions
//
for (uint32_t ii = 0; ii < ARRAY_LENGTH_MACRO(spinel_header->extensions.bitmap); ii++)
{
ext_name_count += __builtin_popcount(spinel_header->extensions.bitmap[ii]);
}
if (requirements->ext_names == NULL)
{
requirements->ext_name_count = ext_name_count;
if (ext_name_count > 0)
{
is_ok = false;
}
}
else
{
if (requirements->ext_name_count < ext_name_count)
{
is_ok = false;
}
else
{
//
// FIXME(allanmac): This can be accelerated by exploiting
// the extension bitmap.
//
uint32_t ii = 0;
#define SPN_TARGET_EXTENSION_STRING(ext_) "VK_" STRINGIFY_MACRO(ext_)
#undef SPN_TARGET_EXTENSION
#define SPN_TARGET_EXTENSION(ext_) \
if (spinel_header->extensions.named.ext_) \
{ \
requirements->ext_names[ii++] = SPN_TARGET_EXTENSION_STRING(ext_); \
}
SPN_TARGET_EXTENSIONS()
}
}
//
// Enable physical device features
//
if ((requirements->pdf == NULL) || (requirements->pdf11 == NULL) || (requirements->pdf12 == NULL))
{
is_ok = false;
}
else
{
#undef SPN_TARGET_FEATURE_VK10
#define SPN_TARGET_FEATURE_VK10(feature_) 1 +
#undef SPN_TARGET_FEATURE_VK11
#define SPN_TARGET_FEATURE_VK11(feature_) 1 +
#undef SPN_TARGET_FEATURE_VK12
#define SPN_TARGET_FEATURE_VK12(feature_) 1 +
//
// Don't create the variable if it's not used
//
#if (SPN_TARGET_FEATURES_VK10() 0)
VkPhysicalDeviceFeatures * const pdf = requirements->pdf;
#endif
#if (SPN_TARGET_FEATURES_VK11() 0)
VkPhysicalDeviceVulkan11Features * const pdf11 = requirements->pdf11;
#endif
#if (SPN_TARGET_FEATURES_VK12() 0)
VkPhysicalDeviceVulkan12Features * const pdf12 = requirements->pdf12;
#endif
//
// Let's always have this on during debug
//
#ifndef NDEBUG
pdf->robustBufferAccess = true;
#endif
//
// VULKAN 1.0
//
#undef SPN_TARGET_FEATURE_VK10
#define SPN_TARGET_FEATURE_VK10(feature_) \
if (spinel_header->features.named.feature_) \
{ \
pdf->feature_ = true; \
}
SPN_TARGET_FEATURES_VK10()
//
// VULKAN 1.1
//
#undef SPN_TARGET_FEATURE_VK11
#define SPN_TARGET_FEATURE_VK11(feature_) \
if (spinel_header->features.named.feature_) \
{ \
pdf11->feature_ = true; \
}
SPN_TARGET_FEATURES_VK11()
//
// VULKAN 1.2
//
#undef SPN_TARGET_FEATURE_VK12
#define SPN_TARGET_FEATURE_VK12(feature_) \
if (spinel_header->features.named.feature_) \
{ \
pdf12->feature_ = true; \
}
SPN_TARGET_FEATURES_VK12()
}
//
// Concatenate radix sort requirements
//
if (requirements->ext_names == NULL)
{
struct radix_sort_vk_target_requirements rs_tr = {
// .ext_name_count = 0,
// .ext_names = NULL
.pdf = requirements->pdf,
.pdf11 = requirements->pdf11,
.pdf12 = requirements->pdf12,
};
bool const rs_is_ok = radix_sort_vk_target_get_requirements(rs_target, &rs_tr);
is_ok = is_ok && rs_is_ok;
requirements->ext_name_count += rs_tr.ext_name_count;
}
else
{
uint32_t const rs_ext_name_count = (requirements->ext_name_count > ext_name_count)
? (requirements->ext_name_count - ext_name_count)
: 0;
struct radix_sort_vk_target_requirements rs_tr = {
.ext_name_count = rs_ext_name_count,
.ext_names = requirements->ext_names + ext_name_count,
.pdf = requirements->pdf,
.pdf11 = requirements->pdf11,
.pdf12 = requirements->pdf12,
};
bool const rs_is_ok = radix_sort_vk_target_get_requirements(rs_target, &rs_tr);
is_ok = is_ok && rs_is_ok;
}
//
//
//
return is_ok;
}
//
//
//