blob: 63e0b8ccad99263ea5134086e15abce36cc78b8e [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 "vk_utils.h"
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
// clang-format off
#define VK_LIST_RESULT_VALUES(macro) \
macro(SUCCESS) \
macro(NOT_READY) \
macro(EVENT_SET) \
macro(INCOMPLETE) \
macro(ERROR_OUT_OF_HOST_MEMORY) \
macro(ERROR_OUT_OF_DEVICE_MEMORY) \
macro(ERROR_INITIALIZATION_FAILED) \
macro(ERROR_DEVICE_LOST) \
macro(ERROR_MEMORY_MAP_FAILED) \
macro(ERROR_LAYER_NOT_PRESENT) \
macro(ERROR_EXTENSION_NOT_PRESENT) \
macro(ERROR_FEATURE_NOT_PRESENT) \
macro(ERROR_INCOMPATIBLE_DRIVER) \
macro(ERROR_TOO_MANY_OBJECTS) \
macro(ERROR_FORMAT_NOT_SUPPORTED) \
macro(ERROR_FRAGMENTED_POOL) \
macro(ERROR_OUT_OF_POOL_MEMORY) \
macro(ERROR_INVALID_EXTERNAL_HANDLE) \
macro(ERROR_SURFACE_LOST_KHR) \
macro(ERROR_NATIVE_WINDOW_IN_USE_KHR) \
macro(SUBOPTIMAL_KHR) \
macro(ERROR_OUT_OF_DATE_KHR) \
macro(ERROR_INCOMPATIBLE_DISPLAY_KHR) \
macro(ERROR_VALIDATION_FAILED_EXT) \
macro(ERROR_INVALID_SHADER_NV) \
macro(ERROR_FRAGMENTATION_EXT) \
macro(ERROR_NOT_PERMITTED_EXT)
// clang-format on
// Note: for simplicity, this returns the address of a mutable static buffer
// if the value is unknown. Not thread-safe, but should not matter in practice.
// Allows to detect unexpected or exotic result values, and the list above
// can be updated if the spec adds new ones.
const char *
vk_result_to_string(VkResult result)
{
switch (result)
{
#define HANDLE_VALUE(result) \
case VK_##result: \
return "VK_" #result;
VK_LIST_RESULT_VALUES(HANDLE_VALUE)
#undef HANDLE_VALUE
default: {
static char temp[16] = {};
snprintf(temp, sizeof(temp), "VkResult(%u)", (uint32_t)result);
return temp;
}
}
}
void
vk_panic_(VkResult result, const char * file, int line, const char * fmt, ...)
{
fprintf(stderr, "%s:%d:PANIC(%s):", file, line, vk_result_to_string(result));
if (fmt)
{
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
fprintf(stderr, "\n");
abort();
}
void
vk_instance_create_info_print(const VkInstanceCreateInfo * info)
{
fprintf(stderr, "Instance create info:\n");
fprintf(stderr, " flags: %u\n", info->flags);
const VkApplicationInfo * appInfo = info->pApplicationInfo;
fprintf(stderr, " app info:\n");
fprintf(stderr, " app name: %s\n", appInfo->pApplicationName);
fprintf(stderr, " app version: %u\n", appInfo->applicationVersion);
fprintf(stderr, " engine name: %s\n", appInfo->pEngineName);
fprintf(stderr, " engine version: %u\n", appInfo->engineVersion);
fprintf(stderr, " api version: %u\n", appInfo->apiVersion);
fprintf(stderr, " layers (%u): ", info->enabledLayerCount);
for (uint32_t nn = 0; nn < info->enabledLayerCount; ++nn)
fprintf(stderr, " %s", info->ppEnabledLayerNames[nn]);
fprintf(stderr, "\n extensions (%u): ", info->enabledExtensionCount);
for (uint32_t nn = 0; nn < info->enabledExtensionCount; ++nn)
fprintf(stderr, " %s", info->ppEnabledExtensionNames[nn]);
fprintf(stderr, "\n");
}
void
vk_device_create_info_print(const VkDeviceCreateInfo * info)
{
fprintf(stderr, "Device creation info:\n");
fprintf(stderr, " flags: %u\n", info->flags);
fprintf(stderr, " queueCreateInfoCount: %u\n", info->queueCreateInfoCount);
if (info->queueCreateInfoCount)
{
for (uint32_t nn = 0; nn < info->queueCreateInfoCount; ++nn)
{
const VkDeviceQueueCreateInfo * qinfo = info->pQueueCreateInfos + nn;
fprintf(stderr, " [%d] flags: %u\n", nn, qinfo->flags);
fprintf(stderr, " familyIndex: %u\n", qinfo->queueFamilyIndex);
fprintf(stderr, " count: %u\n", qinfo->queueCount);
if (qinfo->queueCount > 0)
{
fprintf(stderr, " priorities: ");
for (uint32_t mm = 0; mm < qinfo->queueCount; ++mm)
fprintf(stderr, " %f", qinfo->pQueuePriorities[mm]);
fprintf(stderr, "\n");
}
}
}
fprintf(stderr, " extensions (%d): ", info->enabledExtensionCount);
for (uint32_t nn = 0; nn < info->enabledExtensionCount; ++nn)
fprintf(stderr, " %s", info->ppEnabledExtensionNames[nn]);
if (info->pEnabledFeatures)
{
fprintf(stderr, "\n features:\n");
#define CHECK_FEATURE(feature) \
do \
{ \
if (info->pEnabledFeatures->feature == VK_TRUE) \
{ \
fprintf(stderr, " %s\n", #feature); \
} \
} \
while (0);
CHECK_FEATURE(robustBufferAccess)
CHECK_FEATURE(shaderInt64)
CHECK_FEATURE(shaderFloat64)
#undef CHECK_FEATURE
// Memory dump.
{
const uint32_t * data = (const uint32_t *)info->pEnabledFeatures;
size_t data_size = sizeof(info->pEnabledFeatures[0]);
for (uint32_t nn = 0; nn < data_size / 4; ++nn)
{
fprintf(stderr, " %02X", data[nn]);
if ((nn + 1) % 16 == 0)
fprintf(stderr, "\n");
}
fprintf(stderr, "\n");
}
}
}
bool
vk_check_image_usage_vs_format_features(VkImageUsageFlags image_usage,
VkFormatFeatureFlags format_features)
{
// Helper macro. |usage_| and |feature_| are abbreviated image usage and format
// feature bit constants, respectively.
#define CHECK_COMBO(usage_, feature_) \
if ((image_usage & VK_IMAGE_USAGE_##usage_##_BIT) != 0 && \
(format_features & VK_FORMAT_FEATURE_##feature_##_BIT) == 0) \
{ \
return false; \
}
CHECK_COMBO(TRANSFER_SRC, TRANSFER_SRC)
CHECK_COMBO(TRANSFER_DST, TRANSFER_DST)
CHECK_COMBO(SAMPLED, SAMPLED_IMAGE)
CHECK_COMBO(STORAGE, STORAGE_IMAGE)
CHECK_COMBO(COLOR_ATTACHMENT, COLOR_ATTACHMENT)
CHECK_COMBO(DEPTH_STENCIL_ATTACHMENT, DEPTH_STENCIL_ATTACHMENT)
// CHECK_COMBO(TRANSIENT_ATTACHMENT, ) // No matching format feature flag.
// CHECK_COMBO(INPUT_ATTACHMENT, ) // No matching format feature flag.
#undef CHECK_COMBO
return true;
}
void
vk_submit_one(VkSemaphore wait_semaphore,
VkPipelineStageFlags wait_stages,
VkSemaphore signal_semaphore,
VkQueue command_queue,
VkCommandBuffer command_buffer,
VkFence signal_fence)
{
VkSubmitInfo submit_info = {
.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO,
.waitSemaphoreCount = (wait_semaphore != VK_NULL_HANDLE) ? 1 : 0,
.pWaitSemaphores = (wait_semaphore != VK_NULL_HANDLE) ? &wait_semaphore : NULL,
.pWaitDstStageMask = (wait_semaphore != VK_NULL_HANDLE) ? &wait_stages : NULL,
.commandBufferCount = (command_buffer != VK_NULL_HANDLE) ? 1 : 0,
.pCommandBuffers = (command_buffer != VK_NULL_HANDLE) ? &command_buffer : NULL,
.signalSemaphoreCount = (signal_semaphore != VK_NULL_HANDLE) ? 1 : 0,
.pSignalSemaphores = (signal_semaphore != VK_NULL_HANDLE) ? &signal_semaphore : NULL,
};
vk(QueueSubmit(command_queue, 1, &submit_info, signal_fence));
}
uint32_t
vk_format_to_bytes_per_pixel(VkFormat format)
{
switch (format)
{
case VK_FORMAT_R4G4_UNORM_PACK8:
case VK_FORMAT_R8_UNORM:
case VK_FORMAT_R8_SNORM:
case VK_FORMAT_R8_USCALED:
case VK_FORMAT_R8_SSCALED:
case VK_FORMAT_R8_UINT:
case VK_FORMAT_R8_SINT:
case VK_FORMAT_R8_SRGB:
return 1;
case VK_FORMAT_R4G4B4A4_UNORM_PACK16:
case VK_FORMAT_B4G4R4A4_UNORM_PACK16:
case VK_FORMAT_R5G6B5_UNORM_PACK16:
case VK_FORMAT_B5G6R5_UNORM_PACK16:
case VK_FORMAT_R5G5B5A1_UNORM_PACK16:
case VK_FORMAT_B5G5R5A1_UNORM_PACK16:
case VK_FORMAT_A1R5G5B5_UNORM_PACK16:
case VK_FORMAT_R8G8_UNORM:
case VK_FORMAT_R8G8_SNORM:
case VK_FORMAT_R8G8_USCALED:
case VK_FORMAT_R8G8_SSCALED:
case VK_FORMAT_R8G8_UINT:
case VK_FORMAT_R8G8_SINT:
case VK_FORMAT_R8G8_SRGB:
case VK_FORMAT_R16_UNORM:
case VK_FORMAT_R16_SNORM:
case VK_FORMAT_R16_USCALED:
case VK_FORMAT_R16_SSCALED:
case VK_FORMAT_R16_UINT:
case VK_FORMAT_R16_SINT:
case VK_FORMAT_R16_SFLOAT:
return 2;
case VK_FORMAT_R8G8B8_UNORM:
case VK_FORMAT_R8G8B8_SNORM:
case VK_FORMAT_R8G8B8_USCALED:
case VK_FORMAT_R8G8B8_SSCALED:
case VK_FORMAT_R8G8B8_UINT:
case VK_FORMAT_R8G8B8_SINT:
case VK_FORMAT_R8G8B8_SRGB:
case VK_FORMAT_B8G8R8_UNORM:
case VK_FORMAT_B8G8R8_SNORM:
case VK_FORMAT_B8G8R8_USCALED:
case VK_FORMAT_B8G8R8_SSCALED:
case VK_FORMAT_B8G8R8_UINT:
case VK_FORMAT_B8G8R8_SINT:
case VK_FORMAT_B8G8R8_SRGB:
return 3;
case VK_FORMAT_R8G8B8A8_UNORM:
case VK_FORMAT_R8G8B8A8_SNORM:
case VK_FORMAT_R8G8B8A8_USCALED:
case VK_FORMAT_R8G8B8A8_SSCALED:
case VK_FORMAT_R8G8B8A8_UINT:
case VK_FORMAT_R8G8B8A8_SINT:
case VK_FORMAT_R8G8B8A8_SRGB:
case VK_FORMAT_B8G8R8A8_UNORM:
case VK_FORMAT_B8G8R8A8_SNORM:
case VK_FORMAT_B8G8R8A8_USCALED:
case VK_FORMAT_B8G8R8A8_SSCALED:
case VK_FORMAT_B8G8R8A8_UINT:
case VK_FORMAT_B8G8R8A8_SINT:
case VK_FORMAT_B8G8R8A8_SRGB:
case VK_FORMAT_A8B8G8R8_UNORM_PACK32:
case VK_FORMAT_A8B8G8R8_SNORM_PACK32:
case VK_FORMAT_A8B8G8R8_USCALED_PACK32:
case VK_FORMAT_A8B8G8R8_SSCALED_PACK32:
case VK_FORMAT_A8B8G8R8_UINT_PACK32:
case VK_FORMAT_A8B8G8R8_SINT_PACK32:
case VK_FORMAT_A8B8G8R8_SRGB_PACK32:
case VK_FORMAT_A2R10G10B10_UNORM_PACK32:
case VK_FORMAT_A2R10G10B10_SNORM_PACK32:
case VK_FORMAT_A2R10G10B10_USCALED_PACK32:
case VK_FORMAT_A2R10G10B10_SSCALED_PACK32:
case VK_FORMAT_A2R10G10B10_UINT_PACK32:
case VK_FORMAT_A2R10G10B10_SINT_PACK32:
case VK_FORMAT_A2B10G10R10_UNORM_PACK32:
case VK_FORMAT_A2B10G10R10_SNORM_PACK32:
case VK_FORMAT_A2B10G10R10_USCALED_PACK32:
case VK_FORMAT_A2B10G10R10_SSCALED_PACK32:
case VK_FORMAT_A2B10G10R10_UINT_PACK32:
case VK_FORMAT_A2B10G10R10_SINT_PACK32:
case VK_FORMAT_R16G16_UNORM:
case VK_FORMAT_R16G16_SNORM:
case VK_FORMAT_R16G16_USCALED:
case VK_FORMAT_R16G16_SSCALED:
case VK_FORMAT_R16G16_UINT:
case VK_FORMAT_R16G16_SINT:
case VK_FORMAT_R16G16_SFLOAT:
case VK_FORMAT_R32_UINT:
case VK_FORMAT_R32_SINT:
case VK_FORMAT_R32_SFLOAT:
case VK_FORMAT_B10G11R11_UFLOAT_PACK32:
case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32:
return 4;
case VK_FORMAT_R16G16B16_UNORM:
case VK_FORMAT_R16G16B16_SNORM:
case VK_FORMAT_R16G16B16_USCALED:
case VK_FORMAT_R16G16B16_SSCALED:
case VK_FORMAT_R16G16B16_UINT:
case VK_FORMAT_R16G16B16_SINT:
case VK_FORMAT_R16G16B16_SFLOAT:
case VK_FORMAT_R32G32B32_UINT:
case VK_FORMAT_R32G32B32_SINT:
case VK_FORMAT_R32G32B32_SFLOAT:
return 6;
case VK_FORMAT_R16G16B16A16_UNORM:
case VK_FORMAT_R16G16B16A16_SNORM:
case VK_FORMAT_R16G16B16A16_USCALED:
case VK_FORMAT_R16G16B16A16_SSCALED:
case VK_FORMAT_R16G16B16A16_UINT:
case VK_FORMAT_R16G16B16A16_SINT:
case VK_FORMAT_R16G16B16A16_SFLOAT:
case VK_FORMAT_R32G32_UINT:
case VK_FORMAT_R32G32_SINT:
case VK_FORMAT_R32G32_SFLOAT:
case VK_FORMAT_R64_UINT:
case VK_FORMAT_R64_SINT:
case VK_FORMAT_R64_SFLOAT:
return 8;
case VK_FORMAT_R32G32B32A32_UINT:
case VK_FORMAT_R32G32B32A32_SINT:
case VK_FORMAT_R32G32B32A32_SFLOAT:
case VK_FORMAT_R64G64_UINT:
case VK_FORMAT_R64G64_SINT:
case VK_FORMAT_R64G64_SFLOAT:
return 16;
case VK_FORMAT_R64G64B64_UINT:
case VK_FORMAT_R64G64B64_SINT:
case VK_FORMAT_R64G64B64_SFLOAT:
return 24;
case VK_FORMAT_R64G64B64A64_UINT:
case VK_FORMAT_R64G64B64A64_SINT:
case VK_FORMAT_R64G64B64A64_SFLOAT:
return 32;
default:
// All other formats correspond to stencil/depth or compressed formats.
return 0;
}
}