aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMark Lobodzinski <mark@lunarg.com>2017-06-09 16:35:43 -0600
committerMark Lobodzinski <mark@lunarg.com>2017-06-12 07:32:50 -0600
commitfb005c48ca6d7effceb10dfa39999e2a3674c64d (patch)
treec3910bcf21826622abc24a6927d4e431db625404
parent898f916d8468dcbccf9ee013fc451139fa1e92cb (diff)
downloadusermoji-fb005c48ca6d7effceb10dfa39999e2a3674c64d.tar.xz
layers: Move remaining Swapchain checks into CV
Also refactored modified routines for pre/post call structure. Change-Id: I192e11c1d04effa8d2f3478c1341f6eedea7138a
-rw-r--r--layers/core_validation.cpp207
-rw-r--r--layers/core_validation.h9
-rw-r--r--layers/core_validation_error_enums.h32
-rw-r--r--layers/core_validation_types.h8
4 files changed, 218 insertions, 38 deletions
diff --git a/layers/core_validation.cpp b/layers/core_validation.cpp
index 2e31419d..62a7131d 100644
--- a/layers/core_validation.cpp
+++ b/layers/core_validation.cpp
@@ -8803,51 +8803,93 @@ VKAPI_ATTR void VKAPI_CALL DestroySwapchainKHR(VkDevice device, VkSwapchainKHR s
if (!skip) dev_data->dispatch_table.DestroySwapchainKHR(device, swapchain, pAllocator);
}
-VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pCount,
- VkImage *pSwapchainImages) {
- layer_data *dev_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
- VkResult result = dev_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pCount, pSwapchainImages);
-
- if ((result == VK_SUCCESS || result == VK_INCOMPLETE) && pSwapchainImages != nullptr) {
- // This should never happen and is checked by param checker.
- if (!pCount) return result;
+static bool PreCallValidateGetSwapchainImagesKHR(layer_data *device_data, SWAPCHAIN_NODE *swapchain_state, VkDevice device,
+ uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
+ bool skip = false;
+ if (swapchain_state && pSwapchainImages) {
std::lock_guard<std::mutex> lock(global_lock);
- auto swapchain_node = GetSwapchainNode(dev_data, swapchain);
+ // Compare the preliminary value of *pSwapchainImageCount with the value this time:
+ if (swapchain_state->vkGetSwapchainImagesKHRState == UNCALLED) {
+ skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+ HandleToUint64(device), __LINE__, SWAPCHAIN_PRIOR_COUNT, "DS",
+ "vkGetSwapchainImagesKHR() called with non-NULL pSwapchainImageCount; but no prior positive "
+ "value has been seen for pSwapchainImages.");
+ } else if (*pSwapchainImageCount > swapchain_state->get_swapchain_image_count) {
+ skip |= log_msg(device_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_DEVICE_EXT,
+ HandleToUint64(device), __LINE__, SWAPCHAIN_INVALID_COUNT, "DS",
+ "vkGetSwapchainImagesKHR() called with non-NULL pSwapchainImageCount, and with "
+ "pSwapchainImages set to a value (%d) that is greater than the value (%d) that was returned when "
+ "pSwapchainImageCount was NULL.",
+ *pSwapchainImageCount, swapchain_state->get_swapchain_image_count);
+ }
+ }
+ return skip;
+}
+
+static void PostCallRecordGetSwapchainImagesKHR(layer_data *device_data, SWAPCHAIN_NODE *swapchain_state, VkDevice device,
+ uint32_t *pSwapchainImageCount, VkImage *pSwapchainImages) {
+ std::lock_guard<std::mutex> lock(global_lock);
- if (*pCount > swapchain_node->images.size())
- swapchain_node->images.resize(*pCount);
+ if (*pSwapchainImageCount > swapchain_state->images.size()) swapchain_state->images.resize(*pSwapchainImageCount);
- for (uint32_t i = 0; i < *pCount; ++i) {
- if (swapchain_node->images[i] != VK_NULL_HANDLE)
- continue; // Already retrieved this.
+ if (pSwapchainImages) {
+ if (swapchain_state->vkGetSwapchainImagesKHRState < QUERY_DETAILS) {
+ swapchain_state->vkGetSwapchainImagesKHRState = QUERY_DETAILS;
+ }
+ for (uint32_t i = 0; i < *pSwapchainImageCount; ++i) {
+ if (swapchain_state->images[i] != VK_NULL_HANDLE) continue; // Already retrieved this.
IMAGE_LAYOUT_NODE image_layout_node;
image_layout_node.layout = VK_IMAGE_LAYOUT_UNDEFINED;
- image_layout_node.format = swapchain_node->createInfo.imageFormat;
+ image_layout_node.format = swapchain_state->createInfo.imageFormat;
// Add imageMap entries for each swapchain image
VkImageCreateInfo image_ci = {};
image_ci.flags = 0;
image_ci.imageType = VK_IMAGE_TYPE_2D;
- image_ci.format = swapchain_node->createInfo.imageFormat;
- image_ci.extent.width = swapchain_node->createInfo.imageExtent.width;
- image_ci.extent.height = swapchain_node->createInfo.imageExtent.height;
+ image_ci.format = swapchain_state->createInfo.imageFormat;
+ image_ci.extent.width = swapchain_state->createInfo.imageExtent.width;
+ image_ci.extent.height = swapchain_state->createInfo.imageExtent.height;
image_ci.extent.depth = 1;
image_ci.mipLevels = 1;
- image_ci.arrayLayers = swapchain_node->createInfo.imageArrayLayers;
+ image_ci.arrayLayers = swapchain_state->createInfo.imageArrayLayers;
image_ci.samples = VK_SAMPLE_COUNT_1_BIT;
image_ci.tiling = VK_IMAGE_TILING_OPTIMAL;
- image_ci.usage = swapchain_node->createInfo.imageUsage;
- image_ci.sharingMode = swapchain_node->createInfo.imageSharingMode;
- dev_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
- auto &image_state = dev_data->imageMap[pSwapchainImages[i]];
+ image_ci.usage = swapchain_state->createInfo.imageUsage;
+ image_ci.sharingMode = swapchain_state->createInfo.imageSharingMode;
+ device_data->imageMap[pSwapchainImages[i]] = unique_ptr<IMAGE_STATE>(new IMAGE_STATE(pSwapchainImages[i], &image_ci));
+ auto &image_state = device_data->imageMap[pSwapchainImages[i]];
image_state->valid = false;
image_state->binding.mem = MEMTRACKER_SWAP_CHAIN_IMAGE_KEY;
- swapchain_node->images[i] = pSwapchainImages[i];
+ swapchain_state->images[i] = pSwapchainImages[i];
ImageSubresourcePair subpair = {pSwapchainImages[i], false, VkImageSubresource()};
- dev_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
- dev_data->imageLayoutMap[subpair] = image_layout_node;
+ device_data->imageSubresourceMap[pSwapchainImages[i]].push_back(subpair);
+ device_data->imageLayoutMap[subpair] = image_layout_node;
}
}
+
+ if (*pSwapchainImageCount) {
+ if (swapchain_state->vkGetSwapchainImagesKHRState < QUERY_COUNT) {
+ swapchain_state->vkGetSwapchainImagesKHRState = QUERY_COUNT;
+ }
+ swapchain_state->get_swapchain_image_count = *pSwapchainImageCount;
+ }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetSwapchainImagesKHR(VkDevice device, VkSwapchainKHR swapchain, uint32_t *pSwapchainImageCount,
+ VkImage *pSwapchainImages) {
+ VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+ layer_data *device_data = GetLayerDataPtr(get_dispatch_key(device), layer_data_map);
+
+ auto swapchain_state = GetSwapchainNode(device_data, swapchain);
+ bool skip = PreCallValidateGetSwapchainImagesKHR(device_data, swapchain_state, device, pSwapchainImageCount, pSwapchainImages);
+
+ if (!skip) {
+ result = device_data->dispatch_table.GetSwapchainImagesKHR(device, swapchain, pSwapchainImageCount, pSwapchainImages);
+ }
+
+ if ((result == VK_SUCCESS || result == VK_INCOMPLETE)) {
+ PostCallRecordGetSwapchainImagesKHR(device_data, swapchain_state, device, pSwapchainImageCount, pSwapchainImages);
+ }
return result;
}
@@ -9399,14 +9441,15 @@ VKAPI_ATTR void VKAPI_CALL DestroySurfaceKHR(VkInstance instance, VkSurfaceKHR s
std::unique_lock<std::mutex> lock(global_lock);
auto surface_state = GetSurfaceState(instance_data, surface);
- if (surface_state) {
- // TODO: track swapchains created from this surface.
- instance_data->surface_map.erase(surface);
+ if ((surface_state) && (surface_state->swapchain)) {
+ skip |= log_msg(instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_INSTANCE_EXT,
+ HandleToUint64(instance), __LINE__, VALIDATION_ERROR_26c009e4, "DS",
+ "vkDestroySurfaceKHR() called before its associated VkSwapchainKHR was destroyed. %s",
+ validation_error_map[VALIDATION_ERROR_26c009e4]);
}
+ instance_data->surface_map.erase(surface);
lock.unlock();
-
if (!skip) {
- // Call down the call chain:
instance_data->dispatch_table.DestroySurfaceKHR(instance, surface, pAllocator);
}
}
@@ -10000,6 +10043,105 @@ VKAPI_ATTR void VKAPI_CALL CmdPushDescriptorSetWithTemplateKHR(VkCommandBuffer c
dev_data->dispatch_table.CmdPushDescriptorSetWithTemplateKHR(commandBuffer, descriptorUpdateTemplate, layout, set, pData);
}
+static void PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_layer_data *instanceData,
+ VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+ VkDisplayPlanePropertiesKHR *pProperties) {
+ std::unique_lock<std::mutex> lock(global_lock);
+ auto physical_device_state = GetPhysicalDeviceState(instanceData, physicalDevice);
+
+ if (*pPropertyCount) {
+ if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_COUNT) {
+ physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_COUNT;
+ }
+ physical_device_state->display_plane_property_count = *pPropertyCount;
+ }
+ if (pProperties) {
+ if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState < QUERY_DETAILS) {
+ physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState = QUERY_DETAILS;
+ }
+ }
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetPhysicalDeviceDisplayPlanePropertiesKHR(VkPhysicalDevice physicalDevice, uint32_t *pPropertyCount,
+ VkDisplayPlanePropertiesKHR *pProperties) {
+ VkResult result = VK_SUCCESS;
+ instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+
+ result = instance_data->dispatch_table.GetPhysicalDeviceDisplayPlanePropertiesKHR(physicalDevice, pPropertyCount, pProperties);
+
+ if (result == VK_SUCCESS || result == VK_INCOMPLETE) {
+ PostCallRecordGetPhysicalDeviceDisplayPlanePropertiesKHR(instance_data, physicalDevice, pPropertyCount, pProperties);
+ }
+
+ return result;
+}
+
+static bool ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_layer_data *instance_data,
+ VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+ const char *api_name) {
+ bool skip = false;
+ auto physical_device_state = GetPhysicalDeviceState(instance_data, physicalDevice);
+ if (physical_device_state->vkGetPhysicalDeviceSurfaceFormatsKHRState == UNCALLED) {
+ skip |= log_msg(
+ instance_data->report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+ HandleToUint64(physicalDevice), __LINE__, SWAPCHAIN_GET_SUPPORTED_DISPLAYS_WITHOUT_QUERY, "DL",
+ "Potential problem with calling %s() without first querying vkGetPhysicalDeviceDisplayPlanePropertiesKHR.", api_name);
+ } else {
+ if (planeIndex >= physical_device_state->display_plane_property_count) {
+ skip |= log_msg(
+ instance_data->report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_PHYSICAL_DEVICE_EXT,
+ HandleToUint64(physicalDevice), __LINE__, VALIDATION_ERROR_29c009c2, "DL",
+ "%s(): planeIndex must be in the range [0, %d] that was returned by vkGetPhysicalDeviceDisplayPlanePropertiesKHR. "
+ "Do you have the plane index hardcoded? %s",
+ api_name, physical_device_state->display_plane_property_count - 1, validation_error_map[VALIDATION_ERROR_29c009c2]);
+ }
+ }
+ return skip;
+}
+
+static bool PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
+ uint32_t planeIndex) {
+ bool skip = false;
+ std::lock_guard<std::mutex> lock(global_lock);
+ skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, planeIndex,
+ "vkGetDisplayPlaneSupportedDisplaysKHR");
+ return skip;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneSupportedDisplaysKHR(VkPhysicalDevice physicalDevice, uint32_t planeIndex,
+ uint32_t *pDisplayCount, VkDisplayKHR *pDisplays) {
+ VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+ instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+ bool skip = PreCallValidateGetDisplayPlaneSupportedDisplaysKHR(instance_data, physicalDevice, planeIndex);
+ if (!skip) {
+ result =
+ instance_data->dispatch_table.GetDisplayPlaneSupportedDisplaysKHR(physicalDevice, planeIndex, pDisplayCount, pDisplays);
+ }
+ return result;
+}
+
+static bool PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_layer_data *instance_data, VkPhysicalDevice physicalDevice,
+ uint32_t planeIndex) {
+ bool skip = false;
+ std::lock_guard<std::mutex> lock(global_lock);
+ skip |= ValidateGetPhysicalDeviceDisplayPlanePropertiesKHRQuery(instance_data, physicalDevice, planeIndex,
+ "vkGetDisplayPlaneCapabilitiesKHR");
+ return skip;
+}
+
+VKAPI_ATTR VkResult VKAPI_CALL GetDisplayPlaneCapabilitiesKHR(VkPhysicalDevice physicalDevice, VkDisplayModeKHR mode,
+ uint32_t planeIndex, VkDisplayPlaneCapabilitiesKHR *pCapabilities) {
+ VkResult result = VK_ERROR_VALIDATION_FAILED_EXT;
+ instance_layer_data *instance_data = GetLayerDataPtr(get_dispatch_key(physicalDevice), instance_layer_data_map);
+ bool skip = PreCallValidateGetDisplayPlaneCapabilitiesKHR(instance_data, physicalDevice, planeIndex);
+
+ if (!skip) {
+ result = instance_data->dispatch_table.GetDisplayPlaneCapabilitiesKHR(physicalDevice, mode, planeIndex, pCapabilities);
+ }
+
+ return result;
+}
+
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName);
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetPhysicalDeviceProcAddr(VkInstance instance, const char *funcName);
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetInstanceProcAddr(VkInstance instance, const char *funcName);
@@ -10179,6 +10321,9 @@ static const std::unordered_map<std::string, void*> name_to_funcptr_map = {
{"vkCreateDebugReportCallbackEXT", (void*)CreateDebugReportCallbackEXT},
{"vkDestroyDebugReportCallbackEXT", (void*)DestroyDebugReportCallbackEXT},
{"vkDebugReportMessageEXT", (void*)DebugReportMessageEXT},
+ {"vkGetPhysicalDeviceDisplayPlanePropertiesKHR", (void*)GetPhysicalDeviceDisplayPlanePropertiesKHR},
+ {"GetDisplayPlaneSupportedDisplaysKHR", (void*)GetDisplayPlaneSupportedDisplaysKHR},
+ {"GetDisplayPlaneCapabilitiesKHR", (void*)GetDisplayPlaneCapabilitiesKHR},
};
VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL GetDeviceProcAddr(VkDevice device, const char *funcName) {
diff --git a/layers/core_validation.h b/layers/core_validation.h
index fd1c8b4d..460dba37 100644
--- a/layers/core_validation.h
+++ b/layers/core_validation.h
@@ -140,13 +140,6 @@ class QUERY_POOL_NODE : public BASE_NODE {
VkQueryPoolCreateInfo createInfo;
};
-// Stuff from Device Limits Layer
-enum CALL_STATE {
- UNCALLED, // Function has not been called
- QUERY_COUNT, // Function called once to query a count
- QUERY_DETAILS, // Function called w/ a count to query details
-};
-
struct PHYSICAL_DEVICE_STATE {
// Track the call state and array sizes for various query functions
CALL_STATE vkGetPhysicalDeviceQueueFamilyPropertiesState = UNCALLED;
@@ -156,6 +149,7 @@ struct PHYSICAL_DEVICE_STATE {
CALL_STATE vkGetPhysicalDeviceSurfaceCapabilitiesKHRState = UNCALLED;
CALL_STATE vkGetPhysicalDeviceSurfacePresentModesKHRState = UNCALLED;
CALL_STATE vkGetPhysicalDeviceSurfaceFormatsKHRState = UNCALLED;
+ CALL_STATE vkGetPhysicalDeviceDisplayPlanePropertiesKHRState = UNCALLED;
VkPhysicalDeviceFeatures features = {};
VkPhysicalDevice phys_device = VK_NULL_HANDLE;
uint32_t queue_family_count = 0;
@@ -163,6 +157,7 @@ struct PHYSICAL_DEVICE_STATE {
VkSurfaceCapabilitiesKHR surfaceCapabilities = {};
std::vector<VkPresentModeKHR> present_modes;
std::vector<VkSurfaceFormatKHR> surface_formats;
+ uint32_t display_plane_property_count = 0;
};
struct GpuQueue {
diff --git a/layers/core_validation_error_enums.h b/layers/core_validation_error_enums.h
index c9a3d1eb..12099c32 100644
--- a/layers/core_validation_error_enums.h
+++ b/layers/core_validation_error_enums.h
@@ -201,4 +201,36 @@ enum IMAGE_ERROR {
IMAGE_INVALID_FORMAT_LIMITS_VIOLATION,
IMAGE_ZERO_AREA_SUBREGION,
};
+
+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 supported
+ SWAPCHAIN_CREATE_SWAP_WITHOUT_QUERY, // Called vkCreateSwapchainKHR() without calling a query
+ SWAPCHAIN_CREATE_SWAP_OUT_OF_BOUNDS_EXTENTS, // Called vkCreateSwapchainKHR() with out-of-bounds imageExtent
+ SWAPCHAIN_CREATE_SWAP_EXTENTS_NO_MATCH_WIN, // Called vkCreateSwapchainKHR w/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_LAYERS, // Called vkCreateSwapchainKHR() with a non-supported imageArrayLayers
+ 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_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_GET_SUPPORTED_DISPLAYS_WITHOUT_QUERY, // vkGetDisplayPlaneSupportedDisplaysKHR should be called after querying
+ // device display plane properties
+ SWAPCHAIN_PLANE_INDEX_TOO_LARGE, // a planeIndex value is larger than what vkGetDisplayPlaneSupportedDisplaysKHR returns
+};
+
#endif // CORE_VALIDATION_ERROR_ENUMS_H_
diff --git a/layers/core_validation_types.h b/layers/core_validation_types.h
index 1555850d..ae9c69ea 100644
--- a/layers/core_validation_types.h
+++ b/layers/core_validation_types.h
@@ -70,6 +70,12 @@ class DescriptorSet;
struct GLOBAL_CB_NODE;
+enum CALL_STATE {
+ UNCALLED, // Function has not been called
+ QUERY_COUNT, // Function called once to query a count
+ QUERY_DETAILS, // Function called w/ a count to query details
+};
+
class BASE_NODE {
public:
// Track when object is being used by an in-flight command buffer
@@ -345,6 +351,8 @@ class SWAPCHAIN_NODE {
std::vector<VkImage> images;
bool replaced = false;
bool shared_presentable = false;
+ CALL_STATE vkGetSwapchainImagesKHRState = UNCALLED;
+ uint32_t get_swapchain_image_count = 0;
SWAPCHAIN_NODE(const VkSwapchainCreateInfoKHR *pCreateInfo, VkSwapchainKHR swapchain)
: createInfo(pCreateInfo), swapchain(swapchain) {}
};