C++程序  |  349行  |  19.33 KB

/* Copyright (c) 2015-2016 The Khronos Group Inc.
 * Copyright (c) 2015-2016 Valve Corporation
 * Copyright (c) 2015-2016 LunarG, Inc.
 * Copyright (C) 2015-2016 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 * Author: Ian Elliott <ian@lunarg.com>
 * Author: Ian Elliott <ianelliott@google.com>
 */

#ifndef SWAPCHAIN_H
#define SWAPCHAIN_H

#include "vulkan/vk_layer.h"
#include "vk_layer_config.h"
#include "vk_layer_logging.h"
#include <vector>
#include <unordered_map>

using namespace std;

// Swapchain ERROR codes
enum SWAPCHAIN_ERROR {
    SWAPCHAIN_INVALID_HANDLE,             // Handle used that isn't currently valid
    SWAPCHAIN_NULL_POINTER,               // Pointer set to NULL, instead of being a valid pointer
    SWAPCHAIN_EXT_NOT_ENABLED_BUT_USED,   // Did not enable WSI extension, but called WSI function
    SWAPCHAIN_DEL_OBJECT_BEFORE_CHILDREN, // Called vkDestroyDevice() before vkDestroySwapchainKHR()
    SWAPCHAIN_CREATE_UNSUPPORTED_SURFACE, // Called vkCreateSwapchainKHR() with a pCreateInfo->surface that wasn't seen as supported
                                          // by vkGetPhysicalDeviceSurfaceSupportKHR for the device
    SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY,  // Called vkCreateSwapchainKHR() without calling a query (e.g.
                                          // vkGetPhysicalDeviceSurfaceCapabilitiesKHR())
    SWAPCHAIN_CREATE_SWAP_BAD_MIN_IMG_COUNT,     // Called vkCreateSwapchainKHR() with out-of-bounds minImageCount
    SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS, // Called vkCreateSwapchainKHR() with out-of-bounds imageExtent
    SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN, // Called vkCreateSwapchainKHR() with imageExtent that doesn't match window's extent
    SWAPCHAIN_CREATE_SWAP_BAD_PRE_TRANSFORM,    // Called vkCreateSwapchainKHR() with a non-supported preTransform
    SWAPCHAIN_CREATE_SWAP_BAD_COMPOSITE_ALPHA,  // Called vkCreateSwapchainKHR() with a non-supported compositeAlpha
    SWAPCHAIN_CREATE_SWAP_BAD_IMG_ARRAY_SIZE,   // Called vkCreateSwapchainKHR() with a non-supported imageArraySize
    SWAPCHAIN_CREATE_SWAP_BAD_IMG_USAGE_FLAGS,  // Called vkCreateSwapchainKHR() with a non-supported imageUsageFlags
    SWAPCHAIN_CREATE_SWAP_BAD_IMG_COLOR_SPACE,  // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
    SWAPCHAIN_CREATE_SWAP_BAD_IMG_FORMAT,       // Called vkCreateSwapchainKHR() with a non-supported imageFormat
    SWAPCHAIN_CREATE_SWAP_BAD_IMG_FMT_CLR_SP,   // Called vkCreateSwapchainKHR() with a non-supported imageColorSpace
    SWAPCHAIN_CREATE_SWAP_BAD_PRESENT_MODE,     // Called vkCreateSwapchainKHR() with a non-supported presentMode
    SWAPCHAIN_CREATE_SWAP_BAD_SHARING_MODE,     // Called vkCreateSwapchainKHR() with a non-supported imageSharingMode
    SWAPCHAIN_CREATE_SWAP_BAD_SHARING_VALUES,   // Called vkCreateSwapchainKHR() with bad values when imageSharingMode is
                                                // VK_SHARING_MODE_CONCURRENT
    SWAPCHAIN_CREATE_SWAP_DIFF_SURFACE, // Called vkCreateSwapchainKHR() with pCreateInfo->oldSwapchain that has a different surface
                                        // than pCreateInfo->surface
    SWAPCHAIN_DESTROY_SWAP_DIFF_DEVICE, // Called vkDestroySwapchainKHR() with a different VkDevice than vkCreateSwapchainKHR()
    SWAPCHAIN_APP_ACQUIRES_TOO_MANY_IMAGES, // vkAcquireNextImageKHR() asked for more images than are available
    SWAPCHAIN_INDEX_TOO_LARGE,          // Index is too large for swapchain
    SWAPCHAIN_INDEX_NOT_IN_USE,         // vkQueuePresentKHR() given index that is not acquired by app
    SWAPCHAIN_BAD_BOOL,                 // VkBool32 that doesn't have value of VK_TRUE or VK_FALSE (e.g. is a non-zero form of true)
    SWAPCHAIN_PRIOR_COUNT,              // Query must be called first to get value of pCount, then called second time
    SWAPCHAIN_INVALID_COUNT,            // Second time a query called, the pCount value didn't match first time
    SWAPCHAIN_WRONG_STYPE,              // The sType for a struct has the wrong value
    SWAPCHAIN_WRONG_NEXT,               // The pNext for a struct is not NULL
    SWAPCHAIN_ZERO_VALUE,               // A value should be non-zero
    SWAPCHAIN_INCOMPATIBLE_ALLOCATOR,   // pAllocator must be compatible (i.e. NULL or not) when object is created and destroyed
    SWAPCHAIN_DID_NOT_QUERY_QUEUE_FAMILIES,     // A function using a queueFamilyIndex was called before
                                                // vkGetPhysicalDeviceQueueFamilyProperties() was called
    SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE,     // A queueFamilyIndex value is not less than pQueueFamilyPropertyCount returned by
                                                // vkGetPhysicalDeviceQueueFamilyProperties()
    SWAPCHAIN_SURFACE_NOT_SUPPORTED_WITH_QUEUE, // A surface is not supported by a given queueFamilyIndex, as seen by
                                                // vkGetPhysicalDeviceSurfaceSupportKHR()
    SWAPCHAIN_NO_SYNC_FOR_ACQUIRE,      // vkAcquireNextImageKHR should be called with a valid semaphore and/or fence
};

// The following is for logging error messages:
#define LAYER_NAME (char *) "Swapchain"
#define LOG_ERROR_NON_VALID_OBJ(objType, type, obj)                                                                                \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__,                 \
                        SWAPCHAIN_INVALID_HANDLE, LAYER_NAME, "%s() called with a non-valid %s.", __FUNCTION__, (obj))             \
              : VK_FALSE
#define LOG_ERROR_NULL_POINTER(objType, type, obj)                                                                                 \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
                        SWAPCHAIN_NULL_POINTER, LAYER_NAME, "%s() called with NULL pointer %s.", __FUNCTION__, (obj))              \
              : VK_FALSE
#define LOG_ERROR_INVALID_COUNT(objType, type, obj, obj2, val, val2)                                                               \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
                        SWAPCHAIN_INVALID_COUNT, LAYER_NAME, "%s() called with non-NULL %s, and with %s set to a "                 \
                                                             "value (%d) that is greater than the value (%d) that "                \
                                                             "was returned when %s was NULL.",                                     \
                        __FUNCTION__, (obj2), (obj), (val), (val2), (obj2))                                                        \
              : VK_FALSE
#define LOG_ERROR_ZERO_PRIOR_COUNT(objType, type, obj, obj2)                                                                       \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
                        SWAPCHAIN_PRIOR_COUNT, LAYER_NAME, "%s() called with non-NULL %s; but no prior "                           \
                        "positive value has been seen for %s.",                                                                    \
                        __FUNCTION__, (obj), (obj2))                                                                               \
              : VK_FALSE
#define LOG_ERROR_WRONG_STYPE(objType, type, obj, val)                                                                             \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, SWAPCHAIN_WRONG_STYPE, \
                        LAYER_NAME, "%s() called with the wrong value for %s->sType "                                              \
                                    "(expected %s).",                                                                              \
                        __FUNCTION__, (obj), (val))                                                                                \
              : VK_FALSE
#define LOG_ERROR_ZERO_VALUE(objType, type, obj)                                                                                   \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0, SWAPCHAIN_ZERO_VALUE,  \
                        LAYER_NAME, "%s() called with a zero value for %s.", __FUNCTION__, (obj))                                  \
              : VK_FALSE
#define LOG_ERROR(objType, type, obj, enm, fmt, ...)                                                                               \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, (enm),          \
                        LAYER_NAME, (fmt), __VA_ARGS__)                                                                            \
              : VK_FALSE
#define LOG_ERROR_QUEUE_FAMILY_INDEX_TOO_LARGE(objType, type, obj, val1, val2)                                                     \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (objType), (uint64_t)(obj), 0,                        \
                        SWAPCHAIN_QUEUE_FAMILY_INDEX_TOO_LARGE, LAYER_NAME, "%s() called with a queueFamilyIndex that is too "     \
                                                                            "large (i.e. %d).  The maximum value (returned "       \
                                                                            "by vkGetPhysicalDeviceQueueFamilyProperties) is "     \
                                                                            "only %d.\n",                                          \
                        __FUNCTION__, (val1), (val2))                                                                              \
              : VK_FALSE
#define LOG_PERF_WARNING(objType, type, obj, enm, fmt, ...)                                                                        \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, (objType), (uint64_t)(obj), __LINE__,   \
                        (enm), LAYER_NAME, (fmt), __VA_ARGS__)                                                                     \
              : VK_FALSE
#define LOG_WARNING(objType, type, obj, enm, fmt, ...)                                                                             \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, (objType), (uint64_t)(obj), __LINE__, (enm),        \
                        LAYER_NAME, (fmt), __VA_ARGS__)                                                                            \
              : VK_FALSE
#define LOG_INFO_WRONG_NEXT(objType, type, obj)                                                                                    \
    (my_data) ? log_msg(my_data->report_data, VK_DEBUG_REPORT_INFORMATION_BIT_EXT, (objType), (uint64_t)(obj), 0,                  \
                        SWAPCHAIN_WRONG_NEXT, LAYER_NAME, "%s() called with non-NULL value for %s->pNext.", __FUNCTION__, (obj))   \
              : VK_FALSE

// NOTE: The following struct's/typedef's are for keeping track of
// info that is used for validating the WSI extensions.

// Forward declarations:
struct SwpInstance;
struct SwpSurface;
struct SwpPhysicalDevice;
struct SwpDevice;
struct SwpSwapchain;
struct SwpImage;
struct SwpQueue;

// Create one of these for each VkInstance:
struct SwpInstance {
    // The actual handle for this VkInstance:
    VkInstance instance;

    // Remember the VkSurfaceKHR's that are created for this VkInstance:
    unordered_map<VkSurfaceKHR, SwpSurface *> surfaces;

    // When vkEnumeratePhysicalDevices is called, the VkPhysicalDevice's are
    // remembered:
    unordered_map<const void *, SwpPhysicalDevice *> physicalDevices;

    // Set to true if VK_KHR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool surfaceExtensionEnabled;

// TODO: Add additional booleans for platform-specific extensions:
#ifdef VK_USE_PLATFORM_ANDROID_KHR
    // Set to true if VK_KHR_ANDROID_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool androidSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_ANDROID_KHR
#ifdef VK_USE_PLATFORM_MIR_KHR
    // Set to true if VK_KHR_MIR_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool mirSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_MIR_KHR
#ifdef VK_USE_PLATFORM_WAYLAND_KHR
    // Set to true if VK_KHR_WAYLAND_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool waylandSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_WAYLAND_KHR
#ifdef VK_USE_PLATFORM_WIN32_KHR
    // Set to true if VK_KHR_WIN32_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool win32SurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_WIN32_KHR
#ifdef VK_USE_PLATFORM_XCB_KHR
    // Set to true if VK_KHR_XCB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool xcbSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_XCB_KHR
#ifdef VK_USE_PLATFORM_XLIB_KHR
    // Set to true if VK_KHR_XLIB_SURFACE_EXTENSION_NAME was enabled for this VkInstance:
    bool xlibSurfaceExtensionEnabled;
#endif // VK_USE_PLATFORM_XLIB_KHR
};

// Create one of these for each VkSurfaceKHR:
struct SwpSurface {
    // The actual handle for this VkSurfaceKHR:
    VkSurfaceKHR surface;

    // VkInstance that this VkSurfaceKHR is associated with:
    SwpInstance *pInstance;

    // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
    // remembered:
    unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;

    // 'true' if pAllocator was non-NULL when vkCreate*SurfaceKHR was called:
    bool usedAllocatorToCreate;

    // Value of pQueueFamilyPropertyCount that was returned by the
    // vkGetPhysicalDeviceQueueFamilyProperties() function:
    uint32_t numQueueFamilyIndexSupport;
    // Array of VkBool32's that is intialized by the
    // vkGetPhysicalDeviceSurfaceSupportKHR() function.  First call for a given
    // surface allocates and initializes this array to false for all
    // queueFamilyIndex's (and sets numQueueFamilyIndexSupport to non-zero).
    // All calls set the entry for a given queueFamilyIndex:
    VkBool32 *pQueueFamilyIndexSupport;
};

// Create one of these for each VkPhysicalDevice within a VkInstance:
struct SwpPhysicalDevice {
    // The actual handle for this VkPhysicalDevice:
    VkPhysicalDevice physicalDevice;

    // Corresponding VkDevice (and info) to this VkPhysicalDevice:
    SwpDevice *pDevice;

    // VkInstance that this VkPhysicalDevice is associated with:
    SwpInstance *pInstance;

    // Records results of vkGetPhysicalDeviceQueueFamilyProperties()'s
    // numOfQueueFamilies parameter when pQueueFamilyProperties is NULL:
    bool gotQueueFamilyPropertyCount;
    uint32_t numOfQueueFamilies;

    // Record all surfaces that vkGetPhysicalDeviceSurfaceSupportKHR() was
    // called for:
    unordered_map<VkSurfaceKHR, SwpSurface *> supportedSurfaces;

    // TODO: Record/use this info per-surface, not per-device, once a
    // non-dispatchable surface object is added to WSI:
    // Results of vkGetPhysicalDeviceSurfaceCapabilitiesKHR():
    bool gotSurfaceCapabilities;
    VkSurfaceCapabilitiesKHR surfaceCapabilities;

    // TODO: Record/use this info per-surface, not per-device, once a
    // non-dispatchable surface object is added to WSI:
    // Count and VkSurfaceFormatKHR's returned by vkGetPhysicalDeviceSurfaceFormatsKHR():
    uint32_t surfaceFormatCount;
    VkSurfaceFormatKHR *pSurfaceFormats;

    // TODO: Record/use this info per-surface, not per-device, once a
    // non-dispatchable surface object is added to WSI:
    // Count and VkPresentModeKHR's returned by vkGetPhysicalDeviceSurfacePresentModesKHR():
    uint32_t presentModeCount;
    VkPresentModeKHR *pPresentModes;
};

// Create one of these for each VkDevice within a VkInstance:
struct SwpDevice {
    // The actual handle for this VkDevice:
    VkDevice device;

    // Corresponding VkPhysicalDevice (and info) to this VkDevice:
    SwpPhysicalDevice *pPhysicalDevice;

    // Set to true if VK_KHR_SWAPCHAIN_EXTENSION_NAME was enabled:
    bool swapchainExtensionEnabled;

    // When vkCreateSwapchainKHR is called, the VkSwapchainKHR's are
    // remembered:
    unordered_map<VkSwapchainKHR, SwpSwapchain *> swapchains;

    // When vkGetDeviceQueue is called, the VkQueue's are remembered:
    unordered_map<VkQueue, SwpQueue *> queues;
};

// Create one of these for each VkImage within a VkSwapchainKHR:
struct SwpImage {
    // The actual handle for this VkImage:
    VkImage image;

    // Corresponding VkSwapchainKHR (and info) to this VkImage:
    SwpSwapchain *pSwapchain;

    // true if application acquired this image from vkAcquireNextImageKHR(),
    // and hasn't yet called vkQueuePresentKHR() for it; otherwise false:
    bool acquiredByApp;
};

// Create one of these for each VkSwapchainKHR within a VkDevice:
struct SwpSwapchain {
    // The actual handle for this VkSwapchainKHR:
    VkSwapchainKHR swapchain;

    // Corresponding VkDevice (and info) to this VkSwapchainKHR:
    SwpDevice *pDevice;

    // Corresponding VkSurfaceKHR to this VkSwapchainKHR:
    SwpSurface *pSurface;

    // When vkGetSwapchainImagesKHR is called, the VkImage's are
    // remembered:
    uint32_t imageCount;
    unordered_map<int, SwpImage> images;

    // 'true' if pAllocator was non-NULL when vkCreateSwapchainKHR was called:
    bool usedAllocatorToCreate;
};

// Create one of these for each VkQueue within a VkDevice:
struct SwpQueue {
    // The actual handle for this VkQueue:
    VkQueue queue;

    // Corresponding VkDevice (and info) to this VkSwapchainKHR:
    SwpDevice *pDevice;

    // Which queueFamilyIndex this VkQueue is associated with:
    uint32_t queueFamilyIndex;
};

struct layer_data {
    VkInstance instance;

    debug_report_data *report_data;
    std::vector<VkDebugReportCallbackEXT> logging_callback;
    VkLayerDispatchTable *device_dispatch_table;
    VkLayerInstanceDispatchTable *instance_dispatch_table;

    // The following are for keeping track of the temporary callbacks that can
    // be used in vkCreateInstance and vkDestroyInstance:
    uint32_t num_tmp_callbacks;
    VkDebugReportCallbackCreateInfoEXT *tmp_dbg_create_infos;
    VkDebugReportCallbackEXT *tmp_callbacks;

    // NOTE: The following are for keeping track of info that is used for
    // validating the WSI extensions.
    std::unordered_map<void *, SwpInstance> instanceMap;
    std::unordered_map<VkSurfaceKHR, SwpSurface> surfaceMap;
    std::unordered_map<void *, SwpPhysicalDevice> physicalDeviceMap;
    std::unordered_map<void *, SwpDevice> deviceMap;
    std::unordered_map<VkSwapchainKHR, SwpSwapchain> swapchainMap;
    std::unordered_map<void *, SwpQueue> queueMap;

    layer_data()
        : report_data(nullptr), device_dispatch_table(nullptr), instance_dispatch_table(nullptr), num_tmp_callbacks(0),
          tmp_dbg_create_infos(nullptr), tmp_callbacks(nullptr){};
};

#endif // SWAPCHAIN_H