1*b7893ccfSSadaf Ebrahimi /* Copyright (c) 2015-2019 The Khronos Group Inc.
2*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 Valve Corporation
3*b7893ccfSSadaf Ebrahimi * Copyright (c) 2015-2019 LunarG, Inc.
4*b7893ccfSSadaf Ebrahimi * Copyright (C) 2015-2019 Google Inc.
5*b7893ccfSSadaf Ebrahimi *
6*b7893ccfSSadaf Ebrahimi * Licensed under the Apache License, Version 2.0 (the "License");
7*b7893ccfSSadaf Ebrahimi * you may not use this file except in compliance with the License.
8*b7893ccfSSadaf Ebrahimi * You may obtain a copy of the License at
9*b7893ccfSSadaf Ebrahimi *
10*b7893ccfSSadaf Ebrahimi * http://www.apache.org/licenses/LICENSE-2.0
11*b7893ccfSSadaf Ebrahimi *
12*b7893ccfSSadaf Ebrahimi * Unless required by applicable law or agreed to in writing, software
13*b7893ccfSSadaf Ebrahimi * distributed under the License is distributed on an "AS IS" BASIS,
14*b7893ccfSSadaf Ebrahimi * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15*b7893ccfSSadaf Ebrahimi * See the License for the specific language governing permissions and
16*b7893ccfSSadaf Ebrahimi * limitations under the License.
17*b7893ccfSSadaf Ebrahimi *
18*b7893ccfSSadaf Ebrahimi * Author: Mark Lobodzinski <mark@lunarg.com>
19*b7893ccfSSadaf Ebrahimi * Author: Dave Houlton <daveh@lunarg.com>
20*b7893ccfSSadaf Ebrahimi * Shannon McPherson <shannon@lunarg.com>
21*b7893ccfSSadaf Ebrahimi */
22*b7893ccfSSadaf Ebrahimi
23*b7893ccfSSadaf Ebrahimi // Allow use of STL min and max functions in Windows
24*b7893ccfSSadaf Ebrahimi #define NOMINMAX
25*b7893ccfSSadaf Ebrahimi
26*b7893ccfSSadaf Ebrahimi #include <cmath>
27*b7893ccfSSadaf Ebrahimi #include <set>
28*b7893ccfSSadaf Ebrahimi #include <sstream>
29*b7893ccfSSadaf Ebrahimi #include <string>
30*b7893ccfSSadaf Ebrahimi
31*b7893ccfSSadaf Ebrahimi #include "vk_enum_string_helper.h"
32*b7893ccfSSadaf Ebrahimi #include "vk_format_utils.h"
33*b7893ccfSSadaf Ebrahimi #include "vk_layer_data.h"
34*b7893ccfSSadaf Ebrahimi #include "vk_layer_utils.h"
35*b7893ccfSSadaf Ebrahimi #include "vk_layer_logging.h"
36*b7893ccfSSadaf Ebrahimi #include "vk_typemap_helper.h"
37*b7893ccfSSadaf Ebrahimi
38*b7893ccfSSadaf Ebrahimi #include "chassis.h"
39*b7893ccfSSadaf Ebrahimi #include "core_validation.h"
40*b7893ccfSSadaf Ebrahimi #include "shader_validation.h"
41*b7893ccfSSadaf Ebrahimi #include "descriptor_sets.h"
42*b7893ccfSSadaf Ebrahimi #include "buffer_validation.h"
43*b7893ccfSSadaf Ebrahimi
44*b7893ccfSSadaf Ebrahimi // Transfer VkImageSubresourceLayers into VkImageSubresourceRange struct
RangeFromLayers(const VkImageSubresourceLayers & subresource_layers)45*b7893ccfSSadaf Ebrahimi static VkImageSubresourceRange RangeFromLayers(const VkImageSubresourceLayers &subresource_layers) {
46*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange subresource_range;
47*b7893ccfSSadaf Ebrahimi subresource_range.aspectMask = subresource_layers.aspectMask;
48*b7893ccfSSadaf Ebrahimi subresource_range.baseArrayLayer = subresource_layers.baseArrayLayer;
49*b7893ccfSSadaf Ebrahimi subresource_range.layerCount = subresource_layers.layerCount;
50*b7893ccfSSadaf Ebrahimi subresource_range.baseMipLevel = subresource_layers.mipLevel;
51*b7893ccfSSadaf Ebrahimi subresource_range.levelCount = 1;
52*b7893ccfSSadaf Ebrahimi return subresource_range;
53*b7893ccfSSadaf Ebrahimi }
54*b7893ccfSSadaf Ebrahimi
IMAGE_STATE(VkImage img,const VkImageCreateInfo * pCreateInfo)55*b7893ccfSSadaf Ebrahimi IMAGE_STATE::IMAGE_STATE(VkImage img, const VkImageCreateInfo *pCreateInfo)
56*b7893ccfSSadaf Ebrahimi : image(img),
57*b7893ccfSSadaf Ebrahimi createInfo(*pCreateInfo),
58*b7893ccfSSadaf Ebrahimi valid(false),
59*b7893ccfSSadaf Ebrahimi acquired(false),
60*b7893ccfSSadaf Ebrahimi shared_presentable(false),
61*b7893ccfSSadaf Ebrahimi layout_locked(false),
62*b7893ccfSSadaf Ebrahimi get_sparse_reqs_called(false),
63*b7893ccfSSadaf Ebrahimi sparse_metadata_required(false),
64*b7893ccfSSadaf Ebrahimi sparse_metadata_bound(false),
65*b7893ccfSSadaf Ebrahimi imported_ahb(false),
66*b7893ccfSSadaf Ebrahimi has_ahb_format(false),
67*b7893ccfSSadaf Ebrahimi ahb_format(0),
68*b7893ccfSSadaf Ebrahimi full_range{},
69*b7893ccfSSadaf Ebrahimi create_from_swapchain(VK_NULL_HANDLE),
70*b7893ccfSSadaf Ebrahimi bind_swapchain(VK_NULL_HANDLE),
71*b7893ccfSSadaf Ebrahimi bind_swapchain_imageIndex(0),
72*b7893ccfSSadaf Ebrahimi sparse_requirements{} {
73*b7893ccfSSadaf Ebrahimi if ((createInfo.sharingMode == VK_SHARING_MODE_CONCURRENT) && (createInfo.queueFamilyIndexCount > 0)) {
74*b7893ccfSSadaf Ebrahimi uint32_t *pQueueFamilyIndices = new uint32_t[createInfo.queueFamilyIndexCount];
75*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < createInfo.queueFamilyIndexCount; i++) {
76*b7893ccfSSadaf Ebrahimi pQueueFamilyIndices[i] = pCreateInfo->pQueueFamilyIndices[i];
77*b7893ccfSSadaf Ebrahimi }
78*b7893ccfSSadaf Ebrahimi createInfo.pQueueFamilyIndices = pQueueFamilyIndices;
79*b7893ccfSSadaf Ebrahimi }
80*b7893ccfSSadaf Ebrahimi
81*b7893ccfSSadaf Ebrahimi if (createInfo.flags & VK_IMAGE_CREATE_SPARSE_BINDING_BIT) {
82*b7893ccfSSadaf Ebrahimi sparse = true;
83*b7893ccfSSadaf Ebrahimi }
84*b7893ccfSSadaf Ebrahimi const auto format = createInfo.format;
85*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange init_range{0, 0, VK_REMAINING_MIP_LEVELS, 0, VK_REMAINING_ARRAY_LAYERS};
86*b7893ccfSSadaf Ebrahimi if (FormatIsColor(format) || FormatIsMultiplane(format)) {
87*b7893ccfSSadaf Ebrahimi init_range.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; // Normalization will expand this for multiplane
88*b7893ccfSSadaf Ebrahimi } else {
89*b7893ccfSSadaf Ebrahimi init_range.aspectMask =
90*b7893ccfSSadaf Ebrahimi (FormatHasDepth(format) ? VK_IMAGE_ASPECT_DEPTH_BIT : 0) | (FormatHasStencil(format) ? VK_IMAGE_ASPECT_STENCIL_BIT : 0);
91*b7893ccfSSadaf Ebrahimi }
92*b7893ccfSSadaf Ebrahimi full_range = NormalizeSubresourceRange(*this, init_range);
93*b7893ccfSSadaf Ebrahimi
94*b7893ccfSSadaf Ebrahimi #ifdef VK_USE_PLATFORM_ANDROID_KHR
95*b7893ccfSSadaf Ebrahimi auto external_format = lvl_find_in_chain<VkExternalFormatANDROID>(createInfo.pNext);
96*b7893ccfSSadaf Ebrahimi if (external_format) {
97*b7893ccfSSadaf Ebrahimi external_format_android = external_format->externalFormat;
98*b7893ccfSSadaf Ebrahimi } else {
99*b7893ccfSSadaf Ebrahimi // If externalFormat is zero, the effect is as if the VkExternalFormatANDROID structure was not present.
100*b7893ccfSSadaf Ebrahimi external_format_android = 0;
101*b7893ccfSSadaf Ebrahimi }
102*b7893ccfSSadaf Ebrahimi #endif // VK_USE_PLATFORM_ANDROID_KHR
103*b7893ccfSSadaf Ebrahimi }
104*b7893ccfSSadaf Ebrahimi
IMAGE_VIEW_STATE(const IMAGE_STATE * image_state,VkImageView iv,const VkImageViewCreateInfo * ci)105*b7893ccfSSadaf Ebrahimi IMAGE_VIEW_STATE::IMAGE_VIEW_STATE(const IMAGE_STATE *image_state, VkImageView iv, const VkImageViewCreateInfo *ci)
106*b7893ccfSSadaf Ebrahimi : image_view(iv), create_info(*ci), normalized_subresource_range(ci->subresourceRange), samplerConversion(VK_NULL_HANDLE) {
107*b7893ccfSSadaf Ebrahimi auto *conversionInfo = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info.pNext);
108*b7893ccfSSadaf Ebrahimi if (conversionInfo) samplerConversion = conversionInfo->conversion;
109*b7893ccfSSadaf Ebrahimi if (image_state) {
110*b7893ccfSSadaf Ebrahimi // A light normalization of the createInfo range
111*b7893ccfSSadaf Ebrahimi auto &sub_res_range = create_info.subresourceRange;
112*b7893ccfSSadaf Ebrahimi sub_res_range.levelCount = ResolveRemainingLevels(&sub_res_range, image_state->createInfo.mipLevels);
113*b7893ccfSSadaf Ebrahimi sub_res_range.layerCount = ResolveRemainingLayers(&sub_res_range, image_state->createInfo.arrayLayers);
114*b7893ccfSSadaf Ebrahimi
115*b7893ccfSSadaf Ebrahimi // Cache a full normalization (for "full image/whole image" comparisons)
116*b7893ccfSSadaf Ebrahimi normalized_subresource_range = NormalizeSubresourceRange(*image_state, ci->subresourceRange);
117*b7893ccfSSadaf Ebrahimi samples = image_state->createInfo.samples;
118*b7893ccfSSadaf Ebrahimi descriptor_format_bits = DescriptorRequirementsBitsFromFormat(create_info.format);
119*b7893ccfSSadaf Ebrahimi }
120*b7893ccfSSadaf Ebrahimi }
121*b7893ccfSSadaf Ebrahimi
FullMipChainLevels(uint32_t height,uint32_t width,uint32_t depth)122*b7893ccfSSadaf Ebrahimi uint32_t FullMipChainLevels(uint32_t height, uint32_t width, uint32_t depth) {
123*b7893ccfSSadaf Ebrahimi // uint cast applies floor()
124*b7893ccfSSadaf Ebrahimi return 1u + (uint32_t)log2(std::max({height, width, depth}));
125*b7893ccfSSadaf Ebrahimi }
126*b7893ccfSSadaf Ebrahimi
FullMipChainLevels(VkExtent3D extent)127*b7893ccfSSadaf Ebrahimi uint32_t FullMipChainLevels(VkExtent3D extent) { return FullMipChainLevels(extent.height, extent.width, extent.depth); }
128*b7893ccfSSadaf Ebrahimi
FullMipChainLevels(VkExtent2D extent)129*b7893ccfSSadaf Ebrahimi uint32_t FullMipChainLevels(VkExtent2D extent) { return FullMipChainLevels(extent.height, extent.width); }
130*b7893ccfSSadaf Ebrahimi
NormalizeSubresourceRange(const IMAGE_STATE & image_state,const VkImageSubresourceRange & range)131*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange NormalizeSubresourceRange(const IMAGE_STATE &image_state, const VkImageSubresourceRange &range) {
132*b7893ccfSSadaf Ebrahimi const VkImageCreateInfo &image_create_info = image_state.createInfo;
133*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange norm = range;
134*b7893ccfSSadaf Ebrahimi norm.levelCount = ResolveRemainingLevels(&range, image_create_info.mipLevels);
135*b7893ccfSSadaf Ebrahimi
136*b7893ccfSSadaf Ebrahimi // Special case for 3D images with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR flag bit, where <extent.depth> and
137*b7893ccfSSadaf Ebrahimi // <arrayLayers> can potentially alias.
138*b7893ccfSSadaf Ebrahimi uint32_t layer_limit = (0 != (image_create_info.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR))
139*b7893ccfSSadaf Ebrahimi ? image_create_info.extent.depth
140*b7893ccfSSadaf Ebrahimi : image_create_info.arrayLayers;
141*b7893ccfSSadaf Ebrahimi norm.layerCount = ResolveRemainingLayers(&range, layer_limit);
142*b7893ccfSSadaf Ebrahimi
143*b7893ccfSSadaf Ebrahimi // For multiplanar formats, IMAGE_ASPECT_COLOR is equivalent to adding the aspect of the individual planes
144*b7893ccfSSadaf Ebrahimi VkImageAspectFlags &aspect_mask = norm.aspectMask;
145*b7893ccfSSadaf Ebrahimi if (FormatIsMultiplane(image_create_info.format)) {
146*b7893ccfSSadaf Ebrahimi if (aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) {
147*b7893ccfSSadaf Ebrahimi aspect_mask &= ~VK_IMAGE_ASPECT_COLOR_BIT;
148*b7893ccfSSadaf Ebrahimi aspect_mask |= (VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT);
149*b7893ccfSSadaf Ebrahimi if (FormatPlaneCount(image_create_info.format) > 2) {
150*b7893ccfSSadaf Ebrahimi aspect_mask |= VK_IMAGE_ASPECT_PLANE_2_BIT;
151*b7893ccfSSadaf Ebrahimi }
152*b7893ccfSSadaf Ebrahimi }
153*b7893ccfSSadaf Ebrahimi }
154*b7893ccfSSadaf Ebrahimi return norm;
155*b7893ccfSSadaf Ebrahimi }
156*b7893ccfSSadaf Ebrahimi
157*b7893ccfSSadaf Ebrahimi template <class OBJECT, class LAYOUT>
SetLayout(OBJECT * pObject,VkImage image,VkImageSubresource range,const LAYOUT & layout)158*b7893ccfSSadaf Ebrahimi void CoreChecks::SetLayout(OBJECT *pObject, VkImage image, VkImageSubresource range, const LAYOUT &layout) {
159*b7893ccfSSadaf Ebrahimi ImageSubresourcePair imgpair = {image, true, range};
160*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
161*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
162*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
163*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
164*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
165*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
166*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
167*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
168*b7893ccfSSadaf Ebrahimi }
169*b7893ccfSSadaf Ebrahimi }
170*b7893ccfSSadaf Ebrahimi
171*b7893ccfSSadaf Ebrahimi template <class OBJECT, class LAYOUT>
SetLayout(OBJECT * pObject,ImageSubresourcePair imgpair,const LAYOUT & layout,VkImageAspectFlags aspectMask)172*b7893ccfSSadaf Ebrahimi void CoreChecks::SetLayout(OBJECT *pObject, ImageSubresourcePair imgpair, const LAYOUT &layout, VkImageAspectFlags aspectMask) {
173*b7893ccfSSadaf Ebrahimi if (imgpair.subresource.aspectMask & aspectMask) {
174*b7893ccfSSadaf Ebrahimi imgpair.subresource.aspectMask = aspectMask;
175*b7893ccfSSadaf Ebrahimi SetLayout(pObject, imgpair, layout);
176*b7893ccfSSadaf Ebrahimi }
177*b7893ccfSSadaf Ebrahimi }
178*b7893ccfSSadaf Ebrahimi
179*b7893ccfSSadaf Ebrahimi // Set the layout in supplied map
SetLayout(ImageSubresPairLayoutMap & imageLayoutMap,ImageSubresourcePair imgpair,VkImageLayout layout)180*b7893ccfSSadaf Ebrahimi void CoreChecks::SetLayout(ImageSubresPairLayoutMap &imageLayoutMap, ImageSubresourcePair imgpair, VkImageLayout layout) {
181*b7893ccfSSadaf Ebrahimi auto it = imageLayoutMap.find(imgpair);
182*b7893ccfSSadaf Ebrahimi if (it != imageLayoutMap.end()) {
183*b7893ccfSSadaf Ebrahimi it->second.layout = layout; // Update
184*b7893ccfSSadaf Ebrahimi } else {
185*b7893ccfSSadaf Ebrahimi imageLayoutMap[imgpair].layout = layout; // Insert
186*b7893ccfSSadaf Ebrahimi }
187*b7893ccfSSadaf Ebrahimi }
188*b7893ccfSSadaf Ebrahimi
FindLayoutVerifyLayout(ImageSubresourcePair imgpair,VkImageLayout & layout,const VkImageAspectFlags aspectMask)189*b7893ccfSSadaf Ebrahimi bool CoreChecks::FindLayoutVerifyLayout(ImageSubresourcePair imgpair, VkImageLayout &layout, const VkImageAspectFlags aspectMask) {
190*b7893ccfSSadaf Ebrahimi if (!(imgpair.subresource.aspectMask & aspectMask)) {
191*b7893ccfSSadaf Ebrahimi return false;
192*b7893ccfSSadaf Ebrahimi }
193*b7893ccfSSadaf Ebrahimi VkImageAspectFlags oldAspectMask = imgpair.subresource.aspectMask;
194*b7893ccfSSadaf Ebrahimi imgpair.subresource.aspectMask = aspectMask;
195*b7893ccfSSadaf Ebrahimi auto imgsubIt = imageLayoutMap.find(imgpair);
196*b7893ccfSSadaf Ebrahimi if (imgsubIt == imageLayoutMap.end()) {
197*b7893ccfSSadaf Ebrahimi return false;
198*b7893ccfSSadaf Ebrahimi }
199*b7893ccfSSadaf Ebrahimi if (layout != VK_IMAGE_LAYOUT_MAX_ENUM && layout != imgsubIt->second.layout) {
200*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(imgpair.image),
201*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidLayout,
202*b7893ccfSSadaf Ebrahimi "Cannot query for %s layout when combined aspect mask %d has multiple layout types: %s and %s",
203*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(imgpair.image).c_str(), oldAspectMask, string_VkImageLayout(layout),
204*b7893ccfSSadaf Ebrahimi string_VkImageLayout(imgsubIt->second.layout));
205*b7893ccfSSadaf Ebrahimi }
206*b7893ccfSSadaf Ebrahimi layout = imgsubIt->second.layout;
207*b7893ccfSSadaf Ebrahimi return true;
208*b7893ccfSSadaf Ebrahimi }
209*b7893ccfSSadaf Ebrahimi
210*b7893ccfSSadaf Ebrahimi // Find layout(s) on the global level
FindGlobalLayout(ImageSubresourcePair imgpair,VkImageLayout & layout)211*b7893ccfSSadaf Ebrahimi bool CoreChecks::FindGlobalLayout(ImageSubresourcePair imgpair, VkImageLayout &layout) {
212*b7893ccfSSadaf Ebrahimi layout = VK_IMAGE_LAYOUT_MAX_ENUM;
213*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
214*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
215*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
216*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
217*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
218*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
219*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
220*b7893ccfSSadaf Ebrahimi FindLayoutVerifyLayout(imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
221*b7893ccfSSadaf Ebrahimi }
222*b7893ccfSSadaf Ebrahimi if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
223*b7893ccfSSadaf Ebrahimi imgpair = {imgpair.image, false, VkImageSubresource()};
224*b7893ccfSSadaf Ebrahimi auto imgsubIt = imageLayoutMap.find(imgpair);
225*b7893ccfSSadaf Ebrahimi if (imgsubIt == imageLayoutMap.end()) return false;
226*b7893ccfSSadaf Ebrahimi layout = imgsubIt->second.layout;
227*b7893ccfSSadaf Ebrahimi }
228*b7893ccfSSadaf Ebrahimi return true;
229*b7893ccfSSadaf Ebrahimi }
230*b7893ccfSSadaf Ebrahimi
FindLayouts(VkImage image,std::vector<VkImageLayout> & layouts)231*b7893ccfSSadaf Ebrahimi bool CoreChecks::FindLayouts(VkImage image, std::vector<VkImageLayout> &layouts) {
232*b7893ccfSSadaf Ebrahimi auto sub_data = imageSubresourceMap.find(image);
233*b7893ccfSSadaf Ebrahimi if (sub_data == imageSubresourceMap.end()) return false;
234*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(image);
235*b7893ccfSSadaf Ebrahimi if (!image_state) return false;
236*b7893ccfSSadaf Ebrahimi bool ignoreGlobal = false;
237*b7893ccfSSadaf Ebrahimi // TODO: Make this robust for >1 aspect mask. Now it will just say ignore potential errors in this case.
238*b7893ccfSSadaf Ebrahimi if (sub_data->second.size() >= (image_state->createInfo.arrayLayers * image_state->createInfo.mipLevels + 1)) {
239*b7893ccfSSadaf Ebrahimi ignoreGlobal = true;
240*b7893ccfSSadaf Ebrahimi }
241*b7893ccfSSadaf Ebrahimi for (auto imgsubpair : sub_data->second) {
242*b7893ccfSSadaf Ebrahimi if (ignoreGlobal && !imgsubpair.hasSubresource) continue;
243*b7893ccfSSadaf Ebrahimi auto img_data = imageLayoutMap.find(imgsubpair);
244*b7893ccfSSadaf Ebrahimi if (img_data != imageLayoutMap.end()) {
245*b7893ccfSSadaf Ebrahimi layouts.push_back(img_data->second.layout);
246*b7893ccfSSadaf Ebrahimi }
247*b7893ccfSSadaf Ebrahimi }
248*b7893ccfSSadaf Ebrahimi return true;
249*b7893ccfSSadaf Ebrahimi }
250*b7893ccfSSadaf Ebrahimi
FindLayout(const ImageSubresPairLayoutMap & imageLayoutMap,ImageSubresourcePair imgpair,VkImageLayout & layout,const VkImageAspectFlags aspectMask)251*b7893ccfSSadaf Ebrahimi bool CoreChecks::FindLayout(const ImageSubresPairLayoutMap &imageLayoutMap, ImageSubresourcePair imgpair, VkImageLayout &layout,
252*b7893ccfSSadaf Ebrahimi const VkImageAspectFlags aspectMask) {
253*b7893ccfSSadaf Ebrahimi if (!(imgpair.subresource.aspectMask & aspectMask)) {
254*b7893ccfSSadaf Ebrahimi return false;
255*b7893ccfSSadaf Ebrahimi }
256*b7893ccfSSadaf Ebrahimi imgpair.subresource.aspectMask = aspectMask;
257*b7893ccfSSadaf Ebrahimi auto imgsubIt = imageLayoutMap.find(imgpair);
258*b7893ccfSSadaf Ebrahimi if (imgsubIt == imageLayoutMap.end()) {
259*b7893ccfSSadaf Ebrahimi return false;
260*b7893ccfSSadaf Ebrahimi }
261*b7893ccfSSadaf Ebrahimi layout = imgsubIt->second.layout;
262*b7893ccfSSadaf Ebrahimi return true;
263*b7893ccfSSadaf Ebrahimi }
264*b7893ccfSSadaf Ebrahimi
265*b7893ccfSSadaf Ebrahimi // find layout in supplied map
FindLayout(const ImageSubresPairLayoutMap & imageLayoutMap,ImageSubresourcePair imgpair,VkImageLayout & layout) const266*b7893ccfSSadaf Ebrahimi bool CoreChecks::FindLayout(const ImageSubresPairLayoutMap &imageLayoutMap, ImageSubresourcePair imgpair,
267*b7893ccfSSadaf Ebrahimi VkImageLayout &layout) const {
268*b7893ccfSSadaf Ebrahimi layout = VK_IMAGE_LAYOUT_MAX_ENUM;
269*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_COLOR_BIT);
270*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_DEPTH_BIT);
271*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_STENCIL_BIT);
272*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_METADATA_BIT);
273*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
274*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_0_BIT_KHR);
275*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
276*b7893ccfSSadaf Ebrahimi FindLayout(imageLayoutMap, imgpair, layout, VK_IMAGE_ASPECT_PLANE_2_BIT_KHR);
277*b7893ccfSSadaf Ebrahimi }
278*b7893ccfSSadaf Ebrahimi // Image+subresource not found, look for image handle w/o subresource
279*b7893ccfSSadaf Ebrahimi if (layout == VK_IMAGE_LAYOUT_MAX_ENUM) {
280*b7893ccfSSadaf Ebrahimi imgpair = {imgpair.image, false, VkImageSubresource()};
281*b7893ccfSSadaf Ebrahimi auto imgsubIt = imageLayoutMap.find(imgpair);
282*b7893ccfSSadaf Ebrahimi if (imgsubIt == imageLayoutMap.end()) return false;
283*b7893ccfSSadaf Ebrahimi layout = imgsubIt->second.layout;
284*b7893ccfSSadaf Ebrahimi }
285*b7893ccfSSadaf Ebrahimi return true;
286*b7893ccfSSadaf Ebrahimi }
287*b7893ccfSSadaf Ebrahimi
288*b7893ccfSSadaf Ebrahimi // Set the layout on the global level
SetGlobalLayout(ImageSubresourcePair imgpair,const VkImageLayout & layout)289*b7893ccfSSadaf Ebrahimi void CoreChecks::SetGlobalLayout(ImageSubresourcePair imgpair, const VkImageLayout &layout) {
290*b7893ccfSSadaf Ebrahimi VkImage &image = imgpair.image;
291*b7893ccfSSadaf Ebrahimi auto data = imageLayoutMap.find(imgpair);
292*b7893ccfSSadaf Ebrahimi if (data != imageLayoutMap.end()) {
293*b7893ccfSSadaf Ebrahimi data->second.layout = layout; // Update
294*b7893ccfSSadaf Ebrahimi } else {
295*b7893ccfSSadaf Ebrahimi imageLayoutMap[imgpair].layout = layout; // Insert
296*b7893ccfSSadaf Ebrahimi }
297*b7893ccfSSadaf Ebrahimi auto &image_subresources = imageSubresourceMap[image];
298*b7893ccfSSadaf Ebrahimi auto subresource = std::find(image_subresources.begin(), image_subresources.end(), imgpair);
299*b7893ccfSSadaf Ebrahimi if (subresource == image_subresources.end()) {
300*b7893ccfSSadaf Ebrahimi image_subresources.push_back(imgpair);
301*b7893ccfSSadaf Ebrahimi }
302*b7893ccfSSadaf Ebrahimi }
303*b7893ccfSSadaf Ebrahimi
304*b7893ccfSSadaf Ebrahimi // Set image layout for given VkImageSubresourceRange struct
SetImageLayout(CMD_BUFFER_STATE * cb_node,const IMAGE_STATE & image_state,const VkImageSubresourceRange & image_subresource_range,VkImageLayout layout,VkImageLayout expected_layout)305*b7893ccfSSadaf Ebrahimi void CoreChecks::SetImageLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &image_state,
306*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &image_subresource_range, VkImageLayout layout,
307*b7893ccfSSadaf Ebrahimi VkImageLayout expected_layout) {
308*b7893ccfSSadaf Ebrahimi auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state);
309*b7893ccfSSadaf Ebrahimi assert(subresource_map); // the non-const getter must return a valid pointer
310*b7893ccfSSadaf Ebrahimi if (subresource_map->SetSubresourceRangeLayout(*cb_node, image_subresource_range, layout, expected_layout)) {
311*b7893ccfSSadaf Ebrahimi cb_node->image_layout_change_count++; // Change the version of this data to force revalidation
312*b7893ccfSSadaf Ebrahimi }
313*b7893ccfSSadaf Ebrahimi }
314*b7893ccfSSadaf Ebrahimi
315*b7893ccfSSadaf Ebrahimi // Set the initial image layout for all slices of an image view
SetImageViewInitialLayout(CMD_BUFFER_STATE * cb_node,const IMAGE_VIEW_STATE & view_state,VkImageLayout layout)316*b7893ccfSSadaf Ebrahimi void CoreChecks::SetImageViewInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout) {
317*b7893ccfSSadaf Ebrahimi if (disabled.image_layout_validation) {
318*b7893ccfSSadaf Ebrahimi return;
319*b7893ccfSSadaf Ebrahimi }
320*b7893ccfSSadaf Ebrahimi IMAGE_STATE *image_state = GetImageState(view_state.create_info.image);
321*b7893ccfSSadaf Ebrahimi if (image_state) {
322*b7893ccfSSadaf Ebrahimi auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, *image_state);
323*b7893ccfSSadaf Ebrahimi subresource_map->SetSubresourceRangeInitialLayout(*cb_node, view_state.normalized_subresource_range, layout, &view_state);
324*b7893ccfSSadaf Ebrahimi }
325*b7893ccfSSadaf Ebrahimi }
326*b7893ccfSSadaf Ebrahimi
327*b7893ccfSSadaf Ebrahimi // Set the initial image layout for a passed non-normalized subresource range
SetImageInitialLayout(CMD_BUFFER_STATE * cb_node,const IMAGE_STATE & image_state,const VkImageSubresourceRange & range,VkImageLayout layout)328*b7893ccfSSadaf Ebrahimi void CoreChecks::SetImageInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &image_state,
329*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &range, VkImageLayout layout) {
330*b7893ccfSSadaf Ebrahimi auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state);
331*b7893ccfSSadaf Ebrahimi assert(subresource_map);
332*b7893ccfSSadaf Ebrahimi subresource_map->SetSubresourceRangeInitialLayout(*cb_node, NormalizeSubresourceRange(image_state, range), layout);
333*b7893ccfSSadaf Ebrahimi }
334*b7893ccfSSadaf Ebrahimi
SetImageInitialLayout(CMD_BUFFER_STATE * cb_node,VkImage image,const VkImageSubresourceRange & range,VkImageLayout layout)335*b7893ccfSSadaf Ebrahimi void CoreChecks::SetImageInitialLayout(CMD_BUFFER_STATE *cb_node, VkImage image, const VkImageSubresourceRange &range,
336*b7893ccfSSadaf Ebrahimi VkImageLayout layout) {
337*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *image_state = GetImageState(image);
338*b7893ccfSSadaf Ebrahimi if (!image_state) return;
339*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *image_state, range, layout);
340*b7893ccfSSadaf Ebrahimi };
341*b7893ccfSSadaf Ebrahimi
SetImageInitialLayout(CMD_BUFFER_STATE * cb_node,const IMAGE_STATE & image_state,const VkImageSubresourceLayers & layers,VkImageLayout layout)342*b7893ccfSSadaf Ebrahimi void CoreChecks::SetImageInitialLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_STATE &image_state,
343*b7893ccfSSadaf Ebrahimi const VkImageSubresourceLayers &layers, VkImageLayout layout) {
344*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, image_state, RangeFromLayers(layers), layout);
345*b7893ccfSSadaf Ebrahimi }
346*b7893ccfSSadaf Ebrahimi
347*b7893ccfSSadaf Ebrahimi // Set image layout for all slices of an image view
SetImageViewLayout(CMD_BUFFER_STATE * cb_node,const IMAGE_VIEW_STATE & view_state,VkImageLayout layout)348*b7893ccfSSadaf Ebrahimi void CoreChecks::SetImageViewLayout(CMD_BUFFER_STATE *cb_node, const IMAGE_VIEW_STATE &view_state, VkImageLayout layout) {
349*b7893ccfSSadaf Ebrahimi IMAGE_STATE *image_state = GetImageState(view_state.create_info.image);
350*b7893ccfSSadaf Ebrahimi if (!image_state) return; // TODO: track/report stale image references
351*b7893ccfSSadaf Ebrahimi
352*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange sub_range = view_state.normalized_subresource_range;
353*b7893ccfSSadaf Ebrahimi // When changing the layout of a 3D image subresource via a 2D or 2D_ARRRAY image view, all depth slices of
354*b7893ccfSSadaf Ebrahimi // the subresource mip level(s) are transitioned, ignoring any layers restriction in the subresource info.
355*b7893ccfSSadaf Ebrahimi if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) && (view_state.create_info.viewType != VK_IMAGE_VIEW_TYPE_3D)) {
356*b7893ccfSSadaf Ebrahimi sub_range.baseArrayLayer = 0;
357*b7893ccfSSadaf Ebrahimi sub_range.layerCount = image_state->createInfo.extent.depth;
358*b7893ccfSSadaf Ebrahimi }
359*b7893ccfSSadaf Ebrahimi
360*b7893ccfSSadaf Ebrahimi SetImageLayout(cb_node, *image_state, sub_range, layout);
361*b7893ccfSSadaf Ebrahimi }
362*b7893ccfSSadaf Ebrahimi
ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version,VkImageLayout layout,VkImage image,VkImageView image_view,VkFramebuffer framebuffer,VkRenderPass renderpass,uint32_t attachment_index,const char * variable_name) const363*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateRenderPassLayoutAgainstFramebufferImageUsage(RenderPassCreateVersion rp_version, VkImageLayout layout,
364*b7893ccfSSadaf Ebrahimi VkImage image, VkImageView image_view,
365*b7893ccfSSadaf Ebrahimi VkFramebuffer framebuffer, VkRenderPass renderpass,
366*b7893ccfSSadaf Ebrahimi uint32_t attachment_index, const char *variable_name) const {
367*b7893ccfSSadaf Ebrahimi bool skip = false;
368*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(image);
369*b7893ccfSSadaf Ebrahimi const char *vuid;
370*b7893ccfSSadaf Ebrahimi const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
371*b7893ccfSSadaf Ebrahimi
372*b7893ccfSSadaf Ebrahimi if (!image_state) {
373*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
374*b7893ccfSSadaf Ebrahimi "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
375*b7893ccfSSadaf Ebrahimi "Render Pass begin with %s uses %s where pAttachments[%" PRIu32 "] = %s, which refers to an invalid image",
376*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(renderpass).c_str(), report_data->FormatHandle(framebuffer).c_str(),
377*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(image_view).c_str());
378*b7893ccfSSadaf Ebrahimi return skip;
379*b7893ccfSSadaf Ebrahimi }
380*b7893ccfSSadaf Ebrahimi
381*b7893ccfSSadaf Ebrahimi auto image_usage = image_state->createInfo.usage;
382*b7893ccfSSadaf Ebrahimi
383*b7893ccfSSadaf Ebrahimi // Check for layouts that mismatch image usages in the framebuffer
384*b7893ccfSSadaf Ebrahimi if (layout == VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT)) {
385*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03094" : "VUID-vkCmdBeginRenderPass-initialLayout-00895";
386*b7893ccfSSadaf Ebrahimi skip |=
387*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
388*b7893ccfSSadaf Ebrahimi "Layout/usage mismatch for attachment %u in %s"
389*b7893ccfSSadaf Ebrahimi " - the %s is %s but the image attached to %s via %s"
390*b7893ccfSSadaf Ebrahimi " was not created with VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT",
391*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name, string_VkImageLayout(layout),
392*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer).c_str(), report_data->FormatHandle(image_view).c_str());
393*b7893ccfSSadaf Ebrahimi }
394*b7893ccfSSadaf Ebrahimi
395*b7893ccfSSadaf Ebrahimi if (layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL &&
396*b7893ccfSSadaf Ebrahimi !(image_usage & (VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT))) {
397*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03097" : "VUID-vkCmdBeginRenderPass-initialLayout-00897";
398*b7893ccfSSadaf Ebrahimi skip |=
399*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
400*b7893ccfSSadaf Ebrahimi "Layout/usage mismatch for attachment %u in %s"
401*b7893ccfSSadaf Ebrahimi " - the %s is %s but the image attached to %s via %s"
402*b7893ccfSSadaf Ebrahimi " was not created with VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT or VK_IMAGE_USAGE_SAMPLED_BIT",
403*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name, string_VkImageLayout(layout),
404*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer).c_str(), report_data->FormatHandle(image_view).c_str());
405*b7893ccfSSadaf Ebrahimi }
406*b7893ccfSSadaf Ebrahimi
407*b7893ccfSSadaf Ebrahimi if (layout == VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_SRC_BIT)) {
408*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03098" : "VUID-vkCmdBeginRenderPass-initialLayout-00898";
409*b7893ccfSSadaf Ebrahimi skip |=
410*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
411*b7893ccfSSadaf Ebrahimi "Layout/usage mismatch for attachment %u in %s"
412*b7893ccfSSadaf Ebrahimi " - the %s is %s but the image attached to %s via %s"
413*b7893ccfSSadaf Ebrahimi " was not created with VK_IMAGE_USAGE_TRANSFER_SRC_BIT",
414*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name, string_VkImageLayout(layout),
415*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer).c_str(), report_data->FormatHandle(image_view).c_str());
416*b7893ccfSSadaf Ebrahimi }
417*b7893ccfSSadaf Ebrahimi
418*b7893ccfSSadaf Ebrahimi if (layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL && !(image_usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
419*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03099" : "VUID-vkCmdBeginRenderPass-initialLayout-00899";
420*b7893ccfSSadaf Ebrahimi skip |=
421*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
422*b7893ccfSSadaf Ebrahimi "Layout/usage mismatch for attachment %u in %s"
423*b7893ccfSSadaf Ebrahimi " - the %s is %s but the image attached to %s via %s"
424*b7893ccfSSadaf Ebrahimi " was not created with VK_IMAGE_USAGE_TRANSFER_DST_BIT",
425*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name, string_VkImageLayout(layout),
426*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer).c_str(), report_data->FormatHandle(image_view).c_str());
427*b7893ccfSSadaf Ebrahimi }
428*b7893ccfSSadaf Ebrahimi
429*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance2) {
430*b7893ccfSSadaf Ebrahimi if ((layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL ||
431*b7893ccfSSadaf Ebrahimi layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL ||
432*b7893ccfSSadaf Ebrahimi layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
433*b7893ccfSSadaf Ebrahimi layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
434*b7893ccfSSadaf Ebrahimi !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
435*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-vkCmdBeginRenderPass2KHR-initialLayout-03096" : "VUID-vkCmdBeginRenderPass-initialLayout-01758";
436*b7893ccfSSadaf Ebrahimi skip |= log_msg(
437*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image), vuid,
438*b7893ccfSSadaf Ebrahimi "Layout/usage mismatch for attachment %u in %s"
439*b7893ccfSSadaf Ebrahimi " - the %s is %s but the image attached to %s via %s"
440*b7893ccfSSadaf Ebrahimi " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
441*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name, string_VkImageLayout(layout),
442*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer).c_str(), report_data->FormatHandle(image_view).c_str());
443*b7893ccfSSadaf Ebrahimi }
444*b7893ccfSSadaf Ebrahimi } else {
445*b7893ccfSSadaf Ebrahimi // The create render pass 2 extension requires maintenance 2 (the previous branch), so no vuid switch needed here.
446*b7893ccfSSadaf Ebrahimi if ((layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL ||
447*b7893ccfSSadaf Ebrahimi layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) &&
448*b7893ccfSSadaf Ebrahimi !(image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
449*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
450*b7893ccfSSadaf Ebrahimi HandleToUint64(image), "VUID-vkCmdBeginRenderPass-initialLayout-00896",
451*b7893ccfSSadaf Ebrahimi "Layout/usage mismatch for attachment %u in %s"
452*b7893ccfSSadaf Ebrahimi " - the %s is %s but the image attached to %s via %s"
453*b7893ccfSSadaf Ebrahimi " was not created with VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT",
454*b7893ccfSSadaf Ebrahimi attachment_index, report_data->FormatHandle(renderpass).c_str(), variable_name,
455*b7893ccfSSadaf Ebrahimi string_VkImageLayout(layout), report_data->FormatHandle(framebuffer).c_str(),
456*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image_view).c_str());
457*b7893ccfSSadaf Ebrahimi }
458*b7893ccfSSadaf Ebrahimi }
459*b7893ccfSSadaf Ebrahimi return skip;
460*b7893ccfSSadaf Ebrahimi }
461*b7893ccfSSadaf Ebrahimi
VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version,const CMD_BUFFER_STATE * pCB,const VkRenderPassBeginInfo * pRenderPassBegin,const FRAMEBUFFER_STATE * framebuffer_state) const462*b7893ccfSSadaf Ebrahimi bool CoreChecks::VerifyFramebufferAndRenderPassLayouts(RenderPassCreateVersion rp_version, const CMD_BUFFER_STATE *pCB,
463*b7893ccfSSadaf Ebrahimi const VkRenderPassBeginInfo *pRenderPassBegin,
464*b7893ccfSSadaf Ebrahimi const FRAMEBUFFER_STATE *framebuffer_state) const {
465*b7893ccfSSadaf Ebrahimi bool skip = false;
466*b7893ccfSSadaf Ebrahimi auto const pRenderPassInfo = GetRenderPassState(pRenderPassBegin->renderPass)->createInfo.ptr();
467*b7893ccfSSadaf Ebrahimi auto const &framebufferInfo = framebuffer_state->createInfo;
468*b7893ccfSSadaf Ebrahimi const VkImageView *attachments = framebufferInfo.pAttachments;
469*b7893ccfSSadaf Ebrahimi
470*b7893ccfSSadaf Ebrahimi auto render_pass = GetRenderPassState(pRenderPassBegin->renderPass)->renderPass;
471*b7893ccfSSadaf Ebrahimi auto framebuffer = framebuffer_state->framebuffer;
472*b7893ccfSSadaf Ebrahimi
473*b7893ccfSSadaf Ebrahimi if (pRenderPassInfo->attachmentCount != framebufferInfo.attachmentCount) {
474*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
475*b7893ccfSSadaf Ebrahimi HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidRenderpass,
476*b7893ccfSSadaf Ebrahimi "You cannot start a render pass using a framebuffer with a different number of attachments.");
477*b7893ccfSSadaf Ebrahimi }
478*b7893ccfSSadaf Ebrahimi
479*b7893ccfSSadaf Ebrahimi const auto *attachmentInfo = lvl_find_in_chain<VkRenderPassAttachmentBeginInfoKHR>(pRenderPassBegin->pNext);
480*b7893ccfSSadaf Ebrahimi if (((framebufferInfo.flags & VK_FRAMEBUFFER_CREATE_IMAGELESS_BIT_KHR) != 0) && attachmentInfo != nullptr) {
481*b7893ccfSSadaf Ebrahimi attachments = attachmentInfo->pAttachments;
482*b7893ccfSSadaf Ebrahimi }
483*b7893ccfSSadaf Ebrahimi
484*b7893ccfSSadaf Ebrahimi if (attachments != nullptr) {
485*b7893ccfSSadaf Ebrahimi const auto *const_pCB = static_cast<const CMD_BUFFER_STATE *>(pCB);
486*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
487*b7893ccfSSadaf Ebrahimi auto image_view = attachments[i];
488*b7893ccfSSadaf Ebrahimi auto view_state = GetImageViewState(image_view);
489*b7893ccfSSadaf Ebrahimi
490*b7893ccfSSadaf Ebrahimi if (!view_state) {
491*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
492*b7893ccfSSadaf Ebrahimi HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
493*b7893ccfSSadaf Ebrahimi "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s is not a valid VkImageView handle",
494*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i,
495*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image_view).c_str());
496*b7893ccfSSadaf Ebrahimi continue;
497*b7893ccfSSadaf Ebrahimi }
498*b7893ccfSSadaf Ebrahimi
499*b7893ccfSSadaf Ebrahimi const VkImage image = view_state->create_info.image;
500*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *image_state = GetImageState(image);
501*b7893ccfSSadaf Ebrahimi
502*b7893ccfSSadaf Ebrahimi if (!image_state) {
503*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_RENDER_PASS_EXT,
504*b7893ccfSSadaf Ebrahimi HandleToUint64(pRenderPassBegin->renderPass), "VUID-VkRenderPassBeginInfo-framebuffer-parameter",
505*b7893ccfSSadaf Ebrahimi "vkCmdBeginRenderPass(): %s pAttachments[%" PRIu32 "] = %s references non-extant %s.",
506*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(framebuffer_state->framebuffer).c_str(), i,
507*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image_view).c_str(), report_data->FormatHandle(image).c_str());
508*b7893ccfSSadaf Ebrahimi continue;
509*b7893ccfSSadaf Ebrahimi }
510*b7893ccfSSadaf Ebrahimi auto attachment_initial_layout = pRenderPassInfo->pAttachments[i].initialLayout;
511*b7893ccfSSadaf Ebrahimi auto final_layout = pRenderPassInfo->pAttachments[i].finalLayout;
512*b7893ccfSSadaf Ebrahimi
513*b7893ccfSSadaf Ebrahimi // Cast pCB to const because we don't want to create entries that don't exist here (in case the key changes to something
514*b7893ccfSSadaf Ebrahimi // in common with the non-const version.)
515*b7893ccfSSadaf Ebrahimi const ImageSubresourceLayoutMap *subresource_map =
516*b7893ccfSSadaf Ebrahimi (attachment_initial_layout != VK_IMAGE_LAYOUT_UNDEFINED) ? GetImageSubresourceLayoutMap(const_pCB, image) : nullptr;
517*b7893ccfSSadaf Ebrahimi
518*b7893ccfSSadaf Ebrahimi if (subresource_map) { // If no layout information for image yet, will be checked at QueueSubmit time
519*b7893ccfSSadaf Ebrahimi LayoutUseCheckAndMessage layout_check(subresource_map);
520*b7893ccfSSadaf Ebrahimi bool subres_skip = false;
521*b7893ccfSSadaf Ebrahimi auto subresource_cb = [this, i, attachment_initial_layout, &layout_check, &subres_skip](
522*b7893ccfSSadaf Ebrahimi const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
523*b7893ccfSSadaf Ebrahimi if (!layout_check.Check(subres, attachment_initial_layout, layout, initial_layout)) {
524*b7893ccfSSadaf Ebrahimi subres_skip |=
525*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
526*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidRenderpass,
527*b7893ccfSSadaf Ebrahimi "You cannot start a render pass using attachment %u where the render pass initial layout is %s "
528*b7893ccfSSadaf Ebrahimi "and the %s layout of the attachment is %s. The layouts must match, or the render "
529*b7893ccfSSadaf Ebrahimi "pass initial layout for the attachment must be VK_IMAGE_LAYOUT_UNDEFINED",
530*b7893ccfSSadaf Ebrahimi i, string_VkImageLayout(attachment_initial_layout), layout_check.message,
531*b7893ccfSSadaf Ebrahimi string_VkImageLayout(layout_check.layout));
532*b7893ccfSSadaf Ebrahimi }
533*b7893ccfSSadaf Ebrahimi return !subres_skip; // quit checking subresources once we fail once
534*b7893ccfSSadaf Ebrahimi };
535*b7893ccfSSadaf Ebrahimi
536*b7893ccfSSadaf Ebrahimi subresource_map->ForRange(view_state->normalized_subresource_range, subresource_cb);
537*b7893ccfSSadaf Ebrahimi skip |= subres_skip;
538*b7893ccfSSadaf Ebrahimi }
539*b7893ccfSSadaf Ebrahimi
540*b7893ccfSSadaf Ebrahimi ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_initial_layout, image, image_view,
541*b7893ccfSSadaf Ebrahimi framebuffer, render_pass, i, "initial layout");
542*b7893ccfSSadaf Ebrahimi
543*b7893ccfSSadaf Ebrahimi ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, final_layout, image, image_view, framebuffer,
544*b7893ccfSSadaf Ebrahimi render_pass, i, "final layout");
545*b7893ccfSSadaf Ebrahimi }
546*b7893ccfSSadaf Ebrahimi
547*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < pRenderPassInfo->subpassCount; ++j) {
548*b7893ccfSSadaf Ebrahimi auto &subpass = pRenderPassInfo->pSubpasses[j];
549*b7893ccfSSadaf Ebrahimi for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].inputAttachmentCount; ++k) {
550*b7893ccfSSadaf Ebrahimi auto &attachment_ref = subpass.pInputAttachments[k];
551*b7893ccfSSadaf Ebrahimi if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
552*b7893ccfSSadaf Ebrahimi auto image_view = attachments[attachment_ref.attachment];
553*b7893ccfSSadaf Ebrahimi auto view_state = GetImageViewState(image_view);
554*b7893ccfSSadaf Ebrahimi
555*b7893ccfSSadaf Ebrahimi if (view_state) {
556*b7893ccfSSadaf Ebrahimi auto image = view_state->create_info.image;
557*b7893ccfSSadaf Ebrahimi ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view,
558*b7893ccfSSadaf Ebrahimi framebuffer, render_pass, attachment_ref.attachment,
559*b7893ccfSSadaf Ebrahimi "input attachment layout");
560*b7893ccfSSadaf Ebrahimi }
561*b7893ccfSSadaf Ebrahimi }
562*b7893ccfSSadaf Ebrahimi }
563*b7893ccfSSadaf Ebrahimi
564*b7893ccfSSadaf Ebrahimi for (uint32_t k = 0; k < pRenderPassInfo->pSubpasses[j].colorAttachmentCount; ++k) {
565*b7893ccfSSadaf Ebrahimi auto &attachment_ref = subpass.pColorAttachments[k];
566*b7893ccfSSadaf Ebrahimi if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
567*b7893ccfSSadaf Ebrahimi auto image_view = attachments[attachment_ref.attachment];
568*b7893ccfSSadaf Ebrahimi auto view_state = GetImageViewState(image_view);
569*b7893ccfSSadaf Ebrahimi
570*b7893ccfSSadaf Ebrahimi if (view_state) {
571*b7893ccfSSadaf Ebrahimi auto image = view_state->create_info.image;
572*b7893ccfSSadaf Ebrahimi ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view,
573*b7893ccfSSadaf Ebrahimi framebuffer, render_pass, attachment_ref.attachment,
574*b7893ccfSSadaf Ebrahimi "color attachment layout");
575*b7893ccfSSadaf Ebrahimi if (subpass.pResolveAttachments) {
576*b7893ccfSSadaf Ebrahimi ValidateRenderPassLayoutAgainstFramebufferImageUsage(
577*b7893ccfSSadaf Ebrahimi rp_version, attachment_ref.layout, image, image_view, framebuffer, render_pass,
578*b7893ccfSSadaf Ebrahimi attachment_ref.attachment, "resolve attachment layout");
579*b7893ccfSSadaf Ebrahimi }
580*b7893ccfSSadaf Ebrahimi }
581*b7893ccfSSadaf Ebrahimi }
582*b7893ccfSSadaf Ebrahimi }
583*b7893ccfSSadaf Ebrahimi
584*b7893ccfSSadaf Ebrahimi if (pRenderPassInfo->pSubpasses[j].pDepthStencilAttachment) {
585*b7893ccfSSadaf Ebrahimi auto &attachment_ref = *subpass.pDepthStencilAttachment;
586*b7893ccfSSadaf Ebrahimi if (attachment_ref.attachment != VK_ATTACHMENT_UNUSED) {
587*b7893ccfSSadaf Ebrahimi auto image_view = attachments[attachment_ref.attachment];
588*b7893ccfSSadaf Ebrahimi auto view_state = GetImageViewState(image_view);
589*b7893ccfSSadaf Ebrahimi
590*b7893ccfSSadaf Ebrahimi if (view_state) {
591*b7893ccfSSadaf Ebrahimi auto image = view_state->create_info.image;
592*b7893ccfSSadaf Ebrahimi ValidateRenderPassLayoutAgainstFramebufferImageUsage(rp_version, attachment_ref.layout, image, image_view,
593*b7893ccfSSadaf Ebrahimi framebuffer, render_pass, attachment_ref.attachment,
594*b7893ccfSSadaf Ebrahimi "input attachment layout");
595*b7893ccfSSadaf Ebrahimi }
596*b7893ccfSSadaf Ebrahimi }
597*b7893ccfSSadaf Ebrahimi }
598*b7893ccfSSadaf Ebrahimi }
599*b7893ccfSSadaf Ebrahimi }
600*b7893ccfSSadaf Ebrahimi return skip;
601*b7893ccfSSadaf Ebrahimi }
602*b7893ccfSSadaf Ebrahimi
TransitionAttachmentRefLayout(CMD_BUFFER_STATE * pCB,FRAMEBUFFER_STATE * pFramebuffer,const safe_VkAttachmentReference2KHR & ref)603*b7893ccfSSadaf Ebrahimi void CoreChecks::TransitionAttachmentRefLayout(CMD_BUFFER_STATE *pCB, FRAMEBUFFER_STATE *pFramebuffer,
604*b7893ccfSSadaf Ebrahimi const safe_VkAttachmentReference2KHR &ref) {
605*b7893ccfSSadaf Ebrahimi if (ref.attachment != VK_ATTACHMENT_UNUSED) {
606*b7893ccfSSadaf Ebrahimi auto image_view = GetAttachmentImageViewState(pFramebuffer, ref.attachment);
607*b7893ccfSSadaf Ebrahimi if (image_view) {
608*b7893ccfSSadaf Ebrahimi SetImageViewLayout(pCB, *image_view, ref.layout);
609*b7893ccfSSadaf Ebrahimi }
610*b7893ccfSSadaf Ebrahimi }
611*b7893ccfSSadaf Ebrahimi }
612*b7893ccfSSadaf Ebrahimi
TransitionSubpassLayouts(CMD_BUFFER_STATE * pCB,const RENDER_PASS_STATE * render_pass_state,const int subpass_index,FRAMEBUFFER_STATE * framebuffer_state)613*b7893ccfSSadaf Ebrahimi void CoreChecks::TransitionSubpassLayouts(CMD_BUFFER_STATE *pCB, const RENDER_PASS_STATE *render_pass_state,
614*b7893ccfSSadaf Ebrahimi const int subpass_index, FRAMEBUFFER_STATE *framebuffer_state) {
615*b7893ccfSSadaf Ebrahimi assert(render_pass_state);
616*b7893ccfSSadaf Ebrahimi
617*b7893ccfSSadaf Ebrahimi if (framebuffer_state) {
618*b7893ccfSSadaf Ebrahimi auto const &subpass = render_pass_state->createInfo.pSubpasses[subpass_index];
619*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
620*b7893ccfSSadaf Ebrahimi TransitionAttachmentRefLayout(pCB, framebuffer_state, subpass.pInputAttachments[j]);
621*b7893ccfSSadaf Ebrahimi }
622*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
623*b7893ccfSSadaf Ebrahimi TransitionAttachmentRefLayout(pCB, framebuffer_state, subpass.pColorAttachments[j]);
624*b7893ccfSSadaf Ebrahimi }
625*b7893ccfSSadaf Ebrahimi if (subpass.pDepthStencilAttachment) {
626*b7893ccfSSadaf Ebrahimi TransitionAttachmentRefLayout(pCB, framebuffer_state, *subpass.pDepthStencilAttachment);
627*b7893ccfSSadaf Ebrahimi }
628*b7893ccfSSadaf Ebrahimi }
629*b7893ccfSSadaf Ebrahimi }
630*b7893ccfSSadaf Ebrahimi
631*b7893ccfSSadaf Ebrahimi // Transition the layout state for renderpass attachments based on the BeginRenderPass() call. This includes:
632*b7893ccfSSadaf Ebrahimi // 1. Transition into initialLayout state
633*b7893ccfSSadaf Ebrahimi // 2. Transition from initialLayout to layout used in subpass 0
TransitionBeginRenderPassLayouts(CMD_BUFFER_STATE * cb_state,const RENDER_PASS_STATE * render_pass_state,FRAMEBUFFER_STATE * framebuffer_state)634*b7893ccfSSadaf Ebrahimi void CoreChecks::TransitionBeginRenderPassLayouts(CMD_BUFFER_STATE *cb_state, const RENDER_PASS_STATE *render_pass_state,
635*b7893ccfSSadaf Ebrahimi FRAMEBUFFER_STATE *framebuffer_state) {
636*b7893ccfSSadaf Ebrahimi // First transition into initialLayout
637*b7893ccfSSadaf Ebrahimi auto const rpci = render_pass_state->createInfo.ptr();
638*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < rpci->attachmentCount; ++i) {
639*b7893ccfSSadaf Ebrahimi auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
640*b7893ccfSSadaf Ebrahimi if (view_state) {
641*b7893ccfSSadaf Ebrahimi SetImageViewLayout(cb_state, *view_state, rpci->pAttachments[i].initialLayout);
642*b7893ccfSSadaf Ebrahimi }
643*b7893ccfSSadaf Ebrahimi }
644*b7893ccfSSadaf Ebrahimi // Now transition for first subpass (index 0)
645*b7893ccfSSadaf Ebrahimi TransitionSubpassLayouts(cb_state, render_pass_state, 0, framebuffer_state);
646*b7893ccfSSadaf Ebrahimi }
647*b7893ccfSSadaf Ebrahimi
VerifyAspectsPresent(VkImageAspectFlags aspect_mask,VkFormat format)648*b7893ccfSSadaf Ebrahimi bool VerifyAspectsPresent(VkImageAspectFlags aspect_mask, VkFormat format) {
649*b7893ccfSSadaf Ebrahimi if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != 0) {
650*b7893ccfSSadaf Ebrahimi if (!(FormatIsColor(format) || FormatIsMultiplane(format))) return false;
651*b7893ccfSSadaf Ebrahimi }
652*b7893ccfSSadaf Ebrahimi if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != 0) {
653*b7893ccfSSadaf Ebrahimi if (!FormatHasDepth(format)) return false;
654*b7893ccfSSadaf Ebrahimi }
655*b7893ccfSSadaf Ebrahimi if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != 0) {
656*b7893ccfSSadaf Ebrahimi if (!FormatHasStencil(format)) return false;
657*b7893ccfSSadaf Ebrahimi }
658*b7893ccfSSadaf Ebrahimi if (0 !=
659*b7893ccfSSadaf Ebrahimi (aspect_mask & (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR | VK_IMAGE_ASPECT_PLANE_2_BIT_KHR))) {
660*b7893ccfSSadaf Ebrahimi if (FormatPlaneCount(format) == 1) return false;
661*b7893ccfSSadaf Ebrahimi }
662*b7893ccfSSadaf Ebrahimi return true;
663*b7893ccfSSadaf Ebrahimi }
664*b7893ccfSSadaf Ebrahimi
665*b7893ccfSSadaf Ebrahimi // Verify an ImageMemoryBarrier's old/new ImageLayouts are compatible with the Image's ImageUsageFlags.
ValidateBarrierLayoutToImageUsage(const VkImageMemoryBarrier & img_barrier,bool new_not_old,VkImageUsageFlags usage_flags,const char * func_name,const char * barrier_pname)666*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBarrierLayoutToImageUsage(const VkImageMemoryBarrier &img_barrier, bool new_not_old,
667*b7893ccfSSadaf Ebrahimi VkImageUsageFlags usage_flags, const char *func_name,
668*b7893ccfSSadaf Ebrahimi const char *barrier_pname) {
669*b7893ccfSSadaf Ebrahimi bool skip = false;
670*b7893ccfSSadaf Ebrahimi const VkImageLayout layout = (new_not_old) ? img_barrier.newLayout : img_barrier.oldLayout;
671*b7893ccfSSadaf Ebrahimi const char *msg_code = kVUIDUndefined; // sentinel value meaning "no error"
672*b7893ccfSSadaf Ebrahimi
673*b7893ccfSSadaf Ebrahimi switch (layout) {
674*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
675*b7893ccfSSadaf Ebrahimi if ((usage_flags & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) == 0) {
676*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01208";
677*b7893ccfSSadaf Ebrahimi }
678*b7893ccfSSadaf Ebrahimi break;
679*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
680*b7893ccfSSadaf Ebrahimi if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
681*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01209";
682*b7893ccfSSadaf Ebrahimi }
683*b7893ccfSSadaf Ebrahimi break;
684*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
685*b7893ccfSSadaf Ebrahimi if ((usage_flags & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) == 0) {
686*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01210";
687*b7893ccfSSadaf Ebrahimi }
688*b7893ccfSSadaf Ebrahimi break;
689*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
690*b7893ccfSSadaf Ebrahimi if ((usage_flags & (VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT)) == 0) {
691*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01211";
692*b7893ccfSSadaf Ebrahimi }
693*b7893ccfSSadaf Ebrahimi break;
694*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL:
695*b7893ccfSSadaf Ebrahimi if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_SRC_BIT) == 0) {
696*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01212";
697*b7893ccfSSadaf Ebrahimi }
698*b7893ccfSSadaf Ebrahimi break;
699*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL:
700*b7893ccfSSadaf Ebrahimi if ((usage_flags & VK_IMAGE_USAGE_TRANSFER_DST_BIT) == 0) {
701*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-01213";
702*b7893ccfSSadaf Ebrahimi }
703*b7893ccfSSadaf Ebrahimi break;
704*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_SHADING_RATE_OPTIMAL_NV:
705*b7893ccfSSadaf Ebrahimi if ((usage_flags & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) == 0) {
706*b7893ccfSSadaf Ebrahimi msg_code = "VUID-VkImageMemoryBarrier-oldLayout-02088";
707*b7893ccfSSadaf Ebrahimi }
708*b7893ccfSSadaf Ebrahimi break;
709*b7893ccfSSadaf Ebrahimi default:
710*b7893ccfSSadaf Ebrahimi // Other VkImageLayout values do not have VUs defined in this context.
711*b7893ccfSSadaf Ebrahimi break;
712*b7893ccfSSadaf Ebrahimi }
713*b7893ccfSSadaf Ebrahimi
714*b7893ccfSSadaf Ebrahimi if (msg_code != kVUIDUndefined) {
715*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
716*b7893ccfSSadaf Ebrahimi HandleToUint64(img_barrier.image), msg_code,
717*b7893ccfSSadaf Ebrahimi "%s: Image barrier %s %s Layout=%s is not compatible with %s usage flags 0x%" PRIx32 ".", func_name,
718*b7893ccfSSadaf Ebrahimi barrier_pname, ((new_not_old) ? "new" : "old"), string_VkImageLayout(layout),
719*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(img_barrier.image).c_str(), usage_flags);
720*b7893ccfSSadaf Ebrahimi }
721*b7893ccfSSadaf Ebrahimi return skip;
722*b7893ccfSSadaf Ebrahimi }
723*b7893ccfSSadaf Ebrahimi
724*b7893ccfSSadaf Ebrahimi // Verify image barriers are compatible with the images they reference.
ValidateBarriersToImages(CMD_BUFFER_STATE const * cb_state,uint32_t imageMemoryBarrierCount,const VkImageMemoryBarrier * pImageMemoryBarriers,const char * func_name)725*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBarriersToImages(CMD_BUFFER_STATE const *cb_state, uint32_t imageMemoryBarrierCount,
726*b7893ccfSSadaf Ebrahimi const VkImageMemoryBarrier *pImageMemoryBarriers, const char *func_name) {
727*b7893ccfSSadaf Ebrahimi bool skip = false;
728*b7893ccfSSadaf Ebrahimi
729*b7893ccfSSadaf Ebrahimi // Scoreboard for checking for duplicate and inconsistent barriers to images
730*b7893ccfSSadaf Ebrahimi struct ImageBarrierScoreboardEntry {
731*b7893ccfSSadaf Ebrahimi uint32_t index;
732*b7893ccfSSadaf Ebrahimi // This is designed for temporary storage within the scope of the API call. If retained storage of the barriers is
733*b7893ccfSSadaf Ebrahimi // required, copies should be made and smart or unique pointers used in some other stucture (or this one refactored)
734*b7893ccfSSadaf Ebrahimi const VkImageMemoryBarrier *barrier;
735*b7893ccfSSadaf Ebrahimi };
736*b7893ccfSSadaf Ebrahimi using ImageBarrierScoreboardSubresMap = std::unordered_map<VkImageSubresourceRange, ImageBarrierScoreboardEntry>;
737*b7893ccfSSadaf Ebrahimi using ImageBarrierScoreboardImageMap = std::unordered_map<VkImage, ImageBarrierScoreboardSubresMap>;
738*b7893ccfSSadaf Ebrahimi
739*b7893ccfSSadaf Ebrahimi // Scoreboard for duplicate layout transition barriers within the list
740*b7893ccfSSadaf Ebrahimi // Pointers retained in the scoreboard only have the lifetime of *this* call (i.e. within the scope of the API call)
741*b7893ccfSSadaf Ebrahimi ImageBarrierScoreboardImageMap layout_transitions;
742*b7893ccfSSadaf Ebrahimi
743*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < imageMemoryBarrierCount; ++i) {
744*b7893ccfSSadaf Ebrahimi const auto &img_barrier = pImageMemoryBarriers[i];
745*b7893ccfSSadaf Ebrahimi const std::string barrier_pname = "pImageMemoryBarrier[" + std::to_string(i) + "]";
746*b7893ccfSSadaf Ebrahimi
747*b7893ccfSSadaf Ebrahimi // Update the scoreboard of layout transitions and check for barriers affecting the same image and subresource
748*b7893ccfSSadaf Ebrahimi // TODO: a higher precision could be gained by adapting the command_buffer image_layout_map logic looking for conflicts
749*b7893ccfSSadaf Ebrahimi // at a per sub-resource level
750*b7893ccfSSadaf Ebrahimi if (img_barrier.oldLayout != img_barrier.newLayout) {
751*b7893ccfSSadaf Ebrahimi const ImageBarrierScoreboardEntry new_entry{i, &img_barrier};
752*b7893ccfSSadaf Ebrahimi const auto image_it = layout_transitions.find(img_barrier.image);
753*b7893ccfSSadaf Ebrahimi if (image_it != layout_transitions.end()) {
754*b7893ccfSSadaf Ebrahimi auto &subres_map = image_it->second;
755*b7893ccfSSadaf Ebrahimi auto subres_it = subres_map.find(img_barrier.subresourceRange);
756*b7893ccfSSadaf Ebrahimi if (subres_it != subres_map.end()) {
757*b7893ccfSSadaf Ebrahimi auto &entry = subres_it->second;
758*b7893ccfSSadaf Ebrahimi if ((entry.barrier->newLayout != img_barrier.oldLayout) &&
759*b7893ccfSSadaf Ebrahimi (img_barrier.oldLayout != VK_IMAGE_LAYOUT_UNDEFINED)) {
760*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &range = img_barrier.subresourceRange;
761*b7893ccfSSadaf Ebrahimi skip = log_msg(
762*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
763*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_state->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
764*b7893ccfSSadaf Ebrahimi "%s: %s conflicts with earlier entry pImageMemoryBarrier[%u]. %s"
765*b7893ccfSSadaf Ebrahimi " subresourceRange: aspectMask=%u baseMipLevel=%u levelCount=%u, baseArrayLayer=%u, layerCount=%u; "
766*b7893ccfSSadaf Ebrahimi "conflicting barrier transitions image layout from %s when earlier barrier transitioned to layout %s.",
767*b7893ccfSSadaf Ebrahimi func_name, barrier_pname.c_str(), entry.index, report_data->FormatHandle(img_barrier.image).c_str(),
768*b7893ccfSSadaf Ebrahimi range.aspectMask, range.baseMipLevel, range.levelCount, range.baseArrayLayer, range.layerCount,
769*b7893ccfSSadaf Ebrahimi string_VkImageLayout(img_barrier.oldLayout), string_VkImageLayout(entry.barrier->newLayout));
770*b7893ccfSSadaf Ebrahimi }
771*b7893ccfSSadaf Ebrahimi entry = new_entry;
772*b7893ccfSSadaf Ebrahimi } else {
773*b7893ccfSSadaf Ebrahimi subres_map[img_barrier.subresourceRange] = new_entry;
774*b7893ccfSSadaf Ebrahimi }
775*b7893ccfSSadaf Ebrahimi } else {
776*b7893ccfSSadaf Ebrahimi layout_transitions[img_barrier.image][img_barrier.subresourceRange] = new_entry;
777*b7893ccfSSadaf Ebrahimi }
778*b7893ccfSSadaf Ebrahimi }
779*b7893ccfSSadaf Ebrahimi
780*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(img_barrier.image);
781*b7893ccfSSadaf Ebrahimi if (image_state) {
782*b7893ccfSSadaf Ebrahimi VkImageUsageFlags usage_flags = image_state->createInfo.usage;
783*b7893ccfSSadaf Ebrahimi skip |= ValidateBarrierLayoutToImageUsage(img_barrier, false, usage_flags, func_name, barrier_pname.c_str());
784*b7893ccfSSadaf Ebrahimi skip |= ValidateBarrierLayoutToImageUsage(img_barrier, true, usage_flags, func_name, barrier_pname.c_str());
785*b7893ccfSSadaf Ebrahimi
786*b7893ccfSSadaf Ebrahimi // Make sure layout is able to be transitioned, currently only presented shared presentable images are locked
787*b7893ccfSSadaf Ebrahimi if (image_state->layout_locked) {
788*b7893ccfSSadaf Ebrahimi // TODO: Add unique id for error when available
789*b7893ccfSSadaf Ebrahimi skip |= log_msg(
790*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
791*b7893ccfSSadaf Ebrahimi HandleToUint64(img_barrier.image), 0,
792*b7893ccfSSadaf Ebrahimi "Attempting to transition shared presentable %s"
793*b7893ccfSSadaf Ebrahimi " from layout %s to layout %s, but image has already been presented and cannot have its layout transitioned.",
794*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(img_barrier.image).c_str(), string_VkImageLayout(img_barrier.oldLayout),
795*b7893ccfSSadaf Ebrahimi string_VkImageLayout(img_barrier.newLayout));
796*b7893ccfSSadaf Ebrahimi }
797*b7893ccfSSadaf Ebrahimi
798*b7893ccfSSadaf Ebrahimi VkImageCreateInfo *image_create_info = &image_state->createInfo;
799*b7893ccfSSadaf Ebrahimi // For a Depth/Stencil image both aspects MUST be set
800*b7893ccfSSadaf Ebrahimi if (FormatIsDepthAndStencil(image_create_info->format)) {
801*b7893ccfSSadaf Ebrahimi auto const aspect_mask = img_barrier.subresourceRange.aspectMask;
802*b7893ccfSSadaf Ebrahimi auto const ds_mask = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
803*b7893ccfSSadaf Ebrahimi if ((aspect_mask & ds_mask) != (ds_mask)) {
804*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
805*b7893ccfSSadaf Ebrahimi HandleToUint64(img_barrier.image), "VUID-VkImageMemoryBarrier-image-01207",
806*b7893ccfSSadaf Ebrahimi "%s: Image barrier %s references %s of format %s that must have the depth and stencil "
807*b7893ccfSSadaf Ebrahimi "aspects set, but its aspectMask is 0x%" PRIx32 ".",
808*b7893ccfSSadaf Ebrahimi func_name, barrier_pname.c_str(), report_data->FormatHandle(img_barrier.image).c_str(),
809*b7893ccfSSadaf Ebrahimi string_VkFormat(image_create_info->format), aspect_mask);
810*b7893ccfSSadaf Ebrahimi }
811*b7893ccfSSadaf Ebrahimi }
812*b7893ccfSSadaf Ebrahimi
813*b7893ccfSSadaf Ebrahimi const auto *subresource_map = GetImageSubresourceLayoutMap(cb_state, img_barrier.image);
814*b7893ccfSSadaf Ebrahimi if (img_barrier.oldLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
815*b7893ccfSSadaf Ebrahimi // TODO: Set memory invalid which is in mem_tracker currently
816*b7893ccfSSadaf Ebrahimi // Not sure if this needs to be in the ForRange traversal, pulling it out as it is currently invariant with
817*b7893ccfSSadaf Ebrahimi // subresource.
818*b7893ccfSSadaf Ebrahimi } else if (subresource_map) {
819*b7893ccfSSadaf Ebrahimi bool subres_skip = false;
820*b7893ccfSSadaf Ebrahimi LayoutUseCheckAndMessage layout_check(subresource_map);
821*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, img_barrier.subresourceRange);
822*b7893ccfSSadaf Ebrahimi auto subres_callback = [this, img_barrier, cb_state, &layout_check, &subres_skip](
823*b7893ccfSSadaf Ebrahimi const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
824*b7893ccfSSadaf Ebrahimi if (!layout_check.Check(subres, img_barrier.oldLayout, layout, initial_layout)) {
825*b7893ccfSSadaf Ebrahimi subres_skip =
826*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
827*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_state->commandBuffer), "VUID-VkImageMemoryBarrier-oldLayout-01197",
828*b7893ccfSSadaf Ebrahimi "For %s you cannot transition the layout of aspect=%d level=%d layer=%d from %s when the "
829*b7893ccfSSadaf Ebrahimi "%s layout is %s.",
830*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(img_barrier.image).c_str(), subres.aspectMask, subres.mipLevel,
831*b7893ccfSSadaf Ebrahimi subres.arrayLayer, string_VkImageLayout(img_barrier.oldLayout), layout_check.message,
832*b7893ccfSSadaf Ebrahimi string_VkImageLayout(layout_check.layout));
833*b7893ccfSSadaf Ebrahimi }
834*b7893ccfSSadaf Ebrahimi return !subres_skip;
835*b7893ccfSSadaf Ebrahimi };
836*b7893ccfSSadaf Ebrahimi subresource_map->ForRange(normalized_isr, subres_callback);
837*b7893ccfSSadaf Ebrahimi skip |= subres_skip;
838*b7893ccfSSadaf Ebrahimi }
839*b7893ccfSSadaf Ebrahimi }
840*b7893ccfSSadaf Ebrahimi }
841*b7893ccfSSadaf Ebrahimi return skip;
842*b7893ccfSSadaf Ebrahimi }
843*b7893ccfSSadaf Ebrahimi
IsReleaseOp(CMD_BUFFER_STATE * cb_state,const VkImageMemoryBarrier & barrier) const844*b7893ccfSSadaf Ebrahimi bool CoreChecks::IsReleaseOp(CMD_BUFFER_STATE *cb_state, const VkImageMemoryBarrier &barrier) const {
845*b7893ccfSSadaf Ebrahimi if (!IsTransferOp(&barrier)) return false;
846*b7893ccfSSadaf Ebrahimi
847*b7893ccfSSadaf Ebrahimi auto pool = GetCommandPoolState(cb_state->createInfo.commandPool);
848*b7893ccfSSadaf Ebrahimi return pool && TempIsReleaseOp<VkImageMemoryBarrier, true>(pool, &barrier);
849*b7893ccfSSadaf Ebrahimi }
850*b7893ccfSSadaf Ebrahimi
851*b7893ccfSSadaf Ebrahimi template <typename Barrier>
ValidateQFOTransferBarrierUniqueness(const char * func_name,CMD_BUFFER_STATE * cb_state,uint32_t barrier_count,const Barrier * barriers)852*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateQFOTransferBarrierUniqueness(const char *func_name, CMD_BUFFER_STATE *cb_state, uint32_t barrier_count,
853*b7893ccfSSadaf Ebrahimi const Barrier *barriers) {
854*b7893ccfSSadaf Ebrahimi using BarrierRecord = QFOTransferBarrier<Barrier>;
855*b7893ccfSSadaf Ebrahimi bool skip = false;
856*b7893ccfSSadaf Ebrahimi auto pool = GetCommandPoolState(cb_state->createInfo.commandPool);
857*b7893ccfSSadaf Ebrahimi auto &barrier_sets = GetQFOBarrierSets(cb_state, typename BarrierRecord::Tag());
858*b7893ccfSSadaf Ebrahimi const char *barrier_name = BarrierRecord::BarrierName();
859*b7893ccfSSadaf Ebrahimi const char *handle_name = BarrierRecord::HandleName();
860*b7893ccfSSadaf Ebrahimi const char *transfer_type = nullptr;
861*b7893ccfSSadaf Ebrahimi for (uint32_t b = 0; b < barrier_count; b++) {
862*b7893ccfSSadaf Ebrahimi if (!IsTransferOp(&barriers[b])) continue;
863*b7893ccfSSadaf Ebrahimi const BarrierRecord *barrier_record = nullptr;
864*b7893ccfSSadaf Ebrahimi if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer */>(pool, &barriers[b]) &&
865*b7893ccfSSadaf Ebrahimi !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
866*b7893ccfSSadaf Ebrahimi const auto found = barrier_sets.release.find(barriers[b]);
867*b7893ccfSSadaf Ebrahimi if (found != barrier_sets.release.cend()) {
868*b7893ccfSSadaf Ebrahimi barrier_record = &(*found);
869*b7893ccfSSadaf Ebrahimi transfer_type = "releasing";
870*b7893ccfSSadaf Ebrahimi }
871*b7893ccfSSadaf Ebrahimi } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barriers[b]) &&
872*b7893ccfSSadaf Ebrahimi !IsSpecial(barriers[b].srcQueueFamilyIndex)) {
873*b7893ccfSSadaf Ebrahimi const auto found = barrier_sets.acquire.find(barriers[b]);
874*b7893ccfSSadaf Ebrahimi if (found != barrier_sets.acquire.cend()) {
875*b7893ccfSSadaf Ebrahimi barrier_record = &(*found);
876*b7893ccfSSadaf Ebrahimi transfer_type = "acquiring";
877*b7893ccfSSadaf Ebrahimi }
878*b7893ccfSSadaf Ebrahimi }
879*b7893ccfSSadaf Ebrahimi if (barrier_record != nullptr) {
880*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
881*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInCB(),
882*b7893ccfSSadaf Ebrahimi "%s: %s at index %" PRIu32 " %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
883*b7893ccfSSadaf Ebrahimi " to dstQueueFamilyIndex %" PRIu32 " duplicates existing barrier recorded in this command buffer.",
884*b7893ccfSSadaf Ebrahimi func_name, barrier_name, b, transfer_type, handle_name,
885*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(barrier_record->handle).c_str(), barrier_record->srcQueueFamilyIndex,
886*b7893ccfSSadaf Ebrahimi barrier_record->dstQueueFamilyIndex);
887*b7893ccfSSadaf Ebrahimi }
888*b7893ccfSSadaf Ebrahimi }
889*b7893ccfSSadaf Ebrahimi return skip;
890*b7893ccfSSadaf Ebrahimi }
891*b7893ccfSSadaf Ebrahimi
892*b7893ccfSSadaf Ebrahimi template <typename Barrier>
RecordQFOTransferBarriers(CMD_BUFFER_STATE * cb_state,uint32_t barrier_count,const Barrier * barriers)893*b7893ccfSSadaf Ebrahimi void CoreChecks::RecordQFOTransferBarriers(CMD_BUFFER_STATE *cb_state, uint32_t barrier_count, const Barrier *barriers) {
894*b7893ccfSSadaf Ebrahimi auto pool = GetCommandPoolState(cb_state->createInfo.commandPool);
895*b7893ccfSSadaf Ebrahimi auto &barrier_sets = GetQFOBarrierSets(cb_state, typename QFOTransferBarrier<Barrier>::Tag());
896*b7893ccfSSadaf Ebrahimi for (uint32_t b = 0; b < barrier_count; b++) {
897*b7893ccfSSadaf Ebrahimi if (!IsTransferOp(&barriers[b])) continue;
898*b7893ccfSSadaf Ebrahimi if (TempIsReleaseOp<Barrier, true /* Assume IsTransfer*/>(pool, &barriers[b]) &&
899*b7893ccfSSadaf Ebrahimi !IsSpecial(barriers[b].dstQueueFamilyIndex)) {
900*b7893ccfSSadaf Ebrahimi barrier_sets.release.emplace(barriers[b]);
901*b7893ccfSSadaf Ebrahimi } else if (IsAcquireOp<Barrier, true /*Assume IsTransfer */>(pool, &barriers[b]) &&
902*b7893ccfSSadaf Ebrahimi !IsSpecial(barriers[b].srcQueueFamilyIndex)) {
903*b7893ccfSSadaf Ebrahimi barrier_sets.acquire.emplace(barriers[b]);
904*b7893ccfSSadaf Ebrahimi }
905*b7893ccfSSadaf Ebrahimi }
906*b7893ccfSSadaf Ebrahimi }
907*b7893ccfSSadaf Ebrahimi
ValidateBarriersQFOTransferUniqueness(const char * func_name,CMD_BUFFER_STATE * cb_state,uint32_t bufferBarrierCount,const VkBufferMemoryBarrier * pBufferMemBarriers,uint32_t imageMemBarrierCount,const VkImageMemoryBarrier * pImageMemBarriers)908*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBarriersQFOTransferUniqueness(const char *func_name, CMD_BUFFER_STATE *cb_state,
909*b7893ccfSSadaf Ebrahimi uint32_t bufferBarrierCount, const VkBufferMemoryBarrier *pBufferMemBarriers,
910*b7893ccfSSadaf Ebrahimi uint32_t imageMemBarrierCount,
911*b7893ccfSSadaf Ebrahimi const VkImageMemoryBarrier *pImageMemBarriers) {
912*b7893ccfSSadaf Ebrahimi bool skip = false;
913*b7893ccfSSadaf Ebrahimi skip |= ValidateQFOTransferBarrierUniqueness(func_name, cb_state, bufferBarrierCount, pBufferMemBarriers);
914*b7893ccfSSadaf Ebrahimi skip |= ValidateQFOTransferBarrierUniqueness(func_name, cb_state, imageMemBarrierCount, pImageMemBarriers);
915*b7893ccfSSadaf Ebrahimi return skip;
916*b7893ccfSSadaf Ebrahimi }
917*b7893ccfSSadaf Ebrahimi
RecordBarriersQFOTransfers(CMD_BUFFER_STATE * cb_state,uint32_t bufferBarrierCount,const VkBufferMemoryBarrier * pBufferMemBarriers,uint32_t imageMemBarrierCount,const VkImageMemoryBarrier * pImageMemBarriers)918*b7893ccfSSadaf Ebrahimi void CoreChecks::RecordBarriersQFOTransfers(CMD_BUFFER_STATE *cb_state, uint32_t bufferBarrierCount,
919*b7893ccfSSadaf Ebrahimi const VkBufferMemoryBarrier *pBufferMemBarriers, uint32_t imageMemBarrierCount,
920*b7893ccfSSadaf Ebrahimi const VkImageMemoryBarrier *pImageMemBarriers) {
921*b7893ccfSSadaf Ebrahimi RecordQFOTransferBarriers(cb_state, bufferBarrierCount, pBufferMemBarriers);
922*b7893ccfSSadaf Ebrahimi RecordQFOTransferBarriers(cb_state, imageMemBarrierCount, pImageMemBarriers);
923*b7893ccfSSadaf Ebrahimi }
924*b7893ccfSSadaf Ebrahimi
925*b7893ccfSSadaf Ebrahimi template <typename BarrierRecord, typename Scoreboard>
ValidateAndUpdateQFOScoreboard(const debug_report_data * report_data,const CMD_BUFFER_STATE * cb_state,const char * operation,const BarrierRecord & barrier,Scoreboard * scoreboard) const926*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateAndUpdateQFOScoreboard(const debug_report_data *report_data, const CMD_BUFFER_STATE *cb_state,
927*b7893ccfSSadaf Ebrahimi const char *operation, const BarrierRecord &barrier, Scoreboard *scoreboard) const {
928*b7893ccfSSadaf Ebrahimi // Record to the scoreboard or report that we have a duplication
929*b7893ccfSSadaf Ebrahimi bool skip = false;
930*b7893ccfSSadaf Ebrahimi auto inserted = scoreboard->insert(std::make_pair(barrier, cb_state));
931*b7893ccfSSadaf Ebrahimi if (!inserted.second && inserted.first->second != cb_state) {
932*b7893ccfSSadaf Ebrahimi // This is a duplication (but don't report duplicates from the same CB, as we do that at record time
933*b7893ccfSSadaf Ebrahimi skip = log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
934*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOInSubmit(),
935*b7893ccfSSadaf Ebrahimi "%s: %s %s queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32 " to dstQueueFamilyIndex %" PRIu32
936*b7893ccfSSadaf Ebrahimi " duplicates existing barrier submitted in this batch from %s.",
937*b7893ccfSSadaf Ebrahimi "vkQueueSubmit()", BarrierRecord::BarrierName(), operation, BarrierRecord::HandleName(),
938*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(barrier.handle).c_str(), barrier.srcQueueFamilyIndex, barrier.dstQueueFamilyIndex,
939*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(inserted.first->second->commandBuffer).c_str());
940*b7893ccfSSadaf Ebrahimi }
941*b7893ccfSSadaf Ebrahimi return skip;
942*b7893ccfSSadaf Ebrahimi }
943*b7893ccfSSadaf Ebrahimi
944*b7893ccfSSadaf Ebrahimi template <typename Barrier>
ValidateQueuedQFOTransferBarriers(const CMD_BUFFER_STATE * cb_state,QFOTransferCBScoreboards<Barrier> * scoreboards) const945*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateQueuedQFOTransferBarriers(const CMD_BUFFER_STATE *cb_state,
946*b7893ccfSSadaf Ebrahimi QFOTransferCBScoreboards<Barrier> *scoreboards) const {
947*b7893ccfSSadaf Ebrahimi using BarrierRecord = QFOTransferBarrier<Barrier>;
948*b7893ccfSSadaf Ebrahimi using TypeTag = typename BarrierRecord::Tag;
949*b7893ccfSSadaf Ebrahimi bool skip = false;
950*b7893ccfSSadaf Ebrahimi const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
951*b7893ccfSSadaf Ebrahimi const GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
952*b7893ccfSSadaf Ebrahimi const char *barrier_name = BarrierRecord::BarrierName();
953*b7893ccfSSadaf Ebrahimi const char *handle_name = BarrierRecord::HandleName();
954*b7893ccfSSadaf Ebrahimi // No release should have an extant duplicate (WARNING)
955*b7893ccfSSadaf Ebrahimi for (const auto &release : cb_barriers.release) {
956*b7893ccfSSadaf Ebrahimi // Check the global pending release barriers
957*b7893ccfSSadaf Ebrahimi const auto set_it = global_release_barriers.find(release.handle);
958*b7893ccfSSadaf Ebrahimi if (set_it != global_release_barriers.cend()) {
959*b7893ccfSSadaf Ebrahimi const QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
960*b7893ccfSSadaf Ebrahimi const auto found = set_for_handle.find(release);
961*b7893ccfSSadaf Ebrahimi if (found != set_for_handle.cend()) {
962*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
963*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgDuplicateQFOSubmitted(),
964*b7893ccfSSadaf Ebrahimi "%s: %s releasing queue ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
965*b7893ccfSSadaf Ebrahimi " to dstQueueFamilyIndex %" PRIu32
966*b7893ccfSSadaf Ebrahimi " duplicates existing barrier queued for execution, without intervening acquire operation.",
967*b7893ccfSSadaf Ebrahimi "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(found->handle).c_str(),
968*b7893ccfSSadaf Ebrahimi found->srcQueueFamilyIndex, found->dstQueueFamilyIndex);
969*b7893ccfSSadaf Ebrahimi }
970*b7893ccfSSadaf Ebrahimi }
971*b7893ccfSSadaf Ebrahimi skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "releasing", release, &scoreboards->release);
972*b7893ccfSSadaf Ebrahimi }
973*b7893ccfSSadaf Ebrahimi // Each acquire must have a matching release (ERROR)
974*b7893ccfSSadaf Ebrahimi for (const auto &acquire : cb_barriers.acquire) {
975*b7893ccfSSadaf Ebrahimi const auto set_it = global_release_barriers.find(acquire.handle);
976*b7893ccfSSadaf Ebrahimi bool matching_release_found = false;
977*b7893ccfSSadaf Ebrahimi if (set_it != global_release_barriers.cend()) {
978*b7893ccfSSadaf Ebrahimi const QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
979*b7893ccfSSadaf Ebrahimi matching_release_found = set_for_handle.find(acquire) != set_for_handle.cend();
980*b7893ccfSSadaf Ebrahimi }
981*b7893ccfSSadaf Ebrahimi if (!matching_release_found) {
982*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
983*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_state->commandBuffer), BarrierRecord::ErrMsgMissingQFOReleaseInSubmit(),
984*b7893ccfSSadaf Ebrahimi "%s: in submitted command buffer %s acquiring ownership of %s (%s), from srcQueueFamilyIndex %" PRIu32
985*b7893ccfSSadaf Ebrahimi " to dstQueueFamilyIndex %" PRIu32 " has no matching release barrier queued for execution.",
986*b7893ccfSSadaf Ebrahimi "vkQueueSubmit()", barrier_name, handle_name, report_data->FormatHandle(acquire.handle).c_str(),
987*b7893ccfSSadaf Ebrahimi acquire.srcQueueFamilyIndex, acquire.dstQueueFamilyIndex);
988*b7893ccfSSadaf Ebrahimi }
989*b7893ccfSSadaf Ebrahimi skip |= ValidateAndUpdateQFOScoreboard(report_data, cb_state, "acquiring", acquire, &scoreboards->acquire);
990*b7893ccfSSadaf Ebrahimi }
991*b7893ccfSSadaf Ebrahimi return skip;
992*b7893ccfSSadaf Ebrahimi }
993*b7893ccfSSadaf Ebrahimi
ValidateQueuedQFOTransfers(const CMD_BUFFER_STATE * cb_state,QFOTransferCBScoreboards<VkImageMemoryBarrier> * qfo_image_scoreboards,QFOTransferCBScoreboards<VkBufferMemoryBarrier> * qfo_buffer_scoreboards) const994*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateQueuedQFOTransfers(const CMD_BUFFER_STATE *cb_state,
995*b7893ccfSSadaf Ebrahimi QFOTransferCBScoreboards<VkImageMemoryBarrier> *qfo_image_scoreboards,
996*b7893ccfSSadaf Ebrahimi QFOTransferCBScoreboards<VkBufferMemoryBarrier> *qfo_buffer_scoreboards) const {
997*b7893ccfSSadaf Ebrahimi bool skip = false;
998*b7893ccfSSadaf Ebrahimi skip |= ValidateQueuedQFOTransferBarriers<VkImageMemoryBarrier>(cb_state, qfo_image_scoreboards);
999*b7893ccfSSadaf Ebrahimi skip |= ValidateQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(cb_state, qfo_buffer_scoreboards);
1000*b7893ccfSSadaf Ebrahimi return skip;
1001*b7893ccfSSadaf Ebrahimi }
1002*b7893ccfSSadaf Ebrahimi
1003*b7893ccfSSadaf Ebrahimi template <typename Barrier>
RecordQueuedQFOTransferBarriers(CMD_BUFFER_STATE * cb_state)1004*b7893ccfSSadaf Ebrahimi void CoreChecks::RecordQueuedQFOTransferBarriers(CMD_BUFFER_STATE *cb_state) {
1005*b7893ccfSSadaf Ebrahimi using BarrierRecord = QFOTransferBarrier<Barrier>;
1006*b7893ccfSSadaf Ebrahimi using TypeTag = typename BarrierRecord::Tag;
1007*b7893ccfSSadaf Ebrahimi const auto &cb_barriers = GetQFOBarrierSets(cb_state, TypeTag());
1008*b7893ccfSSadaf Ebrahimi GlobalQFOTransferBarrierMap<Barrier> &global_release_barriers = GetGlobalQFOReleaseBarrierMap(TypeTag());
1009*b7893ccfSSadaf Ebrahimi
1010*b7893ccfSSadaf Ebrahimi // Add release barriers from this submit to the global map
1011*b7893ccfSSadaf Ebrahimi for (const auto &release : cb_barriers.release) {
1012*b7893ccfSSadaf Ebrahimi // the global barrier list is mapped by resource handle to allow cleanup on resource destruction
1013*b7893ccfSSadaf Ebrahimi // NOTE: We're using [] because creation of a Set is a needed side effect for new handles
1014*b7893ccfSSadaf Ebrahimi global_release_barriers[release.handle].insert(release);
1015*b7893ccfSSadaf Ebrahimi }
1016*b7893ccfSSadaf Ebrahimi
1017*b7893ccfSSadaf Ebrahimi // Erase acquired barriers from this submit from the global map -- essentially marking releases as consumed
1018*b7893ccfSSadaf Ebrahimi for (const auto &acquire : cb_barriers.acquire) {
1019*b7893ccfSSadaf Ebrahimi // NOTE: We're not using [] because we don't want to create entries for missing releases
1020*b7893ccfSSadaf Ebrahimi auto set_it = global_release_barriers.find(acquire.handle);
1021*b7893ccfSSadaf Ebrahimi if (set_it != global_release_barriers.end()) {
1022*b7893ccfSSadaf Ebrahimi QFOTransferBarrierSet<Barrier> &set_for_handle = set_it->second;
1023*b7893ccfSSadaf Ebrahimi set_for_handle.erase(acquire);
1024*b7893ccfSSadaf Ebrahimi if (set_for_handle.size() == 0) { // Clean up empty sets
1025*b7893ccfSSadaf Ebrahimi global_release_barriers.erase(set_it);
1026*b7893ccfSSadaf Ebrahimi }
1027*b7893ccfSSadaf Ebrahimi }
1028*b7893ccfSSadaf Ebrahimi }
1029*b7893ccfSSadaf Ebrahimi }
1030*b7893ccfSSadaf Ebrahimi
RecordQueuedQFOTransfers(CMD_BUFFER_STATE * cb_state)1031*b7893ccfSSadaf Ebrahimi void CoreChecks::RecordQueuedQFOTransfers(CMD_BUFFER_STATE *cb_state) {
1032*b7893ccfSSadaf Ebrahimi RecordQueuedQFOTransferBarriers<VkImageMemoryBarrier>(cb_state);
1033*b7893ccfSSadaf Ebrahimi RecordQueuedQFOTransferBarriers<VkBufferMemoryBarrier>(cb_state);
1034*b7893ccfSSadaf Ebrahimi }
1035*b7893ccfSSadaf Ebrahimi
1036*b7893ccfSSadaf Ebrahimi // Avoid making the template globally visible by exporting the one instance of it we need.
EraseQFOImageRelaseBarriers(const VkImage & image)1037*b7893ccfSSadaf Ebrahimi void CoreChecks::EraseQFOImageRelaseBarriers(const VkImage &image) { EraseQFOReleaseBarriers<VkImageMemoryBarrier>(image); }
1038*b7893ccfSSadaf Ebrahimi
TransitionImageLayouts(CMD_BUFFER_STATE * cb_state,uint32_t memBarrierCount,const VkImageMemoryBarrier * pImgMemBarriers)1039*b7893ccfSSadaf Ebrahimi void CoreChecks::TransitionImageLayouts(CMD_BUFFER_STATE *cb_state, uint32_t memBarrierCount,
1040*b7893ccfSSadaf Ebrahimi const VkImageMemoryBarrier *pImgMemBarriers) {
1041*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < memBarrierCount; ++i) {
1042*b7893ccfSSadaf Ebrahimi const auto &mem_barrier = pImgMemBarriers[i];
1043*b7893ccfSSadaf Ebrahimi
1044*b7893ccfSSadaf Ebrahimi // For ownership transfers, the barrier is specified twice; as a release
1045*b7893ccfSSadaf Ebrahimi // operation on the yielding queue family, and as an acquire operation
1046*b7893ccfSSadaf Ebrahimi // on the acquiring queue family. This barrier may also include a layout
1047*b7893ccfSSadaf Ebrahimi // transition, which occurs 'between' the two operations. For validation
1048*b7893ccfSSadaf Ebrahimi // purposes it doesn't seem important which side performs the layout
1049*b7893ccfSSadaf Ebrahimi // transition, but it must not be performed twice. We'll arbitrarily
1050*b7893ccfSSadaf Ebrahimi // choose to perform it as part of the acquire operation.
1051*b7893ccfSSadaf Ebrahimi if (IsReleaseOp(cb_state, mem_barrier)) {
1052*b7893ccfSSadaf Ebrahimi continue;
1053*b7893ccfSSadaf Ebrahimi }
1054*b7893ccfSSadaf Ebrahimi
1055*b7893ccfSSadaf Ebrahimi auto *image_state = GetImageState(mem_barrier.image);
1056*b7893ccfSSadaf Ebrahimi if (!image_state) continue;
1057*b7893ccfSSadaf Ebrahimi
1058*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, mem_barrier.subresourceRange);
1059*b7893ccfSSadaf Ebrahimi const auto &image_create_info = image_state->createInfo;
1060*b7893ccfSSadaf Ebrahimi
1061*b7893ccfSSadaf Ebrahimi // Special case for 3D images with VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR flag bit, where <extent.depth> and
1062*b7893ccfSSadaf Ebrahimi // <arrayLayers> can potentially alias. When recording layout for the entire image, pre-emptively record layouts
1063*b7893ccfSSadaf Ebrahimi // for all (potential) layer sub_resources.
1064*b7893ccfSSadaf Ebrahimi if (0 != (image_create_info.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) {
1065*b7893ccfSSadaf Ebrahimi normalized_isr.baseArrayLayer = 0;
1066*b7893ccfSSadaf Ebrahimi normalized_isr.layerCount = image_create_info.extent.depth; // Treat each depth slice as a layer subresource
1067*b7893ccfSSadaf Ebrahimi }
1068*b7893ccfSSadaf Ebrahimi
1069*b7893ccfSSadaf Ebrahimi SetImageLayout(cb_state, *image_state, normalized_isr, mem_barrier.newLayout, mem_barrier.oldLayout);
1070*b7893ccfSSadaf Ebrahimi }
1071*b7893ccfSSadaf Ebrahimi }
1072*b7893ccfSSadaf Ebrahimi
VerifyImageLayout(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * image_state,const VkImageSubresourceRange & range,VkImageAspectFlags aspect_mask,VkImageLayout explicit_layout,VkImageLayout optimal_layout,const char * caller,const char * layout_invalid_msg_code,const char * layout_mismatch_msg_code,bool * error) const1073*b7893ccfSSadaf Ebrahimi bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
1074*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &range, VkImageAspectFlags aspect_mask,
1075*b7893ccfSSadaf Ebrahimi VkImageLayout explicit_layout, VkImageLayout optimal_layout, const char *caller,
1076*b7893ccfSSadaf Ebrahimi const char *layout_invalid_msg_code, const char *layout_mismatch_msg_code, bool *error) const {
1077*b7893ccfSSadaf Ebrahimi if (disabled.image_layout_validation) return false;
1078*b7893ccfSSadaf Ebrahimi assert(cb_node);
1079*b7893ccfSSadaf Ebrahimi assert(image_state);
1080*b7893ccfSSadaf Ebrahimi const auto image = image_state->image;
1081*b7893ccfSSadaf Ebrahimi bool skip = false;
1082*b7893ccfSSadaf Ebrahimi
1083*b7893ccfSSadaf Ebrahimi const auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image);
1084*b7893ccfSSadaf Ebrahimi if (subresource_map) {
1085*b7893ccfSSadaf Ebrahimi bool subres_skip = false;
1086*b7893ccfSSadaf Ebrahimi LayoutUseCheckAndMessage layout_check(subresource_map, aspect_mask);
1087*b7893ccfSSadaf Ebrahimi auto subresource_cb = [this, explicit_layout, cb_node, layout_mismatch_msg_code, caller, image, &layout_check, &error,
1088*b7893ccfSSadaf Ebrahimi &subres_skip](const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
1089*b7893ccfSSadaf Ebrahimi if (!layout_check.Check(subres, explicit_layout, layout, initial_layout)) {
1090*b7893ccfSSadaf Ebrahimi *error = true;
1091*b7893ccfSSadaf Ebrahimi subres_skip |=
1092*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
1093*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), layout_mismatch_msg_code,
1094*b7893ccfSSadaf Ebrahimi "%s: Cannot use %s (layer=%u mip=%u) with specific layout %s that doesn't match the "
1095*b7893ccfSSadaf Ebrahimi "%s layout %s.",
1096*b7893ccfSSadaf Ebrahimi caller, report_data->FormatHandle(image).c_str(), subres.arrayLayer, subres.mipLevel,
1097*b7893ccfSSadaf Ebrahimi string_VkImageLayout(explicit_layout), layout_check.message, string_VkImageLayout(layout_check.layout));
1098*b7893ccfSSadaf Ebrahimi }
1099*b7893ccfSSadaf Ebrahimi return !subres_skip;
1100*b7893ccfSSadaf Ebrahimi };
1101*b7893ccfSSadaf Ebrahimi subresource_map->ForRange(range, subresource_cb);
1102*b7893ccfSSadaf Ebrahimi skip |= subres_skip;
1103*b7893ccfSSadaf Ebrahimi }
1104*b7893ccfSSadaf Ebrahimi
1105*b7893ccfSSadaf Ebrahimi // If optimal_layout is not UNDEFINED, check that layout matches optimal for this case
1106*b7893ccfSSadaf Ebrahimi if ((VK_IMAGE_LAYOUT_UNDEFINED != optimal_layout) && (explicit_layout != optimal_layout)) {
1107*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_LAYOUT_GENERAL == explicit_layout) {
1108*b7893ccfSSadaf Ebrahimi if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
1109*b7893ccfSSadaf Ebrahimi // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
1110*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
1111*b7893ccfSSadaf Ebrahimi VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, HandleToUint64(cb_node->commandBuffer),
1112*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidImageLayout,
1113*b7893ccfSSadaf Ebrahimi "%s: For optimal performance %s layout should be %s instead of GENERAL.", caller,
1114*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image).c_str(), string_VkImageLayout(optimal_layout));
1115*b7893ccfSSadaf Ebrahimi }
1116*b7893ccfSSadaf Ebrahimi } else if (device_extensions.vk_khr_shared_presentable_image) {
1117*b7893ccfSSadaf Ebrahimi if (image_state->shared_presentable) {
1118*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR != explicit_layout) {
1119*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1120*b7893ccfSSadaf Ebrahimi layout_invalid_msg_code,
1121*b7893ccfSSadaf Ebrahimi "Layout for shared presentable image is %s but must be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.",
1122*b7893ccfSSadaf Ebrahimi string_VkImageLayout(optimal_layout));
1123*b7893ccfSSadaf Ebrahimi }
1124*b7893ccfSSadaf Ebrahimi }
1125*b7893ccfSSadaf Ebrahimi } else {
1126*b7893ccfSSadaf Ebrahimi *error = true;
1127*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
1128*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), layout_invalid_msg_code,
1129*b7893ccfSSadaf Ebrahimi "%s: Layout for %s is %s but can only be %s or VK_IMAGE_LAYOUT_GENERAL.", caller,
1130*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image).c_str(), string_VkImageLayout(explicit_layout),
1131*b7893ccfSSadaf Ebrahimi string_VkImageLayout(optimal_layout));
1132*b7893ccfSSadaf Ebrahimi }
1133*b7893ccfSSadaf Ebrahimi }
1134*b7893ccfSSadaf Ebrahimi return skip;
1135*b7893ccfSSadaf Ebrahimi }
VerifyImageLayout(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * image_state,const VkImageSubresourceLayers & subLayers,VkImageLayout explicit_layout,VkImageLayout optimal_layout,const char * caller,const char * layout_invalid_msg_code,const char * layout_mismatch_msg_code,bool * error) const1136*b7893ccfSSadaf Ebrahimi bool CoreChecks::VerifyImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
1137*b7893ccfSSadaf Ebrahimi const VkImageSubresourceLayers &subLayers, VkImageLayout explicit_layout,
1138*b7893ccfSSadaf Ebrahimi VkImageLayout optimal_layout, const char *caller, const char *layout_invalid_msg_code,
1139*b7893ccfSSadaf Ebrahimi const char *layout_mismatch_msg_code, bool *error) const {
1140*b7893ccfSSadaf Ebrahimi return VerifyImageLayout(cb_node, image_state, RangeFromLayers(subLayers), explicit_layout, optimal_layout, caller,
1141*b7893ccfSSadaf Ebrahimi layout_invalid_msg_code, layout_mismatch_msg_code, error);
1142*b7893ccfSSadaf Ebrahimi }
1143*b7893ccfSSadaf Ebrahimi
TransitionFinalSubpassLayouts(CMD_BUFFER_STATE * pCB,const VkRenderPassBeginInfo * pRenderPassBegin,FRAMEBUFFER_STATE * framebuffer_state)1144*b7893ccfSSadaf Ebrahimi void CoreChecks::TransitionFinalSubpassLayouts(CMD_BUFFER_STATE *pCB, const VkRenderPassBeginInfo *pRenderPassBegin,
1145*b7893ccfSSadaf Ebrahimi FRAMEBUFFER_STATE *framebuffer_state) {
1146*b7893ccfSSadaf Ebrahimi auto renderPass = GetRenderPassState(pRenderPassBegin->renderPass);
1147*b7893ccfSSadaf Ebrahimi if (!renderPass) return;
1148*b7893ccfSSadaf Ebrahimi
1149*b7893ccfSSadaf Ebrahimi const VkRenderPassCreateInfo2KHR *pRenderPassInfo = renderPass->createInfo.ptr();
1150*b7893ccfSSadaf Ebrahimi if (framebuffer_state) {
1151*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < pRenderPassInfo->attachmentCount; ++i) {
1152*b7893ccfSSadaf Ebrahimi auto view_state = GetAttachmentImageViewState(framebuffer_state, i);
1153*b7893ccfSSadaf Ebrahimi if (view_state) {
1154*b7893ccfSSadaf Ebrahimi SetImageViewLayout(pCB, *view_state, pRenderPassInfo->pAttachments[i].finalLayout);
1155*b7893ccfSSadaf Ebrahimi }
1156*b7893ccfSSadaf Ebrahimi }
1157*b7893ccfSSadaf Ebrahimi }
1158*b7893ccfSSadaf Ebrahimi }
1159*b7893ccfSSadaf Ebrahimi
1160*b7893ccfSSadaf Ebrahimi #ifdef VK_USE_PLATFORM_ANDROID_KHR
1161*b7893ccfSSadaf Ebrahimi // Android-specific validation that uses types defined only with VK_USE_PLATFORM_ANDROID_KHR
1162*b7893ccfSSadaf Ebrahimi // This could also move into a seperate core_validation_android.cpp file... ?
1163*b7893ccfSSadaf Ebrahimi
1164*b7893ccfSSadaf Ebrahimi //
1165*b7893ccfSSadaf Ebrahimi // AHB-specific validation within non-AHB APIs
1166*b7893ccfSSadaf Ebrahimi //
ValidateCreateImageANDROID(const debug_report_data * report_data,const VkImageCreateInfo * create_info)1167*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCreateImageANDROID(const debug_report_data *report_data, const VkImageCreateInfo *create_info) {
1168*b7893ccfSSadaf Ebrahimi bool skip = false;
1169*b7893ccfSSadaf Ebrahimi
1170*b7893ccfSSadaf Ebrahimi const VkExternalFormatANDROID *ext_fmt_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
1171*b7893ccfSSadaf Ebrahimi if (ext_fmt_android) {
1172*b7893ccfSSadaf Ebrahimi if (0 != ext_fmt_android->externalFormat) {
1173*b7893ccfSSadaf Ebrahimi if (VK_FORMAT_UNDEFINED != create_info->format) {
1174*b7893ccfSSadaf Ebrahimi skip |=
1175*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1176*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-01974",
1177*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with non-zero "
1178*b7893ccfSSadaf Ebrahimi "externalFormat, but the VkImageCreateInfo's format is not VK_FORMAT_UNDEFINED.");
1179*b7893ccfSSadaf Ebrahimi }
1180*b7893ccfSSadaf Ebrahimi
1181*b7893ccfSSadaf Ebrahimi if (0 != (VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT & create_info->flags)) {
1182*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1183*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-02396",
1184*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1185*b7893ccfSSadaf Ebrahimi "non-zero externalFormat, but flags include VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
1186*b7893ccfSSadaf Ebrahimi }
1187*b7893ccfSSadaf Ebrahimi
1188*b7893ccfSSadaf Ebrahimi if (0 != (~VK_IMAGE_USAGE_SAMPLED_BIT & create_info->usage)) {
1189*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1190*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-02397",
1191*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1192*b7893ccfSSadaf Ebrahimi "non-zero externalFormat, but usage includes bits other than VK_IMAGE_USAGE_SAMPLED_BIT.");
1193*b7893ccfSSadaf Ebrahimi }
1194*b7893ccfSSadaf Ebrahimi
1195*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_TILING_OPTIMAL != create_info->tiling) {
1196*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1197*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-02398",
1198*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct has a chained VkExternalFormatANDROID struct with "
1199*b7893ccfSSadaf Ebrahimi "non-zero externalFormat, but layout is not VK_IMAGE_TILING_OPTIMAL.");
1200*b7893ccfSSadaf Ebrahimi }
1201*b7893ccfSSadaf Ebrahimi }
1202*b7893ccfSSadaf Ebrahimi
1203*b7893ccfSSadaf Ebrahimi if ((0 != ext_fmt_android->externalFormat) && (0 == ahb_ext_formats_set.count(ext_fmt_android->externalFormat))) {
1204*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1205*b7893ccfSSadaf Ebrahimi "VUID-VkExternalFormatANDROID-externalFormat-01894",
1206*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Chained VkExternalFormatANDROID struct contains a non-zero externalFormat which has "
1207*b7893ccfSSadaf Ebrahimi "not been previously retrieved by vkGetAndroidHardwareBufferPropertiesANDROID().");
1208*b7893ccfSSadaf Ebrahimi }
1209*b7893ccfSSadaf Ebrahimi }
1210*b7893ccfSSadaf Ebrahimi
1211*b7893ccfSSadaf Ebrahimi if ((nullptr == ext_fmt_android) || (0 == ext_fmt_android->externalFormat)) {
1212*b7893ccfSSadaf Ebrahimi if (VK_FORMAT_UNDEFINED == create_info->format) {
1213*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1214*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-01975",
1215*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct's format is VK_FORMAT_UNDEFINED, but either does not have a "
1216*b7893ccfSSadaf Ebrahimi "chained VkExternalFormatANDROID struct or the struct exists but has an externalFormat of 0.");
1217*b7893ccfSSadaf Ebrahimi }
1218*b7893ccfSSadaf Ebrahimi }
1219*b7893ccfSSadaf Ebrahimi
1220*b7893ccfSSadaf Ebrahimi const VkExternalMemoryImageCreateInfo *emici = lvl_find_in_chain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
1221*b7893ccfSSadaf Ebrahimi if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
1222*b7893ccfSSadaf Ebrahimi if (create_info->imageType != VK_IMAGE_TYPE_2D) {
1223*b7893ccfSSadaf Ebrahimi skip |=
1224*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1225*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-02393",
1226*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct with imageType %s has chained VkExternalMemoryImageCreateInfo "
1227*b7893ccfSSadaf Ebrahimi "struct with handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID.",
1228*b7893ccfSSadaf Ebrahimi string_VkImageType(create_info->imageType));
1229*b7893ccfSSadaf Ebrahimi }
1230*b7893ccfSSadaf Ebrahimi
1231*b7893ccfSSadaf Ebrahimi if ((create_info->mipLevels != 1) && (create_info->mipLevels != FullMipChainLevels(create_info->extent))) {
1232*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1233*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-pNext-02394",
1234*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkImageCreateInfo struct with chained VkExternalMemoryImageCreateInfo struct of "
1235*b7893ccfSSadaf Ebrahimi "handleType VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID "
1236*b7893ccfSSadaf Ebrahimi "specifies mipLevels = %" PRId32 " (full chain mipLevels are %" PRId32 ").",
1237*b7893ccfSSadaf Ebrahimi create_info->mipLevels, FullMipChainLevels(create_info->extent));
1238*b7893ccfSSadaf Ebrahimi }
1239*b7893ccfSSadaf Ebrahimi }
1240*b7893ccfSSadaf Ebrahimi
1241*b7893ccfSSadaf Ebrahimi return skip;
1242*b7893ccfSSadaf Ebrahimi }
1243*b7893ccfSSadaf Ebrahimi
RecordCreateImageANDROID(const VkImageCreateInfo * create_info,IMAGE_STATE * is_node)1244*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::RecordCreateImageANDROID(const VkImageCreateInfo *create_info, IMAGE_STATE *is_node) {
1245*b7893ccfSSadaf Ebrahimi const VkExternalMemoryImageCreateInfo *emici = lvl_find_in_chain<VkExternalMemoryImageCreateInfo>(create_info->pNext);
1246*b7893ccfSSadaf Ebrahimi if (emici && (emici->handleTypes & VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID)) {
1247*b7893ccfSSadaf Ebrahimi is_node->imported_ahb = true;
1248*b7893ccfSSadaf Ebrahimi }
1249*b7893ccfSSadaf Ebrahimi const VkExternalFormatANDROID *ext_fmt_android = lvl_find_in_chain<VkExternalFormatANDROID>(create_info->pNext);
1250*b7893ccfSSadaf Ebrahimi if (ext_fmt_android && (0 != ext_fmt_android->externalFormat)) {
1251*b7893ccfSSadaf Ebrahimi is_node->has_ahb_format = true;
1252*b7893ccfSSadaf Ebrahimi is_node->ahb_format = ext_fmt_android->externalFormat;
1253*b7893ccfSSadaf Ebrahimi }
1254*b7893ccfSSadaf Ebrahimi }
1255*b7893ccfSSadaf Ebrahimi
ValidateCreateImageViewANDROID(const VkImageViewCreateInfo * create_info)1256*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) {
1257*b7893ccfSSadaf Ebrahimi bool skip = false;
1258*b7893ccfSSadaf Ebrahimi IMAGE_STATE *image_state = GetImageState(create_info->image);
1259*b7893ccfSSadaf Ebrahimi
1260*b7893ccfSSadaf Ebrahimi if (image_state->has_ahb_format) {
1261*b7893ccfSSadaf Ebrahimi if (VK_FORMAT_UNDEFINED != create_info->format) {
1262*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1263*b7893ccfSSadaf Ebrahimi HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02399",
1264*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
1265*b7893ccfSSadaf Ebrahimi "format member is %s.",
1266*b7893ccfSSadaf Ebrahimi string_VkFormat(create_info->format));
1267*b7893ccfSSadaf Ebrahimi }
1268*b7893ccfSSadaf Ebrahimi
1269*b7893ccfSSadaf Ebrahimi // Chain must include a compatible ycbcr conversion
1270*b7893ccfSSadaf Ebrahimi bool conv_found = false;
1271*b7893ccfSSadaf Ebrahimi uint64_t external_format = 0;
1272*b7893ccfSSadaf Ebrahimi const VkSamplerYcbcrConversionInfo *ycbcr_conv_info = lvl_find_in_chain<VkSamplerYcbcrConversionInfo>(create_info->pNext);
1273*b7893ccfSSadaf Ebrahimi if (ycbcr_conv_info != nullptr) {
1274*b7893ccfSSadaf Ebrahimi VkSamplerYcbcrConversion conv_handle = ycbcr_conv_info->conversion;
1275*b7893ccfSSadaf Ebrahimi if (ycbcr_conversion_ahb_fmt_map.find(conv_handle) != ycbcr_conversion_ahb_fmt_map.end()) {
1276*b7893ccfSSadaf Ebrahimi conv_found = true;
1277*b7893ccfSSadaf Ebrahimi external_format = ycbcr_conversion_ahb_fmt_map.at(conv_handle);
1278*b7893ccfSSadaf Ebrahimi }
1279*b7893ccfSSadaf Ebrahimi }
1280*b7893ccfSSadaf Ebrahimi if ((!conv_found) || (external_format != image_state->ahb_format)) {
1281*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1282*b7893ccfSSadaf Ebrahimi HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02400",
1283*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
1284*b7893ccfSSadaf Ebrahimi "without a chained VkSamplerYcbcrConversionInfo struct with the same external format.");
1285*b7893ccfSSadaf Ebrahimi }
1286*b7893ccfSSadaf Ebrahimi
1287*b7893ccfSSadaf Ebrahimi // Errors in create_info swizzles
1288*b7893ccfSSadaf Ebrahimi if ((create_info->components.r != VK_COMPONENT_SWIZZLE_IDENTITY) ||
1289*b7893ccfSSadaf Ebrahimi (create_info->components.g != VK_COMPONENT_SWIZZLE_IDENTITY) ||
1290*b7893ccfSSadaf Ebrahimi (create_info->components.b != VK_COMPONENT_SWIZZLE_IDENTITY) ||
1291*b7893ccfSSadaf Ebrahimi (create_info->components.a != VK_COMPONENT_SWIZZLE_IDENTITY)) {
1292*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1293*b7893ccfSSadaf Ebrahimi HandleToUint64(create_info->image), "VUID-VkImageViewCreateInfo-image-02401",
1294*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): VkImageViewCreateInfo struct has a chained VkExternalFormatANDROID struct, but "
1295*b7893ccfSSadaf Ebrahimi "includes one or more non-identity component swizzles.");
1296*b7893ccfSSadaf Ebrahimi }
1297*b7893ccfSSadaf Ebrahimi }
1298*b7893ccfSSadaf Ebrahimi
1299*b7893ccfSSadaf Ebrahimi return skip;
1300*b7893ccfSSadaf Ebrahimi }
1301*b7893ccfSSadaf Ebrahimi
ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const1302*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const {
1303*b7893ccfSSadaf Ebrahimi bool skip = false;
1304*b7893ccfSSadaf Ebrahimi
1305*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *image_state = GetImageState(image);
1306*b7893ccfSSadaf Ebrahimi if (image_state->imported_ahb && (0 == image_state->GetBoundMemory().size())) {
1307*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
1308*b7893ccfSSadaf Ebrahimi "VUID-vkGetImageSubresourceLayout-image-01895",
1309*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): Attempt to query layout from an image created with "
1310*b7893ccfSSadaf Ebrahimi "VK_EXTERNAL_MEMORY_HANDLE_TYPE_ANDROID_HARDWARE_BUFFER_BIT_ANDROID handleType which has not yet been "
1311*b7893ccfSSadaf Ebrahimi "bound to memory.");
1312*b7893ccfSSadaf Ebrahimi }
1313*b7893ccfSSadaf Ebrahimi return skip;
1314*b7893ccfSSadaf Ebrahimi }
1315*b7893ccfSSadaf Ebrahimi
1316*b7893ccfSSadaf Ebrahimi #else
1317*b7893ccfSSadaf Ebrahimi
ValidateCreateImageANDROID(const debug_report_data * report_data,const VkImageCreateInfo * create_info)1318*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCreateImageANDROID(const debug_report_data *report_data, const VkImageCreateInfo *create_info) {
1319*b7893ccfSSadaf Ebrahimi return false;
1320*b7893ccfSSadaf Ebrahimi }
1321*b7893ccfSSadaf Ebrahimi
RecordCreateImageANDROID(const VkImageCreateInfo * create_info,IMAGE_STATE * is_node)1322*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::RecordCreateImageANDROID(const VkImageCreateInfo *create_info, IMAGE_STATE *is_node) {}
1323*b7893ccfSSadaf Ebrahimi
ValidateCreateImageViewANDROID(const VkImageViewCreateInfo * create_info)1324*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCreateImageViewANDROID(const VkImageViewCreateInfo *create_info) { return false; }
1325*b7893ccfSSadaf Ebrahimi
ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const1326*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateGetImageSubresourceLayoutANDROID(const VkImage image) const { return false; }
1327*b7893ccfSSadaf Ebrahimi
1328*b7893ccfSSadaf Ebrahimi #endif // VK_USE_PLATFORM_ANDROID_KHR
1329*b7893ccfSSadaf Ebrahimi
PreCallValidateCreateImage(VkDevice device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage)1330*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
1331*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkImage *pImage) {
1332*b7893ccfSSadaf Ebrahimi bool skip = false;
1333*b7893ccfSSadaf Ebrahimi
1334*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
1335*b7893ccfSSadaf Ebrahimi skip |= ValidateCreateImageANDROID(report_data, pCreateInfo);
1336*b7893ccfSSadaf Ebrahimi } else { // These checks are omitted or replaced when Android HW Buffer extension is active
1337*b7893ccfSSadaf Ebrahimi if (pCreateInfo->format == VK_FORMAT_UNDEFINED) {
1338*b7893ccfSSadaf Ebrahimi return log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1339*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-format-00943",
1340*b7893ccfSSadaf Ebrahimi "vkCreateImage(): VkFormat for image must not be VK_FORMAT_UNDEFINED.");
1341*b7893ccfSSadaf Ebrahimi }
1342*b7893ccfSSadaf Ebrahimi }
1343*b7893ccfSSadaf Ebrahimi
1344*b7893ccfSSadaf Ebrahimi if (pCreateInfo->flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) {
1345*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_TYPE_2D != pCreateInfo->imageType) {
1346*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1347*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-flags-00949",
1348*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Image type must be VK_IMAGE_TYPE_2D when VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT "
1349*b7893ccfSSadaf Ebrahimi "flag bit is set");
1350*b7893ccfSSadaf Ebrahimi }
1351*b7893ccfSSadaf Ebrahimi
1352*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->extent.width != pCreateInfo->extent.height) || (pCreateInfo->arrayLayers < 6)) {
1353*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1354*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-imageType-00954",
1355*b7893ccfSSadaf Ebrahimi "vkCreateImage(): If VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT flag bit is set, width (%d) must equal "
1356*b7893ccfSSadaf Ebrahimi "height (%d) and arrayLayers (%d) must be >= 6.",
1357*b7893ccfSSadaf Ebrahimi pCreateInfo->extent.width, pCreateInfo->extent.height, pCreateInfo->arrayLayers);
1358*b7893ccfSSadaf Ebrahimi }
1359*b7893ccfSSadaf Ebrahimi }
1360*b7893ccfSSadaf Ebrahimi
1361*b7893ccfSSadaf Ebrahimi const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
1362*b7893ccfSSadaf Ebrahimi VkImageUsageFlags attach_flags = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT |
1363*b7893ccfSSadaf Ebrahimi VK_IMAGE_USAGE_TRANSIENT_ATTACHMENT_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT;
1364*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.width > device_limits->maxFramebufferWidth)) {
1365*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1366*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-usage-00964",
1367*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image width exceeds device "
1368*b7893ccfSSadaf Ebrahimi "maxFramebufferWidth.");
1369*b7893ccfSSadaf Ebrahimi }
1370*b7893ccfSSadaf Ebrahimi
1371*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->usage & attach_flags) && (pCreateInfo->extent.height > device_limits->maxFramebufferHeight)) {
1372*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1373*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-usage-00965",
1374*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Image usage flags include a frame buffer attachment bit and image height exceeds device "
1375*b7893ccfSSadaf Ebrahimi "maxFramebufferHeight");
1376*b7893ccfSSadaf Ebrahimi }
1377*b7893ccfSSadaf Ebrahimi
1378*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_ext_fragment_density_map) {
1379*b7893ccfSSadaf Ebrahimi uint32_t ceiling_width =
1380*b7893ccfSSadaf Ebrahimi (uint32_t)ceil((float)device_limits->maxFramebufferWidth /
1381*b7893ccfSSadaf Ebrahimi std::max((float)phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width, 1.0f));
1382*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.width > ceiling_width)) {
1383*b7893ccfSSadaf Ebrahimi skip |=
1384*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1385*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-usage-02559",
1386*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Image usage flags include a fragment density map bit and image width (%u) exceeds the "
1387*b7893ccfSSadaf Ebrahimi "ceiling of device "
1388*b7893ccfSSadaf Ebrahimi "maxFramebufferWidth (%u) / minFragmentDensityTexelSize.width (%u). The ceiling value: %u",
1389*b7893ccfSSadaf Ebrahimi pCreateInfo->extent.width, device_limits->maxFramebufferWidth,
1390*b7893ccfSSadaf Ebrahimi phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.width, ceiling_width);
1391*b7893ccfSSadaf Ebrahimi }
1392*b7893ccfSSadaf Ebrahimi
1393*b7893ccfSSadaf Ebrahimi uint32_t ceiling_height =
1394*b7893ccfSSadaf Ebrahimi (uint32_t)ceil((float)device_limits->maxFramebufferHeight /
1395*b7893ccfSSadaf Ebrahimi std::max((float)phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height, 1.0f));
1396*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->usage & VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT) && (pCreateInfo->extent.height > ceiling_height)) {
1397*b7893ccfSSadaf Ebrahimi skip |=
1398*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1399*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-usage-02560",
1400*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Image usage flags include a fragment density map bit and image height (%u) exceeds the "
1401*b7893ccfSSadaf Ebrahimi "ceiling of device "
1402*b7893ccfSSadaf Ebrahimi "maxFramebufferHeight (%u) / minFragmentDensityTexelSize.height (%u). The ceiling value: %u",
1403*b7893ccfSSadaf Ebrahimi pCreateInfo->extent.height, device_limits->maxFramebufferHeight,
1404*b7893ccfSSadaf Ebrahimi phys_dev_ext_props.fragment_density_map_props.minFragmentDensityTexelSize.height, ceiling_height);
1405*b7893ccfSSadaf Ebrahimi }
1406*b7893ccfSSadaf Ebrahimi }
1407*b7893ccfSSadaf Ebrahimi
1408*b7893ccfSSadaf Ebrahimi VkImageFormatProperties format_limits = {};
1409*b7893ccfSSadaf Ebrahimi VkResult res = GetPDImageFormatProperties(pCreateInfo, &format_limits);
1410*b7893ccfSSadaf Ebrahimi if (res == VK_ERROR_FORMAT_NOT_SUPPORTED) {
1411*b7893ccfSSadaf Ebrahimi #ifdef VK_USE_PLATFORM_ANDROID_KHR
1412*b7893ccfSSadaf Ebrahimi if (!lvl_find_in_chain<VkExternalFormatANDROID>(pCreateInfo->pNext))
1413*b7893ccfSSadaf Ebrahimi #endif // VK_USE_PLATFORM_ANDROID_KHR
1414*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
1415*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Format %s is not supported for this combination of parameters.",
1416*b7893ccfSSadaf Ebrahimi string_VkFormat(pCreateInfo->format));
1417*b7893ccfSSadaf Ebrahimi } else {
1418*b7893ccfSSadaf Ebrahimi if (pCreateInfo->mipLevels > format_limits.maxMipLevels) {
1419*b7893ccfSSadaf Ebrahimi const char *format_string = string_VkFormat(pCreateInfo->format);
1420*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1421*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-mipLevels-02255",
1422*b7893ccfSSadaf Ebrahimi "vkCreateImage(): Image mip levels=%d exceed image format maxMipLevels=%d for format %s.",
1423*b7893ccfSSadaf Ebrahimi pCreateInfo->mipLevels, format_limits.maxMipLevels, format_string);
1424*b7893ccfSSadaf Ebrahimi }
1425*b7893ccfSSadaf Ebrahimi
1426*b7893ccfSSadaf Ebrahimi uint64_t texel_count = (uint64_t)pCreateInfo->extent.width * (uint64_t)pCreateInfo->extent.height *
1427*b7893ccfSSadaf Ebrahimi (uint64_t)pCreateInfo->extent.depth * (uint64_t)pCreateInfo->arrayLayers *
1428*b7893ccfSSadaf Ebrahimi (uint64_t)pCreateInfo->samples;
1429*b7893ccfSSadaf Ebrahimi uint64_t total_size = (uint64_t)std::ceil(FormatTexelSize(pCreateInfo->format) * texel_count);
1430*b7893ccfSSadaf Ebrahimi
1431*b7893ccfSSadaf Ebrahimi // Round up to imageGranularity boundary
1432*b7893ccfSSadaf Ebrahimi VkDeviceSize imageGranularity = phys_dev_props.limits.bufferImageGranularity;
1433*b7893ccfSSadaf Ebrahimi uint64_t ig_mask = imageGranularity - 1;
1434*b7893ccfSSadaf Ebrahimi total_size = (total_size + ig_mask) & ~ig_mask;
1435*b7893ccfSSadaf Ebrahimi
1436*b7893ccfSSadaf Ebrahimi if (total_size > format_limits.maxResourceSize) {
1437*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
1438*b7893ccfSSadaf Ebrahimi kVUID_Core_Image_InvalidFormatLimitsViolation,
1439*b7893ccfSSadaf Ebrahimi "vkCreateImage(): resource size exceeds allowable maximum Image resource size = 0x%" PRIxLEAST64
1440*b7893ccfSSadaf Ebrahimi ", maximum resource size = 0x%" PRIxLEAST64 " ",
1441*b7893ccfSSadaf Ebrahimi total_size, format_limits.maxResourceSize);
1442*b7893ccfSSadaf Ebrahimi }
1443*b7893ccfSSadaf Ebrahimi
1444*b7893ccfSSadaf Ebrahimi if (pCreateInfo->arrayLayers > format_limits.maxArrayLayers) {
1445*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
1446*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-arrayLayers-02256",
1447*b7893ccfSSadaf Ebrahimi "vkCreateImage(): arrayLayers=%d exceeds allowable maximum supported by format of %d.",
1448*b7893ccfSSadaf Ebrahimi pCreateInfo->arrayLayers, format_limits.maxArrayLayers);
1449*b7893ccfSSadaf Ebrahimi }
1450*b7893ccfSSadaf Ebrahimi
1451*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_sampler_ycbcr_conversion && FormatRequiresYcbcrConversion(pCreateInfo->format) &&
1452*b7893ccfSSadaf Ebrahimi !device_extensions.vk_ext_ycbcr_image_arrays && pCreateInfo->arrayLayers > 1) {
1453*b7893ccfSSadaf Ebrahimi skip |= log_msg(
1454*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
1455*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-format-02653",
1456*b7893ccfSSadaf Ebrahimi "vkCreateImage(): arrayLayers=%d exceeds the maximum allowed of 1 for formats requiring sampler ycbcr conversion",
1457*b7893ccfSSadaf Ebrahimi pCreateInfo->arrayLayers);
1458*b7893ccfSSadaf Ebrahimi }
1459*b7893ccfSSadaf Ebrahimi
1460*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->samples & format_limits.sampleCounts) == 0) {
1461*b7893ccfSSadaf Ebrahimi skip |=
1462*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, 0,
1463*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-samples-02258", "vkCreateImage(): samples %s is not supported by format 0x%.8X.",
1464*b7893ccfSSadaf Ebrahimi string_VkSampleCountFlagBits(pCreateInfo->samples), format_limits.sampleCounts);
1465*b7893ccfSSadaf Ebrahimi }
1466*b7893ccfSSadaf Ebrahimi }
1467*b7893ccfSSadaf Ebrahimi
1468*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->flags & VK_IMAGE_CREATE_SPARSE_ALIASED_BIT) && (!enabled_features.core.sparseResidencyAliased)) {
1469*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
1470*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-flags-01924",
1471*b7893ccfSSadaf Ebrahimi "vkCreateImage(): the sparseResidencyAliased device feature is disabled: Images cannot be created with the "
1472*b7893ccfSSadaf Ebrahimi "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT set.");
1473*b7893ccfSSadaf Ebrahimi }
1474*b7893ccfSSadaf Ebrahimi
1475*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance2) {
1476*b7893ccfSSadaf Ebrahimi if (pCreateInfo->flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR) {
1477*b7893ccfSSadaf Ebrahimi if (!(FormatIsCompressed_BC(pCreateInfo->format) || FormatIsCompressed_ASTC_LDR(pCreateInfo->format) ||
1478*b7893ccfSSadaf Ebrahimi FormatIsCompressed_ETC2_EAC(pCreateInfo->format))) {
1479*b7893ccfSSadaf Ebrahimi // TODO: Add Maintenance2 VUID
1480*b7893ccfSSadaf Ebrahimi skip |=
1481*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
1482*b7893ccfSSadaf Ebrahimi "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR, "
1483*b7893ccfSSadaf Ebrahimi "format must be block, ETC or ASTC compressed, but is %s",
1484*b7893ccfSSadaf Ebrahimi string_VkFormat(pCreateInfo->format));
1485*b7893ccfSSadaf Ebrahimi }
1486*b7893ccfSSadaf Ebrahimi if (!(pCreateInfo->flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT)) {
1487*b7893ccfSSadaf Ebrahimi // TODO: Add Maintenance2 VUID
1488*b7893ccfSSadaf Ebrahimi skip |=
1489*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUIDUndefined,
1490*b7893ccfSSadaf Ebrahimi "vkCreateImage(): If pCreateInfo->flags contains VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR, "
1491*b7893ccfSSadaf Ebrahimi "flags must also contain VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT.");
1492*b7893ccfSSadaf Ebrahimi }
1493*b7893ccfSSadaf Ebrahimi }
1494*b7893ccfSSadaf Ebrahimi }
1495*b7893ccfSSadaf Ebrahimi
1496*b7893ccfSSadaf Ebrahimi if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
1497*b7893ccfSSadaf Ebrahimi skip |= ValidateQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices, "vkCreateImage",
1498*b7893ccfSSadaf Ebrahimi "pCreateInfo->pQueueFamilyIndices", "VUID-VkImageCreateInfo-sharingMode-01420",
1499*b7893ccfSSadaf Ebrahimi "VUID-VkImageCreateInfo-sharingMode-01420", false);
1500*b7893ccfSSadaf Ebrahimi }
1501*b7893ccfSSadaf Ebrahimi
1502*b7893ccfSSadaf Ebrahimi return skip;
1503*b7893ccfSSadaf Ebrahimi }
1504*b7893ccfSSadaf Ebrahimi
PostCallRecordCreateImage(VkDevice device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage,VkResult result)1505*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
1506*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) {
1507*b7893ccfSSadaf Ebrahimi if (VK_SUCCESS != result) return;
1508*b7893ccfSSadaf Ebrahimi std::unique_ptr<IMAGE_STATE> is_node(new IMAGE_STATE(*pImage, pCreateInfo));
1509*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
1510*b7893ccfSSadaf Ebrahimi RecordCreateImageANDROID(pCreateInfo, is_node.get());
1511*b7893ccfSSadaf Ebrahimi }
1512*b7893ccfSSadaf Ebrahimi const auto swapchain_info = lvl_find_in_chain<VkImageSwapchainCreateInfoKHR>(pCreateInfo->pNext);
1513*b7893ccfSSadaf Ebrahimi if (swapchain_info) {
1514*b7893ccfSSadaf Ebrahimi is_node->create_from_swapchain = swapchain_info->swapchain;
1515*b7893ccfSSadaf Ebrahimi }
1516*b7893ccfSSadaf Ebrahimi
1517*b7893ccfSSadaf Ebrahimi bool pre_fetch_memory_reqs = true;
1518*b7893ccfSSadaf Ebrahimi #ifdef VK_USE_PLATFORM_ANDROID_KHR
1519*b7893ccfSSadaf Ebrahimi if (is_node->external_format_android) {
1520*b7893ccfSSadaf Ebrahimi // Do not fetch requirements for external memory images
1521*b7893ccfSSadaf Ebrahimi pre_fetch_memory_reqs = false;
1522*b7893ccfSSadaf Ebrahimi }
1523*b7893ccfSSadaf Ebrahimi #endif
1524*b7893ccfSSadaf Ebrahimi // Record the memory requirements in case they won't be queried
1525*b7893ccfSSadaf Ebrahimi if (pre_fetch_memory_reqs) {
1526*b7893ccfSSadaf Ebrahimi DispatchGetImageMemoryRequirements(device, *pImage, &is_node->requirements);
1527*b7893ccfSSadaf Ebrahimi }
1528*b7893ccfSSadaf Ebrahimi imageMap.insert(std::make_pair(*pImage, std::move(is_node)));
1529*b7893ccfSSadaf Ebrahimi }
1530*b7893ccfSSadaf Ebrahimi
PostCallRecordCreateImage(VkDevice device,const VkImageCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImage * pImage,VkResult result)1531*b7893ccfSSadaf Ebrahimi void CoreChecks::PostCallRecordCreateImage(VkDevice device, const VkImageCreateInfo *pCreateInfo,
1532*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkImage *pImage, VkResult result) {
1533*b7893ccfSSadaf Ebrahimi if (VK_SUCCESS != result) return;
1534*b7893ccfSSadaf Ebrahimi
1535*b7893ccfSSadaf Ebrahimi StateTracker::PostCallRecordCreateImage(device, pCreateInfo, pAllocator, pImage, result);
1536*b7893ccfSSadaf Ebrahimi
1537*b7893ccfSSadaf Ebrahimi IMAGE_LAYOUT_STATE image_state;
1538*b7893ccfSSadaf Ebrahimi image_state.layout = pCreateInfo->initialLayout;
1539*b7893ccfSSadaf Ebrahimi image_state.format = pCreateInfo->format;
1540*b7893ccfSSadaf Ebrahimi ImageSubresourcePair subpair{*pImage, false, VkImageSubresource()};
1541*b7893ccfSSadaf Ebrahimi imageSubresourceMap[*pImage].push_back(subpair);
1542*b7893ccfSSadaf Ebrahimi imageLayoutMap[subpair] = image_state;
1543*b7893ccfSSadaf Ebrahimi }
1544*b7893ccfSSadaf Ebrahimi
PreCallValidateDestroyImage(VkDevice device,VkImage image,const VkAllocationCallbacks * pAllocator)1545*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
1546*b7893ccfSSadaf Ebrahimi IMAGE_STATE *image_state = GetImageState(image);
1547*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(image, kVulkanObjectTypeImage);
1548*b7893ccfSSadaf Ebrahimi bool skip = false;
1549*b7893ccfSSadaf Ebrahimi if (image_state) {
1550*b7893ccfSSadaf Ebrahimi skip |= ValidateObjectNotInUse(image_state, obj_struct, "vkDestroyImage", "VUID-vkDestroyImage-image-01000");
1551*b7893ccfSSadaf Ebrahimi }
1552*b7893ccfSSadaf Ebrahimi return skip;
1553*b7893ccfSSadaf Ebrahimi }
1554*b7893ccfSSadaf Ebrahimi
PreCallRecordDestroyImage(VkDevice device,VkImage image,const VkAllocationCallbacks * pAllocator)1555*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
1556*b7893ccfSSadaf Ebrahimi if (!image) return;
1557*b7893ccfSSadaf Ebrahimi IMAGE_STATE *image_state = GetImageState(image);
1558*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(image, kVulkanObjectTypeImage);
1559*b7893ccfSSadaf Ebrahimi InvalidateCommandBuffers(image_state->cb_bindings, obj_struct);
1560*b7893ccfSSadaf Ebrahimi // Clean up memory mapping, bindings and range references for image
1561*b7893ccfSSadaf Ebrahimi for (auto mem_binding : image_state->GetBoundMemory()) {
1562*b7893ccfSSadaf Ebrahimi auto mem_info = GetDevMemState(mem_binding);
1563*b7893ccfSSadaf Ebrahimi if (mem_info) {
1564*b7893ccfSSadaf Ebrahimi RemoveImageMemoryRange(obj_struct.handle, mem_info);
1565*b7893ccfSSadaf Ebrahimi }
1566*b7893ccfSSadaf Ebrahimi }
1567*b7893ccfSSadaf Ebrahimi ClearMemoryObjectBindings(obj_struct);
1568*b7893ccfSSadaf Ebrahimi // Remove image from imageMap
1569*b7893ccfSSadaf Ebrahimi imageMap.erase(image);
1570*b7893ccfSSadaf Ebrahimi }
1571*b7893ccfSSadaf Ebrahimi
PreCallRecordDestroyImage(VkDevice device,VkImage image,const VkAllocationCallbacks * pAllocator)1572*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordDestroyImage(VkDevice device, VkImage image, const VkAllocationCallbacks *pAllocator) {
1573*b7893ccfSSadaf Ebrahimi // Clean up validation specific data
1574*b7893ccfSSadaf Ebrahimi EraseQFOReleaseBarriers<VkImageMemoryBarrier>(image);
1575*b7893ccfSSadaf Ebrahimi
1576*b7893ccfSSadaf Ebrahimi const auto &sub_entry = imageSubresourceMap.find(image);
1577*b7893ccfSSadaf Ebrahimi if (sub_entry != imageSubresourceMap.end()) {
1578*b7893ccfSSadaf Ebrahimi for (const auto &pair : sub_entry->second) {
1579*b7893ccfSSadaf Ebrahimi imageLayoutMap.erase(pair);
1580*b7893ccfSSadaf Ebrahimi }
1581*b7893ccfSSadaf Ebrahimi imageSubresourceMap.erase(sub_entry);
1582*b7893ccfSSadaf Ebrahimi }
1583*b7893ccfSSadaf Ebrahimi
1584*b7893ccfSSadaf Ebrahimi // Clean up generic image state
1585*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordDestroyImage(device, image, pAllocator);
1586*b7893ccfSSadaf Ebrahimi }
1587*b7893ccfSSadaf Ebrahimi
ValidateImageAttributes(const IMAGE_STATE * image_state,const VkImageSubresourceRange & range) const1588*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageAttributes(const IMAGE_STATE *image_state, const VkImageSubresourceRange &range) const {
1589*b7893ccfSSadaf Ebrahimi bool skip = false;
1590*b7893ccfSSadaf Ebrahimi
1591*b7893ccfSSadaf Ebrahimi if (range.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) {
1592*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdClearColorImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_COLOR_BIT";
1593*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1594*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), kVUID_Core_DrawState_InvalidImageAspect, str);
1595*b7893ccfSSadaf Ebrahimi }
1596*b7893ccfSSadaf Ebrahimi
1597*b7893ccfSSadaf Ebrahimi if (FormatIsDepthOrStencil(image_state->createInfo.format)) {
1598*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdClearColorImage called with depth/stencil image.";
1599*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1600*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-vkCmdClearColorImage-image-00007", "%s.", str);
1601*b7893ccfSSadaf Ebrahimi } else if (FormatIsCompressed(image_state->createInfo.format)) {
1602*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdClearColorImage called with compressed image.";
1603*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1604*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-vkCmdClearColorImage-image-00007", "%s.", str);
1605*b7893ccfSSadaf Ebrahimi }
1606*b7893ccfSSadaf Ebrahimi
1607*b7893ccfSSadaf Ebrahimi if (!(image_state->createInfo.usage & VK_IMAGE_USAGE_TRANSFER_DST_BIT)) {
1608*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdClearColorImage called with image created without VK_IMAGE_USAGE_TRANSFER_DST_BIT.";
1609*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1610*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-vkCmdClearColorImage-image-00002", "%s.", str);
1611*b7893ccfSSadaf Ebrahimi }
1612*b7893ccfSSadaf Ebrahimi return skip;
1613*b7893ccfSSadaf Ebrahimi }
1614*b7893ccfSSadaf Ebrahimi
ResolveRemainingLevels(const VkImageSubresourceRange * range,uint32_t mip_levels)1615*b7893ccfSSadaf Ebrahimi uint32_t ResolveRemainingLevels(const VkImageSubresourceRange *range, uint32_t mip_levels) {
1616*b7893ccfSSadaf Ebrahimi // Return correct number of mip levels taking into account VK_REMAINING_MIP_LEVELS
1617*b7893ccfSSadaf Ebrahimi uint32_t mip_level_count = range->levelCount;
1618*b7893ccfSSadaf Ebrahimi if (range->levelCount == VK_REMAINING_MIP_LEVELS) {
1619*b7893ccfSSadaf Ebrahimi mip_level_count = mip_levels - range->baseMipLevel;
1620*b7893ccfSSadaf Ebrahimi }
1621*b7893ccfSSadaf Ebrahimi return mip_level_count;
1622*b7893ccfSSadaf Ebrahimi }
1623*b7893ccfSSadaf Ebrahimi
ResolveRemainingLayers(const VkImageSubresourceRange * range,uint32_t layers)1624*b7893ccfSSadaf Ebrahimi uint32_t ResolveRemainingLayers(const VkImageSubresourceRange *range, uint32_t layers) {
1625*b7893ccfSSadaf Ebrahimi // Return correct number of layers taking into account VK_REMAINING_ARRAY_LAYERS
1626*b7893ccfSSadaf Ebrahimi uint32_t array_layer_count = range->layerCount;
1627*b7893ccfSSadaf Ebrahimi if (range->layerCount == VK_REMAINING_ARRAY_LAYERS) {
1628*b7893ccfSSadaf Ebrahimi array_layer_count = layers - range->baseArrayLayer;
1629*b7893ccfSSadaf Ebrahimi }
1630*b7893ccfSSadaf Ebrahimi return array_layer_count;
1631*b7893ccfSSadaf Ebrahimi }
1632*b7893ccfSSadaf Ebrahimi
VerifyClearImageLayout(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * image_state,const VkImageSubresourceRange & range,VkImageLayout dest_image_layout,const char * func_name) const1633*b7893ccfSSadaf Ebrahimi bool CoreChecks::VerifyClearImageLayout(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *image_state,
1634*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &range, VkImageLayout dest_image_layout,
1635*b7893ccfSSadaf Ebrahimi const char *func_name) const {
1636*b7893ccfSSadaf Ebrahimi bool skip = false;
1637*b7893ccfSSadaf Ebrahimi
1638*b7893ccfSSadaf Ebrahimi if (dest_image_layout != VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
1639*b7893ccfSSadaf Ebrahimi if (dest_image_layout == VK_IMAGE_LAYOUT_GENERAL) {
1640*b7893ccfSSadaf Ebrahimi if (image_state->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
1641*b7893ccfSSadaf Ebrahimi // LAYOUT_GENERAL is allowed, but may not be performance optimal, flag as perf warning.
1642*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1643*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), kVUID_Core_DrawState_InvalidImageLayout,
1644*b7893ccfSSadaf Ebrahimi "%s: Layout for cleared image should be TRANSFER_DST_OPTIMAL instead of GENERAL.", func_name);
1645*b7893ccfSSadaf Ebrahimi }
1646*b7893ccfSSadaf Ebrahimi } else if (VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR == dest_image_layout) {
1647*b7893ccfSSadaf Ebrahimi if (!device_extensions.vk_khr_shared_presentable_image) {
1648*b7893ccfSSadaf Ebrahimi // TODO: Add unique error id when available.
1649*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1650*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), 0,
1651*b7893ccfSSadaf Ebrahimi "Must enable VK_KHR_shared_presentable_image extension before creating images with a layout type "
1652*b7893ccfSSadaf Ebrahimi "of VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.");
1653*b7893ccfSSadaf Ebrahimi
1654*b7893ccfSSadaf Ebrahimi } else {
1655*b7893ccfSSadaf Ebrahimi if (image_state->shared_presentable) {
1656*b7893ccfSSadaf Ebrahimi skip |= log_msg(
1657*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1658*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), 0,
1659*b7893ccfSSadaf Ebrahimi "Layout for shared presentable cleared image is %s but can only be VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR.",
1660*b7893ccfSSadaf Ebrahimi string_VkImageLayout(dest_image_layout));
1661*b7893ccfSSadaf Ebrahimi }
1662*b7893ccfSSadaf Ebrahimi }
1663*b7893ccfSSadaf Ebrahimi } else {
1664*b7893ccfSSadaf Ebrahimi const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00005";
1665*b7893ccfSSadaf Ebrahimi if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
1666*b7893ccfSSadaf Ebrahimi error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00012";
1667*b7893ccfSSadaf Ebrahimi } else {
1668*b7893ccfSSadaf Ebrahimi assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
1669*b7893ccfSSadaf Ebrahimi }
1670*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1671*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), error_code,
1672*b7893ccfSSadaf Ebrahimi "%s: Layout for cleared image is %s but can only be TRANSFER_DST_OPTIMAL or GENERAL.", func_name,
1673*b7893ccfSSadaf Ebrahimi string_VkImageLayout(dest_image_layout));
1674*b7893ccfSSadaf Ebrahimi }
1675*b7893ccfSSadaf Ebrahimi }
1676*b7893ccfSSadaf Ebrahimi
1677*b7893ccfSSadaf Ebrahimi // Cast to const to prevent creation at validate time.
1678*b7893ccfSSadaf Ebrahimi const auto *subresource_map = GetImageSubresourceLayoutMap(cb_node, image_state->image);
1679*b7893ccfSSadaf Ebrahimi if (subresource_map) {
1680*b7893ccfSSadaf Ebrahimi bool subres_skip = false;
1681*b7893ccfSSadaf Ebrahimi LayoutUseCheckAndMessage layout_check(subresource_map);
1682*b7893ccfSSadaf Ebrahimi VkImageSubresourceRange normalized_isr = NormalizeSubresourceRange(*image_state, range);
1683*b7893ccfSSadaf Ebrahimi auto subres_callback = [this, cb_node, dest_image_layout, func_name, &layout_check, &subres_skip](
1684*b7893ccfSSadaf Ebrahimi const VkImageSubresource &subres, VkImageLayout layout, VkImageLayout initial_layout) {
1685*b7893ccfSSadaf Ebrahimi if (!layout_check.Check(subres, dest_image_layout, layout, initial_layout)) {
1686*b7893ccfSSadaf Ebrahimi const char *error_code = "VUID-vkCmdClearColorImage-imageLayout-00004";
1687*b7893ccfSSadaf Ebrahimi if (strcmp(func_name, "vkCmdClearDepthStencilImage()") == 0) {
1688*b7893ccfSSadaf Ebrahimi error_code = "VUID-vkCmdClearDepthStencilImage-imageLayout-00011";
1689*b7893ccfSSadaf Ebrahimi } else {
1690*b7893ccfSSadaf Ebrahimi assert(strcmp(func_name, "vkCmdClearColorImage()") == 0);
1691*b7893ccfSSadaf Ebrahimi }
1692*b7893ccfSSadaf Ebrahimi subres_skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
1693*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), error_code,
1694*b7893ccfSSadaf Ebrahimi "%s: Cannot clear an image whose layout is %s and doesn't match the %s layout %s.",
1695*b7893ccfSSadaf Ebrahimi func_name, string_VkImageLayout(dest_image_layout), layout_check.message,
1696*b7893ccfSSadaf Ebrahimi string_VkImageLayout(layout_check.layout));
1697*b7893ccfSSadaf Ebrahimi }
1698*b7893ccfSSadaf Ebrahimi return !subres_skip;
1699*b7893ccfSSadaf Ebrahimi };
1700*b7893ccfSSadaf Ebrahimi subresource_map->ForRange(normalized_isr, subres_callback);
1701*b7893ccfSSadaf Ebrahimi skip |= subres_skip;
1702*b7893ccfSSadaf Ebrahimi }
1703*b7893ccfSSadaf Ebrahimi
1704*b7893ccfSSadaf Ebrahimi return skip;
1705*b7893ccfSSadaf Ebrahimi }
1706*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearColorValue * pColor,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)1707*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
1708*b7893ccfSSadaf Ebrahimi const VkClearColorValue *pColor, uint32_t rangeCount,
1709*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange *pRanges) {
1710*b7893ccfSSadaf Ebrahimi bool skip = false;
1711*b7893ccfSSadaf Ebrahimi // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
1712*b7893ccfSSadaf Ebrahimi const auto *cb_node = GetCBState(commandBuffer);
1713*b7893ccfSSadaf Ebrahimi const auto *image_state = GetImageState(image);
1714*b7893ccfSSadaf Ebrahimi if (cb_node && image_state) {
1715*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(image_state, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-image-00003");
1716*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearColorImage()", VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
1717*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearColorImage-commandBuffer-cmdpool");
1718*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_CLEARCOLORIMAGE, "vkCmdClearColorImage()");
1719*b7893ccfSSadaf Ebrahimi if (api_version >= VK_API_VERSION_1_1 || device_extensions.vk_khr_maintenance1) {
1720*b7893ccfSSadaf Ebrahimi skip |=
1721*b7893ccfSSadaf Ebrahimi ValidateImageFormatFeatureFlags(image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdClearColorImage",
1722*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearColorImage-image-01993", "VUID-vkCmdClearColorImage-image-01993");
1723*b7893ccfSSadaf Ebrahimi }
1724*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdClearColorImage()", "VUID-vkCmdClearColorImage-renderpass");
1725*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < rangeCount; ++i) {
1726*b7893ccfSSadaf Ebrahimi std::string param_name = "pRanges[" + std::to_string(i) + "]";
1727*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdClearColorSubresourceRange(image_state, pRanges[i], param_name.c_str());
1728*b7893ccfSSadaf Ebrahimi skip |= ValidateImageAttributes(image_state, pRanges[i]);
1729*b7893ccfSSadaf Ebrahimi skip |= VerifyClearImageLayout(cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearColorImage()");
1730*b7893ccfSSadaf Ebrahimi }
1731*b7893ccfSSadaf Ebrahimi }
1732*b7893ccfSSadaf Ebrahimi return skip;
1733*b7893ccfSSadaf Ebrahimi }
1734*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearColorValue * pColor,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)1735*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image,
1736*b7893ccfSSadaf Ebrahimi VkImageLayout imageLayout, const VkClearColorValue *pColor,
1737*b7893ccfSSadaf Ebrahimi uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
1738*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
1739*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(image);
1740*b7893ccfSSadaf Ebrahimi if (cb_node && image_state) {
1741*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, image_state);
1742*b7893ccfSSadaf Ebrahimi }
1743*b7893ccfSSadaf Ebrahimi }
1744*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearColorValue * pColor,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)1745*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
1746*b7893ccfSSadaf Ebrahimi const VkClearColorValue *pColor, uint32_t rangeCount,
1747*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange *pRanges) {
1748*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordCmdClearColorImage(commandBuffer, image, imageLayout, pColor, rangeCount, pRanges);
1749*b7893ccfSSadaf Ebrahimi
1750*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
1751*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(image);
1752*b7893ccfSSadaf Ebrahimi if (cb_node && image_state) {
1753*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < rangeCount; ++i) {
1754*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, image, pRanges[i], imageLayout);
1755*b7893ccfSSadaf Ebrahimi }
1756*b7893ccfSSadaf Ebrahimi }
1757*b7893ccfSSadaf Ebrahimi }
1758*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearDepthStencilValue * pDepthStencil,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)1759*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
1760*b7893ccfSSadaf Ebrahimi const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
1761*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange *pRanges) {
1762*b7893ccfSSadaf Ebrahimi bool skip = false;
1763*b7893ccfSSadaf Ebrahimi
1764*b7893ccfSSadaf Ebrahimi // TODO : Verify memory is in VK_IMAGE_STATE_CLEAR state
1765*b7893ccfSSadaf Ebrahimi const auto *cb_node = GetCBState(commandBuffer);
1766*b7893ccfSSadaf Ebrahimi const auto *image_state = GetImageState(image);
1767*b7893ccfSSadaf Ebrahimi if (cb_node && image_state) {
1768*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(image_state, "vkCmdClearDepthStencilImage()",
1769*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearDepthStencilImage-image-00010");
1770*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearDepthStencilImage()", VK_QUEUE_GRAPHICS_BIT,
1771*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearDepthStencilImage-commandBuffer-cmdpool");
1772*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_CLEARDEPTHSTENCILIMAGE, "vkCmdClearDepthStencilImage()");
1773*b7893ccfSSadaf Ebrahimi if (api_version >= VK_API_VERSION_1_1 || device_extensions.vk_khr_maintenance1) {
1774*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdClearDepthStencilImage",
1775*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearDepthStencilImage-image-01994",
1776*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearDepthStencilImage-image-01994");
1777*b7893ccfSSadaf Ebrahimi }
1778*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdClearDepthStencilImage()", "VUID-vkCmdClearDepthStencilImage-renderpass");
1779*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < rangeCount; ++i) {
1780*b7893ccfSSadaf Ebrahimi std::string param_name = "pRanges[" + std::to_string(i) + "]";
1781*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdClearDepthSubresourceRange(image_state, pRanges[i], param_name.c_str());
1782*b7893ccfSSadaf Ebrahimi skip |= VerifyClearImageLayout(cb_node, image_state, pRanges[i], imageLayout, "vkCmdClearDepthStencilImage()");
1783*b7893ccfSSadaf Ebrahimi // Image aspect must be depth or stencil or both
1784*b7893ccfSSadaf Ebrahimi VkImageAspectFlags valid_aspects = VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT;
1785*b7893ccfSSadaf Ebrahimi if (((pRanges[i].aspectMask & valid_aspects) == 0) || ((pRanges[i].aspectMask & ~valid_aspects) != 0)) {
1786*b7893ccfSSadaf Ebrahimi char const str[] =
1787*b7893ccfSSadaf Ebrahimi "vkCmdClearDepthStencilImage aspectMasks for all subresource ranges must be set to VK_IMAGE_ASPECT_DEPTH_BIT "
1788*b7893ccfSSadaf Ebrahimi "and/or VK_IMAGE_ASPECT_STENCIL_BIT";
1789*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
1790*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), kVUID_Core_DrawState_InvalidImageAspect, str);
1791*b7893ccfSSadaf Ebrahimi }
1792*b7893ccfSSadaf Ebrahimi }
1793*b7893ccfSSadaf Ebrahimi if (image_state && !FormatIsDepthOrStencil(image_state->createInfo.format)) {
1794*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdClearDepthStencilImage called without a depth/stencil image.";
1795*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1796*b7893ccfSSadaf Ebrahimi HandleToUint64(image), "VUID-vkCmdClearDepthStencilImage-image-00014", "%s.", str);
1797*b7893ccfSSadaf Ebrahimi }
1798*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_USAGE_TRANSFER_DST_BIT != (VK_IMAGE_USAGE_TRANSFER_DST_BIT & image_state->createInfo.usage)) {
1799*b7893ccfSSadaf Ebrahimi char const str[] =
1800*b7893ccfSSadaf Ebrahimi "vkCmdClearDepthStencilImage() called with an image that was not created with the VK_IMAGE_USAGE_TRANSFER_DST_BIT "
1801*b7893ccfSSadaf Ebrahimi "set.";
1802*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
1803*b7893ccfSSadaf Ebrahimi HandleToUint64(image), "VUID-vkCmdClearDepthStencilImage-image-00009", "%s.", str);
1804*b7893ccfSSadaf Ebrahimi }
1805*b7893ccfSSadaf Ebrahimi }
1806*b7893ccfSSadaf Ebrahimi return skip;
1807*b7893ccfSSadaf Ebrahimi }
1808*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearDepthStencilValue * pDepthStencil,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)1809*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image,
1810*b7893ccfSSadaf Ebrahimi VkImageLayout imageLayout,
1811*b7893ccfSSadaf Ebrahimi const VkClearDepthStencilValue *pDepthStencil,
1812*b7893ccfSSadaf Ebrahimi uint32_t rangeCount, const VkImageSubresourceRange *pRanges) {
1813*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
1814*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(image);
1815*b7893ccfSSadaf Ebrahimi if (cb_node && image_state) {
1816*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, image_state);
1817*b7893ccfSSadaf Ebrahimi }
1818*b7893ccfSSadaf Ebrahimi }
1819*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer,VkImage image,VkImageLayout imageLayout,const VkClearDepthStencilValue * pDepthStencil,uint32_t rangeCount,const VkImageSubresourceRange * pRanges)1820*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdClearDepthStencilImage(VkCommandBuffer commandBuffer, VkImage image, VkImageLayout imageLayout,
1821*b7893ccfSSadaf Ebrahimi const VkClearDepthStencilValue *pDepthStencil, uint32_t rangeCount,
1822*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange *pRanges) {
1823*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordCmdClearDepthStencilImage(commandBuffer, image, imageLayout, pDepthStencil, rangeCount, pRanges);
1824*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
1825*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(image);
1826*b7893ccfSSadaf Ebrahimi if (cb_node && image_state) {
1827*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < rangeCount; ++i) {
1828*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, image, pRanges[i], imageLayout);
1829*b7893ccfSSadaf Ebrahimi }
1830*b7893ccfSSadaf Ebrahimi }
1831*b7893ccfSSadaf Ebrahimi }
1832*b7893ccfSSadaf Ebrahimi
1833*b7893ccfSSadaf Ebrahimi // Returns true if [x, xoffset] and [y, yoffset] overlap
RangesIntersect(int32_t start,uint32_t start_offset,int32_t end,uint32_t end_offset)1834*b7893ccfSSadaf Ebrahimi static bool RangesIntersect(int32_t start, uint32_t start_offset, int32_t end, uint32_t end_offset) {
1835*b7893ccfSSadaf Ebrahimi bool result = false;
1836*b7893ccfSSadaf Ebrahimi uint32_t intersection_min = std::max(static_cast<uint32_t>(start), static_cast<uint32_t>(end));
1837*b7893ccfSSadaf Ebrahimi uint32_t intersection_max = std::min(static_cast<uint32_t>(start) + start_offset, static_cast<uint32_t>(end) + end_offset);
1838*b7893ccfSSadaf Ebrahimi
1839*b7893ccfSSadaf Ebrahimi if (intersection_max > intersection_min) {
1840*b7893ccfSSadaf Ebrahimi result = true;
1841*b7893ccfSSadaf Ebrahimi }
1842*b7893ccfSSadaf Ebrahimi return result;
1843*b7893ccfSSadaf Ebrahimi }
1844*b7893ccfSSadaf Ebrahimi
1845*b7893ccfSSadaf Ebrahimi // Returns true if source area of first copy region intersects dest area of second region
1846*b7893ccfSSadaf Ebrahimi // It is assumed that these are copy regions within a single image (otherwise no possibility of collision)
RegionIntersects(const VkImageCopy * rgn0,const VkImageCopy * rgn1,VkImageType type,bool is_multiplane)1847*b7893ccfSSadaf Ebrahimi static bool RegionIntersects(const VkImageCopy *rgn0, const VkImageCopy *rgn1, VkImageType type, bool is_multiplane) {
1848*b7893ccfSSadaf Ebrahimi bool result = false;
1849*b7893ccfSSadaf Ebrahimi
1850*b7893ccfSSadaf Ebrahimi // Separate planes within a multiplane image cannot intersect
1851*b7893ccfSSadaf Ebrahimi if (is_multiplane && (rgn0->srcSubresource.aspectMask != rgn1->dstSubresource.aspectMask)) {
1852*b7893ccfSSadaf Ebrahimi return result;
1853*b7893ccfSSadaf Ebrahimi }
1854*b7893ccfSSadaf Ebrahimi
1855*b7893ccfSSadaf Ebrahimi if ((rgn0->srcSubresource.mipLevel == rgn1->dstSubresource.mipLevel) &&
1856*b7893ccfSSadaf Ebrahimi (RangesIntersect(rgn0->srcSubresource.baseArrayLayer, rgn0->srcSubresource.layerCount, rgn1->dstSubresource.baseArrayLayer,
1857*b7893ccfSSadaf Ebrahimi rgn1->dstSubresource.layerCount))) {
1858*b7893ccfSSadaf Ebrahimi result = true;
1859*b7893ccfSSadaf Ebrahimi switch (type) {
1860*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_3D:
1861*b7893ccfSSadaf Ebrahimi result &= RangesIntersect(rgn0->srcOffset.z, rgn0->extent.depth, rgn1->dstOffset.z, rgn1->extent.depth);
1862*b7893ccfSSadaf Ebrahimi // fall through
1863*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_2D:
1864*b7893ccfSSadaf Ebrahimi result &= RangesIntersect(rgn0->srcOffset.y, rgn0->extent.height, rgn1->dstOffset.y, rgn1->extent.height);
1865*b7893ccfSSadaf Ebrahimi // fall through
1866*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_1D:
1867*b7893ccfSSadaf Ebrahimi result &= RangesIntersect(rgn0->srcOffset.x, rgn0->extent.width, rgn1->dstOffset.x, rgn1->extent.width);
1868*b7893ccfSSadaf Ebrahimi break;
1869*b7893ccfSSadaf Ebrahimi default:
1870*b7893ccfSSadaf Ebrahimi // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
1871*b7893ccfSSadaf Ebrahimi assert(false);
1872*b7893ccfSSadaf Ebrahimi }
1873*b7893ccfSSadaf Ebrahimi }
1874*b7893ccfSSadaf Ebrahimi return result;
1875*b7893ccfSSadaf Ebrahimi }
1876*b7893ccfSSadaf Ebrahimi
1877*b7893ccfSSadaf Ebrahimi // Returns non-zero if offset and extent exceed image extents
1878*b7893ccfSSadaf Ebrahimi static const uint32_t x_bit = 1;
1879*b7893ccfSSadaf Ebrahimi static const uint32_t y_bit = 2;
1880*b7893ccfSSadaf Ebrahimi static const uint32_t z_bit = 4;
ExceedsBounds(const VkOffset3D * offset,const VkExtent3D * extent,const VkExtent3D * image_extent)1881*b7893ccfSSadaf Ebrahimi static uint32_t ExceedsBounds(const VkOffset3D *offset, const VkExtent3D *extent, const VkExtent3D *image_extent) {
1882*b7893ccfSSadaf Ebrahimi uint32_t result = 0;
1883*b7893ccfSSadaf Ebrahimi // Extents/depths cannot be negative but checks left in for clarity
1884*b7893ccfSSadaf Ebrahimi if ((offset->z + extent->depth > image_extent->depth) || (offset->z < 0) ||
1885*b7893ccfSSadaf Ebrahimi ((offset->z + static_cast<int32_t>(extent->depth)) < 0)) {
1886*b7893ccfSSadaf Ebrahimi result |= z_bit;
1887*b7893ccfSSadaf Ebrahimi }
1888*b7893ccfSSadaf Ebrahimi if ((offset->y + extent->height > image_extent->height) || (offset->y < 0) ||
1889*b7893ccfSSadaf Ebrahimi ((offset->y + static_cast<int32_t>(extent->height)) < 0)) {
1890*b7893ccfSSadaf Ebrahimi result |= y_bit;
1891*b7893ccfSSadaf Ebrahimi }
1892*b7893ccfSSadaf Ebrahimi if ((offset->x + extent->width > image_extent->width) || (offset->x < 0) ||
1893*b7893ccfSSadaf Ebrahimi ((offset->x + static_cast<int32_t>(extent->width)) < 0)) {
1894*b7893ccfSSadaf Ebrahimi result |= x_bit;
1895*b7893ccfSSadaf Ebrahimi }
1896*b7893ccfSSadaf Ebrahimi return result;
1897*b7893ccfSSadaf Ebrahimi }
1898*b7893ccfSSadaf Ebrahimi
1899*b7893ccfSSadaf Ebrahimi // Test if two VkExtent3D structs are equivalent
IsExtentEqual(const VkExtent3D * extent,const VkExtent3D * other_extent)1900*b7893ccfSSadaf Ebrahimi static inline bool IsExtentEqual(const VkExtent3D *extent, const VkExtent3D *other_extent) {
1901*b7893ccfSSadaf Ebrahimi bool result = true;
1902*b7893ccfSSadaf Ebrahimi if ((extent->width != other_extent->width) || (extent->height != other_extent->height) ||
1903*b7893ccfSSadaf Ebrahimi (extent->depth != other_extent->depth)) {
1904*b7893ccfSSadaf Ebrahimi result = false;
1905*b7893ccfSSadaf Ebrahimi }
1906*b7893ccfSSadaf Ebrahimi return result;
1907*b7893ccfSSadaf Ebrahimi }
1908*b7893ccfSSadaf Ebrahimi
1909*b7893ccfSSadaf Ebrahimi // For image copies between compressed/uncompressed formats, the extent is provided in source image texels
1910*b7893ccfSSadaf Ebrahimi // Destination image texel extents must be adjusted by block size for the dest validation checks
GetAdjustedDestImageExtent(VkFormat src_format,VkFormat dst_format,VkExtent3D extent)1911*b7893ccfSSadaf Ebrahimi VkExtent3D GetAdjustedDestImageExtent(VkFormat src_format, VkFormat dst_format, VkExtent3D extent) {
1912*b7893ccfSSadaf Ebrahimi VkExtent3D adjusted_extent = extent;
1913*b7893ccfSSadaf Ebrahimi if ((FormatIsCompressed(src_format) && (!FormatIsCompressed(dst_format)))) {
1914*b7893ccfSSadaf Ebrahimi VkExtent3D block_size = FormatTexelBlockExtent(src_format);
1915*b7893ccfSSadaf Ebrahimi adjusted_extent.width /= block_size.width;
1916*b7893ccfSSadaf Ebrahimi adjusted_extent.height /= block_size.height;
1917*b7893ccfSSadaf Ebrahimi adjusted_extent.depth /= block_size.depth;
1918*b7893ccfSSadaf Ebrahimi } else if ((!FormatIsCompressed(src_format) && (FormatIsCompressed(dst_format)))) {
1919*b7893ccfSSadaf Ebrahimi VkExtent3D block_size = FormatTexelBlockExtent(dst_format);
1920*b7893ccfSSadaf Ebrahimi adjusted_extent.width *= block_size.width;
1921*b7893ccfSSadaf Ebrahimi adjusted_extent.height *= block_size.height;
1922*b7893ccfSSadaf Ebrahimi adjusted_extent.depth *= block_size.depth;
1923*b7893ccfSSadaf Ebrahimi }
1924*b7893ccfSSadaf Ebrahimi return adjusted_extent;
1925*b7893ccfSSadaf Ebrahimi }
1926*b7893ccfSSadaf Ebrahimi
1927*b7893ccfSSadaf Ebrahimi // Returns the effective extent of an image subresource, adjusted for mip level and array depth.
GetImageSubresourceExtent(const IMAGE_STATE * img,const VkImageSubresourceLayers * subresource)1928*b7893ccfSSadaf Ebrahimi static inline VkExtent3D GetImageSubresourceExtent(const IMAGE_STATE *img, const VkImageSubresourceLayers *subresource) {
1929*b7893ccfSSadaf Ebrahimi const uint32_t mip = subresource->mipLevel;
1930*b7893ccfSSadaf Ebrahimi
1931*b7893ccfSSadaf Ebrahimi // Return zero extent if mip level doesn't exist
1932*b7893ccfSSadaf Ebrahimi if (mip >= img->createInfo.mipLevels) {
1933*b7893ccfSSadaf Ebrahimi return VkExtent3D{0, 0, 0};
1934*b7893ccfSSadaf Ebrahimi }
1935*b7893ccfSSadaf Ebrahimi
1936*b7893ccfSSadaf Ebrahimi // Don't allow mip adjustment to create 0 dim, but pass along a 0 if that's what subresource specified
1937*b7893ccfSSadaf Ebrahimi VkExtent3D extent = img->createInfo.extent;
1938*b7893ccfSSadaf Ebrahimi
1939*b7893ccfSSadaf Ebrahimi // If multi-plane, adjust per-plane extent
1940*b7893ccfSSadaf Ebrahimi if (FormatIsMultiplane(img->createInfo.format)) {
1941*b7893ccfSSadaf Ebrahimi VkExtent2D divisors = FindMultiplaneExtentDivisors(img->createInfo.format, subresource->aspectMask);
1942*b7893ccfSSadaf Ebrahimi extent.width /= divisors.width;
1943*b7893ccfSSadaf Ebrahimi extent.height /= divisors.height;
1944*b7893ccfSSadaf Ebrahimi }
1945*b7893ccfSSadaf Ebrahimi
1946*b7893ccfSSadaf Ebrahimi if (img->createInfo.flags & VK_IMAGE_CREATE_CORNER_SAMPLED_BIT_NV) {
1947*b7893ccfSSadaf Ebrahimi extent.width = (0 == extent.width ? 0 : std::max(2U, 1 + ((extent.width - 1) >> mip)));
1948*b7893ccfSSadaf Ebrahimi extent.height = (0 == extent.height ? 0 : std::max(2U, 1 + ((extent.height - 1) >> mip)));
1949*b7893ccfSSadaf Ebrahimi extent.depth = (0 == extent.depth ? 0 : std::max(2U, 1 + ((extent.depth - 1) >> mip)));
1950*b7893ccfSSadaf Ebrahimi } else {
1951*b7893ccfSSadaf Ebrahimi extent.width = (0 == extent.width ? 0 : std::max(1U, extent.width >> mip));
1952*b7893ccfSSadaf Ebrahimi extent.height = (0 == extent.height ? 0 : std::max(1U, extent.height >> mip));
1953*b7893ccfSSadaf Ebrahimi extent.depth = (0 == extent.depth ? 0 : std::max(1U, extent.depth >> mip));
1954*b7893ccfSSadaf Ebrahimi }
1955*b7893ccfSSadaf Ebrahimi
1956*b7893ccfSSadaf Ebrahimi // Image arrays have an effective z extent that isn't diminished by mip level
1957*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_TYPE_3D != img->createInfo.imageType) {
1958*b7893ccfSSadaf Ebrahimi extent.depth = img->createInfo.arrayLayers;
1959*b7893ccfSSadaf Ebrahimi }
1960*b7893ccfSSadaf Ebrahimi
1961*b7893ccfSSadaf Ebrahimi return extent;
1962*b7893ccfSSadaf Ebrahimi }
1963*b7893ccfSSadaf Ebrahimi
1964*b7893ccfSSadaf Ebrahimi // Test if the extent argument has all dimensions set to 0.
IsExtentAllZeroes(const VkExtent3D * extent)1965*b7893ccfSSadaf Ebrahimi static inline bool IsExtentAllZeroes(const VkExtent3D *extent) {
1966*b7893ccfSSadaf Ebrahimi return ((extent->width == 0) && (extent->height == 0) && (extent->depth == 0));
1967*b7893ccfSSadaf Ebrahimi }
1968*b7893ccfSSadaf Ebrahimi
1969*b7893ccfSSadaf Ebrahimi // Test if the extent argument has any dimensions set to 0.
IsExtentSizeZero(const VkExtent3D * extent)1970*b7893ccfSSadaf Ebrahimi static inline bool IsExtentSizeZero(const VkExtent3D *extent) {
1971*b7893ccfSSadaf Ebrahimi return ((extent->width == 0) || (extent->height == 0) || (extent->depth == 0));
1972*b7893ccfSSadaf Ebrahimi }
1973*b7893ccfSSadaf Ebrahimi
1974*b7893ccfSSadaf Ebrahimi // Returns the image transfer granularity for a specific image scaled by compressed block size if necessary.
GetScaledItg(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img) const1975*b7893ccfSSadaf Ebrahimi VkExtent3D CoreChecks::GetScaledItg(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img) const {
1976*b7893ccfSSadaf Ebrahimi // Default to (0, 0, 0) granularity in case we can't find the real granularity for the physical device.
1977*b7893ccfSSadaf Ebrahimi VkExtent3D granularity = {0, 0, 0};
1978*b7893ccfSSadaf Ebrahimi auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool);
1979*b7893ccfSSadaf Ebrahimi if (pPool) {
1980*b7893ccfSSadaf Ebrahimi granularity = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].minImageTransferGranularity;
1981*b7893ccfSSadaf Ebrahimi if (FormatIsCompressed(img->createInfo.format)) {
1982*b7893ccfSSadaf Ebrahimi auto block_size = FormatTexelBlockExtent(img->createInfo.format);
1983*b7893ccfSSadaf Ebrahimi granularity.width *= block_size.width;
1984*b7893ccfSSadaf Ebrahimi granularity.height *= block_size.height;
1985*b7893ccfSSadaf Ebrahimi }
1986*b7893ccfSSadaf Ebrahimi }
1987*b7893ccfSSadaf Ebrahimi return granularity;
1988*b7893ccfSSadaf Ebrahimi }
1989*b7893ccfSSadaf Ebrahimi
1990*b7893ccfSSadaf Ebrahimi // Test elements of a VkExtent3D structure against alignment constraints contained in another VkExtent3D structure
IsExtentAligned(const VkExtent3D * extent,const VkExtent3D * granularity)1991*b7893ccfSSadaf Ebrahimi static inline bool IsExtentAligned(const VkExtent3D *extent, const VkExtent3D *granularity) {
1992*b7893ccfSSadaf Ebrahimi bool valid = true;
1993*b7893ccfSSadaf Ebrahimi if ((SafeModulo(extent->depth, granularity->depth) != 0) || (SafeModulo(extent->width, granularity->width) != 0) ||
1994*b7893ccfSSadaf Ebrahimi (SafeModulo(extent->height, granularity->height) != 0)) {
1995*b7893ccfSSadaf Ebrahimi valid = false;
1996*b7893ccfSSadaf Ebrahimi }
1997*b7893ccfSSadaf Ebrahimi return valid;
1998*b7893ccfSSadaf Ebrahimi }
1999*b7893ccfSSadaf Ebrahimi
2000*b7893ccfSSadaf Ebrahimi // Check elements of a VkOffset3D structure against a queue family's Image Transfer Granularity values
CheckItgOffset(const CMD_BUFFER_STATE * cb_node,const VkOffset3D * offset,const VkExtent3D * granularity,const uint32_t i,const char * function,const char * member,const char * vuid) const2001*b7893ccfSSadaf Ebrahimi bool CoreChecks::CheckItgOffset(const CMD_BUFFER_STATE *cb_node, const VkOffset3D *offset, const VkExtent3D *granularity,
2002*b7893ccfSSadaf Ebrahimi const uint32_t i, const char *function, const char *member, const char *vuid) const {
2003*b7893ccfSSadaf Ebrahimi bool skip = false;
2004*b7893ccfSSadaf Ebrahimi VkExtent3D offset_extent = {};
2005*b7893ccfSSadaf Ebrahimi offset_extent.width = static_cast<uint32_t>(abs(offset->x));
2006*b7893ccfSSadaf Ebrahimi offset_extent.height = static_cast<uint32_t>(abs(offset->y));
2007*b7893ccfSSadaf Ebrahimi offset_extent.depth = static_cast<uint32_t>(abs(offset->z));
2008*b7893ccfSSadaf Ebrahimi if (IsExtentAllZeroes(granularity)) {
2009*b7893ccfSSadaf Ebrahimi // If the queue family image transfer granularity is (0, 0, 0), then the offset must always be (0, 0, 0)
2010*b7893ccfSSadaf Ebrahimi if (IsExtentAllZeroes(&offset_extent) == false) {
2011*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2012*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), vuid,
2013*b7893ccfSSadaf Ebrahimi "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) must be (x=0, y=0, z=0) when the command buffer's queue family "
2014*b7893ccfSSadaf Ebrahimi "image transfer granularity is (w=0, h=0, d=0).",
2015*b7893ccfSSadaf Ebrahimi function, i, member, offset->x, offset->y, offset->z);
2016*b7893ccfSSadaf Ebrahimi }
2017*b7893ccfSSadaf Ebrahimi } else {
2018*b7893ccfSSadaf Ebrahimi // If the queue family image transfer granularity is not (0, 0, 0), then the offset dimensions must always be even
2019*b7893ccfSSadaf Ebrahimi // integer multiples of the image transfer granularity.
2020*b7893ccfSSadaf Ebrahimi if (IsExtentAligned(&offset_extent, granularity) == false) {
2021*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2022*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), vuid,
2023*b7893ccfSSadaf Ebrahimi "%s: pRegion[%d].%s (x=%d, y=%d, z=%d) dimensions must be even integer multiples of this command "
2024*b7893ccfSSadaf Ebrahimi "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d).",
2025*b7893ccfSSadaf Ebrahimi function, i, member, offset->x, offset->y, offset->z, granularity->width, granularity->height,
2026*b7893ccfSSadaf Ebrahimi granularity->depth);
2027*b7893ccfSSadaf Ebrahimi }
2028*b7893ccfSSadaf Ebrahimi }
2029*b7893ccfSSadaf Ebrahimi return skip;
2030*b7893ccfSSadaf Ebrahimi }
2031*b7893ccfSSadaf Ebrahimi
2032*b7893ccfSSadaf Ebrahimi // Check elements of a VkExtent3D structure against a queue family's Image Transfer Granularity values
CheckItgExtent(const CMD_BUFFER_STATE * cb_node,const VkExtent3D * extent,const VkOffset3D * offset,const VkExtent3D * granularity,const VkExtent3D * subresource_extent,const VkImageType image_type,const uint32_t i,const char * function,const char * member,const char * vuid) const2033*b7893ccfSSadaf Ebrahimi bool CoreChecks::CheckItgExtent(const CMD_BUFFER_STATE *cb_node, const VkExtent3D *extent, const VkOffset3D *offset,
2034*b7893ccfSSadaf Ebrahimi const VkExtent3D *granularity, const VkExtent3D *subresource_extent, const VkImageType image_type,
2035*b7893ccfSSadaf Ebrahimi const uint32_t i, const char *function, const char *member, const char *vuid) const {
2036*b7893ccfSSadaf Ebrahimi bool skip = false;
2037*b7893ccfSSadaf Ebrahimi if (IsExtentAllZeroes(granularity)) {
2038*b7893ccfSSadaf Ebrahimi // If the queue family image transfer granularity is (0, 0, 0), then the extent must always match the image
2039*b7893ccfSSadaf Ebrahimi // subresource extent.
2040*b7893ccfSSadaf Ebrahimi if (IsExtentEqual(extent, subresource_extent) == false) {
2041*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2042*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), vuid,
2043*b7893ccfSSadaf Ebrahimi "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d) "
2044*b7893ccfSSadaf Ebrahimi "when the command buffer's queue family image transfer granularity is (w=0, h=0, d=0).",
2045*b7893ccfSSadaf Ebrahimi function, i, member, extent->width, extent->height, extent->depth, subresource_extent->width,
2046*b7893ccfSSadaf Ebrahimi subresource_extent->height, subresource_extent->depth);
2047*b7893ccfSSadaf Ebrahimi }
2048*b7893ccfSSadaf Ebrahimi } else {
2049*b7893ccfSSadaf Ebrahimi // If the queue family image transfer granularity is not (0, 0, 0), then the extent dimensions must always be even
2050*b7893ccfSSadaf Ebrahimi // integer multiples of the image transfer granularity or the offset + extent dimensions must always match the image
2051*b7893ccfSSadaf Ebrahimi // subresource extent dimensions.
2052*b7893ccfSSadaf Ebrahimi VkExtent3D offset_extent_sum = {};
2053*b7893ccfSSadaf Ebrahimi offset_extent_sum.width = static_cast<uint32_t>(abs(offset->x)) + extent->width;
2054*b7893ccfSSadaf Ebrahimi offset_extent_sum.height = static_cast<uint32_t>(abs(offset->y)) + extent->height;
2055*b7893ccfSSadaf Ebrahimi offset_extent_sum.depth = static_cast<uint32_t>(abs(offset->z)) + extent->depth;
2056*b7893ccfSSadaf Ebrahimi bool x_ok = true;
2057*b7893ccfSSadaf Ebrahimi bool y_ok = true;
2058*b7893ccfSSadaf Ebrahimi bool z_ok = true;
2059*b7893ccfSSadaf Ebrahimi switch (image_type) {
2060*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_3D:
2061*b7893ccfSSadaf Ebrahimi z_ok = ((0 == SafeModulo(extent->depth, granularity->depth)) ||
2062*b7893ccfSSadaf Ebrahimi (subresource_extent->depth == offset_extent_sum.depth));
2063*b7893ccfSSadaf Ebrahimi // fall through
2064*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_2D:
2065*b7893ccfSSadaf Ebrahimi y_ok = ((0 == SafeModulo(extent->height, granularity->height)) ||
2066*b7893ccfSSadaf Ebrahimi (subresource_extent->height == offset_extent_sum.height));
2067*b7893ccfSSadaf Ebrahimi // fall through
2068*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_1D:
2069*b7893ccfSSadaf Ebrahimi x_ok = ((0 == SafeModulo(extent->width, granularity->width)) ||
2070*b7893ccfSSadaf Ebrahimi (subresource_extent->width == offset_extent_sum.width));
2071*b7893ccfSSadaf Ebrahimi break;
2072*b7893ccfSSadaf Ebrahimi default:
2073*b7893ccfSSadaf Ebrahimi // Unrecognized or new IMAGE_TYPE enums will be caught in parameter_validation
2074*b7893ccfSSadaf Ebrahimi assert(false);
2075*b7893ccfSSadaf Ebrahimi }
2076*b7893ccfSSadaf Ebrahimi if (!(x_ok && y_ok && z_ok)) {
2077*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2078*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), vuid,
2079*b7893ccfSSadaf Ebrahimi "%s: pRegion[%d].%s (w=%d, h=%d, d=%d) dimensions must be even integer multiples of this command "
2080*b7893ccfSSadaf Ebrahimi "buffer's queue family image transfer granularity (w=%d, h=%d, d=%d) or offset (x=%d, y=%d, z=%d) + "
2081*b7893ccfSSadaf Ebrahimi "extent (w=%d, h=%d, d=%d) must match the image subresource extents (w=%d, h=%d, d=%d).",
2082*b7893ccfSSadaf Ebrahimi function, i, member, extent->width, extent->height, extent->depth, granularity->width,
2083*b7893ccfSSadaf Ebrahimi granularity->height, granularity->depth, offset->x, offset->y, offset->z, extent->width, extent->height,
2084*b7893ccfSSadaf Ebrahimi extent->depth, subresource_extent->width, subresource_extent->height, subresource_extent->depth);
2085*b7893ccfSSadaf Ebrahimi }
2086*b7893ccfSSadaf Ebrahimi }
2087*b7893ccfSSadaf Ebrahimi return skip;
2088*b7893ccfSSadaf Ebrahimi }
2089*b7893ccfSSadaf Ebrahimi
ValidateImageMipLevel(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img,uint32_t mip_level,const uint32_t i,const char * function,const char * member,const char * vuid) const2090*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageMipLevel(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, uint32_t mip_level,
2091*b7893ccfSSadaf Ebrahimi const uint32_t i, const char *function, const char *member, const char *vuid) const {
2092*b7893ccfSSadaf Ebrahimi bool skip = false;
2093*b7893ccfSSadaf Ebrahimi if (mip_level >= img->createInfo.mipLevels) {
2094*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2095*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), vuid,
2096*b7893ccfSSadaf Ebrahimi "In %s, pRegions[%u].%s.mipLevel is %u, but provided %s has %u mip levels.", function, i, member, mip_level,
2097*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(img->image).c_str(), img->createInfo.mipLevels);
2098*b7893ccfSSadaf Ebrahimi }
2099*b7893ccfSSadaf Ebrahimi return skip;
2100*b7893ccfSSadaf Ebrahimi }
2101*b7893ccfSSadaf Ebrahimi
ValidateImageArrayLayerRange(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img,const uint32_t base_layer,const uint32_t layer_count,const uint32_t i,const char * function,const char * member,const char * vuid) const2102*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageArrayLayerRange(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img, const uint32_t base_layer,
2103*b7893ccfSSadaf Ebrahimi const uint32_t layer_count, const uint32_t i, const char *function,
2104*b7893ccfSSadaf Ebrahimi const char *member, const char *vuid) const {
2105*b7893ccfSSadaf Ebrahimi bool skip = false;
2106*b7893ccfSSadaf Ebrahimi if (base_layer >= img->createInfo.arrayLayers || layer_count > img->createInfo.arrayLayers ||
2107*b7893ccfSSadaf Ebrahimi (base_layer + layer_count) > img->createInfo.arrayLayers) {
2108*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2109*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), vuid,
2110*b7893ccfSSadaf Ebrahimi "In %s, pRegions[%u].%s.baseArrayLayer is %u and .layerCount is "
2111*b7893ccfSSadaf Ebrahimi "%u, but provided %s has %u array layers.",
2112*b7893ccfSSadaf Ebrahimi function, i, member, base_layer, layer_count, report_data->FormatHandle(img->image).c_str(),
2113*b7893ccfSSadaf Ebrahimi img->createInfo.arrayLayers);
2114*b7893ccfSSadaf Ebrahimi }
2115*b7893ccfSSadaf Ebrahimi return skip;
2116*b7893ccfSSadaf Ebrahimi }
2117*b7893ccfSSadaf Ebrahimi
2118*b7893ccfSSadaf Ebrahimi // Check valid usage Image Transfer Granularity requirements for elements of a VkBufferImageCopy structure
ValidateCopyBufferImageTransferGranularityRequirements(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * img,const VkBufferImageCopy * region,const uint32_t i,const char * function,const char * vuid) const2119*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCopyBufferImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *img,
2120*b7893ccfSSadaf Ebrahimi const VkBufferImageCopy *region, const uint32_t i,
2121*b7893ccfSSadaf Ebrahimi const char *function, const char *vuid) const {
2122*b7893ccfSSadaf Ebrahimi bool skip = false;
2123*b7893ccfSSadaf Ebrahimi VkExtent3D granularity = GetScaledItg(cb_node, img);
2124*b7893ccfSSadaf Ebrahimi skip |= CheckItgOffset(cb_node, ®ion->imageOffset, &granularity, i, function, "imageOffset", vuid);
2125*b7893ccfSSadaf Ebrahimi VkExtent3D subresource_extent = GetImageSubresourceExtent(img, ®ion->imageSubresource);
2126*b7893ccfSSadaf Ebrahimi skip |= CheckItgExtent(cb_node, ®ion->imageExtent, ®ion->imageOffset, &granularity, &subresource_extent,
2127*b7893ccfSSadaf Ebrahimi img->createInfo.imageType, i, function, "imageExtent", vuid);
2128*b7893ccfSSadaf Ebrahimi return skip;
2129*b7893ccfSSadaf Ebrahimi }
2130*b7893ccfSSadaf Ebrahimi
2131*b7893ccfSSadaf Ebrahimi // Check valid usage Image Transfer Granularity requirements for elements of a VkImageCopy structure
ValidateCopyImageTransferGranularityRequirements(const CMD_BUFFER_STATE * cb_node,const IMAGE_STATE * src_img,const IMAGE_STATE * dst_img,const VkImageCopy * region,const uint32_t i,const char * function) const2132*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCopyImageTransferGranularityRequirements(const CMD_BUFFER_STATE *cb_node, const IMAGE_STATE *src_img,
2133*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *dst_img, const VkImageCopy *region,
2134*b7893ccfSSadaf Ebrahimi const uint32_t i, const char *function) const {
2135*b7893ccfSSadaf Ebrahimi bool skip = false;
2136*b7893ccfSSadaf Ebrahimi // Source image checks
2137*b7893ccfSSadaf Ebrahimi VkExtent3D granularity = GetScaledItg(cb_node, src_img);
2138*b7893ccfSSadaf Ebrahimi skip |=
2139*b7893ccfSSadaf Ebrahimi CheckItgOffset(cb_node, ®ion->srcOffset, &granularity, i, function, "srcOffset", "VUID-vkCmdCopyImage-srcOffset-01783");
2140*b7893ccfSSadaf Ebrahimi VkExtent3D subresource_extent = GetImageSubresourceExtent(src_img, ®ion->srcSubresource);
2141*b7893ccfSSadaf Ebrahimi const VkExtent3D extent = region->extent;
2142*b7893ccfSSadaf Ebrahimi skip |= CheckItgExtent(cb_node, &extent, ®ion->srcOffset, &granularity, &subresource_extent, src_img->createInfo.imageType,
2143*b7893ccfSSadaf Ebrahimi i, function, "extent", "VUID-vkCmdCopyImage-srcOffset-01783");
2144*b7893ccfSSadaf Ebrahimi
2145*b7893ccfSSadaf Ebrahimi // Destination image checks
2146*b7893ccfSSadaf Ebrahimi granularity = GetScaledItg(cb_node, dst_img);
2147*b7893ccfSSadaf Ebrahimi skip |=
2148*b7893ccfSSadaf Ebrahimi CheckItgOffset(cb_node, ®ion->dstOffset, &granularity, i, function, "dstOffset", "VUID-vkCmdCopyImage-dstOffset-01784");
2149*b7893ccfSSadaf Ebrahimi // Adjust dest extent, if necessary
2150*b7893ccfSSadaf Ebrahimi const VkExtent3D dest_effective_extent =
2151*b7893ccfSSadaf Ebrahimi GetAdjustedDestImageExtent(src_img->createInfo.format, dst_img->createInfo.format, extent);
2152*b7893ccfSSadaf Ebrahimi subresource_extent = GetImageSubresourceExtent(dst_img, ®ion->dstSubresource);
2153*b7893ccfSSadaf Ebrahimi skip |= CheckItgExtent(cb_node, &dest_effective_extent, ®ion->dstOffset, &granularity, &subresource_extent,
2154*b7893ccfSSadaf Ebrahimi dst_img->createInfo.imageType, i, function, "extent", "VUID-vkCmdCopyImage-dstOffset-01784");
2155*b7893ccfSSadaf Ebrahimi return skip;
2156*b7893ccfSSadaf Ebrahimi }
2157*b7893ccfSSadaf Ebrahimi
2158*b7893ccfSSadaf Ebrahimi // Validate contents of a VkImageCopy struct
ValidateImageCopyData(const uint32_t regionCount,const VkImageCopy * ic_regions,const IMAGE_STATE * src_state,const IMAGE_STATE * dst_state) const2159*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageCopyData(const uint32_t regionCount, const VkImageCopy *ic_regions, const IMAGE_STATE *src_state,
2160*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *dst_state) const {
2161*b7893ccfSSadaf Ebrahimi bool skip = false;
2162*b7893ccfSSadaf Ebrahimi
2163*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
2164*b7893ccfSSadaf Ebrahimi const VkImageCopy region = ic_regions[i];
2165*b7893ccfSSadaf Ebrahimi
2166*b7893ccfSSadaf Ebrahimi // For comp<->uncomp copies, the copy extent for the dest image must be adjusted
2167*b7893ccfSSadaf Ebrahimi const VkExtent3D src_copy_extent = region.extent;
2168*b7893ccfSSadaf Ebrahimi const VkExtent3D dst_copy_extent =
2169*b7893ccfSSadaf Ebrahimi GetAdjustedDestImageExtent(src_state->createInfo.format, dst_state->createInfo.format, region.extent);
2170*b7893ccfSSadaf Ebrahimi
2171*b7893ccfSSadaf Ebrahimi bool slice_override = false;
2172*b7893ccfSSadaf Ebrahimi uint32_t depth_slices = 0;
2173*b7893ccfSSadaf Ebrahimi
2174*b7893ccfSSadaf Ebrahimi // Special case for copying between a 1D/2D array and a 3D image
2175*b7893ccfSSadaf Ebrahimi // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
2176*b7893ccfSSadaf Ebrahimi if ((VK_IMAGE_TYPE_3D == src_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != dst_state->createInfo.imageType)) {
2177*b7893ccfSSadaf Ebrahimi depth_slices = region.dstSubresource.layerCount; // Slice count from 2D subresource
2178*b7893ccfSSadaf Ebrahimi slice_override = (depth_slices != 1);
2179*b7893ccfSSadaf Ebrahimi } else if ((VK_IMAGE_TYPE_3D == dst_state->createInfo.imageType) && (VK_IMAGE_TYPE_3D != src_state->createInfo.imageType)) {
2180*b7893ccfSSadaf Ebrahimi depth_slices = region.srcSubresource.layerCount; // Slice count from 2D subresource
2181*b7893ccfSSadaf Ebrahimi slice_override = (depth_slices != 1);
2182*b7893ccfSSadaf Ebrahimi }
2183*b7893ccfSSadaf Ebrahimi
2184*b7893ccfSSadaf Ebrahimi // Do all checks on source image
2185*b7893ccfSSadaf Ebrahimi //
2186*b7893ccfSSadaf Ebrahimi if (src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
2187*b7893ccfSSadaf Ebrahimi if ((0 != region.srcOffset.y) || (1 != src_copy_extent.height)) {
2188*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2189*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-00146",
2190*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] srcOffset.y is %d and extent.height is %d. For 1D images these must "
2191*b7893ccfSSadaf Ebrahimi "be 0 and 1, respectively.",
2192*b7893ccfSSadaf Ebrahimi i, region.srcOffset.y, src_copy_extent.height);
2193*b7893ccfSSadaf Ebrahimi }
2194*b7893ccfSSadaf Ebrahimi }
2195*b7893ccfSSadaf Ebrahimi
2196*b7893ccfSSadaf Ebrahimi // VUID-VkImageCopy-srcImage-01785
2197*b7893ccfSSadaf Ebrahimi if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.srcOffset.z) || (1 != src_copy_extent.depth))) {
2198*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2199*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-01785",
2200*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] srcOffset.z is %d and extent.depth is %d. For 1D images "
2201*b7893ccfSSadaf Ebrahimi "these must be 0 and 1, respectively.",
2202*b7893ccfSSadaf Ebrahimi i, region.srcOffset.z, src_copy_extent.depth);
2203*b7893ccfSSadaf Ebrahimi }
2204*b7893ccfSSadaf Ebrahimi
2205*b7893ccfSSadaf Ebrahimi // VUID-VkImageCopy-srcImage-01787
2206*b7893ccfSSadaf Ebrahimi if ((src_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.srcOffset.z)) {
2207*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2208*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-01787",
2209*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] srcOffset.z is %d. For 2D images the z-offset must be 0.", i,
2210*b7893ccfSSadaf Ebrahimi region.srcOffset.z);
2211*b7893ccfSSadaf Ebrahimi }
2212*b7893ccfSSadaf Ebrahimi
2213*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance1) {
2214*b7893ccfSSadaf Ebrahimi if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2215*b7893ccfSSadaf Ebrahimi if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
2216*b7893ccfSSadaf Ebrahimi skip |=
2217*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2218*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-00141",
2219*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] srcSubresource.baseArrayLayer is %d and srcSubresource.layerCount "
2220*b7893ccfSSadaf Ebrahimi "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2221*b7893ccfSSadaf Ebrahimi i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
2222*b7893ccfSSadaf Ebrahimi }
2223*b7893ccfSSadaf Ebrahimi }
2224*b7893ccfSSadaf Ebrahimi } else { // Pre maint 1
2225*b7893ccfSSadaf Ebrahimi if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D || dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2226*b7893ccfSSadaf Ebrahimi if ((0 != region.srcSubresource.baseArrayLayer) || (1 != region.srcSubresource.layerCount)) {
2227*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2228*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), "VUID-VkImageCopy-srcImage-00141",
2229*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] srcSubresource.baseArrayLayer is %d and "
2230*b7893ccfSSadaf Ebrahimi "srcSubresource.layerCount is %d. For copies with either source or dest of type "
2231*b7893ccfSSadaf Ebrahimi "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
2232*b7893ccfSSadaf Ebrahimi i, region.srcSubresource.baseArrayLayer, region.srcSubresource.layerCount);
2233*b7893ccfSSadaf Ebrahimi }
2234*b7893ccfSSadaf Ebrahimi }
2235*b7893ccfSSadaf Ebrahimi }
2236*b7893ccfSSadaf Ebrahimi
2237*b7893ccfSSadaf Ebrahimi // Source checks that apply only to compressed images (or to _422 images if ycbcr enabled)
2238*b7893ccfSSadaf Ebrahimi bool ext_ycbcr = device_extensions.vk_khr_sampler_ycbcr_conversion;
2239*b7893ccfSSadaf Ebrahimi if (FormatIsCompressed(src_state->createInfo.format) ||
2240*b7893ccfSSadaf Ebrahimi (ext_ycbcr && FormatIsSinglePlane_422(src_state->createInfo.format))) {
2241*b7893ccfSSadaf Ebrahimi const VkExtent3D block_size = FormatTexelBlockExtent(src_state->createInfo.format);
2242*b7893ccfSSadaf Ebrahimi // image offsets must be multiples of block dimensions
2243*b7893ccfSSadaf Ebrahimi if ((SafeModulo(region.srcOffset.x, block_size.width) != 0) ||
2244*b7893ccfSSadaf Ebrahimi (SafeModulo(region.srcOffset.y, block_size.height) != 0) ||
2245*b7893ccfSSadaf Ebrahimi (SafeModulo(region.srcOffset.z, block_size.depth) != 0)) {
2246*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01727" : "VUID-VkImageCopy-srcOffset-00157";
2247*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2248*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), vuid,
2249*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] srcOffset (%d, %d) must be multiples of the compressed image's "
2250*b7893ccfSSadaf Ebrahimi "texel width & height (%d, %d).",
2251*b7893ccfSSadaf Ebrahimi i, region.srcOffset.x, region.srcOffset.y, block_size.width, block_size.height);
2252*b7893ccfSSadaf Ebrahimi }
2253*b7893ccfSSadaf Ebrahimi
2254*b7893ccfSSadaf Ebrahimi const VkExtent3D mip_extent = GetImageSubresourceExtent(src_state, &(region.srcSubresource));
2255*b7893ccfSSadaf Ebrahimi if ((SafeModulo(src_copy_extent.width, block_size.width) != 0) &&
2256*b7893ccfSSadaf Ebrahimi (src_copy_extent.width + region.srcOffset.x != mip_extent.width)) {
2257*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01728" : "VUID-VkImageCopy-extent-00158";
2258*b7893ccfSSadaf Ebrahimi skip |=
2259*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2260*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), vuid,
2261*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
2262*b7893ccfSSadaf Ebrahimi "width (%d), or when added to srcOffset.x (%d) must equal the image subresource width (%d).",
2263*b7893ccfSSadaf Ebrahimi i, src_copy_extent.width, block_size.width, region.srcOffset.x, mip_extent.width);
2264*b7893ccfSSadaf Ebrahimi }
2265*b7893ccfSSadaf Ebrahimi
2266*b7893ccfSSadaf Ebrahimi // Extent height must be a multiple of block height, or extent+offset height must equal subresource height
2267*b7893ccfSSadaf Ebrahimi if ((SafeModulo(src_copy_extent.height, block_size.height) != 0) &&
2268*b7893ccfSSadaf Ebrahimi (src_copy_extent.height + region.srcOffset.y != mip_extent.height)) {
2269*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01729" : "VUID-VkImageCopy-extent-00159";
2270*b7893ccfSSadaf Ebrahimi skip |=
2271*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2272*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), vuid,
2273*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] extent height (%d) must be a multiple of the compressed texture block "
2274*b7893ccfSSadaf Ebrahimi "height (%d), or when added to srcOffset.y (%d) must equal the image subresource height (%d).",
2275*b7893ccfSSadaf Ebrahimi i, src_copy_extent.height, block_size.height, region.srcOffset.y, mip_extent.height);
2276*b7893ccfSSadaf Ebrahimi }
2277*b7893ccfSSadaf Ebrahimi
2278*b7893ccfSSadaf Ebrahimi // Extent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
2279*b7893ccfSSadaf Ebrahimi uint32_t copy_depth = (slice_override ? depth_slices : src_copy_extent.depth);
2280*b7893ccfSSadaf Ebrahimi if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.srcOffset.z != mip_extent.depth)) {
2281*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-srcImage-01730" : "VUID-VkImageCopy-extent-00160";
2282*b7893ccfSSadaf Ebrahimi skip |=
2283*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2284*b7893ccfSSadaf Ebrahimi HandleToUint64(src_state->image), vuid,
2285*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block "
2286*b7893ccfSSadaf Ebrahimi "depth (%d), or when added to srcOffset.z (%d) must equal the image subresource depth (%d).",
2287*b7893ccfSSadaf Ebrahimi i, src_copy_extent.depth, block_size.depth, region.srcOffset.z, mip_extent.depth);
2288*b7893ccfSSadaf Ebrahimi }
2289*b7893ccfSSadaf Ebrahimi } // Compressed
2290*b7893ccfSSadaf Ebrahimi
2291*b7893ccfSSadaf Ebrahimi // Do all checks on dest image
2292*b7893ccfSSadaf Ebrahimi //
2293*b7893ccfSSadaf Ebrahimi if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
2294*b7893ccfSSadaf Ebrahimi if ((0 != region.dstOffset.y) || (1 != dst_copy_extent.height)) {
2295*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2296*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), "VUID-VkImageCopy-dstImage-00152",
2297*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstOffset.y is %d and dst_copy_extent.height is %d. For 1D images "
2298*b7893ccfSSadaf Ebrahimi "these must be 0 and 1, respectively.",
2299*b7893ccfSSadaf Ebrahimi i, region.dstOffset.y, dst_copy_extent.height);
2300*b7893ccfSSadaf Ebrahimi }
2301*b7893ccfSSadaf Ebrahimi }
2302*b7893ccfSSadaf Ebrahimi
2303*b7893ccfSSadaf Ebrahimi // VUID-VkImageCopy-dstImage-01786
2304*b7893ccfSSadaf Ebrahimi if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_1D) && ((0 != region.dstOffset.z) || (1 != dst_copy_extent.depth))) {
2305*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2306*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), "VUID-VkImageCopy-dstImage-01786",
2307*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstOffset.z is %d and extent.depth is %d. For 1D images these must be 0 "
2308*b7893ccfSSadaf Ebrahimi "and 1, respectively.",
2309*b7893ccfSSadaf Ebrahimi i, region.dstOffset.z, dst_copy_extent.depth);
2310*b7893ccfSSadaf Ebrahimi }
2311*b7893ccfSSadaf Ebrahimi
2312*b7893ccfSSadaf Ebrahimi // VUID-VkImageCopy-dstImage-01788
2313*b7893ccfSSadaf Ebrahimi if ((dst_state->createInfo.imageType == VK_IMAGE_TYPE_2D) && (0 != region.dstOffset.z)) {
2314*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2315*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), "VUID-VkImageCopy-dstImage-01788",
2316*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstOffset.z is %d. For 2D images the z-offset must be 0.", i,
2317*b7893ccfSSadaf Ebrahimi region.dstOffset.z);
2318*b7893ccfSSadaf Ebrahimi }
2319*b7893ccfSSadaf Ebrahimi
2320*b7893ccfSSadaf Ebrahimi if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2321*b7893ccfSSadaf Ebrahimi if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
2322*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2323*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), "VUID-VkImageCopy-srcImage-00141",
2324*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstSubresource.baseArrayLayer is %d and dstSubresource.layerCount "
2325*b7893ccfSSadaf Ebrahimi "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2326*b7893ccfSSadaf Ebrahimi i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
2327*b7893ccfSSadaf Ebrahimi }
2328*b7893ccfSSadaf Ebrahimi }
2329*b7893ccfSSadaf Ebrahimi // VU01199 changed with mnt1
2330*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance1) {
2331*b7893ccfSSadaf Ebrahimi if (dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2332*b7893ccfSSadaf Ebrahimi if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
2333*b7893ccfSSadaf Ebrahimi skip |=
2334*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2335*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), "VUID-VkImageCopy-srcImage-00141",
2336*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstSubresource.baseArrayLayer is %d and dstSubresource.layerCount "
2337*b7893ccfSSadaf Ebrahimi "is %d. For VK_IMAGE_TYPE_3D images these must be 0 and 1, respectively.",
2338*b7893ccfSSadaf Ebrahimi i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
2339*b7893ccfSSadaf Ebrahimi }
2340*b7893ccfSSadaf Ebrahimi }
2341*b7893ccfSSadaf Ebrahimi } else { // Pre maint 1
2342*b7893ccfSSadaf Ebrahimi if (src_state->createInfo.imageType == VK_IMAGE_TYPE_3D || dst_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
2343*b7893ccfSSadaf Ebrahimi if ((0 != region.dstSubresource.baseArrayLayer) || (1 != region.dstSubresource.layerCount)) {
2344*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2345*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), "VUID-VkImageCopy-srcImage-00141",
2346*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstSubresource.baseArrayLayer is %d and "
2347*b7893ccfSSadaf Ebrahimi "dstSubresource.layerCount is %d. For copies with either source or dest of type "
2348*b7893ccfSSadaf Ebrahimi "VK_IMAGE_TYPE_3D, these must be 0 and 1, respectively.",
2349*b7893ccfSSadaf Ebrahimi i, region.dstSubresource.baseArrayLayer, region.dstSubresource.layerCount);
2350*b7893ccfSSadaf Ebrahimi }
2351*b7893ccfSSadaf Ebrahimi }
2352*b7893ccfSSadaf Ebrahimi }
2353*b7893ccfSSadaf Ebrahimi
2354*b7893ccfSSadaf Ebrahimi // Dest checks that apply only to compressed images (or to _422 images if ycbcr enabled)
2355*b7893ccfSSadaf Ebrahimi if (FormatIsCompressed(dst_state->createInfo.format) ||
2356*b7893ccfSSadaf Ebrahimi (ext_ycbcr && FormatIsSinglePlane_422(dst_state->createInfo.format))) {
2357*b7893ccfSSadaf Ebrahimi const VkExtent3D block_size = FormatTexelBlockExtent(dst_state->createInfo.format);
2358*b7893ccfSSadaf Ebrahimi
2359*b7893ccfSSadaf Ebrahimi // image offsets must be multiples of block dimensions
2360*b7893ccfSSadaf Ebrahimi if ((SafeModulo(region.dstOffset.x, block_size.width) != 0) ||
2361*b7893ccfSSadaf Ebrahimi (SafeModulo(region.dstOffset.y, block_size.height) != 0) ||
2362*b7893ccfSSadaf Ebrahimi (SafeModulo(region.dstOffset.z, block_size.depth) != 0)) {
2363*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01731" : "VUID-VkImageCopy-dstOffset-00162";
2364*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2365*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), vuid,
2366*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dstOffset (%d, %d) must be multiples of the compressed image's "
2367*b7893ccfSSadaf Ebrahimi "texel width & height (%d, %d).",
2368*b7893ccfSSadaf Ebrahimi i, region.dstOffset.x, region.dstOffset.y, block_size.width, block_size.height);
2369*b7893ccfSSadaf Ebrahimi }
2370*b7893ccfSSadaf Ebrahimi
2371*b7893ccfSSadaf Ebrahimi const VkExtent3D mip_extent = GetImageSubresourceExtent(dst_state, &(region.dstSubresource));
2372*b7893ccfSSadaf Ebrahimi if ((SafeModulo(dst_copy_extent.width, block_size.width) != 0) &&
2373*b7893ccfSSadaf Ebrahimi (dst_copy_extent.width + region.dstOffset.x != mip_extent.width)) {
2374*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01732" : "VUID-VkImageCopy-extent-00163";
2375*b7893ccfSSadaf Ebrahimi skip |=
2376*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2377*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), vuid,
2378*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
2379*b7893ccfSSadaf Ebrahimi "block width (%d), or when added to dstOffset.x (%d) must equal the image subresource width (%d).",
2380*b7893ccfSSadaf Ebrahimi i, dst_copy_extent.width, block_size.width, region.dstOffset.x, mip_extent.width);
2381*b7893ccfSSadaf Ebrahimi }
2382*b7893ccfSSadaf Ebrahimi
2383*b7893ccfSSadaf Ebrahimi // Extent height must be a multiple of block height, or dst_copy_extent+offset height must equal subresource height
2384*b7893ccfSSadaf Ebrahimi if ((SafeModulo(dst_copy_extent.height, block_size.height) != 0) &&
2385*b7893ccfSSadaf Ebrahimi (dst_copy_extent.height + region.dstOffset.y != mip_extent.height)) {
2386*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01733" : "VUID-VkImageCopy-extent-00164";
2387*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2388*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), vuid,
2389*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dst_copy_extent height (%d) must be a multiple of the compressed "
2390*b7893ccfSSadaf Ebrahimi "texture block height (%d), or when added to dstOffset.y (%d) must equal the image subresource "
2391*b7893ccfSSadaf Ebrahimi "height (%d).",
2392*b7893ccfSSadaf Ebrahimi i, dst_copy_extent.height, block_size.height, region.dstOffset.y, mip_extent.height);
2393*b7893ccfSSadaf Ebrahimi }
2394*b7893ccfSSadaf Ebrahimi
2395*b7893ccfSSadaf Ebrahimi // Extent depth must be a multiple of block depth, or dst_copy_extent+offset depth must equal subresource depth
2396*b7893ccfSSadaf Ebrahimi uint32_t copy_depth = (slice_override ? depth_slices : dst_copy_extent.depth);
2397*b7893ccfSSadaf Ebrahimi if ((SafeModulo(copy_depth, block_size.depth) != 0) && (copy_depth + region.dstOffset.z != mip_extent.depth)) {
2398*b7893ccfSSadaf Ebrahimi const char *vuid = ext_ycbcr ? "VUID-VkImageCopy-dstImage-01734" : "VUID-VkImageCopy-extent-00165";
2399*b7893ccfSSadaf Ebrahimi skip |=
2400*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
2401*b7893ccfSSadaf Ebrahimi HandleToUint64(dst_state->image), vuid,
2402*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): pRegion[%d] dst_copy_extent width (%d) must be a multiple of the compressed texture "
2403*b7893ccfSSadaf Ebrahimi "block depth (%d), or when added to dstOffset.z (%d) must equal the image subresource depth (%d).",
2404*b7893ccfSSadaf Ebrahimi i, dst_copy_extent.depth, block_size.depth, region.dstOffset.z, mip_extent.depth);
2405*b7893ccfSSadaf Ebrahimi }
2406*b7893ccfSSadaf Ebrahimi } // Compressed
2407*b7893ccfSSadaf Ebrahimi }
2408*b7893ccfSSadaf Ebrahimi return skip;
2409*b7893ccfSSadaf Ebrahimi }
2410*b7893ccfSSadaf Ebrahimi
2411*b7893ccfSSadaf Ebrahimi // vkCmdCopyImage checks that only apply if the multiplane extension is enabled
CopyImageMultiplaneValidation(VkCommandBuffer command_buffer,const IMAGE_STATE * src_image_state,const IMAGE_STATE * dst_image_state,const VkImageCopy region) const2412*b7893ccfSSadaf Ebrahimi bool CoreChecks::CopyImageMultiplaneValidation(VkCommandBuffer command_buffer, const IMAGE_STATE *src_image_state,
2413*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *dst_image_state, const VkImageCopy region) const {
2414*b7893ccfSSadaf Ebrahimi bool skip = false;
2415*b7893ccfSSadaf Ebrahimi
2416*b7893ccfSSadaf Ebrahimi // Neither image is multiplane
2417*b7893ccfSSadaf Ebrahimi if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format))) {
2418*b7893ccfSSadaf Ebrahimi // If neither image is multi-plane the aspectMask member of src and dst must match
2419*b7893ccfSSadaf Ebrahimi if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
2420*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2421*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Copy between non-multiplane images with differing aspectMasks ( 0x" << std::hex
2422*b7893ccfSSadaf Ebrahimi << region.srcSubresource.aspectMask << " and 0x" << region.dstSubresource.aspectMask << " )";
2423*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2424*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01551", "%s.", ss.str().c_str());
2425*b7893ccfSSadaf Ebrahimi }
2426*b7893ccfSSadaf Ebrahimi } else {
2427*b7893ccfSSadaf Ebrahimi // Source image multiplane checks
2428*b7893ccfSSadaf Ebrahimi uint32_t planes = FormatPlaneCount(src_image_state->createInfo.format);
2429*b7893ccfSSadaf Ebrahimi VkImageAspectFlags aspect = region.srcSubresource.aspectMask;
2430*b7893ccfSSadaf Ebrahimi if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) {
2431*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2432*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
2433*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2434*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01552", "%s.", ss.str().c_str());
2435*b7893ccfSSadaf Ebrahimi }
2436*b7893ccfSSadaf Ebrahimi if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) &&
2437*b7893ccfSSadaf Ebrahimi (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) {
2438*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2439*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
2440*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2441*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01553", "%s.", ss.str().c_str());
2442*b7893ccfSSadaf Ebrahimi }
2443*b7893ccfSSadaf Ebrahimi // Single-plane to multi-plane
2444*b7893ccfSSadaf Ebrahimi if ((!FormatIsMultiplane(src_image_state->createInfo.format)) && (FormatIsMultiplane(dst_image_state->createInfo.format)) &&
2445*b7893ccfSSadaf Ebrahimi (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
2446*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2447*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Source image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
2448*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2449*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01557", "%s.", ss.str().c_str());
2450*b7893ccfSSadaf Ebrahimi }
2451*b7893ccfSSadaf Ebrahimi
2452*b7893ccfSSadaf Ebrahimi // Dest image multiplane checks
2453*b7893ccfSSadaf Ebrahimi planes = FormatPlaneCount(dst_image_state->createInfo.format);
2454*b7893ccfSSadaf Ebrahimi aspect = region.dstSubresource.aspectMask;
2455*b7893ccfSSadaf Ebrahimi if ((2 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR)) {
2456*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2457*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 2-plane format";
2458*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2459*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01554", "%s.", ss.str().c_str());
2460*b7893ccfSSadaf Ebrahimi }
2461*b7893ccfSSadaf Ebrahimi if ((3 == planes) && (aspect != VK_IMAGE_ASPECT_PLANE_0_BIT_KHR) && (aspect != VK_IMAGE_ASPECT_PLANE_1_BIT_KHR) &&
2462*b7893ccfSSadaf Ebrahimi (aspect != VK_IMAGE_ASPECT_PLANE_2_BIT_KHR)) {
2463*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2464*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is invalid for 3-plane format";
2465*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2466*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-dstImage-01555", "%s.", ss.str().c_str());
2467*b7893ccfSSadaf Ebrahimi }
2468*b7893ccfSSadaf Ebrahimi // Multi-plane to single-plane
2469*b7893ccfSSadaf Ebrahimi if ((FormatIsMultiplane(src_image_state->createInfo.format)) && (!FormatIsMultiplane(dst_image_state->createInfo.format)) &&
2470*b7893ccfSSadaf Ebrahimi (VK_IMAGE_ASPECT_COLOR_BIT != aspect)) {
2471*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2472*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Dest image aspect mask (0x" << std::hex << aspect << ") is not VK_IMAGE_ASPECT_COLOR_BIT";
2473*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2474*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcImage-01556", "%s.", ss.str().c_str());
2475*b7893ccfSSadaf Ebrahimi }
2476*b7893ccfSSadaf Ebrahimi }
2477*b7893ccfSSadaf Ebrahimi
2478*b7893ccfSSadaf Ebrahimi return skip;
2479*b7893ccfSSadaf Ebrahimi }
2480*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageCopy * pRegions)2481*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
2482*b7893ccfSSadaf Ebrahimi VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
2483*b7893ccfSSadaf Ebrahimi const VkImageCopy *pRegions) {
2484*b7893ccfSSadaf Ebrahimi const auto *cb_node = GetCBState(commandBuffer);
2485*b7893ccfSSadaf Ebrahimi const auto *src_image_state = GetImageState(srcImage);
2486*b7893ccfSSadaf Ebrahimi const auto *dst_image_state = GetImageState(dstImage);
2487*b7893ccfSSadaf Ebrahimi bool skip = false;
2488*b7893ccfSSadaf Ebrahimi
2489*b7893ccfSSadaf Ebrahimi skip = ValidateImageCopyData(regionCount, pRegions, src_image_state, dst_image_state);
2490*b7893ccfSSadaf Ebrahimi
2491*b7893ccfSSadaf Ebrahimi VkCommandBuffer command_buffer = cb_node->commandBuffer;
2492*b7893ccfSSadaf Ebrahimi
2493*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
2494*b7893ccfSSadaf Ebrahimi const VkImageCopy region = pRegions[i];
2495*b7893ccfSSadaf Ebrahimi
2496*b7893ccfSSadaf Ebrahimi // For comp/uncomp copies, the copy extent for the dest image must be adjusted
2497*b7893ccfSSadaf Ebrahimi VkExtent3D src_copy_extent = region.extent;
2498*b7893ccfSSadaf Ebrahimi VkExtent3D dst_copy_extent =
2499*b7893ccfSSadaf Ebrahimi GetAdjustedDestImageExtent(src_image_state->createInfo.format, dst_image_state->createInfo.format, region.extent);
2500*b7893ccfSSadaf Ebrahimi
2501*b7893ccfSSadaf Ebrahimi bool slice_override = false;
2502*b7893ccfSSadaf Ebrahimi uint32_t depth_slices = 0;
2503*b7893ccfSSadaf Ebrahimi
2504*b7893ccfSSadaf Ebrahimi // Special case for copying between a 1D/2D array and a 3D image
2505*b7893ccfSSadaf Ebrahimi // TBD: This seems like the only way to reconcile 3 mutually-exclusive VU checks for 2D/3D copies. Heads up.
2506*b7893ccfSSadaf Ebrahimi if ((VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType) &&
2507*b7893ccfSSadaf Ebrahimi (VK_IMAGE_TYPE_3D != dst_image_state->createInfo.imageType)) {
2508*b7893ccfSSadaf Ebrahimi depth_slices = region.dstSubresource.layerCount; // Slice count from 2D subresource
2509*b7893ccfSSadaf Ebrahimi slice_override = (depth_slices != 1);
2510*b7893ccfSSadaf Ebrahimi } else if ((VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType) &&
2511*b7893ccfSSadaf Ebrahimi (VK_IMAGE_TYPE_3D != src_image_state->createInfo.imageType)) {
2512*b7893ccfSSadaf Ebrahimi depth_slices = region.srcSubresource.layerCount; // Slice count from 2D subresource
2513*b7893ccfSSadaf Ebrahimi slice_override = (depth_slices != 1);
2514*b7893ccfSSadaf Ebrahimi }
2515*b7893ccfSSadaf Ebrahimi
2516*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSubresourceLayers(cb_node, ®ion.srcSubresource, "vkCmdCopyImage", "srcSubresource", i);
2517*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSubresourceLayers(cb_node, ®ion.dstSubresource, "vkCmdCopyImage", "dstSubresource", i);
2518*b7893ccfSSadaf Ebrahimi skip |= ValidateImageMipLevel(cb_node, src_image_state, region.srcSubresource.mipLevel, i, "vkCmdCopyImage",
2519*b7893ccfSSadaf Ebrahimi "srcSubresource", "VUID-vkCmdCopyImage-srcSubresource-01696");
2520*b7893ccfSSadaf Ebrahimi skip |= ValidateImageMipLevel(cb_node, dst_image_state, region.dstSubresource.mipLevel, i, "vkCmdCopyImage",
2521*b7893ccfSSadaf Ebrahimi "dstSubresource", "VUID-vkCmdCopyImage-dstSubresource-01697");
2522*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, region.srcSubresource.baseArrayLayer,
2523*b7893ccfSSadaf Ebrahimi region.srcSubresource.layerCount, i, "vkCmdCopyImage", "srcSubresource",
2524*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-srcSubresource-01698");
2525*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, region.dstSubresource.baseArrayLayer,
2526*b7893ccfSSadaf Ebrahimi region.dstSubresource.layerCount, i, "vkCmdCopyImage", "dstSubresource",
2527*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-dstSubresource-01699");
2528*b7893ccfSSadaf Ebrahimi
2529*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance1) {
2530*b7893ccfSSadaf Ebrahimi // No chance of mismatch if we're overriding depth slice count
2531*b7893ccfSSadaf Ebrahimi if (!slice_override) {
2532*b7893ccfSSadaf Ebrahimi // The number of depth slices in srcSubresource and dstSubresource must match
2533*b7893ccfSSadaf Ebrahimi // Depth comes from layerCount for 1D,2D resources, from extent.depth for 3D
2534*b7893ccfSSadaf Ebrahimi uint32_t src_slices =
2535*b7893ccfSSadaf Ebrahimi (VK_IMAGE_TYPE_3D == src_image_state->createInfo.imageType ? src_copy_extent.depth
2536*b7893ccfSSadaf Ebrahimi : region.srcSubresource.layerCount);
2537*b7893ccfSSadaf Ebrahimi uint32_t dst_slices =
2538*b7893ccfSSadaf Ebrahimi (VK_IMAGE_TYPE_3D == dst_image_state->createInfo.imageType ? dst_copy_extent.depth
2539*b7893ccfSSadaf Ebrahimi : region.dstSubresource.layerCount);
2540*b7893ccfSSadaf Ebrahimi if (src_slices != dst_slices) {
2541*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2542*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): number of depth slices in source and destination subresources for pRegions[" << i
2543*b7893ccfSSadaf Ebrahimi << "] do not match";
2544*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2545*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-extent-00140", "%s.", ss.str().c_str());
2546*b7893ccfSSadaf Ebrahimi }
2547*b7893ccfSSadaf Ebrahimi }
2548*b7893ccfSSadaf Ebrahimi } else {
2549*b7893ccfSSadaf Ebrahimi // For each region the layerCount member of srcSubresource and dstSubresource must match
2550*b7893ccfSSadaf Ebrahimi if (region.srcSubresource.layerCount != region.dstSubresource.layerCount) {
2551*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2552*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): number of layers in source and destination subresources for pRegions[" << i
2553*b7893ccfSSadaf Ebrahimi << "] do not match";
2554*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2555*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-extent-00140", "%s.", ss.str().c_str());
2556*b7893ccfSSadaf Ebrahimi }
2557*b7893ccfSSadaf Ebrahimi }
2558*b7893ccfSSadaf Ebrahimi
2559*b7893ccfSSadaf Ebrahimi // Do multiplane-specific checks, if extension enabled
2560*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_sampler_ycbcr_conversion) {
2561*b7893ccfSSadaf Ebrahimi skip |= CopyImageMultiplaneValidation(command_buffer, src_image_state, dst_image_state, region);
2562*b7893ccfSSadaf Ebrahimi }
2563*b7893ccfSSadaf Ebrahimi
2564*b7893ccfSSadaf Ebrahimi if (!device_extensions.vk_khr_sampler_ycbcr_conversion) {
2565*b7893ccfSSadaf Ebrahimi // not multi-plane, the aspectMask member of srcSubresource and dstSubresource must match
2566*b7893ccfSSadaf Ebrahimi if (region.srcSubresource.aspectMask != region.dstSubresource.aspectMask) {
2567*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdCopyImage(): Src and dest aspectMasks for each region must match";
2568*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2569*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00137", "%s.", str);
2570*b7893ccfSSadaf Ebrahimi }
2571*b7893ccfSSadaf Ebrahimi }
2572*b7893ccfSSadaf Ebrahimi
2573*b7893ccfSSadaf Ebrahimi // For each region, the aspectMask member of srcSubresource must be present in the source image
2574*b7893ccfSSadaf Ebrahimi if (!VerifyAspectsPresent(region.srcSubresource.aspectMask, src_image_state->createInfo.format)) {
2575*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2576*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): pRegion[" << i
2577*b7893ccfSSadaf Ebrahimi << "] srcSubresource.aspectMask cannot specify aspects not present in source image";
2578*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2579*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00142", "%s.", ss.str().c_str());
2580*b7893ccfSSadaf Ebrahimi }
2581*b7893ccfSSadaf Ebrahimi
2582*b7893ccfSSadaf Ebrahimi // For each region, the aspectMask member of dstSubresource must be present in the destination image
2583*b7893ccfSSadaf Ebrahimi if (!VerifyAspectsPresent(region.dstSubresource.aspectMask, dst_image_state->createInfo.format)) {
2584*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2585*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): pRegion[" << i
2586*b7893ccfSSadaf Ebrahimi << "] dstSubresource.aspectMask cannot specify aspects not present in dest image";
2587*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2588*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-aspectMask-00143", "%s.", ss.str().c_str());
2589*b7893ccfSSadaf Ebrahimi }
2590*b7893ccfSSadaf Ebrahimi
2591*b7893ccfSSadaf Ebrahimi // Check region extents for 1D-1D, 2D-2D, and 3D-3D copies
2592*b7893ccfSSadaf Ebrahimi if (src_image_state->createInfo.imageType == dst_image_state->createInfo.imageType) {
2593*b7893ccfSSadaf Ebrahimi // The source region specified by a given element of regions must be a region that is contained within srcImage
2594*b7893ccfSSadaf Ebrahimi VkExtent3D img_extent = GetImageSubresourceExtent(src_image_state, &(region.srcSubresource));
2595*b7893ccfSSadaf Ebrahimi if (0 != ExceedsBounds(®ion.srcOffset, &src_copy_extent, &img_extent)) {
2596*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2597*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Source pRegion[" << i << "] with mipLevel [ " << region.srcSubresource.mipLevel
2598*b7893ccfSSadaf Ebrahimi << " ], offset [ " << region.srcOffset.x << ", " << region.srcOffset.y << ", " << region.srcOffset.z
2599*b7893ccfSSadaf Ebrahimi << " ], extent [ " << src_copy_extent.width << ", " << src_copy_extent.height << ", " << src_copy_extent.depth
2600*b7893ccfSSadaf Ebrahimi << " ] exceeds the source image dimensions";
2601*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2602*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00122", "%s.", ss.str().c_str());
2603*b7893ccfSSadaf Ebrahimi }
2604*b7893ccfSSadaf Ebrahimi
2605*b7893ccfSSadaf Ebrahimi // The destination region specified by a given element of regions must be a region that is contained within dst_image
2606*b7893ccfSSadaf Ebrahimi img_extent = GetImageSubresourceExtent(dst_image_state, &(region.dstSubresource));
2607*b7893ccfSSadaf Ebrahimi if (0 != ExceedsBounds(®ion.dstOffset, &dst_copy_extent, &img_extent)) {
2608*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2609*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): Dest pRegion[" << i << "] with mipLevel [ " << region.dstSubresource.mipLevel
2610*b7893ccfSSadaf Ebrahimi << " ], offset [ " << region.dstOffset.x << ", " << region.dstOffset.y << ", " << region.dstOffset.z
2611*b7893ccfSSadaf Ebrahimi << " ], extent [ " << dst_copy_extent.width << ", " << dst_copy_extent.height << ", " << dst_copy_extent.depth
2612*b7893ccfSSadaf Ebrahimi << " ] exceeds the destination image dimensions";
2613*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2614*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00123", "%s.", ss.str().c_str());
2615*b7893ccfSSadaf Ebrahimi }
2616*b7893ccfSSadaf Ebrahimi }
2617*b7893ccfSSadaf Ebrahimi
2618*b7893ccfSSadaf Ebrahimi // Each dimension offset + extent limits must fall with image subresource extent
2619*b7893ccfSSadaf Ebrahimi VkExtent3D subresource_extent = GetImageSubresourceExtent(src_image_state, &(region.srcSubresource));
2620*b7893ccfSSadaf Ebrahimi if (slice_override) src_copy_extent.depth = depth_slices;
2621*b7893ccfSSadaf Ebrahimi uint32_t extent_check = ExceedsBounds(&(region.srcOffset), &src_copy_extent, &subresource_extent);
2622*b7893ccfSSadaf Ebrahimi if (extent_check & x_bit) {
2623*b7893ccfSSadaf Ebrahimi skip |=
2624*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2625*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00144",
2626*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): Source image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
2627*b7893ccfSSadaf Ebrahimi "width [%1d].",
2628*b7893ccfSSadaf Ebrahimi i, region.srcOffset.x, src_copy_extent.width, subresource_extent.width);
2629*b7893ccfSSadaf Ebrahimi }
2630*b7893ccfSSadaf Ebrahimi
2631*b7893ccfSSadaf Ebrahimi if (extent_check & y_bit) {
2632*b7893ccfSSadaf Ebrahimi skip |=
2633*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2634*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00145",
2635*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): Source image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
2636*b7893ccfSSadaf Ebrahimi "height [%1d].",
2637*b7893ccfSSadaf Ebrahimi i, region.srcOffset.y, src_copy_extent.height, subresource_extent.height);
2638*b7893ccfSSadaf Ebrahimi }
2639*b7893ccfSSadaf Ebrahimi if (extent_check & z_bit) {
2640*b7893ccfSSadaf Ebrahimi skip |=
2641*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2642*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-srcOffset-00147",
2643*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): Source image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
2644*b7893ccfSSadaf Ebrahimi "depth [%1d].",
2645*b7893ccfSSadaf Ebrahimi i, region.srcOffset.z, src_copy_extent.depth, subresource_extent.depth);
2646*b7893ccfSSadaf Ebrahimi }
2647*b7893ccfSSadaf Ebrahimi
2648*b7893ccfSSadaf Ebrahimi // Adjust dest extent if necessary
2649*b7893ccfSSadaf Ebrahimi subresource_extent = GetImageSubresourceExtent(dst_image_state, &(region.dstSubresource));
2650*b7893ccfSSadaf Ebrahimi if (slice_override) dst_copy_extent.depth = depth_slices;
2651*b7893ccfSSadaf Ebrahimi
2652*b7893ccfSSadaf Ebrahimi extent_check = ExceedsBounds(&(region.dstOffset), &dst_copy_extent, &subresource_extent);
2653*b7893ccfSSadaf Ebrahimi if (extent_check & x_bit) {
2654*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2655*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00150",
2656*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): Dest image pRegion %1d x-dimension offset [%1d] + extent [%1d] exceeds subResource "
2657*b7893ccfSSadaf Ebrahimi "width [%1d].",
2658*b7893ccfSSadaf Ebrahimi i, region.dstOffset.x, dst_copy_extent.width, subresource_extent.width);
2659*b7893ccfSSadaf Ebrahimi }
2660*b7893ccfSSadaf Ebrahimi if (extent_check & y_bit) {
2661*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2662*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00151",
2663*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): Dest image pRegion %1d y-dimension offset [%1d] + extent [%1d] exceeds subResource "
2664*b7893ccfSSadaf Ebrahimi "height [%1d].",
2665*b7893ccfSSadaf Ebrahimi i, region.dstOffset.y, dst_copy_extent.height, subresource_extent.height);
2666*b7893ccfSSadaf Ebrahimi }
2667*b7893ccfSSadaf Ebrahimi if (extent_check & z_bit) {
2668*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2669*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-VkImageCopy-dstOffset-00153",
2670*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage(): Dest image pRegion %1d z-dimension offset [%1d] + extent [%1d] exceeds subResource "
2671*b7893ccfSSadaf Ebrahimi "depth [%1d].",
2672*b7893ccfSSadaf Ebrahimi i, region.dstOffset.z, dst_copy_extent.depth, subresource_extent.depth);
2673*b7893ccfSSadaf Ebrahimi }
2674*b7893ccfSSadaf Ebrahimi
2675*b7893ccfSSadaf Ebrahimi // The union of all source regions, and the union of all destination regions, specified by the elements of regions,
2676*b7893ccfSSadaf Ebrahimi // must not overlap in memory
2677*b7893ccfSSadaf Ebrahimi if (src_image_state->image == dst_image_state->image) {
2678*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < regionCount; j++) {
2679*b7893ccfSSadaf Ebrahimi if (RegionIntersects(®ion, &pRegions[j], src_image_state->createInfo.imageType,
2680*b7893ccfSSadaf Ebrahimi FormatIsMultiplane(src_image_state->createInfo.format))) {
2681*b7893ccfSSadaf Ebrahimi std::stringstream ss;
2682*b7893ccfSSadaf Ebrahimi ss << "vkCmdCopyImage(): pRegions[" << i << "] src overlaps with pRegions[" << j << "].";
2683*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2684*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-pRegions-00124", "%s.", ss.str().c_str());
2685*b7893ccfSSadaf Ebrahimi }
2686*b7893ccfSSadaf Ebrahimi }
2687*b7893ccfSSadaf Ebrahimi }
2688*b7893ccfSSadaf Ebrahimi }
2689*b7893ccfSSadaf Ebrahimi
2690*b7893ccfSSadaf Ebrahimi // The formats of src_image and dst_image must be compatible. Formats are considered compatible if their texel size in bytes
2691*b7893ccfSSadaf Ebrahimi // is the same between both formats. For example, VK_FORMAT_R8G8B8A8_UNORM is compatible with VK_FORMAT_R32_UINT because
2692*b7893ccfSSadaf Ebrahimi // because both texels are 4 bytes in size. Depth/stencil formats must match exactly.
2693*b7893ccfSSadaf Ebrahimi if (FormatIsDepthOrStencil(src_image_state->createInfo.format) || FormatIsDepthOrStencil(dst_image_state->createInfo.format)) {
2694*b7893ccfSSadaf Ebrahimi if (src_image_state->createInfo.format != dst_image_state->createInfo.format) {
2695*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdCopyImage called with unmatched source and dest image depth/stencil formats.";
2696*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2697*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), kVUID_Core_DrawState_MismatchedImageFormat, str);
2698*b7893ccfSSadaf Ebrahimi }
2699*b7893ccfSSadaf Ebrahimi } else {
2700*b7893ccfSSadaf Ebrahimi if (!FormatSizesAreEqual(src_image_state->createInfo.format, dst_image_state->createInfo.format, regionCount, pRegions)) {
2701*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdCopyImage called with unmatched source and dest image format sizes.";
2702*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2703*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-srcImage-00135", "%s.", str);
2704*b7893ccfSSadaf Ebrahimi }
2705*b7893ccfSSadaf Ebrahimi }
2706*b7893ccfSSadaf Ebrahimi
2707*b7893ccfSSadaf Ebrahimi // Source and dest image sample counts must match
2708*b7893ccfSSadaf Ebrahimi if (src_image_state->createInfo.samples != dst_image_state->createInfo.samples) {
2709*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdCopyImage() called on image pair with non-identical sample counts.";
2710*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2711*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdCopyImage-srcImage-00136", "%s", str);
2712*b7893ccfSSadaf Ebrahimi }
2713*b7893ccfSSadaf Ebrahimi
2714*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(src_image_state, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-srcImage-00127");
2715*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(dst_image_state, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-dstImage-00132");
2716*b7893ccfSSadaf Ebrahimi // Validate that SRC & DST images have correct usage flags set
2717*b7893ccfSSadaf Ebrahimi skip |= ValidateImageUsageFlags(src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, "VUID-vkCmdCopyImage-srcImage-00126",
2718*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
2719*b7893ccfSSadaf Ebrahimi skip |= ValidateImageUsageFlags(dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdCopyImage-dstImage-00131",
2720*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
2721*b7893ccfSSadaf Ebrahimi if (api_version >= VK_API_VERSION_1_1 || device_extensions.vk_khr_maintenance1) {
2722*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, "vkCmdCopyImage()",
2723*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-srcImage-01995", "VUID-vkCmdCopyImage-srcImage-01995");
2724*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdCopyImage()",
2725*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-dstImage-01996", "VUID-vkCmdCopyImage-dstImage-01996");
2726*b7893ccfSSadaf Ebrahimi }
2727*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdQueueFlags(cb_node, "vkCmdCopyImage()", VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
2728*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-commandBuffer-cmdpool");
2729*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_COPYIMAGE, "vkCmdCopyImage()");
2730*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdCopyImage()", "VUID-vkCmdCopyImage-renderpass");
2731*b7893ccfSSadaf Ebrahimi bool hit_error = false;
2732*b7893ccfSSadaf Ebrahimi const char *invalid_src_layout_vuid = (src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
2733*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdCopyImage-srcImageLayout-01917"
2734*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdCopyImage-srcImageLayout-00129";
2735*b7893ccfSSadaf Ebrahimi const char *invalid_dst_layout_vuid = (dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
2736*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdCopyImage-dstImageLayout-01395"
2737*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdCopyImage-dstImageLayout-00134";
2738*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
2739*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
2740*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdCopyImage()", invalid_src_layout_vuid,
2741*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-srcImageLayout-00128", &hit_error);
2742*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
2743*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdCopyImage()", invalid_dst_layout_vuid,
2744*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImage-dstImageLayout-00133", &hit_error);
2745*b7893ccfSSadaf Ebrahimi skip |= ValidateCopyImageTransferGranularityRequirements(cb_node, src_image_state, dst_image_state, &pRegions[i], i,
2746*b7893ccfSSadaf Ebrahimi "vkCmdCopyImage()");
2747*b7893ccfSSadaf Ebrahimi }
2748*b7893ccfSSadaf Ebrahimi
2749*b7893ccfSSadaf Ebrahimi return skip;
2750*b7893ccfSSadaf Ebrahimi }
2751*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageCopy * pRegions)2752*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage,
2753*b7893ccfSSadaf Ebrahimi VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout,
2754*b7893ccfSSadaf Ebrahimi uint32_t regionCount, const VkImageCopy *pRegions) {
2755*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
2756*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
2757*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
2758*b7893ccfSSadaf Ebrahimi
2759*b7893ccfSSadaf Ebrahimi // Update bindings between images and cmd buffer
2760*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, src_image_state);
2761*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, dst_image_state);
2762*b7893ccfSSadaf Ebrahimi }
2763*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageCopy * pRegions)2764*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdCopyImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
2765*b7893ccfSSadaf Ebrahimi VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
2766*b7893ccfSSadaf Ebrahimi const VkImageCopy *pRegions) {
2767*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordCmdCopyImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
2768*b7893ccfSSadaf Ebrahimi pRegions);
2769*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
2770*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
2771*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
2772*b7893ccfSSadaf Ebrahimi
2773*b7893ccfSSadaf Ebrahimi // Make sure that all image slices are updated to correct layout
2774*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
2775*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].srcSubresource, srcImageLayout);
2776*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
2777*b7893ccfSSadaf Ebrahimi }
2778*b7893ccfSSadaf Ebrahimi }
2779*b7893ccfSSadaf Ebrahimi
2780*b7893ccfSSadaf Ebrahimi // Returns true if sub_rect is entirely contained within rect
ContainsRect(VkRect2D rect,VkRect2D sub_rect)2781*b7893ccfSSadaf Ebrahimi static inline bool ContainsRect(VkRect2D rect, VkRect2D sub_rect) {
2782*b7893ccfSSadaf Ebrahimi if ((sub_rect.offset.x < rect.offset.x) || (sub_rect.offset.x + sub_rect.extent.width > rect.offset.x + rect.extent.width) ||
2783*b7893ccfSSadaf Ebrahimi (sub_rect.offset.y < rect.offset.y) || (sub_rect.offset.y + sub_rect.extent.height > rect.offset.y + rect.extent.height))
2784*b7893ccfSSadaf Ebrahimi return false;
2785*b7893ccfSSadaf Ebrahimi return true;
2786*b7893ccfSSadaf Ebrahimi }
2787*b7893ccfSSadaf Ebrahimi
ValidateClearAttachmentExtent(VkCommandBuffer command_buffer,uint32_t attachment_index,const FRAMEBUFFER_STATE * framebuffer,uint32_t fb_attachment,const VkRect2D & render_area,uint32_t rect_count,const VkClearRect * clear_rects) const2788*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateClearAttachmentExtent(VkCommandBuffer command_buffer, uint32_t attachment_index,
2789*b7893ccfSSadaf Ebrahimi const FRAMEBUFFER_STATE *framebuffer, uint32_t fb_attachment,
2790*b7893ccfSSadaf Ebrahimi const VkRect2D &render_area, uint32_t rect_count,
2791*b7893ccfSSadaf Ebrahimi const VkClearRect *clear_rects) const {
2792*b7893ccfSSadaf Ebrahimi bool skip = false;
2793*b7893ccfSSadaf Ebrahimi const IMAGE_VIEW_STATE *image_view_state = nullptr;
2794*b7893ccfSSadaf Ebrahimi if (framebuffer && (fb_attachment != VK_ATTACHMENT_UNUSED) && (fb_attachment < framebuffer->createInfo.attachmentCount)) {
2795*b7893ccfSSadaf Ebrahimi image_view_state = GetImageViewState(framebuffer->createInfo.pAttachments[fb_attachment]);
2796*b7893ccfSSadaf Ebrahimi }
2797*b7893ccfSSadaf Ebrahimi
2798*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < rect_count; j++) {
2799*b7893ccfSSadaf Ebrahimi if (!ContainsRect(render_area, clear_rects[j].rect)) {
2800*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2801*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdClearAttachments-pRects-00016",
2802*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments(): The area defined by pRects[%d] is not contained in the area of "
2803*b7893ccfSSadaf Ebrahimi "the current render pass instance.",
2804*b7893ccfSSadaf Ebrahimi j);
2805*b7893ccfSSadaf Ebrahimi }
2806*b7893ccfSSadaf Ebrahimi
2807*b7893ccfSSadaf Ebrahimi if (image_view_state) {
2808*b7893ccfSSadaf Ebrahimi // The layers specified by a given element of pRects must be contained within every attachment that
2809*b7893ccfSSadaf Ebrahimi // pAttachments refers to
2810*b7893ccfSSadaf Ebrahimi const auto attachment_layer_count = image_view_state->create_info.subresourceRange.layerCount;
2811*b7893ccfSSadaf Ebrahimi if ((clear_rects[j].baseArrayLayer >= attachment_layer_count) ||
2812*b7893ccfSSadaf Ebrahimi (clear_rects[j].baseArrayLayer + clear_rects[j].layerCount > attachment_layer_count)) {
2813*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2814*b7893ccfSSadaf Ebrahimi HandleToUint64(command_buffer), "VUID-vkCmdClearAttachments-pRects-00017",
2815*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments(): The layers defined in pRects[%d] are not contained in the layers "
2816*b7893ccfSSadaf Ebrahimi "of pAttachment[%d].",
2817*b7893ccfSSadaf Ebrahimi j, attachment_index);
2818*b7893ccfSSadaf Ebrahimi }
2819*b7893ccfSSadaf Ebrahimi }
2820*b7893ccfSSadaf Ebrahimi }
2821*b7893ccfSSadaf Ebrahimi return skip;
2822*b7893ccfSSadaf Ebrahimi }
2823*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer,uint32_t attachmentCount,const VkClearAttachment * pAttachments,uint32_t rectCount,const VkClearRect * pRects)2824*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
2825*b7893ccfSSadaf Ebrahimi const VkClearAttachment *pAttachments, uint32_t rectCount,
2826*b7893ccfSSadaf Ebrahimi const VkClearRect *pRects) {
2827*b7893ccfSSadaf Ebrahimi bool skip = false;
2828*b7893ccfSSadaf Ebrahimi const CMD_BUFFER_STATE *cb_node = GetCBState(commandBuffer); // TODO: Should be const, and never modified during validation
2829*b7893ccfSSadaf Ebrahimi if (!cb_node) return skip;
2830*b7893ccfSSadaf Ebrahimi
2831*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdQueueFlags(cb_node, "vkCmdClearAttachments()", VK_QUEUE_GRAPHICS_BIT,
2832*b7893ccfSSadaf Ebrahimi "VUID-vkCmdClearAttachments-commandBuffer-cmdpool");
2833*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_CLEARATTACHMENTS, "vkCmdClearAttachments()");
2834*b7893ccfSSadaf Ebrahimi // Warn if this is issued prior to Draw Cmd and clearing the entire attachment
2835*b7893ccfSSadaf Ebrahimi if (!cb_node->hasDrawCmd && (cb_node->activeRenderPassBeginInfo.renderArea.extent.width == pRects[0].rect.extent.width) &&
2836*b7893ccfSSadaf Ebrahimi (cb_node->activeRenderPassBeginInfo.renderArea.extent.height == pRects[0].rect.extent.height)) {
2837*b7893ccfSSadaf Ebrahimi // There are times where app needs to use ClearAttachments (generally when reusing a buffer inside of a render pass)
2838*b7893ccfSSadaf Ebrahimi // This warning should be made more specific. It'd be best to avoid triggering this test if it's a use that must call
2839*b7893ccfSSadaf Ebrahimi // CmdClearAttachments.
2840*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2841*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), kVUID_Core_DrawState_ClearCmdBeforeDraw,
2842*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments() issued on %s prior to any Draw Cmds. It is recommended you "
2843*b7893ccfSSadaf Ebrahimi "use RenderPass LOAD_OP_CLEAR on Attachments prior to any Draw.",
2844*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(commandBuffer).c_str());
2845*b7893ccfSSadaf Ebrahimi }
2846*b7893ccfSSadaf Ebrahimi skip |= OutsideRenderPass(cb_node, "vkCmdClearAttachments()", "VUID-vkCmdClearAttachments-renderpass");
2847*b7893ccfSSadaf Ebrahimi
2848*b7893ccfSSadaf Ebrahimi // Validate that attachment is in reference list of active subpass
2849*b7893ccfSSadaf Ebrahimi if (cb_node->activeRenderPass) {
2850*b7893ccfSSadaf Ebrahimi const VkRenderPassCreateInfo2KHR *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
2851*b7893ccfSSadaf Ebrahimi const uint32_t renderpass_attachment_count = renderpass_create_info->attachmentCount;
2852*b7893ccfSSadaf Ebrahimi const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
2853*b7893ccfSSadaf Ebrahimi const auto *framebuffer = GetFramebufferState(cb_node->activeFramebuffer);
2854*b7893ccfSSadaf Ebrahimi const auto &render_area = cb_node->activeRenderPassBeginInfo.renderArea;
2855*b7893ccfSSadaf Ebrahimi
2856*b7893ccfSSadaf Ebrahimi for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
2857*b7893ccfSSadaf Ebrahimi auto clear_desc = &pAttachments[attachment_index];
2858*b7893ccfSSadaf Ebrahimi uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
2859*b7893ccfSSadaf Ebrahimi
2860*b7893ccfSSadaf Ebrahimi if (0 == clear_desc->aspectMask) {
2861*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2862*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-requiredbitmask", " ");
2863*b7893ccfSSadaf Ebrahimi } else if (clear_desc->aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
2864*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2865*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00020", " ");
2866*b7893ccfSSadaf Ebrahimi } else if (clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) {
2867*b7893ccfSSadaf Ebrahimi uint32_t color_attachment = VK_ATTACHMENT_UNUSED;
2868*b7893ccfSSadaf Ebrahimi if (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount) {
2869*b7893ccfSSadaf Ebrahimi color_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
2870*b7893ccfSSadaf Ebrahimi if ((color_attachment != VK_ATTACHMENT_UNUSED) && (color_attachment >= renderpass_attachment_count)) {
2871*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2872*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-02501",
2873*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u is not VK_ATTACHMENT_UNUSED "
2874*b7893ccfSSadaf Ebrahimi "and not a valid attachment for %s attachmentCount=%u. Subpass %u pColorAttachment[%u]=%u.",
2875*b7893ccfSSadaf Ebrahimi attachment_index, clear_desc->colorAttachment,
2876*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(),
2877*b7893ccfSSadaf Ebrahimi cb_node->activeSubpass, clear_desc->colorAttachment, color_attachment,
2878*b7893ccfSSadaf Ebrahimi renderpass_attachment_count);
2879*b7893ccfSSadaf Ebrahimi
2880*b7893ccfSSadaf Ebrahimi color_attachment = VK_ATTACHMENT_UNUSED; // Defensive, prevent lookup past end of renderpass attachment
2881*b7893ccfSSadaf Ebrahimi }
2882*b7893ccfSSadaf Ebrahimi } else {
2883*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2884*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), "VUID-vkCmdClearAttachments-aspectMask-02501",
2885*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments() pAttachments[%u].colorAttachment=%u out of range for %s"
2886*b7893ccfSSadaf Ebrahimi " subpass %u. colorAttachmentCount=%u",
2887*b7893ccfSSadaf Ebrahimi attachment_index, clear_desc->colorAttachment,
2888*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(cb_node->activeRenderPass->renderPass).c_str(),
2889*b7893ccfSSadaf Ebrahimi cb_node->activeSubpass, subpass_desc->colorAttachmentCount);
2890*b7893ccfSSadaf Ebrahimi }
2891*b7893ccfSSadaf Ebrahimi fb_attachment = color_attachment;
2892*b7893ccfSSadaf Ebrahimi
2893*b7893ccfSSadaf Ebrahimi if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) ||
2894*b7893ccfSSadaf Ebrahimi (clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT)) {
2895*b7893ccfSSadaf Ebrahimi char const str[] =
2896*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments() aspectMask [%d] must set only VK_IMAGE_ASPECT_COLOR_BIT of a color attachment.";
2897*b7893ccfSSadaf Ebrahimi skip |=
2898*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2899*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-00019", str, attachment_index);
2900*b7893ccfSSadaf Ebrahimi }
2901*b7893ccfSSadaf Ebrahimi } else { // Must be depth and/or stencil
2902*b7893ccfSSadaf Ebrahimi if (((clear_desc->aspectMask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) &&
2903*b7893ccfSSadaf Ebrahimi ((clear_desc->aspectMask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT)) {
2904*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdClearAttachments() aspectMask [%d] is not a valid combination of bits.";
2905*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2906*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), "VUID-VkClearAttachment-aspectMask-parameter", str,
2907*b7893ccfSSadaf Ebrahimi attachment_index);
2908*b7893ccfSSadaf Ebrahimi }
2909*b7893ccfSSadaf Ebrahimi if (!subpass_desc->pDepthStencilAttachment ||
2910*b7893ccfSSadaf Ebrahimi (subpass_desc->pDepthStencilAttachment->attachment == VK_ATTACHMENT_UNUSED)) {
2911*b7893ccfSSadaf Ebrahimi skip |= log_msg(
2912*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
2913*b7893ccfSSadaf Ebrahimi HandleToUint64(commandBuffer), kVUID_Core_DrawState_MissingAttachmentReference,
2914*b7893ccfSSadaf Ebrahimi "vkCmdClearAttachments() depth/stencil clear with no depth/stencil attachment in subpass; ignored");
2915*b7893ccfSSadaf Ebrahimi } else {
2916*b7893ccfSSadaf Ebrahimi fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
2917*b7893ccfSSadaf Ebrahimi }
2918*b7893ccfSSadaf Ebrahimi }
2919*b7893ccfSSadaf Ebrahimi if (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_PRIMARY) {
2920*b7893ccfSSadaf Ebrahimi skip |= ValidateClearAttachmentExtent(commandBuffer, attachment_index, framebuffer, fb_attachment, render_area,
2921*b7893ccfSSadaf Ebrahimi rectCount, pRects);
2922*b7893ccfSSadaf Ebrahimi }
2923*b7893ccfSSadaf Ebrahimi }
2924*b7893ccfSSadaf Ebrahimi }
2925*b7893ccfSSadaf Ebrahimi return skip;
2926*b7893ccfSSadaf Ebrahimi }
2927*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdClearAttachments(VkCommandBuffer commandBuffer,uint32_t attachmentCount,const VkClearAttachment * pAttachments,uint32_t rectCount,const VkClearRect * pRects)2928*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdClearAttachments(VkCommandBuffer commandBuffer, uint32_t attachmentCount,
2929*b7893ccfSSadaf Ebrahimi const VkClearAttachment *pAttachments, uint32_t rectCount,
2930*b7893ccfSSadaf Ebrahimi const VkClearRect *pRects) {
2931*b7893ccfSSadaf Ebrahimi auto *cb_node = GetCBState(commandBuffer);
2932*b7893ccfSSadaf Ebrahimi if (cb_node->activeRenderPass && (cb_node->createInfo.level == VK_COMMAND_BUFFER_LEVEL_SECONDARY)) {
2933*b7893ccfSSadaf Ebrahimi const VkRenderPassCreateInfo2KHR *renderpass_create_info = cb_node->activeRenderPass->createInfo.ptr();
2934*b7893ccfSSadaf Ebrahimi const VkSubpassDescription2KHR *subpass_desc = &renderpass_create_info->pSubpasses[cb_node->activeSubpass];
2935*b7893ccfSSadaf Ebrahimi std::shared_ptr<std::vector<VkClearRect>> clear_rect_copy;
2936*b7893ccfSSadaf Ebrahimi for (uint32_t attachment_index = 0; attachment_index < attachmentCount; attachment_index++) {
2937*b7893ccfSSadaf Ebrahimi const auto clear_desc = &pAttachments[attachment_index];
2938*b7893ccfSSadaf Ebrahimi uint32_t fb_attachment = VK_ATTACHMENT_UNUSED;
2939*b7893ccfSSadaf Ebrahimi if ((clear_desc->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
2940*b7893ccfSSadaf Ebrahimi (clear_desc->colorAttachment < subpass_desc->colorAttachmentCount)) {
2941*b7893ccfSSadaf Ebrahimi fb_attachment = subpass_desc->pColorAttachments[clear_desc->colorAttachment].attachment;
2942*b7893ccfSSadaf Ebrahimi } else if ((clear_desc->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) &&
2943*b7893ccfSSadaf Ebrahimi subpass_desc->pDepthStencilAttachment) {
2944*b7893ccfSSadaf Ebrahimi fb_attachment = subpass_desc->pDepthStencilAttachment->attachment;
2945*b7893ccfSSadaf Ebrahimi }
2946*b7893ccfSSadaf Ebrahimi if (fb_attachment != VK_ATTACHMENT_UNUSED) {
2947*b7893ccfSSadaf Ebrahimi if (!clear_rect_copy) {
2948*b7893ccfSSadaf Ebrahimi // We need a copy of the clear rectangles that will persist until the last lambda executes
2949*b7893ccfSSadaf Ebrahimi // but we want to create it as lazily as possible
2950*b7893ccfSSadaf Ebrahimi clear_rect_copy.reset(new std::vector<VkClearRect>(pRects, pRects + rectCount));
2951*b7893ccfSSadaf Ebrahimi }
2952*b7893ccfSSadaf Ebrahimi // if a secondary level command buffer inherits the framebuffer from the primary command buffer
2953*b7893ccfSSadaf Ebrahimi // (see VkCommandBufferInheritanceInfo), this validation must be deferred until queue submit time
2954*b7893ccfSSadaf Ebrahimi auto val_fn = [this, commandBuffer, attachment_index, fb_attachment, rectCount, clear_rect_copy](
2955*b7893ccfSSadaf Ebrahimi const CMD_BUFFER_STATE *prim_cb, VkFramebuffer fb) {
2956*b7893ccfSSadaf Ebrahimi assert(rectCount == clear_rect_copy->size());
2957*b7893ccfSSadaf Ebrahimi const FRAMEBUFFER_STATE *framebuffer = GetFramebufferState(fb);
2958*b7893ccfSSadaf Ebrahimi const auto &render_area = prim_cb->activeRenderPassBeginInfo.renderArea;
2959*b7893ccfSSadaf Ebrahimi bool skip = false;
2960*b7893ccfSSadaf Ebrahimi skip = ValidateClearAttachmentExtent(commandBuffer, attachment_index, framebuffer, fb_attachment, render_area,
2961*b7893ccfSSadaf Ebrahimi rectCount, clear_rect_copy->data());
2962*b7893ccfSSadaf Ebrahimi return skip;
2963*b7893ccfSSadaf Ebrahimi };
2964*b7893ccfSSadaf Ebrahimi cb_node->cmd_execute_commands_functions.emplace_back(val_fn);
2965*b7893ccfSSadaf Ebrahimi }
2966*b7893ccfSSadaf Ebrahimi }
2967*b7893ccfSSadaf Ebrahimi }
2968*b7893ccfSSadaf Ebrahimi }
2969*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageResolve * pRegions)2970*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
2971*b7893ccfSSadaf Ebrahimi VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
2972*b7893ccfSSadaf Ebrahimi const VkImageResolve *pRegions) {
2973*b7893ccfSSadaf Ebrahimi const auto *cb_node = GetCBState(commandBuffer);
2974*b7893ccfSSadaf Ebrahimi const auto *src_image_state = GetImageState(srcImage);
2975*b7893ccfSSadaf Ebrahimi const auto *dst_image_state = GetImageState(dstImage);
2976*b7893ccfSSadaf Ebrahimi
2977*b7893ccfSSadaf Ebrahimi bool skip = false;
2978*b7893ccfSSadaf Ebrahimi if (cb_node && src_image_state && dst_image_state) {
2979*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(src_image_state, "vkCmdResolveImage()", "VUID-vkCmdResolveImage-srcImage-00256");
2980*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(dst_image_state, "vkCmdResolveImage()", "VUID-vkCmdResolveImage-dstImage-00258");
2981*b7893ccfSSadaf Ebrahimi skip |= ValidateCmdQueueFlags(cb_node, "vkCmdResolveImage()", VK_QUEUE_GRAPHICS_BIT,
2982*b7893ccfSSadaf Ebrahimi "VUID-vkCmdResolveImage-commandBuffer-cmdpool");
2983*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_RESOLVEIMAGE, "vkCmdResolveImage()");
2984*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdResolveImage()", "VUID-vkCmdResolveImage-renderpass");
2985*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT, "vkCmdResolveImage()",
2986*b7893ccfSSadaf Ebrahimi "VUID-vkCmdResolveImage-dstImage-02003", "VUID-vkCmdResolveImage-dstImage-02003");
2987*b7893ccfSSadaf Ebrahimi
2988*b7893ccfSSadaf Ebrahimi bool hit_error = false;
2989*b7893ccfSSadaf Ebrahimi const char *invalid_src_layout_vuid =
2990*b7893ccfSSadaf Ebrahimi (src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
2991*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdResolveImage-srcImageLayout-01400"
2992*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdResolveImage-srcImageLayout-00261";
2993*b7893ccfSSadaf Ebrahimi const char *invalid_dst_layout_vuid =
2994*b7893ccfSSadaf Ebrahimi (dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
2995*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdResolveImage-dstImageLayout-01401"
2996*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdResolveImage-dstImageLayout-00263";
2997*b7893ccfSSadaf Ebrahimi // For each region, the number of layers in the image subresource should not be zero
2998*b7893ccfSSadaf Ebrahimi // For each region, src and dest image aspect must be color only
2999*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
3000*b7893ccfSSadaf Ebrahimi skip |=
3001*b7893ccfSSadaf Ebrahimi ValidateImageSubresourceLayers(cb_node, &pRegions[i].srcSubresource, "vkCmdResolveImage()", "srcSubresource", i);
3002*b7893ccfSSadaf Ebrahimi skip |=
3003*b7893ccfSSadaf Ebrahimi ValidateImageSubresourceLayers(cb_node, &pRegions[i].dstSubresource, "vkCmdResolveImage()", "dstSubresource", i);
3004*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, src_image_state, pRegions[i].srcSubresource, srcImageLayout,
3005*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdResolveImage()", invalid_src_layout_vuid,
3006*b7893ccfSSadaf Ebrahimi "VUID-vkCmdResolveImage-srcImageLayout-00260", &hit_error);
3007*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, dst_image_state, pRegions[i].dstSubresource, dstImageLayout,
3008*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdResolveImage()", invalid_dst_layout_vuid,
3009*b7893ccfSSadaf Ebrahimi "VUID-vkCmdResolveImage-dstImageLayout-00262", &hit_error);
3010*b7893ccfSSadaf Ebrahimi skip |= ValidateImageMipLevel(cb_node, src_image_state, pRegions[i].srcSubresource.mipLevel, i, "vkCmdResolveImage()",
3011*b7893ccfSSadaf Ebrahimi "srcSubresource", "VUID-vkCmdResolveImage-srcSubresource-01709");
3012*b7893ccfSSadaf Ebrahimi skip |= ValidateImageMipLevel(cb_node, dst_image_state, pRegions[i].dstSubresource.mipLevel, i, "vkCmdResolveImage()",
3013*b7893ccfSSadaf Ebrahimi "dstSubresource", "VUID-vkCmdResolveImage-dstSubresource-01710");
3014*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, pRegions[i].srcSubresource.baseArrayLayer,
3015*b7893ccfSSadaf Ebrahimi pRegions[i].srcSubresource.layerCount, i, "vkCmdResolveImage()", "srcSubresource",
3016*b7893ccfSSadaf Ebrahimi "VUID-vkCmdResolveImage-srcSubresource-01711");
3017*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, pRegions[i].dstSubresource.baseArrayLayer,
3018*b7893ccfSSadaf Ebrahimi pRegions[i].dstSubresource.layerCount, i, "vkCmdResolveImage()", "srcSubresource",
3019*b7893ccfSSadaf Ebrahimi "VUID-vkCmdResolveImage-dstSubresource-01712");
3020*b7893ccfSSadaf Ebrahimi
3021*b7893ccfSSadaf Ebrahimi // layer counts must match
3022*b7893ccfSSadaf Ebrahimi if (pRegions[i].srcSubresource.layerCount != pRegions[i].dstSubresource.layerCount) {
3023*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3024*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3025*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageResolve-layerCount-00267",
3026*b7893ccfSSadaf Ebrahimi "vkCmdResolveImage(): layerCount in source and destination subresource of pRegions[%d] does not match.", i);
3027*b7893ccfSSadaf Ebrahimi }
3028*b7893ccfSSadaf Ebrahimi // For each region, src and dest image aspect must be color only
3029*b7893ccfSSadaf Ebrahimi if ((pRegions[i].srcSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT) ||
3030*b7893ccfSSadaf Ebrahimi (pRegions[i].dstSubresource.aspectMask != VK_IMAGE_ASPECT_COLOR_BIT)) {
3031*b7893ccfSSadaf Ebrahimi char const str[] =
3032*b7893ccfSSadaf Ebrahimi "vkCmdResolveImage(): src and dest aspectMasks for each region must specify only VK_IMAGE_ASPECT_COLOR_BIT";
3033*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3034*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageResolve-aspectMask-00266", "%s.", str);
3035*b7893ccfSSadaf Ebrahimi }
3036*b7893ccfSSadaf Ebrahimi }
3037*b7893ccfSSadaf Ebrahimi
3038*b7893ccfSSadaf Ebrahimi if (src_image_state->createInfo.format != dst_image_state->createInfo.format) {
3039*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdResolveImage called with unmatched source and dest formats.";
3040*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3041*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_MismatchedImageFormat, str);
3042*b7893ccfSSadaf Ebrahimi }
3043*b7893ccfSSadaf Ebrahimi if (src_image_state->createInfo.imageType != dst_image_state->createInfo.imageType) {
3044*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdResolveImage called with unmatched source and dest image types.";
3045*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3046*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_MismatchedImageType, str);
3047*b7893ccfSSadaf Ebrahimi }
3048*b7893ccfSSadaf Ebrahimi if (src_image_state->createInfo.samples == VK_SAMPLE_COUNT_1_BIT) {
3049*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdResolveImage called with source sample count less than 2.";
3050*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3051*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdResolveImage-srcImage-00257", "%s.", str);
3052*b7893ccfSSadaf Ebrahimi }
3053*b7893ccfSSadaf Ebrahimi if (dst_image_state->createInfo.samples != VK_SAMPLE_COUNT_1_BIT) {
3054*b7893ccfSSadaf Ebrahimi char const str[] = "vkCmdResolveImage called with dest sample count greater than 1.";
3055*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3056*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdResolveImage-dstImage-00259", "%s.", str);
3057*b7893ccfSSadaf Ebrahimi }
3058*b7893ccfSSadaf Ebrahimi } else {
3059*b7893ccfSSadaf Ebrahimi assert(0);
3060*b7893ccfSSadaf Ebrahimi }
3061*b7893ccfSSadaf Ebrahimi return skip;
3062*b7893ccfSSadaf Ebrahimi }
3063*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdResolveImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageResolve * pRegions)3064*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage,
3065*b7893ccfSSadaf Ebrahimi VkImageLayout srcImageLayout, VkImage dstImage,
3066*b7893ccfSSadaf Ebrahimi VkImageLayout dstImageLayout, uint32_t regionCount,
3067*b7893ccfSSadaf Ebrahimi const VkImageResolve *pRegions) {
3068*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
3069*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
3070*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
3071*b7893ccfSSadaf Ebrahimi
3072*b7893ccfSSadaf Ebrahimi // Update bindings between images and cmd buffer
3073*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, src_image_state);
3074*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, dst_image_state);
3075*b7893ccfSSadaf Ebrahimi }
3076*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageBlit * pRegions,VkFilter filter)3077*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3078*b7893ccfSSadaf Ebrahimi VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3079*b7893ccfSSadaf Ebrahimi const VkImageBlit *pRegions, VkFilter filter) {
3080*b7893ccfSSadaf Ebrahimi const auto *cb_node = GetCBState(commandBuffer);
3081*b7893ccfSSadaf Ebrahimi const auto *src_image_state = GetImageState(srcImage);
3082*b7893ccfSSadaf Ebrahimi const auto *dst_image_state = GetImageState(dstImage);
3083*b7893ccfSSadaf Ebrahimi
3084*b7893ccfSSadaf Ebrahimi bool skip = false;
3085*b7893ccfSSadaf Ebrahimi if (cb_node) {
3086*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_BLITIMAGE, "vkCmdBlitImage()");
3087*b7893ccfSSadaf Ebrahimi }
3088*b7893ccfSSadaf Ebrahimi if (cb_node && src_image_state && dst_image_state) {
3089*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSampleCount(src_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdBlitImage(): srcImage",
3090*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-srcImage-00233");
3091*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSampleCount(dst_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdBlitImage(): dstImage",
3092*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-dstImage-00234");
3093*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(src_image_state, "vkCmdBlitImage()", "VUID-vkCmdBlitImage-srcImage-00220");
3094*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(dst_image_state, "vkCmdBlitImage()", "VUID-vkCmdBlitImage-dstImage-00225");
3095*b7893ccfSSadaf Ebrahimi skip |=
3096*b7893ccfSSadaf Ebrahimi ValidateImageUsageFlags(src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true, "VUID-vkCmdBlitImage-srcImage-00219",
3097*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
3098*b7893ccfSSadaf Ebrahimi skip |=
3099*b7893ccfSSadaf Ebrahimi ValidateImageUsageFlags(dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdBlitImage-dstImage-00224",
3100*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage()", "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
3101*b7893ccfSSadaf Ebrahimi skip |=
3102*b7893ccfSSadaf Ebrahimi ValidateCmdQueueFlags(cb_node, "vkCmdBlitImage()", VK_QUEUE_GRAPHICS_BIT, "VUID-vkCmdBlitImage-commandBuffer-cmdpool");
3103*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_BLITIMAGE, "vkCmdBlitImage()");
3104*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdBlitImage()", "VUID-vkCmdBlitImage-renderpass");
3105*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_BLIT_SRC_BIT, "vkCmdBlitImage()",
3106*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-srcImage-01999", "VUID-vkCmdBlitImage-srcImage-01999");
3107*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_BLIT_DST_BIT, "vkCmdBlitImage()",
3108*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-dstImage-02000", "VUID-vkCmdBlitImage-dstImage-02000");
3109*b7893ccfSSadaf Ebrahimi
3110*b7893ccfSSadaf Ebrahimi // TODO: Need to validate image layouts, which will include layout validation for shared presentable images
3111*b7893ccfSSadaf Ebrahimi
3112*b7893ccfSSadaf Ebrahimi VkFormat src_format = src_image_state->createInfo.format;
3113*b7893ccfSSadaf Ebrahimi VkFormat dst_format = dst_image_state->createInfo.format;
3114*b7893ccfSSadaf Ebrahimi VkImageType src_type = src_image_state->createInfo.imageType;
3115*b7893ccfSSadaf Ebrahimi VkImageType dst_type = dst_image_state->createInfo.imageType;
3116*b7893ccfSSadaf Ebrahimi
3117*b7893ccfSSadaf Ebrahimi if (VK_FILTER_LINEAR == filter) {
3118*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_LINEAR_BIT,
3119*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage()", "VUID-vkCmdBlitImage-filter-02001",
3120*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-filter-02001");
3121*b7893ccfSSadaf Ebrahimi } else if (VK_FILTER_CUBIC_IMG == filter) {
3122*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_SAMPLED_IMAGE_FILTER_CUBIC_BIT_IMG,
3123*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage()", "VUID-vkCmdBlitImage-filter-02002",
3124*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-filter-02002");
3125*b7893ccfSSadaf Ebrahimi }
3126*b7893ccfSSadaf Ebrahimi
3127*b7893ccfSSadaf Ebrahimi if ((VK_FILTER_CUBIC_IMG == filter) && (VK_IMAGE_TYPE_3D != src_type)) {
3128*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3129*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-filter-00237",
3130*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): source image type must be VK_IMAGE_TYPE_3D when cubic filtering is specified.");
3131*b7893ccfSSadaf Ebrahimi }
3132*b7893ccfSSadaf Ebrahimi
3133*b7893ccfSSadaf Ebrahimi if ((VK_SAMPLE_COUNT_1_BIT != src_image_state->createInfo.samples) ||
3134*b7893ccfSSadaf Ebrahimi (VK_SAMPLE_COUNT_1_BIT != dst_image_state->createInfo.samples)) {
3135*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3136*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00228",
3137*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): source or dest image has sample count other than VK_SAMPLE_COUNT_1_BIT.");
3138*b7893ccfSSadaf Ebrahimi }
3139*b7893ccfSSadaf Ebrahimi
3140*b7893ccfSSadaf Ebrahimi // Validate consistency for unsigned formats
3141*b7893ccfSSadaf Ebrahimi if (FormatIsUInt(src_format) != FormatIsUInt(dst_format)) {
3142*b7893ccfSSadaf Ebrahimi std::stringstream ss;
3143*b7893ccfSSadaf Ebrahimi ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has unsigned integer format, "
3144*b7893ccfSSadaf Ebrahimi << "the other one must also have unsigned integer format. "
3145*b7893ccfSSadaf Ebrahimi << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
3146*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3147*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00230", "%s.", ss.str().c_str());
3148*b7893ccfSSadaf Ebrahimi }
3149*b7893ccfSSadaf Ebrahimi
3150*b7893ccfSSadaf Ebrahimi // Validate consistency for signed formats
3151*b7893ccfSSadaf Ebrahimi if (FormatIsSInt(src_format) != FormatIsSInt(dst_format)) {
3152*b7893ccfSSadaf Ebrahimi std::stringstream ss;
3153*b7893ccfSSadaf Ebrahimi ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has signed integer format, "
3154*b7893ccfSSadaf Ebrahimi << "the other one must also have signed integer format. "
3155*b7893ccfSSadaf Ebrahimi << "Source format is " << string_VkFormat(src_format) << " Destination format is " << string_VkFormat(dst_format);
3156*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3157*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00229", "%s.", ss.str().c_str());
3158*b7893ccfSSadaf Ebrahimi }
3159*b7893ccfSSadaf Ebrahimi
3160*b7893ccfSSadaf Ebrahimi // Validate filter for Depth/Stencil formats
3161*b7893ccfSSadaf Ebrahimi if (FormatIsDepthOrStencil(src_format) && (filter != VK_FILTER_NEAREST)) {
3162*b7893ccfSSadaf Ebrahimi std::stringstream ss;
3163*b7893ccfSSadaf Ebrahimi ss << "vkCmdBlitImage(): If the format of srcImage is a depth, stencil, or depth stencil "
3164*b7893ccfSSadaf Ebrahimi << "then filter must be VK_FILTER_NEAREST.";
3165*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3166*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00232", "%s.", ss.str().c_str());
3167*b7893ccfSSadaf Ebrahimi }
3168*b7893ccfSSadaf Ebrahimi
3169*b7893ccfSSadaf Ebrahimi // Validate aspect bits and formats for depth/stencil images
3170*b7893ccfSSadaf Ebrahimi if (FormatIsDepthOrStencil(src_format) || FormatIsDepthOrStencil(dst_format)) {
3171*b7893ccfSSadaf Ebrahimi if (src_format != dst_format) {
3172*b7893ccfSSadaf Ebrahimi std::stringstream ss;
3173*b7893ccfSSadaf Ebrahimi ss << "vkCmdBlitImage(): If one of srcImage and dstImage images has a format of depth, stencil or depth "
3174*b7893ccfSSadaf Ebrahimi << "stencil, the other one must have exactly the same format. "
3175*b7893ccfSSadaf Ebrahimi << "Source format is " << string_VkFormat(src_format) << " Destination format is "
3176*b7893ccfSSadaf Ebrahimi << string_VkFormat(dst_format);
3177*b7893ccfSSadaf Ebrahimi skip |=
3178*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3179*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-srcImage-00231", "%s.", ss.str().c_str());
3180*b7893ccfSSadaf Ebrahimi }
3181*b7893ccfSSadaf Ebrahimi } // Depth or Stencil
3182*b7893ccfSSadaf Ebrahimi
3183*b7893ccfSSadaf Ebrahimi // Do per-region checks
3184*b7893ccfSSadaf Ebrahimi const char *invalid_src_layout_vuid =
3185*b7893ccfSSadaf Ebrahimi (src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3186*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdBlitImage-srcImageLayout-01398"
3187*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdBlitImage-srcImageLayout-00222";
3188*b7893ccfSSadaf Ebrahimi const char *invalid_dst_layout_vuid =
3189*b7893ccfSSadaf Ebrahimi (dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
3190*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdBlitImage-dstImageLayout-01399"
3191*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdBlitImage-dstImageLayout-00227";
3192*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
3193*b7893ccfSSadaf Ebrahimi const VkImageBlit rgn = pRegions[i];
3194*b7893ccfSSadaf Ebrahimi bool hit_error = false;
3195*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, src_image_state, rgn.srcSubresource, srcImageLayout,
3196*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdBlitImage()", invalid_src_layout_vuid,
3197*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-srcImageLayout-00221", &hit_error);
3198*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, dst_image_state, rgn.dstSubresource, dstImageLayout,
3199*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdBlitImage()", invalid_dst_layout_vuid,
3200*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-dstImageLayout-00226", &hit_error);
3201*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSubresourceLayers(cb_node, &rgn.srcSubresource, "vkCmdBlitImage()", "srcSubresource", i);
3202*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSubresourceLayers(cb_node, &rgn.dstSubresource, "vkCmdBlitImage()", "dstSubresource", i);
3203*b7893ccfSSadaf Ebrahimi skip |= ValidateImageMipLevel(cb_node, src_image_state, rgn.srcSubresource.mipLevel, i, "vkCmdBlitImage()",
3204*b7893ccfSSadaf Ebrahimi "srcSubresource", "VUID-vkCmdBlitImage-srcSubresource-01705");
3205*b7893ccfSSadaf Ebrahimi skip |= ValidateImageMipLevel(cb_node, dst_image_state, rgn.dstSubresource.mipLevel, i, "vkCmdBlitImage()",
3206*b7893ccfSSadaf Ebrahimi "dstSubresource", "VUID-vkCmdBlitImage-dstSubresource-01706");
3207*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, rgn.srcSubresource.baseArrayLayer,
3208*b7893ccfSSadaf Ebrahimi rgn.srcSubresource.layerCount, i, "vkCmdBlitImage()", "srcSubresource",
3209*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-srcSubresource-01707");
3210*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, rgn.dstSubresource.baseArrayLayer,
3211*b7893ccfSSadaf Ebrahimi rgn.dstSubresource.layerCount, i, "vkCmdBlitImage()", "dstSubresource",
3212*b7893ccfSSadaf Ebrahimi "VUID-vkCmdBlitImage-dstSubresource-01708");
3213*b7893ccfSSadaf Ebrahimi // Warn for zero-sized regions
3214*b7893ccfSSadaf Ebrahimi if ((rgn.srcOffsets[0].x == rgn.srcOffsets[1].x) || (rgn.srcOffsets[0].y == rgn.srcOffsets[1].y) ||
3215*b7893ccfSSadaf Ebrahimi (rgn.srcOffsets[0].z == rgn.srcOffsets[1].z)) {
3216*b7893ccfSSadaf Ebrahimi std::stringstream ss;
3217*b7893ccfSSadaf Ebrahimi ss << "vkCmdBlitImage(): pRegions[" << i << "].srcOffsets specify a zero-volume area.";
3218*b7893ccfSSadaf Ebrahimi skip |=
3219*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3220*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
3221*b7893ccfSSadaf Ebrahimi }
3222*b7893ccfSSadaf Ebrahimi if ((rgn.dstOffsets[0].x == rgn.dstOffsets[1].x) || (rgn.dstOffsets[0].y == rgn.dstOffsets[1].y) ||
3223*b7893ccfSSadaf Ebrahimi (rgn.dstOffsets[0].z == rgn.dstOffsets[1].z)) {
3224*b7893ccfSSadaf Ebrahimi std::stringstream ss;
3225*b7893ccfSSadaf Ebrahimi ss << "vkCmdBlitImage(): pRegions[" << i << "].dstOffsets specify a zero-volume area.";
3226*b7893ccfSSadaf Ebrahimi skip |=
3227*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3228*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), kVUID_Core_DrawState_InvalidExtents, "%s", ss.str().c_str());
3229*b7893ccfSSadaf Ebrahimi }
3230*b7893ccfSSadaf Ebrahimi
3231*b7893ccfSSadaf Ebrahimi // Check that src/dst layercounts match
3232*b7893ccfSSadaf Ebrahimi if (rgn.srcSubresource.layerCount != rgn.dstSubresource.layerCount) {
3233*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3234*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3235*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-layerCount-00239",
3236*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): layerCount in source and destination subresource of pRegions[%d] does not match.", i);
3237*b7893ccfSSadaf Ebrahimi }
3238*b7893ccfSSadaf Ebrahimi
3239*b7893ccfSSadaf Ebrahimi if (rgn.srcSubresource.aspectMask != rgn.dstSubresource.aspectMask) {
3240*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3241*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00238",
3242*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): aspectMask members for pRegion[%d] do not match.", i);
3243*b7893ccfSSadaf Ebrahimi }
3244*b7893ccfSSadaf Ebrahimi
3245*b7893ccfSSadaf Ebrahimi if (!VerifyAspectsPresent(rgn.srcSubresource.aspectMask, src_format)) {
3246*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3247*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00241",
3248*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] source aspectMask (0x%x) specifies aspects not present in source "
3249*b7893ccfSSadaf Ebrahimi "image format %s.",
3250*b7893ccfSSadaf Ebrahimi i, rgn.srcSubresource.aspectMask, string_VkFormat(src_format));
3251*b7893ccfSSadaf Ebrahimi }
3252*b7893ccfSSadaf Ebrahimi
3253*b7893ccfSSadaf Ebrahimi if (!VerifyAspectsPresent(rgn.dstSubresource.aspectMask, dst_format)) {
3254*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3255*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3256*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-aspectMask-00242",
3257*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] dest aspectMask (0x%x) specifies aspects not present in dest image format %s.",
3258*b7893ccfSSadaf Ebrahimi i, rgn.dstSubresource.aspectMask, string_VkFormat(dst_format));
3259*b7893ccfSSadaf Ebrahimi }
3260*b7893ccfSSadaf Ebrahimi
3261*b7893ccfSSadaf Ebrahimi // Validate source image offsets
3262*b7893ccfSSadaf Ebrahimi VkExtent3D src_extent = GetImageSubresourceExtent(src_image_state, &(rgn.srcSubresource));
3263*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_TYPE_1D == src_type) {
3264*b7893ccfSSadaf Ebrahimi if ((0 != rgn.srcOffsets[0].y) || (1 != rgn.srcOffsets[1].y)) {
3265*b7893ccfSSadaf Ebrahimi skip |=
3266*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3267*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00245",
3268*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d], source image of type VK_IMAGE_TYPE_1D with srcOffset[].y values "
3269*b7893ccfSSadaf Ebrahimi "of (%1d, %1d). These must be (0, 1).",
3270*b7893ccfSSadaf Ebrahimi i, rgn.srcOffsets[0].y, rgn.srcOffsets[1].y);
3271*b7893ccfSSadaf Ebrahimi }
3272*b7893ccfSSadaf Ebrahimi }
3273*b7893ccfSSadaf Ebrahimi
3274*b7893ccfSSadaf Ebrahimi if ((VK_IMAGE_TYPE_1D == src_type) || (VK_IMAGE_TYPE_2D == src_type)) {
3275*b7893ccfSSadaf Ebrahimi if ((0 != rgn.srcOffsets[0].z) || (1 != rgn.srcOffsets[1].z)) {
3276*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3277*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00247",
3278*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d], source image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
3279*b7893ccfSSadaf Ebrahimi "srcOffset[].z values of (%1d, %1d). These must be (0, 1).",
3280*b7893ccfSSadaf Ebrahimi i, rgn.srcOffsets[0].z, rgn.srcOffsets[1].z);
3281*b7893ccfSSadaf Ebrahimi }
3282*b7893ccfSSadaf Ebrahimi }
3283*b7893ccfSSadaf Ebrahimi
3284*b7893ccfSSadaf Ebrahimi bool oob = false;
3285*b7893ccfSSadaf Ebrahimi if ((rgn.srcOffsets[0].x < 0) || (rgn.srcOffsets[0].x > static_cast<int32_t>(src_extent.width)) ||
3286*b7893ccfSSadaf Ebrahimi (rgn.srcOffsets[1].x < 0) || (rgn.srcOffsets[1].x > static_cast<int32_t>(src_extent.width))) {
3287*b7893ccfSSadaf Ebrahimi oob = true;
3288*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3289*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3290*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00243",
3291*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] srcOffset[].x values (%1d, %1d) exceed srcSubresource width extent (%1d).", i,
3292*b7893ccfSSadaf Ebrahimi rgn.srcOffsets[0].x, rgn.srcOffsets[1].x, src_extent.width);
3293*b7893ccfSSadaf Ebrahimi }
3294*b7893ccfSSadaf Ebrahimi if ((rgn.srcOffsets[0].y < 0) || (rgn.srcOffsets[0].y > static_cast<int32_t>(src_extent.height)) ||
3295*b7893ccfSSadaf Ebrahimi (rgn.srcOffsets[1].y < 0) || (rgn.srcOffsets[1].y > static_cast<int32_t>(src_extent.height))) {
3296*b7893ccfSSadaf Ebrahimi oob = true;
3297*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3298*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3299*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00244",
3300*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] srcOffset[].y values (%1d, %1d) exceed srcSubresource height extent (%1d).", i,
3301*b7893ccfSSadaf Ebrahimi rgn.srcOffsets[0].y, rgn.srcOffsets[1].y, src_extent.height);
3302*b7893ccfSSadaf Ebrahimi }
3303*b7893ccfSSadaf Ebrahimi if ((rgn.srcOffsets[0].z < 0) || (rgn.srcOffsets[0].z > static_cast<int32_t>(src_extent.depth)) ||
3304*b7893ccfSSadaf Ebrahimi (rgn.srcOffsets[1].z < 0) || (rgn.srcOffsets[1].z > static_cast<int32_t>(src_extent.depth))) {
3305*b7893ccfSSadaf Ebrahimi oob = true;
3306*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3307*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3308*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcOffset-00246",
3309*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] srcOffset[].z values (%1d, %1d) exceed srcSubresource depth extent (%1d).", i,
3310*b7893ccfSSadaf Ebrahimi rgn.srcOffsets[0].z, rgn.srcOffsets[1].z, src_extent.depth);
3311*b7893ccfSSadaf Ebrahimi }
3312*b7893ccfSSadaf Ebrahimi if (oob) {
3313*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3314*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-pRegions-00215",
3315*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] source image blit region exceeds image dimensions.", i);
3316*b7893ccfSSadaf Ebrahimi }
3317*b7893ccfSSadaf Ebrahimi
3318*b7893ccfSSadaf Ebrahimi // Validate dest image offsets
3319*b7893ccfSSadaf Ebrahimi VkExtent3D dst_extent = GetImageSubresourceExtent(dst_image_state, &(rgn.dstSubresource));
3320*b7893ccfSSadaf Ebrahimi if (VK_IMAGE_TYPE_1D == dst_type) {
3321*b7893ccfSSadaf Ebrahimi if ((0 != rgn.dstOffsets[0].y) || (1 != rgn.dstOffsets[1].y)) {
3322*b7893ccfSSadaf Ebrahimi skip |=
3323*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3324*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00250",
3325*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d], dest image of type VK_IMAGE_TYPE_1D with dstOffset[].y values of "
3326*b7893ccfSSadaf Ebrahimi "(%1d, %1d). These must be (0, 1).",
3327*b7893ccfSSadaf Ebrahimi i, rgn.dstOffsets[0].y, rgn.dstOffsets[1].y);
3328*b7893ccfSSadaf Ebrahimi }
3329*b7893ccfSSadaf Ebrahimi }
3330*b7893ccfSSadaf Ebrahimi
3331*b7893ccfSSadaf Ebrahimi if ((VK_IMAGE_TYPE_1D == dst_type) || (VK_IMAGE_TYPE_2D == dst_type)) {
3332*b7893ccfSSadaf Ebrahimi if ((0 != rgn.dstOffsets[0].z) || (1 != rgn.dstOffsets[1].z)) {
3333*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3334*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstImage-00252",
3335*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d], dest image of type VK_IMAGE_TYPE_1D or VK_IMAGE_TYPE_2D with "
3336*b7893ccfSSadaf Ebrahimi "dstOffset[].z values of (%1d, %1d). These must be (0, 1).",
3337*b7893ccfSSadaf Ebrahimi i, rgn.dstOffsets[0].z, rgn.dstOffsets[1].z);
3338*b7893ccfSSadaf Ebrahimi }
3339*b7893ccfSSadaf Ebrahimi }
3340*b7893ccfSSadaf Ebrahimi
3341*b7893ccfSSadaf Ebrahimi oob = false;
3342*b7893ccfSSadaf Ebrahimi if ((rgn.dstOffsets[0].x < 0) || (rgn.dstOffsets[0].x > static_cast<int32_t>(dst_extent.width)) ||
3343*b7893ccfSSadaf Ebrahimi (rgn.dstOffsets[1].x < 0) || (rgn.dstOffsets[1].x > static_cast<int32_t>(dst_extent.width))) {
3344*b7893ccfSSadaf Ebrahimi oob = true;
3345*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3346*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3347*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00248",
3348*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] dstOffset[].x values (%1d, %1d) exceed dstSubresource width extent (%1d).", i,
3349*b7893ccfSSadaf Ebrahimi rgn.dstOffsets[0].x, rgn.dstOffsets[1].x, dst_extent.width);
3350*b7893ccfSSadaf Ebrahimi }
3351*b7893ccfSSadaf Ebrahimi if ((rgn.dstOffsets[0].y < 0) || (rgn.dstOffsets[0].y > static_cast<int32_t>(dst_extent.height)) ||
3352*b7893ccfSSadaf Ebrahimi (rgn.dstOffsets[1].y < 0) || (rgn.dstOffsets[1].y > static_cast<int32_t>(dst_extent.height))) {
3353*b7893ccfSSadaf Ebrahimi oob = true;
3354*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3355*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3356*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00249",
3357*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] dstOffset[].y values (%1d, %1d) exceed dstSubresource height extent (%1d).", i,
3358*b7893ccfSSadaf Ebrahimi rgn.dstOffsets[0].y, rgn.dstOffsets[1].y, dst_extent.height);
3359*b7893ccfSSadaf Ebrahimi }
3360*b7893ccfSSadaf Ebrahimi if ((rgn.dstOffsets[0].z < 0) || (rgn.dstOffsets[0].z > static_cast<int32_t>(dst_extent.depth)) ||
3361*b7893ccfSSadaf Ebrahimi (rgn.dstOffsets[1].z < 0) || (rgn.dstOffsets[1].z > static_cast<int32_t>(dst_extent.depth))) {
3362*b7893ccfSSadaf Ebrahimi oob = true;
3363*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3364*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3365*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-dstOffset-00251",
3366*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] dstOffset[].z values (%1d, %1d) exceed dstSubresource depth extent (%1d).", i,
3367*b7893ccfSSadaf Ebrahimi rgn.dstOffsets[0].z, rgn.dstOffsets[1].z, dst_extent.depth);
3368*b7893ccfSSadaf Ebrahimi }
3369*b7893ccfSSadaf Ebrahimi if (oob) {
3370*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3371*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-vkCmdBlitImage-pRegions-00216",
3372*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] destination image blit region exceeds image dimensions.", i);
3373*b7893ccfSSadaf Ebrahimi }
3374*b7893ccfSSadaf Ebrahimi
3375*b7893ccfSSadaf Ebrahimi if ((VK_IMAGE_TYPE_3D == src_type) || (VK_IMAGE_TYPE_3D == dst_type)) {
3376*b7893ccfSSadaf Ebrahimi if ((0 != rgn.srcSubresource.baseArrayLayer) || (1 != rgn.srcSubresource.layerCount) ||
3377*b7893ccfSSadaf Ebrahimi (0 != rgn.dstSubresource.baseArrayLayer) || (1 != rgn.dstSubresource.layerCount)) {
3378*b7893ccfSSadaf Ebrahimi skip |=
3379*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3380*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageBlit-srcImage-00240",
3381*b7893ccfSSadaf Ebrahimi "vkCmdBlitImage(): region [%d] blit to/from a 3D image type with a non-zero baseArrayLayer, or a "
3382*b7893ccfSSadaf Ebrahimi "layerCount other than 1.",
3383*b7893ccfSSadaf Ebrahimi i);
3384*b7893ccfSSadaf Ebrahimi }
3385*b7893ccfSSadaf Ebrahimi }
3386*b7893ccfSSadaf Ebrahimi } // per-region checks
3387*b7893ccfSSadaf Ebrahimi } else {
3388*b7893ccfSSadaf Ebrahimi assert(0);
3389*b7893ccfSSadaf Ebrahimi }
3390*b7893ccfSSadaf Ebrahimi return skip;
3391*b7893ccfSSadaf Ebrahimi }
3392*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageBlit * pRegions,VkFilter filter)3393*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage,
3394*b7893ccfSSadaf Ebrahimi VkImageLayout srcImageLayout, VkImage dstImage, VkImageLayout dstImageLayout,
3395*b7893ccfSSadaf Ebrahimi uint32_t regionCount, const VkImageBlit *pRegions, VkFilter filter) {
3396*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
3397*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
3398*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
3399*b7893ccfSSadaf Ebrahimi
3400*b7893ccfSSadaf Ebrahimi // Update bindings between images and cmd buffer
3401*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, src_image_state);
3402*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, dst_image_state);
3403*b7893ccfSSadaf Ebrahimi }
3404*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkImageBlit * pRegions,VkFilter filter)3405*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdBlitImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
3406*b7893ccfSSadaf Ebrahimi VkImage dstImage, VkImageLayout dstImageLayout, uint32_t regionCount,
3407*b7893ccfSSadaf Ebrahimi const VkImageBlit *pRegions, VkFilter filter) {
3408*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordCmdBlitImage(commandBuffer, srcImage, srcImageLayout, dstImage, dstImageLayout, regionCount,
3409*b7893ccfSSadaf Ebrahimi pRegions, filter);
3410*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
3411*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
3412*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
3413*b7893ccfSSadaf Ebrahimi
3414*b7893ccfSSadaf Ebrahimi // Make sure that all image slices are updated to correct layout
3415*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
3416*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].srcSubresource, srcImageLayout);
3417*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].dstSubresource, dstImageLayout);
3418*b7893ccfSSadaf Ebrahimi }
3419*b7893ccfSSadaf Ebrahimi }
3420*b7893ccfSSadaf Ebrahimi
3421*b7893ccfSSadaf Ebrahimi // This validates that the initial layout specified in the command buffer for the IMAGE is the same as the global IMAGE layout
ValidateCmdBufImageLayouts(const CMD_BUFFER_STATE * pCB,const ImageSubresPairLayoutMap & globalImageLayoutMap,ImageSubresPairLayoutMap * overlayLayoutMap_arg) const3422*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCmdBufImageLayouts(const CMD_BUFFER_STATE *pCB, const ImageSubresPairLayoutMap &globalImageLayoutMap,
3423*b7893ccfSSadaf Ebrahimi ImageSubresPairLayoutMap *overlayLayoutMap_arg) const {
3424*b7893ccfSSadaf Ebrahimi if (disabled.image_layout_validation) return false;
3425*b7893ccfSSadaf Ebrahimi bool skip = false;
3426*b7893ccfSSadaf Ebrahimi ImageSubresPairLayoutMap &overlayLayoutMap = *overlayLayoutMap_arg;
3427*b7893ccfSSadaf Ebrahimi // Iterate over the layout maps for each referenced image
3428*b7893ccfSSadaf Ebrahimi for (const auto &layout_map_entry : pCB->image_layout_map) {
3429*b7893ccfSSadaf Ebrahimi const auto image = layout_map_entry.first;
3430*b7893ccfSSadaf Ebrahimi const auto *image_state = GetImageState(image);
3431*b7893ccfSSadaf Ebrahimi if (!image_state) continue; // Can't check layouts of a dead image
3432*b7893ccfSSadaf Ebrahimi auto subres_map = layout_map_entry.second.get();
3433*b7893ccfSSadaf Ebrahimi ImageSubresourcePair isr_pair;
3434*b7893ccfSSadaf Ebrahimi isr_pair.image = image;
3435*b7893ccfSSadaf Ebrahimi isr_pair.hasSubresource = true;
3436*b7893ccfSSadaf Ebrahimi
3437*b7893ccfSSadaf Ebrahimi std::string bind_swapchain_msg = "";
3438*b7893ccfSSadaf Ebrahimi if (image_state->bind_swapchain) {
3439*b7893ccfSSadaf Ebrahimi auto swapchain_node = GetSwapchainState(image_state->bind_swapchain);
3440*b7893ccfSSadaf Ebrahimi const auto swapchain_image = swapchain_node->images[image_state->bind_swapchain_imageIndex];
3441*b7893ccfSSadaf Ebrahimi isr_pair.image = swapchain_image;
3442*b7893ccfSSadaf Ebrahimi
3443*b7893ccfSSadaf Ebrahimi string_sprintf(&bind_swapchain_msg, "bind %s imageIndex %d (%s)",
3444*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image_state->bind_swapchain).c_str(), image_state->bind_swapchain_imageIndex,
3445*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(swapchain_image).c_str());
3446*b7893ccfSSadaf Ebrahimi }
3447*b7893ccfSSadaf Ebrahimi
3448*b7893ccfSSadaf Ebrahimi // Validate the initial_uses for each subresource referenced
3449*b7893ccfSSadaf Ebrahimi for (auto it_init = subres_map->BeginInitialUse(); !it_init.AtEnd(); ++it_init) {
3450*b7893ccfSSadaf Ebrahimi isr_pair.subresource = (*it_init).subresource;
3451*b7893ccfSSadaf Ebrahimi VkImageLayout initial_layout = (*it_init).layout;
3452*b7893ccfSSadaf Ebrahimi VkImageLayout image_layout;
3453*b7893ccfSSadaf Ebrahimi if (FindLayout(overlayLayoutMap, isr_pair, image_layout) || FindLayout(globalImageLayoutMap, isr_pair, image_layout)) {
3454*b7893ccfSSadaf Ebrahimi if (initial_layout == VK_IMAGE_LAYOUT_UNDEFINED) {
3455*b7893ccfSSadaf Ebrahimi // TODO: Set memory invalid which is in mem_tracker currently
3456*b7893ccfSSadaf Ebrahimi } else if (image_layout != initial_layout) {
3457*b7893ccfSSadaf Ebrahimi // Need to look up the inital layout *state* to get a bit more information
3458*b7893ccfSSadaf Ebrahimi const auto *initial_layout_state = subres_map->GetSubresourceInitialLayoutState(isr_pair.subresource);
3459*b7893ccfSSadaf Ebrahimi assert(initial_layout_state); // There's no way we should have an initial layout without matching state...
3460*b7893ccfSSadaf Ebrahimi bool matches = ImageLayoutMatches(initial_layout_state->aspect_mask, image_layout, initial_layout);
3461*b7893ccfSSadaf Ebrahimi if (!matches) {
3462*b7893ccfSSadaf Ebrahimi std::string formatted_label = FormatDebugLabel(" ", pCB->debug_label);
3463*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3464*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3465*b7893ccfSSadaf Ebrahimi HandleToUint64(pCB->commandBuffer), kVUID_Core_DrawState_InvalidImageLayout,
3466*b7893ccfSSadaf Ebrahimi "Submitted command buffer expects %s %s (subresource: aspectMask 0x%X array layer %u, mip level %u) "
3467*b7893ccfSSadaf Ebrahimi "to be in layout %s--instead, current layout is %s.%s",
3468*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image).c_str(), bind_swapchain_msg.c_str(), isr_pair.subresource.aspectMask,
3469*b7893ccfSSadaf Ebrahimi isr_pair.subresource.arrayLayer, isr_pair.subresource.mipLevel, string_VkImageLayout(initial_layout),
3470*b7893ccfSSadaf Ebrahimi string_VkImageLayout(image_layout), formatted_label.c_str());
3471*b7893ccfSSadaf Ebrahimi }
3472*b7893ccfSSadaf Ebrahimi }
3473*b7893ccfSSadaf Ebrahimi }
3474*b7893ccfSSadaf Ebrahimi }
3475*b7893ccfSSadaf Ebrahimi
3476*b7893ccfSSadaf Ebrahimi // Update all layout set operations (which will be a subset of the initial_layouts
3477*b7893ccfSSadaf Ebrahimi for (auto it_set = subres_map->BeginSetLayout(); !it_set.AtEnd(); ++it_set) {
3478*b7893ccfSSadaf Ebrahimi VkImageLayout layout = (*it_set).layout;
3479*b7893ccfSSadaf Ebrahimi isr_pair.subresource = (*it_set).subresource;
3480*b7893ccfSSadaf Ebrahimi SetLayout(overlayLayoutMap, isr_pair, layout);
3481*b7893ccfSSadaf Ebrahimi }
3482*b7893ccfSSadaf Ebrahimi }
3483*b7893ccfSSadaf Ebrahimi
3484*b7893ccfSSadaf Ebrahimi return skip;
3485*b7893ccfSSadaf Ebrahimi }
3486*b7893ccfSSadaf Ebrahimi
UpdateCmdBufImageLayouts(CMD_BUFFER_STATE * pCB)3487*b7893ccfSSadaf Ebrahimi void CoreChecks::UpdateCmdBufImageLayouts(CMD_BUFFER_STATE *pCB) {
3488*b7893ccfSSadaf Ebrahimi for (const auto &layout_map_entry : pCB->image_layout_map) {
3489*b7893ccfSSadaf Ebrahimi const auto image = layout_map_entry.first;
3490*b7893ccfSSadaf Ebrahimi const auto *image_state = GetImageState(image);
3491*b7893ccfSSadaf Ebrahimi if (!image_state) continue; // Can't set layouts of a dead image
3492*b7893ccfSSadaf Ebrahimi const auto &subres_map = layout_map_entry.second;
3493*b7893ccfSSadaf Ebrahimi ImageSubresourcePair isr_pair;
3494*b7893ccfSSadaf Ebrahimi isr_pair.image = image;
3495*b7893ccfSSadaf Ebrahimi isr_pair.hasSubresource = true;
3496*b7893ccfSSadaf Ebrahimi
3497*b7893ccfSSadaf Ebrahimi // Update all layout set operations (which will be a subset of the initial_layouts
3498*b7893ccfSSadaf Ebrahimi for (auto it_set = subres_map->BeginSetLayout(); !it_set.AtEnd(); ++it_set) {
3499*b7893ccfSSadaf Ebrahimi VkImageLayout layout = (*it_set).layout;
3500*b7893ccfSSadaf Ebrahimi isr_pair.subresource = (*it_set).subresource;
3501*b7893ccfSSadaf Ebrahimi SetGlobalLayout(isr_pair, layout);
3502*b7893ccfSSadaf Ebrahimi }
3503*b7893ccfSSadaf Ebrahimi }
3504*b7893ccfSSadaf Ebrahimi }
3505*b7893ccfSSadaf Ebrahimi
3506*b7893ccfSSadaf Ebrahimi // ValidateLayoutVsAttachmentDescription is a general function where we can validate various state associated with the
3507*b7893ccfSSadaf Ebrahimi // VkAttachmentDescription structs that are used by the sub-passes of a renderpass. Initial check is to make sure that READ_ONLY
3508*b7893ccfSSadaf Ebrahimi // layout attachments don't have CLEAR as their loadOp.
ValidateLayoutVsAttachmentDescription(const debug_report_data * report_data,RenderPassCreateVersion rp_version,const VkImageLayout first_layout,const uint32_t attachment,const VkAttachmentDescription2KHR & attachment_description) const3509*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateLayoutVsAttachmentDescription(const debug_report_data *report_data, RenderPassCreateVersion rp_version,
3510*b7893ccfSSadaf Ebrahimi const VkImageLayout first_layout, const uint32_t attachment,
3511*b7893ccfSSadaf Ebrahimi const VkAttachmentDescription2KHR &attachment_description) const {
3512*b7893ccfSSadaf Ebrahimi bool skip = false;
3513*b7893ccfSSadaf Ebrahimi const char *vuid;
3514*b7893ccfSSadaf Ebrahimi const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
3515*b7893ccfSSadaf Ebrahimi
3516*b7893ccfSSadaf Ebrahimi // Verify that initial loadOp on READ_ONLY attachments is not CLEAR
3517*b7893ccfSSadaf Ebrahimi if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
3518*b7893ccfSSadaf Ebrahimi if (use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
3519*b7893ccfSSadaf Ebrahimi (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) ||
3520*b7893ccfSSadaf Ebrahimi (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL))) {
3521*b7893ccfSSadaf Ebrahimi skip |=
3522*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3523*b7893ccfSSadaf Ebrahimi "VUID-VkRenderPassCreateInfo2KHR-pAttachments-02522",
3524*b7893ccfSSadaf Ebrahimi "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
3525*b7893ccfSSadaf Ebrahimi } else if (!use_rp2 && ((first_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL) ||
3526*b7893ccfSSadaf Ebrahimi (first_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL))) {
3527*b7893ccfSSadaf Ebrahimi skip |=
3528*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3529*b7893ccfSSadaf Ebrahimi "VUID-VkRenderPassCreateInfo-pAttachments-00836",
3530*b7893ccfSSadaf Ebrahimi "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
3531*b7893ccfSSadaf Ebrahimi }
3532*b7893ccfSSadaf Ebrahimi }
3533*b7893ccfSSadaf Ebrahimi if (attachment_description.loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
3534*b7893ccfSSadaf Ebrahimi if (first_layout == VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL) {
3535*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pAttachments-01566";
3536*b7893ccfSSadaf Ebrahimi skip |=
3537*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3538*b7893ccfSSadaf Ebrahimi "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
3539*b7893ccfSSadaf Ebrahimi }
3540*b7893ccfSSadaf Ebrahimi }
3541*b7893ccfSSadaf Ebrahimi
3542*b7893ccfSSadaf Ebrahimi if (attachment_description.stencilLoadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
3543*b7893ccfSSadaf Ebrahimi if (first_layout == VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL) {
3544*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? kVUID_Core_DrawState_InvalidRenderpass : "VUID-VkRenderPassCreateInfo-pAttachments-01567";
3545*b7893ccfSSadaf Ebrahimi skip |=
3546*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3547*b7893ccfSSadaf Ebrahimi "Cannot clear attachment %d with invalid first layout %s.", attachment, string_VkImageLayout(first_layout));
3548*b7893ccfSSadaf Ebrahimi }
3549*b7893ccfSSadaf Ebrahimi }
3550*b7893ccfSSadaf Ebrahimi return skip;
3551*b7893ccfSSadaf Ebrahimi }
3552*b7893ccfSSadaf Ebrahimi
ValidateLayouts(RenderPassCreateVersion rp_version,VkDevice device,const VkRenderPassCreateInfo2KHR * pCreateInfo) const3553*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateLayouts(RenderPassCreateVersion rp_version, VkDevice device,
3554*b7893ccfSSadaf Ebrahimi const VkRenderPassCreateInfo2KHR *pCreateInfo) const {
3555*b7893ccfSSadaf Ebrahimi bool skip = false;
3556*b7893ccfSSadaf Ebrahimi const char *vuid;
3557*b7893ccfSSadaf Ebrahimi const bool use_rp2 = (rp_version == RENDER_PASS_VERSION_2);
3558*b7893ccfSSadaf Ebrahimi const char *const function_name = use_rp2 ? "vkCreateRenderPass2KHR()" : "vkCreateRenderPass()";
3559*b7893ccfSSadaf Ebrahimi
3560*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < pCreateInfo->attachmentCount; ++i) {
3561*b7893ccfSSadaf Ebrahimi VkFormat format = pCreateInfo->pAttachments[i].format;
3562*b7893ccfSSadaf Ebrahimi if (pCreateInfo->pAttachments[i].initialLayout == VK_IMAGE_LAYOUT_UNDEFINED) {
3563*b7893ccfSSadaf Ebrahimi if ((FormatIsColor(format) || FormatHasDepth(format)) &&
3564*b7893ccfSSadaf Ebrahimi pCreateInfo->pAttachments[i].loadOp == VK_ATTACHMENT_LOAD_OP_LOAD) {
3565*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3566*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidRenderpass,
3567*b7893ccfSSadaf Ebrahimi "Render pass has an attachment with loadOp == VK_ATTACHMENT_LOAD_OP_LOAD and initialLayout == "
3568*b7893ccfSSadaf Ebrahimi "VK_IMAGE_LAYOUT_UNDEFINED. This is probably not what you intended. Consider using "
3569*b7893ccfSSadaf Ebrahimi "VK_ATTACHMENT_LOAD_OP_DONT_CARE instead if the image truely is undefined at the start of the "
3570*b7893ccfSSadaf Ebrahimi "render pass.");
3571*b7893ccfSSadaf Ebrahimi }
3572*b7893ccfSSadaf Ebrahimi if (FormatHasStencil(format) && pCreateInfo->pAttachments[i].stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD) {
3573*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3574*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidRenderpass,
3575*b7893ccfSSadaf Ebrahimi "Render pass has an attachment with stencilLoadOp == VK_ATTACHMENT_LOAD_OP_LOAD and initialLayout "
3576*b7893ccfSSadaf Ebrahimi "== VK_IMAGE_LAYOUT_UNDEFINED. This is probably not what you intended. Consider using "
3577*b7893ccfSSadaf Ebrahimi "VK_ATTACHMENT_LOAD_OP_DONT_CARE instead if the image truely is undefined at the start of the "
3578*b7893ccfSSadaf Ebrahimi "render pass.");
3579*b7893ccfSSadaf Ebrahimi }
3580*b7893ccfSSadaf Ebrahimi }
3581*b7893ccfSSadaf Ebrahimi }
3582*b7893ccfSSadaf Ebrahimi
3583*b7893ccfSSadaf Ebrahimi // Track when we're observing the first use of an attachment
3584*b7893ccfSSadaf Ebrahimi std::vector<bool> attach_first_use(pCreateInfo->attachmentCount, true);
3585*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < pCreateInfo->subpassCount; ++i) {
3586*b7893ccfSSadaf Ebrahimi const VkSubpassDescription2KHR &subpass = pCreateInfo->pSubpasses[i];
3587*b7893ccfSSadaf Ebrahimi
3588*b7893ccfSSadaf Ebrahimi // Check input attachments first, so we can detect first-use-as-input for VU #00349
3589*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < subpass.inputAttachmentCount; ++j) {
3590*b7893ccfSSadaf Ebrahimi auto attach_index = subpass.pInputAttachments[j].attachment;
3591*b7893ccfSSadaf Ebrahimi if (attach_index == VK_ATTACHMENT_UNUSED) continue;
3592*b7893ccfSSadaf Ebrahimi switch (subpass.pInputAttachments[j].layout) {
3593*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
3594*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL:
3595*b7893ccfSSadaf Ebrahimi // These are ideal.
3596*b7893ccfSSadaf Ebrahimi break;
3597*b7893ccfSSadaf Ebrahimi
3598*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_GENERAL:
3599*b7893ccfSSadaf Ebrahimi // May not be optimal. TODO: reconsider this warning based on other constraints.
3600*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
3601*b7893ccfSSadaf Ebrahimi VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout,
3602*b7893ccfSSadaf Ebrahimi "Layout for input attachment is GENERAL but should be READ_ONLY_OPTIMAL.");
3603*b7893ccfSSadaf Ebrahimi break;
3604*b7893ccfSSadaf Ebrahimi
3605*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_UNDEFINED:
3606*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_PREINITIALIZED:
3607*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
3608*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3609*b7893ccfSSadaf Ebrahimi "Layout for input attachment reference %u in subpass %u is %s but must be "
3610*b7893ccfSSadaf Ebrahimi "DEPTH_STENCIL_READ_ONLY, SHADER_READ_ONLY_OPTIMAL, or GENERAL.",
3611*b7893ccfSSadaf Ebrahimi j, i, string_VkImageLayout(subpass.pInputAttachments[j].layout));
3612*b7893ccfSSadaf Ebrahimi break;
3613*b7893ccfSSadaf Ebrahimi
3614*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
3615*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
3616*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance2) {
3617*b7893ccfSSadaf Ebrahimi break;
3618*b7893ccfSSadaf Ebrahimi } else {
3619*b7893ccfSSadaf Ebrahimi // Intentionally fall through to generic error message
3620*b7893ccfSSadaf Ebrahimi }
3621*b7893ccfSSadaf Ebrahimi // fall through
3622*b7893ccfSSadaf Ebrahimi
3623*b7893ccfSSadaf Ebrahimi default:
3624*b7893ccfSSadaf Ebrahimi // No other layouts are acceptable
3625*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3626*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidImageLayout,
3627*b7893ccfSSadaf Ebrahimi "Layout for input attachment is %s but can only be READ_ONLY_OPTIMAL or GENERAL.",
3628*b7893ccfSSadaf Ebrahimi string_VkImageLayout(subpass.pInputAttachments[j].layout));
3629*b7893ccfSSadaf Ebrahimi }
3630*b7893ccfSSadaf Ebrahimi
3631*b7893ccfSSadaf Ebrahimi if (attach_first_use[attach_index]) {
3632*b7893ccfSSadaf Ebrahimi skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pInputAttachments[j].layout,
3633*b7893ccfSSadaf Ebrahimi attach_index, pCreateInfo->pAttachments[attach_index]);
3634*b7893ccfSSadaf Ebrahimi
3635*b7893ccfSSadaf Ebrahimi bool used_as_depth =
3636*b7893ccfSSadaf Ebrahimi (subpass.pDepthStencilAttachment != NULL && subpass.pDepthStencilAttachment->attachment == attach_index);
3637*b7893ccfSSadaf Ebrahimi bool used_as_color = false;
3638*b7893ccfSSadaf Ebrahimi for (uint32_t k = 0; !used_as_depth && !used_as_color && k < subpass.colorAttachmentCount; ++k) {
3639*b7893ccfSSadaf Ebrahimi used_as_color = (subpass.pColorAttachments[k].attachment == attach_index);
3640*b7893ccfSSadaf Ebrahimi }
3641*b7893ccfSSadaf Ebrahimi if (!used_as_depth && !used_as_color &&
3642*b7893ccfSSadaf Ebrahimi pCreateInfo->pAttachments[attach_index].loadOp == VK_ATTACHMENT_LOAD_OP_CLEAR) {
3643*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-VkSubpassDescription2KHR-loadOp-03064" : "VUID-VkSubpassDescription-loadOp-00846";
3644*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3645*b7893ccfSSadaf Ebrahimi "%s: attachment %u is first used as an input attachment in subpass %u with loadOp=CLEAR.",
3646*b7893ccfSSadaf Ebrahimi function_name, attach_index, attach_index);
3647*b7893ccfSSadaf Ebrahimi }
3648*b7893ccfSSadaf Ebrahimi }
3649*b7893ccfSSadaf Ebrahimi attach_first_use[attach_index] = false;
3650*b7893ccfSSadaf Ebrahimi }
3651*b7893ccfSSadaf Ebrahimi
3652*b7893ccfSSadaf Ebrahimi for (uint32_t j = 0; j < subpass.colorAttachmentCount; ++j) {
3653*b7893ccfSSadaf Ebrahimi auto attach_index = subpass.pColorAttachments[j].attachment;
3654*b7893ccfSSadaf Ebrahimi if (attach_index == VK_ATTACHMENT_UNUSED) continue;
3655*b7893ccfSSadaf Ebrahimi
3656*b7893ccfSSadaf Ebrahimi // TODO: Need a way to validate shared presentable images here, currently just allowing
3657*b7893ccfSSadaf Ebrahimi // VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR
3658*b7893ccfSSadaf Ebrahimi // as an acceptable layout, but need to make sure shared presentable images ONLY use that layout
3659*b7893ccfSSadaf Ebrahimi switch (subpass.pColorAttachments[j].layout) {
3660*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL:
3661*b7893ccfSSadaf Ebrahimi // This is ideal.
3662*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_SHARED_PRESENT_KHR:
3663*b7893ccfSSadaf Ebrahimi // TODO: See note above, just assuming that attachment is shared presentable and allowing this for now.
3664*b7893ccfSSadaf Ebrahimi break;
3665*b7893ccfSSadaf Ebrahimi
3666*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_GENERAL:
3667*b7893ccfSSadaf Ebrahimi // May not be optimal; TODO: reconsider this warning based on other constraints?
3668*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
3669*b7893ccfSSadaf Ebrahimi VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout,
3670*b7893ccfSSadaf Ebrahimi "Layout for color attachment is GENERAL but should be COLOR_ATTACHMENT_OPTIMAL.");
3671*b7893ccfSSadaf Ebrahimi break;
3672*b7893ccfSSadaf Ebrahimi
3673*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_UNDEFINED:
3674*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_PREINITIALIZED:
3675*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
3676*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3677*b7893ccfSSadaf Ebrahimi "Layout for color attachment reference %u in subpass %u is %s but should be "
3678*b7893ccfSSadaf Ebrahimi "COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
3679*b7893ccfSSadaf Ebrahimi j, i, string_VkImageLayout(subpass.pColorAttachments[j].layout));
3680*b7893ccfSSadaf Ebrahimi break;
3681*b7893ccfSSadaf Ebrahimi
3682*b7893ccfSSadaf Ebrahimi default:
3683*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3684*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidImageLayout,
3685*b7893ccfSSadaf Ebrahimi "Layout for color attachment is %s but can only be COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
3686*b7893ccfSSadaf Ebrahimi string_VkImageLayout(subpass.pColorAttachments[j].layout));
3687*b7893ccfSSadaf Ebrahimi }
3688*b7893ccfSSadaf Ebrahimi
3689*b7893ccfSSadaf Ebrahimi if (subpass.pResolveAttachments && (subpass.pResolveAttachments[j].attachment != VK_ATTACHMENT_UNUSED) &&
3690*b7893ccfSSadaf Ebrahimi (subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_UNDEFINED ||
3691*b7893ccfSSadaf Ebrahimi subpass.pResolveAttachments[j].layout == VK_IMAGE_LAYOUT_PREINITIALIZED)) {
3692*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
3693*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3694*b7893ccfSSadaf Ebrahimi "Layout for resolve attachment reference %u in subpass %u is %s but should be "
3695*b7893ccfSSadaf Ebrahimi "COLOR_ATTACHMENT_OPTIMAL or GENERAL.",
3696*b7893ccfSSadaf Ebrahimi j, i, string_VkImageLayout(subpass.pResolveAttachments[j].layout));
3697*b7893ccfSSadaf Ebrahimi }
3698*b7893ccfSSadaf Ebrahimi
3699*b7893ccfSSadaf Ebrahimi if (attach_first_use[attach_index]) {
3700*b7893ccfSSadaf Ebrahimi skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pColorAttachments[j].layout,
3701*b7893ccfSSadaf Ebrahimi attach_index, pCreateInfo->pAttachments[attach_index]);
3702*b7893ccfSSadaf Ebrahimi }
3703*b7893ccfSSadaf Ebrahimi attach_first_use[attach_index] = false;
3704*b7893ccfSSadaf Ebrahimi }
3705*b7893ccfSSadaf Ebrahimi
3706*b7893ccfSSadaf Ebrahimi if (subpass.pDepthStencilAttachment && subpass.pDepthStencilAttachment->attachment != VK_ATTACHMENT_UNUSED) {
3707*b7893ccfSSadaf Ebrahimi switch (subpass.pDepthStencilAttachment->layout) {
3708*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL:
3709*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_STENCIL_READ_ONLY_OPTIMAL:
3710*b7893ccfSSadaf Ebrahimi // These are ideal.
3711*b7893ccfSSadaf Ebrahimi break;
3712*b7893ccfSSadaf Ebrahimi
3713*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_GENERAL:
3714*b7893ccfSSadaf Ebrahimi // May not be optimal; TODO: reconsider this warning based on other constraints? GENERAL can be better than
3715*b7893ccfSSadaf Ebrahimi // doing a bunch of transitions.
3716*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_PERFORMANCE_WARNING_BIT_EXT,
3717*b7893ccfSSadaf Ebrahimi VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, kVUID_Core_DrawState_InvalidImageLayout,
3718*b7893ccfSSadaf Ebrahimi "GENERAL layout for depth attachment may not give optimal performance.");
3719*b7893ccfSSadaf Ebrahimi break;
3720*b7893ccfSSadaf Ebrahimi
3721*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_UNDEFINED:
3722*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_PREINITIALIZED:
3723*b7893ccfSSadaf Ebrahimi vuid = use_rp2 ? "VUID-VkAttachmentReference2KHR-layout-03077" : "VUID-VkAttachmentReference-layout-00857";
3724*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0, vuid,
3725*b7893ccfSSadaf Ebrahimi "Layout for depth attachment reference in subpass %u is %s but must be a valid depth/stencil "
3726*b7893ccfSSadaf Ebrahimi "layout or GENERAL.",
3727*b7893ccfSSadaf Ebrahimi i, string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
3728*b7893ccfSSadaf Ebrahimi break;
3729*b7893ccfSSadaf Ebrahimi
3730*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL_KHR:
3731*b7893ccfSSadaf Ebrahimi case VK_IMAGE_LAYOUT_DEPTH_ATTACHMENT_STENCIL_READ_ONLY_OPTIMAL_KHR:
3732*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance2) {
3733*b7893ccfSSadaf Ebrahimi break;
3734*b7893ccfSSadaf Ebrahimi } else {
3735*b7893ccfSSadaf Ebrahimi // Intentionally fall through to generic error message
3736*b7893ccfSSadaf Ebrahimi }
3737*b7893ccfSSadaf Ebrahimi // fall through
3738*b7893ccfSSadaf Ebrahimi
3739*b7893ccfSSadaf Ebrahimi default:
3740*b7893ccfSSadaf Ebrahimi // No other layouts are acceptable
3741*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3742*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_InvalidImageLayout,
3743*b7893ccfSSadaf Ebrahimi "Layout for depth attachment is %s but can only be DEPTH_STENCIL_ATTACHMENT_OPTIMAL, "
3744*b7893ccfSSadaf Ebrahimi "DEPTH_STENCIL_READ_ONLY_OPTIMAL or GENERAL.",
3745*b7893ccfSSadaf Ebrahimi string_VkImageLayout(subpass.pDepthStencilAttachment->layout));
3746*b7893ccfSSadaf Ebrahimi }
3747*b7893ccfSSadaf Ebrahimi
3748*b7893ccfSSadaf Ebrahimi auto attach_index = subpass.pDepthStencilAttachment->attachment;
3749*b7893ccfSSadaf Ebrahimi if (attach_first_use[attach_index]) {
3750*b7893ccfSSadaf Ebrahimi skip |= ValidateLayoutVsAttachmentDescription(report_data, rp_version, subpass.pDepthStencilAttachment->layout,
3751*b7893ccfSSadaf Ebrahimi attach_index, pCreateInfo->pAttachments[attach_index]);
3752*b7893ccfSSadaf Ebrahimi }
3753*b7893ccfSSadaf Ebrahimi attach_first_use[attach_index] = false;
3754*b7893ccfSSadaf Ebrahimi }
3755*b7893ccfSSadaf Ebrahimi }
3756*b7893ccfSSadaf Ebrahimi return skip;
3757*b7893ccfSSadaf Ebrahimi }
3758*b7893ccfSSadaf Ebrahimi
3759*b7893ccfSSadaf Ebrahimi // Helper function to validate correct usage bits set for buffers or images. Verify that (actual & desired) flags != 0 or, if strict
3760*b7893ccfSSadaf Ebrahimi // is true, verify that (actual & desired) flags == desired
ValidateUsageFlags(VkFlags actual,VkFlags desired,VkBool32 strict,const VulkanTypedHandle & typed_handle,const char * msgCode,char const * func_name,char const * usage_str) const3761*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateUsageFlags(VkFlags actual, VkFlags desired, VkBool32 strict, const VulkanTypedHandle &typed_handle,
3762*b7893ccfSSadaf Ebrahimi const char *msgCode, char const *func_name, char const *usage_str) const {
3763*b7893ccfSSadaf Ebrahimi bool correct_usage = false;
3764*b7893ccfSSadaf Ebrahimi bool skip = false;
3765*b7893ccfSSadaf Ebrahimi const char *type_str = object_string[typed_handle.type];
3766*b7893ccfSSadaf Ebrahimi if (strict) {
3767*b7893ccfSSadaf Ebrahimi correct_usage = ((actual & desired) == desired);
3768*b7893ccfSSadaf Ebrahimi } else {
3769*b7893ccfSSadaf Ebrahimi correct_usage = ((actual & desired) != 0);
3770*b7893ccfSSadaf Ebrahimi }
3771*b7893ccfSSadaf Ebrahimi if (!correct_usage) {
3772*b7893ccfSSadaf Ebrahimi if (msgCode == kVUIDUndefined) {
3773*b7893ccfSSadaf Ebrahimi // TODO: Fix callers with kVUIDUndefined to use correct validation checks.
3774*b7893ccfSSadaf Ebrahimi skip = log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[typed_handle.type],
3775*b7893ccfSSadaf Ebrahimi typed_handle.handle, kVUID_Core_MemTrack_InvalidUsageFlag,
3776*b7893ccfSSadaf Ebrahimi "Invalid usage flag for %s used by %s. In this case, %s should have %s set during creation.",
3777*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(typed_handle).c_str(), func_name, type_str, usage_str);
3778*b7893ccfSSadaf Ebrahimi } else {
3779*b7893ccfSSadaf Ebrahimi skip =
3780*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, get_debug_report_enum[typed_handle.type], typed_handle.handle,
3781*b7893ccfSSadaf Ebrahimi msgCode, "Invalid usage flag for %s used by %s. In this case, %s should have %s set during creation.",
3782*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(typed_handle).c_str(), func_name, type_str, usage_str);
3783*b7893ccfSSadaf Ebrahimi }
3784*b7893ccfSSadaf Ebrahimi }
3785*b7893ccfSSadaf Ebrahimi return skip;
3786*b7893ccfSSadaf Ebrahimi }
3787*b7893ccfSSadaf Ebrahimi
3788*b7893ccfSSadaf Ebrahimi // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
3789*b7893ccfSSadaf Ebrahimi // where an error will be flagged if usage is not correct
ValidateImageUsageFlags(IMAGE_STATE const * image_state,VkFlags desired,bool strict,const char * msgCode,char const * func_name,char const * usage_string) const3790*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageUsageFlags(IMAGE_STATE const *image_state, VkFlags desired, bool strict, const char *msgCode,
3791*b7893ccfSSadaf Ebrahimi char const *func_name, char const *usage_string) const {
3792*b7893ccfSSadaf Ebrahimi return ValidateUsageFlags(image_state->createInfo.usage, desired, strict,
3793*b7893ccfSSadaf Ebrahimi VulkanTypedHandle(image_state->image, kVulkanObjectTypeImage), msgCode, func_name, usage_string);
3794*b7893ccfSSadaf Ebrahimi }
3795*b7893ccfSSadaf Ebrahimi
ValidateImageFormatFeatureFlags(IMAGE_STATE const * image_state,VkFormatFeatureFlags desired,char const * func_name,const char * linear_vuid,const char * optimal_vuid) const3796*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageFormatFeatureFlags(IMAGE_STATE const *image_state, VkFormatFeatureFlags desired,
3797*b7893ccfSSadaf Ebrahimi char const *func_name, const char *linear_vuid, const char *optimal_vuid) const {
3798*b7893ccfSSadaf Ebrahimi VkFormatProperties format_properties = GetPDFormatProperties(image_state->createInfo.format);
3799*b7893ccfSSadaf Ebrahimi bool skip = false;
3800*b7893ccfSSadaf Ebrahimi if (image_state->createInfo.tiling == VK_IMAGE_TILING_LINEAR) {
3801*b7893ccfSSadaf Ebrahimi if ((format_properties.linearTilingFeatures & desired) != desired) {
3802*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3803*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), linear_vuid,
3804*b7893ccfSSadaf Ebrahimi "In %s, invalid linearTilingFeatures (0x%08X) for format %u used by %s.", func_name,
3805*b7893ccfSSadaf Ebrahimi format_properties.linearTilingFeatures, image_state->createInfo.format,
3806*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image_state->image).c_str());
3807*b7893ccfSSadaf Ebrahimi }
3808*b7893ccfSSadaf Ebrahimi } else if (image_state->createInfo.tiling == VK_IMAGE_TILING_OPTIMAL) {
3809*b7893ccfSSadaf Ebrahimi if ((format_properties.optimalTilingFeatures & desired) != desired) {
3810*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
3811*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), optimal_vuid,
3812*b7893ccfSSadaf Ebrahimi "In %s, invalid optimalTilingFeatures (0x%08X) for format %u used by %s.", func_name,
3813*b7893ccfSSadaf Ebrahimi format_properties.optimalTilingFeatures, image_state->createInfo.format,
3814*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(image_state->image).c_str());
3815*b7893ccfSSadaf Ebrahimi }
3816*b7893ccfSSadaf Ebrahimi }
3817*b7893ccfSSadaf Ebrahimi return skip;
3818*b7893ccfSSadaf Ebrahimi }
3819*b7893ccfSSadaf Ebrahimi
ValidateImageSubresourceLayers(const CMD_BUFFER_STATE * cb_node,const VkImageSubresourceLayers * subresource_layers,char const * func_name,char const * member,uint32_t i) const3820*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageSubresourceLayers(const CMD_BUFFER_STATE *cb_node, const VkImageSubresourceLayers *subresource_layers,
3821*b7893ccfSSadaf Ebrahimi char const *func_name, char const *member, uint32_t i) const {
3822*b7893ccfSSadaf Ebrahimi bool skip = false;
3823*b7893ccfSSadaf Ebrahimi // layerCount must not be zero
3824*b7893ccfSSadaf Ebrahimi if (subresource_layers->layerCount == 0) {
3825*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3826*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageSubresourceLayers-layerCount-01700",
3827*b7893ccfSSadaf Ebrahimi "In %s, pRegions[%u].%s.layerCount must not be zero.", func_name, i, member);
3828*b7893ccfSSadaf Ebrahimi }
3829*b7893ccfSSadaf Ebrahimi // aspectMask must not contain VK_IMAGE_ASPECT_METADATA_BIT
3830*b7893ccfSSadaf Ebrahimi if (subresource_layers->aspectMask & VK_IMAGE_ASPECT_METADATA_BIT) {
3831*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3832*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageSubresourceLayers-aspectMask-00168",
3833*b7893ccfSSadaf Ebrahimi "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_METADATA_BIT set.", func_name, i, member);
3834*b7893ccfSSadaf Ebrahimi }
3835*b7893ccfSSadaf Ebrahimi // if aspectMask contains COLOR, it must not contain either DEPTH or STENCIL
3836*b7893ccfSSadaf Ebrahimi if ((subresource_layers->aspectMask & VK_IMAGE_ASPECT_COLOR_BIT) &&
3837*b7893ccfSSadaf Ebrahimi (subresource_layers->aspectMask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT))) {
3838*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
3839*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->commandBuffer), "VUID-VkImageSubresourceLayers-aspectMask-00167",
3840*b7893ccfSSadaf Ebrahimi "In %s, pRegions[%u].%s.aspectMask has VK_IMAGE_ASPECT_COLOR_BIT and either VK_IMAGE_ASPECT_DEPTH_BIT or "
3841*b7893ccfSSadaf Ebrahimi "VK_IMAGE_ASPECT_STENCIL_BIT set.",
3842*b7893ccfSSadaf Ebrahimi func_name, i, member);
3843*b7893ccfSSadaf Ebrahimi }
3844*b7893ccfSSadaf Ebrahimi return skip;
3845*b7893ccfSSadaf Ebrahimi }
3846*b7893ccfSSadaf Ebrahimi
3847*b7893ccfSSadaf Ebrahimi // Helper function to validate usage flags for buffers. For given buffer_state send actual vs. desired usage off to helper above
3848*b7893ccfSSadaf Ebrahimi // where an error will be flagged if usage is not correct
ValidateBufferUsageFlags(BUFFER_STATE const * buffer_state,VkFlags desired,bool strict,const char * msgCode,char const * func_name,char const * usage_string) const3849*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBufferUsageFlags(BUFFER_STATE const *buffer_state, VkFlags desired, bool strict, const char *msgCode,
3850*b7893ccfSSadaf Ebrahimi char const *func_name, char const *usage_string) const {
3851*b7893ccfSSadaf Ebrahimi return ValidateUsageFlags(buffer_state->createInfo.usage, desired, strict,
3852*b7893ccfSSadaf Ebrahimi VulkanTypedHandle(buffer_state->buffer, kVulkanObjectTypeBuffer), msgCode, func_name, usage_string);
3853*b7893ccfSSadaf Ebrahimi }
3854*b7893ccfSSadaf Ebrahimi
ValidateBufferViewRange(const BUFFER_STATE * buffer_state,const VkBufferViewCreateInfo * pCreateInfo,const VkPhysicalDeviceLimits * device_limits)3855*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBufferViewRange(const BUFFER_STATE *buffer_state, const VkBufferViewCreateInfo *pCreateInfo,
3856*b7893ccfSSadaf Ebrahimi const VkPhysicalDeviceLimits *device_limits) {
3857*b7893ccfSSadaf Ebrahimi bool skip = false;
3858*b7893ccfSSadaf Ebrahimi
3859*b7893ccfSSadaf Ebrahimi const VkDeviceSize &range = pCreateInfo->range;
3860*b7893ccfSSadaf Ebrahimi if (range != VK_WHOLE_SIZE) {
3861*b7893ccfSSadaf Ebrahimi // Range must be greater than 0
3862*b7893ccfSSadaf Ebrahimi if (range <= 0) {
3863*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3864*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00928",
3865*b7893ccfSSadaf Ebrahimi "If VkBufferViewCreateInfo range (%" PRIuLEAST64
3866*b7893ccfSSadaf Ebrahimi ") does not equal VK_WHOLE_SIZE, range must be greater than 0.",
3867*b7893ccfSSadaf Ebrahimi range);
3868*b7893ccfSSadaf Ebrahimi }
3869*b7893ccfSSadaf Ebrahimi // Range must be a multiple of the element size of format
3870*b7893ccfSSadaf Ebrahimi const uint32_t format_size = FormatElementSize(pCreateInfo->format);
3871*b7893ccfSSadaf Ebrahimi if (SafeModulo(range, format_size) != 0) {
3872*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3873*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00929",
3874*b7893ccfSSadaf Ebrahimi "If VkBufferViewCreateInfo range (%" PRIuLEAST64
3875*b7893ccfSSadaf Ebrahimi ") does not equal VK_WHOLE_SIZE, range must be a multiple of the element size of the format "
3876*b7893ccfSSadaf Ebrahimi "(%" PRIu32 ").",
3877*b7893ccfSSadaf Ebrahimi range, format_size);
3878*b7893ccfSSadaf Ebrahimi }
3879*b7893ccfSSadaf Ebrahimi // Range divided by the element size of format must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements
3880*b7893ccfSSadaf Ebrahimi if (SafeDivision(range, format_size) > device_limits->maxTexelBufferElements) {
3881*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3882*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-range-00930",
3883*b7893ccfSSadaf Ebrahimi "If VkBufferViewCreateInfo range (%" PRIuLEAST64
3884*b7893ccfSSadaf Ebrahimi ") does not equal VK_WHOLE_SIZE, range divided by the element size of the format (%" PRIu32
3885*b7893ccfSSadaf Ebrahimi ") must be less than or equal to VkPhysicalDeviceLimits::maxTexelBufferElements (%" PRIuLEAST32 ").",
3886*b7893ccfSSadaf Ebrahimi range, format_size, device_limits->maxTexelBufferElements);
3887*b7893ccfSSadaf Ebrahimi }
3888*b7893ccfSSadaf Ebrahimi // The sum of range and offset must be less than or equal to the size of buffer
3889*b7893ccfSSadaf Ebrahimi if (range + pCreateInfo->offset > buffer_state->createInfo.size) {
3890*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3891*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-00931",
3892*b7893ccfSSadaf Ebrahimi "If VkBufferViewCreateInfo range (%" PRIuLEAST64
3893*b7893ccfSSadaf Ebrahimi ") does not equal VK_WHOLE_SIZE, the sum of offset (%" PRIuLEAST64
3894*b7893ccfSSadaf Ebrahimi ") and range must be less than or equal to the size of the buffer (%" PRIuLEAST64 ").",
3895*b7893ccfSSadaf Ebrahimi range, pCreateInfo->offset, buffer_state->createInfo.size);
3896*b7893ccfSSadaf Ebrahimi }
3897*b7893ccfSSadaf Ebrahimi }
3898*b7893ccfSSadaf Ebrahimi return skip;
3899*b7893ccfSSadaf Ebrahimi }
3900*b7893ccfSSadaf Ebrahimi
ValidateBufferViewBuffer(const BUFFER_STATE * buffer_state,const VkBufferViewCreateInfo * pCreateInfo)3901*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBufferViewBuffer(const BUFFER_STATE *buffer_state, const VkBufferViewCreateInfo *pCreateInfo) {
3902*b7893ccfSSadaf Ebrahimi bool skip = false;
3903*b7893ccfSSadaf Ebrahimi const VkFormatProperties format_properties = GetPDFormatProperties(pCreateInfo->format);
3904*b7893ccfSSadaf Ebrahimi if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) &&
3905*b7893ccfSSadaf Ebrahimi !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_UNIFORM_TEXEL_BUFFER_BIT)) {
3906*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3907*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-00933",
3908*b7893ccfSSadaf Ebrahimi "If buffer was created with `usage` containing VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, format must "
3909*b7893ccfSSadaf Ebrahimi "be supported for uniform texel buffers");
3910*b7893ccfSSadaf Ebrahimi }
3911*b7893ccfSSadaf Ebrahimi if ((buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) &&
3912*b7893ccfSSadaf Ebrahimi !(format_properties.bufferFeatures & VK_FORMAT_FEATURE_STORAGE_TEXEL_BUFFER_BIT)) {
3913*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
3914*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-00934",
3915*b7893ccfSSadaf Ebrahimi "If buffer was created with `usage` containing VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, format must "
3916*b7893ccfSSadaf Ebrahimi "be supported for storage texel buffers");
3917*b7893ccfSSadaf Ebrahimi }
3918*b7893ccfSSadaf Ebrahimi return skip;
3919*b7893ccfSSadaf Ebrahimi }
3920*b7893ccfSSadaf Ebrahimi
PreCallValidateCreateBuffer(VkDevice device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer)3921*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
3922*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer) {
3923*b7893ccfSSadaf Ebrahimi bool skip = false;
3924*b7893ccfSSadaf Ebrahimi
3925*b7893ccfSSadaf Ebrahimi // TODO: Add check for "VUID-vkCreateBuffer-flags-00911" (sparse address space accounting)
3926*b7893ccfSSadaf Ebrahimi
3927*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_BINDING_BIT) && (!enabled_features.core.sparseBinding)) {
3928*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3929*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-flags-00915",
3930*b7893ccfSSadaf Ebrahimi "vkCreateBuffer(): the sparseBinding device feature is disabled: Buffers cannot be created with the "
3931*b7893ccfSSadaf Ebrahimi "VK_BUFFER_CREATE_SPARSE_BINDING_BIT set.");
3932*b7893ccfSSadaf Ebrahimi }
3933*b7893ccfSSadaf Ebrahimi
3934*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT) && (!enabled_features.core.sparseResidencyBuffer)) {
3935*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3936*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-flags-00916",
3937*b7893ccfSSadaf Ebrahimi "vkCreateBuffer(): the sparseResidencyBuffer device feature is disabled: Buffers cannot be created with "
3938*b7893ccfSSadaf Ebrahimi "the VK_BUFFER_CREATE_SPARSE_RESIDENCY_BIT set.");
3939*b7893ccfSSadaf Ebrahimi }
3940*b7893ccfSSadaf Ebrahimi
3941*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->flags & VK_BUFFER_CREATE_SPARSE_ALIASED_BIT) && (!enabled_features.core.sparseResidencyAliased)) {
3942*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3943*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-flags-00917",
3944*b7893ccfSSadaf Ebrahimi "vkCreateBuffer(): the sparseResidencyAliased device feature is disabled: Buffers cannot be created with "
3945*b7893ccfSSadaf Ebrahimi "the VK_BUFFER_CREATE_SPARSE_ALIASED_BIT set.");
3946*b7893ccfSSadaf Ebrahimi }
3947*b7893ccfSSadaf Ebrahimi
3948*b7893ccfSSadaf Ebrahimi auto chained_devaddr_struct = lvl_find_in_chain<VkBufferDeviceAddressCreateInfoEXT>(pCreateInfo->pNext);
3949*b7893ccfSSadaf Ebrahimi if (chained_devaddr_struct) {
3950*b7893ccfSSadaf Ebrahimi if (!(pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
3951*b7893ccfSSadaf Ebrahimi chained_devaddr_struct->deviceAddress != 0) {
3952*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3953*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-deviceAddress-02604",
3954*b7893ccfSSadaf Ebrahimi "vkCreateBuffer(): Non-zero VkBufferDeviceAddressCreateInfoEXT::deviceAddress "
3955*b7893ccfSSadaf Ebrahimi "requires VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT.");
3956*b7893ccfSSadaf Ebrahimi }
3957*b7893ccfSSadaf Ebrahimi }
3958*b7893ccfSSadaf Ebrahimi
3959*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->flags & VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT) &&
3960*b7893ccfSSadaf Ebrahimi !enabled_features.buffer_address.bufferDeviceAddressCaptureReplay) {
3961*b7893ccfSSadaf Ebrahimi skip |= log_msg(
3962*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3963*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-flags-02605",
3964*b7893ccfSSadaf Ebrahimi "vkCreateBuffer(): the bufferDeviceAddressCaptureReplay device feature is disabled: Buffers cannot be created with "
3965*b7893ccfSSadaf Ebrahimi "the VK_BUFFER_CREATE_DEVICE_ADDRESS_CAPTURE_REPLAY_BIT_EXT set.");
3966*b7893ccfSSadaf Ebrahimi }
3967*b7893ccfSSadaf Ebrahimi
3968*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->usage & VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT) &&
3969*b7893ccfSSadaf Ebrahimi !enabled_features.buffer_address.bufferDeviceAddress) {
3970*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT, 0,
3971*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-usage-02606",
3972*b7893ccfSSadaf Ebrahimi "vkCreateBuffer(): the bufferDeviceAddress device feature is disabled: Buffers cannot be created with "
3973*b7893ccfSSadaf Ebrahimi "the VK_BUFFER_USAGE_SHADER_DEVICE_ADDRESS_BIT_EXT set.");
3974*b7893ccfSSadaf Ebrahimi }
3975*b7893ccfSSadaf Ebrahimi
3976*b7893ccfSSadaf Ebrahimi if (pCreateInfo->sharingMode == VK_SHARING_MODE_CONCURRENT && pCreateInfo->pQueueFamilyIndices) {
3977*b7893ccfSSadaf Ebrahimi skip |= ValidateQueueFamilies(pCreateInfo->queueFamilyIndexCount, pCreateInfo->pQueueFamilyIndices, "vkCreateBuffer",
3978*b7893ccfSSadaf Ebrahimi "pCreateInfo->pQueueFamilyIndices", "VUID-VkBufferCreateInfo-sharingMode-01419",
3979*b7893ccfSSadaf Ebrahimi "VUID-VkBufferCreateInfo-sharingMode-01419", false);
3980*b7893ccfSSadaf Ebrahimi }
3981*b7893ccfSSadaf Ebrahimi
3982*b7893ccfSSadaf Ebrahimi return skip;
3983*b7893ccfSSadaf Ebrahimi }
3984*b7893ccfSSadaf Ebrahimi
PostCallRecordCreateBuffer(VkDevice device,const VkBufferCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBuffer * pBuffer,VkResult result)3985*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PostCallRecordCreateBuffer(VkDevice device, const VkBufferCreateInfo *pCreateInfo,
3986*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkBuffer *pBuffer,
3987*b7893ccfSSadaf Ebrahimi VkResult result) {
3988*b7893ccfSSadaf Ebrahimi if (result != VK_SUCCESS) return;
3989*b7893ccfSSadaf Ebrahimi // TODO : This doesn't create deep copy of pQueueFamilyIndices so need to fix that if/when we want that data to be valid
3990*b7893ccfSSadaf Ebrahimi std::unique_ptr<BUFFER_STATE> buffer_state(new BUFFER_STATE(*pBuffer, pCreateInfo));
3991*b7893ccfSSadaf Ebrahimi
3992*b7893ccfSSadaf Ebrahimi // Get a set of requirements in the case the app does not
3993*b7893ccfSSadaf Ebrahimi DispatchGetBufferMemoryRequirements(device, *pBuffer, &buffer_state->requirements);
3994*b7893ccfSSadaf Ebrahimi
3995*b7893ccfSSadaf Ebrahimi bufferMap.insert(std::make_pair(*pBuffer, std::move(buffer_state)));
3996*b7893ccfSSadaf Ebrahimi }
3997*b7893ccfSSadaf Ebrahimi
PreCallValidateCreateBufferView(VkDevice device,const VkBufferViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBufferView * pView)3998*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
3999*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkBufferView *pView) {
4000*b7893ccfSSadaf Ebrahimi bool skip = false;
4001*b7893ccfSSadaf Ebrahimi BUFFER_STATE *buffer_state = GetBufferState(pCreateInfo->buffer);
4002*b7893ccfSSadaf Ebrahimi // If this isn't a sparse buffer, it needs to have memory backing it at CreateBufferView time
4003*b7893ccfSSadaf Ebrahimi if (buffer_state) {
4004*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToBuffer(buffer_state, "vkCreateBufferView()", "VUID-VkBufferViewCreateInfo-buffer-00935");
4005*b7893ccfSSadaf Ebrahimi // In order to create a valid buffer view, the buffer must have been created with at least one of the following flags:
4006*b7893ccfSSadaf Ebrahimi // UNIFORM_TEXEL_BUFFER_BIT or STORAGE_TEXEL_BUFFER_BIT
4007*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferUsageFlags(buffer_state,
4008*b7893ccfSSadaf Ebrahimi VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT | VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, false,
4009*b7893ccfSSadaf Ebrahimi "VUID-VkBufferViewCreateInfo-buffer-00932", "vkCreateBufferView()",
4010*b7893ccfSSadaf Ebrahimi "VK_BUFFER_USAGE_[STORAGE|UNIFORM]_TEXEL_BUFFER_BIT");
4011*b7893ccfSSadaf Ebrahimi
4012*b7893ccfSSadaf Ebrahimi // Buffer view offset must be less than the size of buffer
4013*b7893ccfSSadaf Ebrahimi if (pCreateInfo->offset >= buffer_state->createInfo.size) {
4014*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4015*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-00925",
4016*b7893ccfSSadaf Ebrahimi "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4017*b7893ccfSSadaf Ebrahimi ") must be less than the size of the buffer (%" PRIuLEAST64 ").",
4018*b7893ccfSSadaf Ebrahimi pCreateInfo->offset, buffer_state->createInfo.size);
4019*b7893ccfSSadaf Ebrahimi }
4020*b7893ccfSSadaf Ebrahimi
4021*b7893ccfSSadaf Ebrahimi const VkPhysicalDeviceLimits *device_limits = &phys_dev_props.limits;
4022*b7893ccfSSadaf Ebrahimi // Buffer view offset must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment
4023*b7893ccfSSadaf Ebrahimi if ((pCreateInfo->offset % device_limits->minTexelBufferOffsetAlignment) != 0 &&
4024*b7893ccfSSadaf Ebrahimi !enabled_features.texel_buffer_alignment_features.texelBufferAlignment) {
4025*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4026*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-offset-02749",
4027*b7893ccfSSadaf Ebrahimi "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4028*b7893ccfSSadaf Ebrahimi ") must be a multiple of VkPhysicalDeviceLimits::minTexelBufferOffsetAlignment (%" PRIuLEAST64 ").",
4029*b7893ccfSSadaf Ebrahimi pCreateInfo->offset, device_limits->minTexelBufferOffsetAlignment);
4030*b7893ccfSSadaf Ebrahimi }
4031*b7893ccfSSadaf Ebrahimi
4032*b7893ccfSSadaf Ebrahimi if (enabled_features.texel_buffer_alignment_features.texelBufferAlignment) {
4033*b7893ccfSSadaf Ebrahimi VkDeviceSize elementSize = FormatElementSize(pCreateInfo->format);
4034*b7893ccfSSadaf Ebrahimi if ((elementSize % 3) == 0) {
4035*b7893ccfSSadaf Ebrahimi elementSize /= 3;
4036*b7893ccfSSadaf Ebrahimi }
4037*b7893ccfSSadaf Ebrahimi if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT) {
4038*b7893ccfSSadaf Ebrahimi VkDeviceSize alignmentRequirement =
4039*b7893ccfSSadaf Ebrahimi phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes;
4040*b7893ccfSSadaf Ebrahimi if (phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment) {
4041*b7893ccfSSadaf Ebrahimi alignmentRequirement = std::min(alignmentRequirement, elementSize);
4042*b7893ccfSSadaf Ebrahimi }
4043*b7893ccfSSadaf Ebrahimi if (SafeModulo(pCreateInfo->offset, alignmentRequirement) != 0) {
4044*b7893ccfSSadaf Ebrahimi skip |= log_msg(
4045*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4046*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-02750",
4047*b7893ccfSSadaf Ebrahimi "If buffer was created with usage containing VK_BUFFER_USAGE_STORAGE_TEXEL_BUFFER_BIT, "
4048*b7893ccfSSadaf Ebrahimi "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4049*b7893ccfSSadaf Ebrahimi ") must be a multiple of the lesser of "
4050*b7893ccfSSadaf Ebrahimi "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64
4051*b7893ccfSSadaf Ebrahimi ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::storageTexelBufferOffsetSingleTexelAlignment "
4052*b7893ccfSSadaf Ebrahimi "(%" PRId32
4053*b7893ccfSSadaf Ebrahimi ") is VK_TRUE, the size of a texel of the requested format. "
4054*b7893ccfSSadaf Ebrahimi "If the size of a texel is a multiple of three bytes, then the size of a "
4055*b7893ccfSSadaf Ebrahimi "single component of format is used instead",
4056*b7893ccfSSadaf Ebrahimi pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetAlignmentBytes,
4057*b7893ccfSSadaf Ebrahimi phys_dev_ext_props.texel_buffer_alignment_props.storageTexelBufferOffsetSingleTexelAlignment);
4058*b7893ccfSSadaf Ebrahimi }
4059*b7893ccfSSadaf Ebrahimi }
4060*b7893ccfSSadaf Ebrahimi if (buffer_state->createInfo.usage & VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT) {
4061*b7893ccfSSadaf Ebrahimi VkDeviceSize alignmentRequirement =
4062*b7893ccfSSadaf Ebrahimi phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes;
4063*b7893ccfSSadaf Ebrahimi if (phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment) {
4064*b7893ccfSSadaf Ebrahimi alignmentRequirement = std::min(alignmentRequirement, elementSize);
4065*b7893ccfSSadaf Ebrahimi }
4066*b7893ccfSSadaf Ebrahimi if (SafeModulo(pCreateInfo->offset, alignmentRequirement) != 0) {
4067*b7893ccfSSadaf Ebrahimi skip |= log_msg(
4068*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4069*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer_state->buffer), "VUID-VkBufferViewCreateInfo-buffer-02751",
4070*b7893ccfSSadaf Ebrahimi "If buffer was created with usage containing VK_BUFFER_USAGE_UNIFORM_TEXEL_BUFFER_BIT, "
4071*b7893ccfSSadaf Ebrahimi "VkBufferViewCreateInfo offset (%" PRIuLEAST64
4072*b7893ccfSSadaf Ebrahimi ") must be a multiple of the lesser of "
4073*b7893ccfSSadaf Ebrahimi "VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetAlignmentBytes (%" PRIuLEAST64
4074*b7893ccfSSadaf Ebrahimi ") or, if VkPhysicalDeviceTexelBufferAlignmentPropertiesEXT::uniformTexelBufferOffsetSingleTexelAlignment "
4075*b7893ccfSSadaf Ebrahimi "(%" PRId32
4076*b7893ccfSSadaf Ebrahimi ") is VK_TRUE, the size of a texel of the requested format. "
4077*b7893ccfSSadaf Ebrahimi "If the size of a texel is a multiple of three bytes, then the size of a "
4078*b7893ccfSSadaf Ebrahimi "single component of format is used instead",
4079*b7893ccfSSadaf Ebrahimi pCreateInfo->offset, phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetAlignmentBytes,
4080*b7893ccfSSadaf Ebrahimi phys_dev_ext_props.texel_buffer_alignment_props.uniformTexelBufferOffsetSingleTexelAlignment);
4081*b7893ccfSSadaf Ebrahimi }
4082*b7893ccfSSadaf Ebrahimi }
4083*b7893ccfSSadaf Ebrahimi }
4084*b7893ccfSSadaf Ebrahimi
4085*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferViewRange(buffer_state, pCreateInfo, device_limits);
4086*b7893ccfSSadaf Ebrahimi
4087*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferViewBuffer(buffer_state, pCreateInfo);
4088*b7893ccfSSadaf Ebrahimi }
4089*b7893ccfSSadaf Ebrahimi return skip;
4090*b7893ccfSSadaf Ebrahimi }
4091*b7893ccfSSadaf Ebrahimi
PostCallRecordCreateBufferView(VkDevice device,const VkBufferViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkBufferView * pView,VkResult result)4092*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PostCallRecordCreateBufferView(VkDevice device, const VkBufferViewCreateInfo *pCreateInfo,
4093*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkBufferView *pView,
4094*b7893ccfSSadaf Ebrahimi VkResult result) {
4095*b7893ccfSSadaf Ebrahimi if (result != VK_SUCCESS) return;
4096*b7893ccfSSadaf Ebrahimi bufferViewMap[*pView] = std::unique_ptr<BUFFER_VIEW_STATE>(new BUFFER_VIEW_STATE(*pView, pCreateInfo));
4097*b7893ccfSSadaf Ebrahimi }
4098*b7893ccfSSadaf Ebrahimi
4099*b7893ccfSSadaf Ebrahimi // For the given format verify that the aspect masks make sense
ValidateImageAspectMask(VkImage image,VkFormat format,VkImageAspectFlags aspect_mask,const char * func_name,const char * vuid) const4100*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageAspectMask(VkImage image, VkFormat format, VkImageAspectFlags aspect_mask, const char *func_name,
4101*b7893ccfSSadaf Ebrahimi const char *vuid) const {
4102*b7893ccfSSadaf Ebrahimi bool skip = false;
4103*b7893ccfSSadaf Ebrahimi VkDebugReportObjectTypeEXT objectType = VK_DEBUG_REPORT_OBJECT_TYPE_UNKNOWN_EXT;
4104*b7893ccfSSadaf Ebrahimi if (image != VK_NULL_HANDLE) {
4105*b7893ccfSSadaf Ebrahimi objectType = VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT;
4106*b7893ccfSSadaf Ebrahimi }
4107*b7893ccfSSadaf Ebrahimi
4108*b7893ccfSSadaf Ebrahimi if (FormatIsColor(format)) {
4109*b7893ccfSSadaf Ebrahimi if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != VK_IMAGE_ASPECT_COLOR_BIT) {
4110*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4111*b7893ccfSSadaf Ebrahimi "%s: Color image formats must have the VK_IMAGE_ASPECT_COLOR_BIT set.", func_name);
4112*b7893ccfSSadaf Ebrahimi } else if ((aspect_mask & VK_IMAGE_ASPECT_COLOR_BIT) != aspect_mask) {
4113*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4114*b7893ccfSSadaf Ebrahimi "%s: Color image formats must have ONLY the VK_IMAGE_ASPECT_COLOR_BIT set.", func_name);
4115*b7893ccfSSadaf Ebrahimi }
4116*b7893ccfSSadaf Ebrahimi } else if (FormatIsDepthAndStencil(format)) {
4117*b7893ccfSSadaf Ebrahimi if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) == 0) {
4118*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4119*b7893ccfSSadaf Ebrahimi "%s: Depth/stencil image formats must have at least one of VK_IMAGE_ASPECT_DEPTH_BIT and "
4120*b7893ccfSSadaf Ebrahimi "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4121*b7893ccfSSadaf Ebrahimi func_name);
4122*b7893ccfSSadaf Ebrahimi } else if ((aspect_mask & (VK_IMAGE_ASPECT_DEPTH_BIT | VK_IMAGE_ASPECT_STENCIL_BIT)) != aspect_mask) {
4123*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4124*b7893ccfSSadaf Ebrahimi "%s: Combination depth/stencil image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT and "
4125*b7893ccfSSadaf Ebrahimi "VK_IMAGE_ASPECT_STENCIL_BIT set.",
4126*b7893ccfSSadaf Ebrahimi func_name);
4127*b7893ccfSSadaf Ebrahimi }
4128*b7893ccfSSadaf Ebrahimi } else if (FormatIsDepthOnly(format)) {
4129*b7893ccfSSadaf Ebrahimi if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != VK_IMAGE_ASPECT_DEPTH_BIT) {
4130*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4131*b7893ccfSSadaf Ebrahimi "%s: Depth-only image formats must have the VK_IMAGE_ASPECT_DEPTH_BIT set.", func_name);
4132*b7893ccfSSadaf Ebrahimi } else if ((aspect_mask & VK_IMAGE_ASPECT_DEPTH_BIT) != aspect_mask) {
4133*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4134*b7893ccfSSadaf Ebrahimi "%s: Depth-only image formats can have only the VK_IMAGE_ASPECT_DEPTH_BIT set.", func_name);
4135*b7893ccfSSadaf Ebrahimi }
4136*b7893ccfSSadaf Ebrahimi } else if (FormatIsStencilOnly(format)) {
4137*b7893ccfSSadaf Ebrahimi if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != VK_IMAGE_ASPECT_STENCIL_BIT) {
4138*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4139*b7893ccfSSadaf Ebrahimi "%s: Stencil-only image formats must have the VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name);
4140*b7893ccfSSadaf Ebrahimi } else if ((aspect_mask & VK_IMAGE_ASPECT_STENCIL_BIT) != aspect_mask) {
4141*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4142*b7893ccfSSadaf Ebrahimi "%s: Stencil-only image formats can have only the VK_IMAGE_ASPECT_STENCIL_BIT set.", func_name);
4143*b7893ccfSSadaf Ebrahimi }
4144*b7893ccfSSadaf Ebrahimi } else if (FormatIsMultiplane(format)) {
4145*b7893ccfSSadaf Ebrahimi VkImageAspectFlags valid_flags = VK_IMAGE_ASPECT_COLOR_BIT | VK_IMAGE_ASPECT_PLANE_0_BIT | VK_IMAGE_ASPECT_PLANE_1_BIT;
4146*b7893ccfSSadaf Ebrahimi if (3 == FormatPlaneCount(format)) {
4147*b7893ccfSSadaf Ebrahimi valid_flags = valid_flags | VK_IMAGE_ASPECT_PLANE_2_BIT;
4148*b7893ccfSSadaf Ebrahimi }
4149*b7893ccfSSadaf Ebrahimi if ((aspect_mask & valid_flags) != aspect_mask) {
4150*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, objectType, HandleToUint64(image), vuid,
4151*b7893ccfSSadaf Ebrahimi "%s: Multi-plane image formats may have only VK_IMAGE_ASPECT_COLOR_BIT or VK_IMAGE_ASPECT_PLANE_n_BITs "
4152*b7893ccfSSadaf Ebrahimi "set, where n = [0, 1, 2].",
4153*b7893ccfSSadaf Ebrahimi func_name);
4154*b7893ccfSSadaf Ebrahimi }
4155*b7893ccfSSadaf Ebrahimi }
4156*b7893ccfSSadaf Ebrahimi return skip;
4157*b7893ccfSSadaf Ebrahimi }
4158*b7893ccfSSadaf Ebrahimi
ValidateImageSubresourceRange(const uint32_t image_mip_count,const uint32_t image_layer_count,const VkImageSubresourceRange & subresourceRange,const char * cmd_name,const char * param_name,const char * image_layer_count_var_name,const uint64_t image_handle,SubresourceRangeErrorCodes errorCodes) const4159*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageSubresourceRange(const uint32_t image_mip_count, const uint32_t image_layer_count,
4160*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
4161*b7893ccfSSadaf Ebrahimi const char *param_name, const char *image_layer_count_var_name,
4162*b7893ccfSSadaf Ebrahimi const uint64_t image_handle, SubresourceRangeErrorCodes errorCodes) const {
4163*b7893ccfSSadaf Ebrahimi bool skip = false;
4164*b7893ccfSSadaf Ebrahimi
4165*b7893ccfSSadaf Ebrahimi // Validate mip levels
4166*b7893ccfSSadaf Ebrahimi if (subresourceRange.baseMipLevel >= image_mip_count) {
4167*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
4168*b7893ccfSSadaf Ebrahimi errorCodes.base_mip_err,
4169*b7893ccfSSadaf Ebrahimi "%s: %s.baseMipLevel (= %" PRIu32
4170*b7893ccfSSadaf Ebrahimi ") is greater or equal to the mip level count of the image (i.e. greater or equal to %" PRIu32 ").",
4171*b7893ccfSSadaf Ebrahimi cmd_name, param_name, subresourceRange.baseMipLevel, image_mip_count);
4172*b7893ccfSSadaf Ebrahimi }
4173*b7893ccfSSadaf Ebrahimi
4174*b7893ccfSSadaf Ebrahimi if (subresourceRange.levelCount != VK_REMAINING_MIP_LEVELS) {
4175*b7893ccfSSadaf Ebrahimi if (subresourceRange.levelCount == 0) {
4176*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
4177*b7893ccfSSadaf Ebrahimi errorCodes.mip_count_err, "%s: %s.levelCount is 0.", cmd_name, param_name);
4178*b7893ccfSSadaf Ebrahimi } else {
4179*b7893ccfSSadaf Ebrahimi const uint64_t necessary_mip_count = uint64_t{subresourceRange.baseMipLevel} + uint64_t{subresourceRange.levelCount};
4180*b7893ccfSSadaf Ebrahimi
4181*b7893ccfSSadaf Ebrahimi if (necessary_mip_count > image_mip_count) {
4182*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
4183*b7893ccfSSadaf Ebrahimi errorCodes.mip_count_err,
4184*b7893ccfSSadaf Ebrahimi "%s: %s.baseMipLevel + .levelCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
4185*b7893ccfSSadaf Ebrahimi ") is greater than the mip level count of the image (i.e. greater than %" PRIu32 ").",
4186*b7893ccfSSadaf Ebrahimi cmd_name, param_name, subresourceRange.baseMipLevel, subresourceRange.levelCount,
4187*b7893ccfSSadaf Ebrahimi necessary_mip_count, image_mip_count);
4188*b7893ccfSSadaf Ebrahimi }
4189*b7893ccfSSadaf Ebrahimi }
4190*b7893ccfSSadaf Ebrahimi }
4191*b7893ccfSSadaf Ebrahimi
4192*b7893ccfSSadaf Ebrahimi // Validate array layers
4193*b7893ccfSSadaf Ebrahimi if (subresourceRange.baseArrayLayer >= image_layer_count) {
4194*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
4195*b7893ccfSSadaf Ebrahimi errorCodes.base_layer_err,
4196*b7893ccfSSadaf Ebrahimi "%s: %s.baseArrayLayer (= %" PRIu32
4197*b7893ccfSSadaf Ebrahimi ") is greater or equal to the %s of the image when it was created (i.e. greater or equal to %" PRIu32 ").",
4198*b7893ccfSSadaf Ebrahimi cmd_name, param_name, subresourceRange.baseArrayLayer, image_layer_count_var_name, image_layer_count);
4199*b7893ccfSSadaf Ebrahimi }
4200*b7893ccfSSadaf Ebrahimi
4201*b7893ccfSSadaf Ebrahimi if (subresourceRange.layerCount != VK_REMAINING_ARRAY_LAYERS) {
4202*b7893ccfSSadaf Ebrahimi if (subresourceRange.layerCount == 0) {
4203*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
4204*b7893ccfSSadaf Ebrahimi errorCodes.layer_count_err, "%s: %s.layerCount is 0.", cmd_name, param_name);
4205*b7893ccfSSadaf Ebrahimi } else {
4206*b7893ccfSSadaf Ebrahimi const uint64_t necessary_layer_count =
4207*b7893ccfSSadaf Ebrahimi uint64_t{subresourceRange.baseArrayLayer} + uint64_t{subresourceRange.layerCount};
4208*b7893ccfSSadaf Ebrahimi
4209*b7893ccfSSadaf Ebrahimi if (necessary_layer_count > image_layer_count) {
4210*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, image_handle,
4211*b7893ccfSSadaf Ebrahimi errorCodes.layer_count_err,
4212*b7893ccfSSadaf Ebrahimi "%s: %s.baseArrayLayer + .layerCount (= %" PRIu32 " + %" PRIu32 " = %" PRIu64
4213*b7893ccfSSadaf Ebrahimi ") is greater than the %s of the image when it was created (i.e. greater than %" PRIu32 ").",
4214*b7893ccfSSadaf Ebrahimi cmd_name, param_name, subresourceRange.baseArrayLayer, subresourceRange.layerCount,
4215*b7893ccfSSadaf Ebrahimi necessary_layer_count, image_layer_count_var_name, image_layer_count);
4216*b7893ccfSSadaf Ebrahimi }
4217*b7893ccfSSadaf Ebrahimi }
4218*b7893ccfSSadaf Ebrahimi }
4219*b7893ccfSSadaf Ebrahimi
4220*b7893ccfSSadaf Ebrahimi return skip;
4221*b7893ccfSSadaf Ebrahimi }
4222*b7893ccfSSadaf Ebrahimi
ValidateCreateImageViewSubresourceRange(const IMAGE_STATE * image_state,bool is_imageview_2d_type,const VkImageSubresourceRange & subresourceRange)4223*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCreateImageViewSubresourceRange(const IMAGE_STATE *image_state, bool is_imageview_2d_type,
4224*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &subresourceRange) {
4225*b7893ccfSSadaf Ebrahimi bool is_khr_maintenance1 = device_extensions.vk_khr_maintenance1;
4226*b7893ccfSSadaf Ebrahimi bool is_image_slicable = image_state->createInfo.imageType == VK_IMAGE_TYPE_3D &&
4227*b7893ccfSSadaf Ebrahimi (image_state->createInfo.flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR);
4228*b7893ccfSSadaf Ebrahimi bool is_3D_to_2D_map = is_khr_maintenance1 && is_image_slicable && is_imageview_2d_type;
4229*b7893ccfSSadaf Ebrahimi
4230*b7893ccfSSadaf Ebrahimi const auto image_layer_count = is_3D_to_2D_map ? image_state->createInfo.extent.depth : image_state->createInfo.arrayLayers;
4231*b7893ccfSSadaf Ebrahimi const auto image_layer_count_var_name = is_3D_to_2D_map ? "extent.depth" : "arrayLayers";
4232*b7893ccfSSadaf Ebrahimi
4233*b7893ccfSSadaf Ebrahimi SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
4234*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_mip_err = "VUID-VkImageViewCreateInfo-subresourceRange-01478";
4235*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.mip_count_err = "VUID-VkImageViewCreateInfo-subresourceRange-01718";
4236*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_layer_err = is_khr_maintenance1 ? (is_3D_to_2D_map ? "VUID-VkImageViewCreateInfo-image-02724"
4237*b7893ccfSSadaf Ebrahimi : "VUID-VkImageViewCreateInfo-image-01482")
4238*b7893ccfSSadaf Ebrahimi : "VUID-VkImageViewCreateInfo-subresourceRange-01480";
4239*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.layer_count_err = is_khr_maintenance1
4240*b7893ccfSSadaf Ebrahimi ? (is_3D_to_2D_map ? "VUID-VkImageViewCreateInfo-subresourceRange-02725"
4241*b7893ccfSSadaf Ebrahimi : "VUID-VkImageViewCreateInfo-subresourceRange-01483")
4242*b7893ccfSSadaf Ebrahimi : "VUID-VkImageViewCreateInfo-subresourceRange-01719";
4243*b7893ccfSSadaf Ebrahimi
4244*b7893ccfSSadaf Ebrahimi return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_layer_count, subresourceRange,
4245*b7893ccfSSadaf Ebrahimi "vkCreateImageView", "pCreateInfo->subresourceRange", image_layer_count_var_name,
4246*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), subresourceRangeErrorCodes);
4247*b7893ccfSSadaf Ebrahimi }
4248*b7893ccfSSadaf Ebrahimi
ValidateCmdClearColorSubresourceRange(const IMAGE_STATE * image_state,const VkImageSubresourceRange & subresourceRange,const char * param_name) const4249*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCmdClearColorSubresourceRange(const IMAGE_STATE *image_state,
4250*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &subresourceRange,
4251*b7893ccfSSadaf Ebrahimi const char *param_name) const {
4252*b7893ccfSSadaf Ebrahimi SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
4253*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_mip_err = "VUID-vkCmdClearColorImage-baseMipLevel-01470";
4254*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.mip_count_err = "VUID-vkCmdClearColorImage-pRanges-01692";
4255*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_layer_err = "VUID-vkCmdClearColorImage-baseArrayLayer-01472";
4256*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.layer_count_err = "VUID-vkCmdClearColorImage-pRanges-01693";
4257*b7893ccfSSadaf Ebrahimi
4258*b7893ccfSSadaf Ebrahimi return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
4259*b7893ccfSSadaf Ebrahimi "vkCmdClearColorImage", param_name, "arrayLayers", HandleToUint64(image_state->image),
4260*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes);
4261*b7893ccfSSadaf Ebrahimi }
4262*b7893ccfSSadaf Ebrahimi
ValidateCmdClearDepthSubresourceRange(const IMAGE_STATE * image_state,const VkImageSubresourceRange & subresourceRange,const char * param_name) const4263*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateCmdClearDepthSubresourceRange(const IMAGE_STATE *image_state,
4264*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &subresourceRange,
4265*b7893ccfSSadaf Ebrahimi const char *param_name) const {
4266*b7893ccfSSadaf Ebrahimi SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
4267*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_mip_err = "VUID-vkCmdClearDepthStencilImage-baseMipLevel-01474";
4268*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.mip_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01694";
4269*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_layer_err = "VUID-vkCmdClearDepthStencilImage-baseArrayLayer-01476";
4270*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.layer_count_err = "VUID-vkCmdClearDepthStencilImage-pRanges-01695";
4271*b7893ccfSSadaf Ebrahimi
4272*b7893ccfSSadaf Ebrahimi return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
4273*b7893ccfSSadaf Ebrahimi "vkCmdClearDepthStencilImage", param_name, "arrayLayers",
4274*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), subresourceRangeErrorCodes);
4275*b7893ccfSSadaf Ebrahimi }
4276*b7893ccfSSadaf Ebrahimi
ValidateImageBarrierSubresourceRange(const IMAGE_STATE * image_state,const VkImageSubresourceRange & subresourceRange,const char * cmd_name,const char * param_name)4277*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateImageBarrierSubresourceRange(const IMAGE_STATE *image_state,
4278*b7893ccfSSadaf Ebrahimi const VkImageSubresourceRange &subresourceRange, const char *cmd_name,
4279*b7893ccfSSadaf Ebrahimi const char *param_name) {
4280*b7893ccfSSadaf Ebrahimi SubresourceRangeErrorCodes subresourceRangeErrorCodes = {};
4281*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_mip_err = "VUID-VkImageMemoryBarrier-subresourceRange-01486";
4282*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.mip_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01724";
4283*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.base_layer_err = "VUID-VkImageMemoryBarrier-subresourceRange-01488";
4284*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes.layer_count_err = "VUID-VkImageMemoryBarrier-subresourceRange-01725";
4285*b7893ccfSSadaf Ebrahimi
4286*b7893ccfSSadaf Ebrahimi return ValidateImageSubresourceRange(image_state->createInfo.mipLevels, image_state->createInfo.arrayLayers, subresourceRange,
4287*b7893ccfSSadaf Ebrahimi cmd_name, param_name, "arrayLayers", HandleToUint64(image_state->image),
4288*b7893ccfSSadaf Ebrahimi subresourceRangeErrorCodes);
4289*b7893ccfSSadaf Ebrahimi }
4290*b7893ccfSSadaf Ebrahimi
PreCallValidateCreateImageView(VkDevice device,const VkImageViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImageView * pView)4291*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
4292*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkImageView *pView) {
4293*b7893ccfSSadaf Ebrahimi bool skip = false;
4294*b7893ccfSSadaf Ebrahimi IMAGE_STATE *image_state = GetImageState(pCreateInfo->image);
4295*b7893ccfSSadaf Ebrahimi if (image_state) {
4296*b7893ccfSSadaf Ebrahimi skip |=
4297*b7893ccfSSadaf Ebrahimi ValidateImageUsageFlags(image_state,
4298*b7893ccfSSadaf Ebrahimi VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_STORAGE_BIT | VK_IMAGE_USAGE_INPUT_ATTACHMENT_BIT |
4299*b7893ccfSSadaf Ebrahimi VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT | VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT |
4300*b7893ccfSSadaf Ebrahimi VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV | VK_IMAGE_USAGE_FRAGMENT_DENSITY_MAP_BIT_EXT,
4301*b7893ccfSSadaf Ebrahimi false, kVUIDUndefined, "vkCreateImageView()",
4302*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_[SAMPLED|STORAGE|COLOR_ATTACHMENT|DEPTH_STENCIL_ATTACHMENT|INPUT_ATTACHMENT|"
4303*b7893ccfSSadaf Ebrahimi "SHADING_RATE_IMAGE|FRAGMENT_DENSITY_MAP]_BIT");
4304*b7893ccfSSadaf Ebrahimi // If this isn't a sparse image, it needs to have memory backing it at CreateImageView time
4305*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(image_state, "vkCreateImageView()", "VUID-VkImageViewCreateInfo-image-01020");
4306*b7893ccfSSadaf Ebrahimi // Checks imported from image layer
4307*b7893ccfSSadaf Ebrahimi skip |= ValidateCreateImageViewSubresourceRange(
4308*b7893ccfSSadaf Ebrahimi image_state, pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D || pCreateInfo->viewType == VK_IMAGE_VIEW_TYPE_2D_ARRAY,
4309*b7893ccfSSadaf Ebrahimi pCreateInfo->subresourceRange);
4310*b7893ccfSSadaf Ebrahimi
4311*b7893ccfSSadaf Ebrahimi VkImageCreateFlags image_flags = image_state->createInfo.flags;
4312*b7893ccfSSadaf Ebrahimi VkFormat image_format = image_state->createInfo.format;
4313*b7893ccfSSadaf Ebrahimi VkImageUsageFlags image_usage = image_state->createInfo.usage;
4314*b7893ccfSSadaf Ebrahimi VkImageTiling image_tiling = image_state->createInfo.tiling;
4315*b7893ccfSSadaf Ebrahimi VkFormat view_format = pCreateInfo->format;
4316*b7893ccfSSadaf Ebrahimi VkImageAspectFlags aspect_mask = pCreateInfo->subresourceRange.aspectMask;
4317*b7893ccfSSadaf Ebrahimi VkImageType image_type = image_state->createInfo.imageType;
4318*b7893ccfSSadaf Ebrahimi VkImageViewType view_type = pCreateInfo->viewType;
4319*b7893ccfSSadaf Ebrahimi
4320*b7893ccfSSadaf Ebrahimi // If there's a chained VkImageViewUsageCreateInfo struct, modify image_usage to match
4321*b7893ccfSSadaf Ebrahimi auto chained_ivuci_struct = lvl_find_in_chain<VkImageViewUsageCreateInfoKHR>(pCreateInfo->pNext);
4322*b7893ccfSSadaf Ebrahimi if (chained_ivuci_struct) {
4323*b7893ccfSSadaf Ebrahimi image_usage = chained_ivuci_struct->usage;
4324*b7893ccfSSadaf Ebrahimi }
4325*b7893ccfSSadaf Ebrahimi
4326*b7893ccfSSadaf Ebrahimi // Validate VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT state, if view/image formats differ
4327*b7893ccfSSadaf Ebrahimi if ((image_flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) && (image_format != view_format)) {
4328*b7893ccfSSadaf Ebrahimi if (FormatIsMultiplane(image_format)) {
4329*b7893ccfSSadaf Ebrahimi VkFormat compat_format = FindMultiplaneCompatibleFormat(image_format, aspect_mask);
4330*b7893ccfSSadaf Ebrahimi if (view_format != compat_format) {
4331*b7893ccfSSadaf Ebrahimi // View format must match the multiplane compatible format
4332*b7893ccfSSadaf Ebrahimi std::stringstream ss;
4333*b7893ccfSSadaf Ebrahimi ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
4334*b7893ccfSSadaf Ebrahimi << " is not compatible with plane " << GetPlaneIndex(aspect_mask) << " of underlying image format "
4335*b7893ccfSSadaf Ebrahimi << string_VkFormat(image_format) << ", must be " << string_VkFormat(compat_format) << ".";
4336*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4337*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01586", "%s",
4338*b7893ccfSSadaf Ebrahimi ss.str().c_str());
4339*b7893ccfSSadaf Ebrahimi }
4340*b7893ccfSSadaf Ebrahimi } else {
4341*b7893ccfSSadaf Ebrahimi if ((!device_extensions.vk_khr_maintenance2 ||
4342*b7893ccfSSadaf Ebrahimi !(image_flags & VK_IMAGE_CREATE_BLOCK_TEXEL_VIEW_COMPATIBLE_BIT_KHR))) {
4343*b7893ccfSSadaf Ebrahimi // Format MUST be compatible (in the same format compatibility class) as the format the image was created with
4344*b7893ccfSSadaf Ebrahimi if (FormatCompatibilityClass(image_format) != FormatCompatibilityClass(view_format)) {
4345*b7893ccfSSadaf Ebrahimi std::stringstream ss;
4346*b7893ccfSSadaf Ebrahimi ss << "vkCreateImageView(): ImageView format " << string_VkFormat(view_format)
4347*b7893ccfSSadaf Ebrahimi << " is not in the same format compatibility class as "
4348*b7893ccfSSadaf Ebrahimi << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
4349*b7893ccfSSadaf Ebrahimi << ". Images created with the VK_IMAGE_CREATE_MUTABLE_FORMAT BIT "
4350*b7893ccfSSadaf Ebrahimi << "can support ImageViews with differing formats but they must be in the same compatibility class.";
4351*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4352*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01018", "%s",
4353*b7893ccfSSadaf Ebrahimi ss.str().c_str());
4354*b7893ccfSSadaf Ebrahimi }
4355*b7893ccfSSadaf Ebrahimi }
4356*b7893ccfSSadaf Ebrahimi }
4357*b7893ccfSSadaf Ebrahimi } else {
4358*b7893ccfSSadaf Ebrahimi // Format MUST be IDENTICAL to the format the image was created with
4359*b7893ccfSSadaf Ebrahimi if (image_format != view_format) {
4360*b7893ccfSSadaf Ebrahimi std::stringstream ss;
4361*b7893ccfSSadaf Ebrahimi ss << "vkCreateImageView() format " << string_VkFormat(view_format) << " differs from "
4362*b7893ccfSSadaf Ebrahimi << report_data->FormatHandle(pCreateInfo->image).c_str() << " format " << string_VkFormat(image_format)
4363*b7893ccfSSadaf Ebrahimi << ". Formats MUST be IDENTICAL unless VK_IMAGE_CREATE_MUTABLE_FORMAT BIT was set on image creation.";
4364*b7893ccfSSadaf Ebrahimi skip |=
4365*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4366*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01019", "%s", ss.str().c_str());
4367*b7893ccfSSadaf Ebrahimi }
4368*b7893ccfSSadaf Ebrahimi }
4369*b7893ccfSSadaf Ebrahimi
4370*b7893ccfSSadaf Ebrahimi // Validate correct image aspect bits for desired formats and format consistency
4371*b7893ccfSSadaf Ebrahimi skip |= ValidateImageAspectMask(image_state->image, image_format, aspect_mask, "vkCreateImageView()");
4372*b7893ccfSSadaf Ebrahimi
4373*b7893ccfSSadaf Ebrahimi switch (image_type) {
4374*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_1D:
4375*b7893ccfSSadaf Ebrahimi if (view_type != VK_IMAGE_VIEW_TYPE_1D && view_type != VK_IMAGE_VIEW_TYPE_1D_ARRAY) {
4376*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4377*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
4378*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
4379*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4380*b7893ccfSSadaf Ebrahimi }
4381*b7893ccfSSadaf Ebrahimi break;
4382*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_2D:
4383*b7893ccfSSadaf Ebrahimi if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
4384*b7893ccfSSadaf Ebrahimi if ((view_type == VK_IMAGE_VIEW_TYPE_CUBE || view_type == VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) &&
4385*b7893ccfSSadaf Ebrahimi !(image_flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT)) {
4386*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4387*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01003",
4388*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
4389*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4390*b7893ccfSSadaf Ebrahimi } else if (view_type != VK_IMAGE_VIEW_TYPE_CUBE && view_type != VK_IMAGE_VIEW_TYPE_CUBE_ARRAY) {
4391*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4392*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
4393*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
4394*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4395*b7893ccfSSadaf Ebrahimi }
4396*b7893ccfSSadaf Ebrahimi }
4397*b7893ccfSSadaf Ebrahimi break;
4398*b7893ccfSSadaf Ebrahimi case VK_IMAGE_TYPE_3D:
4399*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_khr_maintenance1) {
4400*b7893ccfSSadaf Ebrahimi if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
4401*b7893ccfSSadaf Ebrahimi if ((view_type == VK_IMAGE_VIEW_TYPE_2D || view_type == VK_IMAGE_VIEW_TYPE_2D_ARRAY)) {
4402*b7893ccfSSadaf Ebrahimi if (!(image_flags & VK_IMAGE_CREATE_2D_ARRAY_COMPATIBLE_BIT_KHR)) {
4403*b7893ccfSSadaf Ebrahimi skip |=
4404*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4405*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-01005",
4406*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
4407*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4408*b7893ccfSSadaf Ebrahimi } else if ((image_flags & (VK_IMAGE_CREATE_SPARSE_BINDING_BIT | VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT |
4409*b7893ccfSSadaf Ebrahimi VK_IMAGE_CREATE_SPARSE_ALIASED_BIT))) {
4410*b7893ccfSSadaf Ebrahimi skip |=
4411*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4412*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
4413*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s "
4414*b7893ccfSSadaf Ebrahimi "when the VK_IMAGE_CREATE_SPARSE_BINDING_BIT, VK_IMAGE_CREATE_SPARSE_RESIDENCY_BIT, or "
4415*b7893ccfSSadaf Ebrahimi "VK_IMAGE_CREATE_SPARSE_ALIASED_BIT flags are enabled.",
4416*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4417*b7893ccfSSadaf Ebrahimi }
4418*b7893ccfSSadaf Ebrahimi } else {
4419*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4420*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
4421*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
4422*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4423*b7893ccfSSadaf Ebrahimi }
4424*b7893ccfSSadaf Ebrahimi }
4425*b7893ccfSSadaf Ebrahimi } else {
4426*b7893ccfSSadaf Ebrahimi if (view_type != VK_IMAGE_VIEW_TYPE_3D) {
4427*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4428*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-subResourceRange-01021",
4429*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->viewType %s is not compatible with image type %s.",
4430*b7893ccfSSadaf Ebrahimi string_VkImageViewType(view_type), string_VkImageType(image_type));
4431*b7893ccfSSadaf Ebrahimi }
4432*b7893ccfSSadaf Ebrahimi }
4433*b7893ccfSSadaf Ebrahimi break;
4434*b7893ccfSSadaf Ebrahimi default:
4435*b7893ccfSSadaf Ebrahimi break;
4436*b7893ccfSSadaf Ebrahimi }
4437*b7893ccfSSadaf Ebrahimi
4438*b7893ccfSSadaf Ebrahimi // External format checks needed when VK_ANDROID_external_memory_android_hardware_buffer enabled
4439*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
4440*b7893ccfSSadaf Ebrahimi skip |= ValidateCreateImageViewANDROID(pCreateInfo);
4441*b7893ccfSSadaf Ebrahimi }
4442*b7893ccfSSadaf Ebrahimi
4443*b7893ccfSSadaf Ebrahimi VkFormatProperties format_properties = GetPDFormatProperties(view_format);
4444*b7893ccfSSadaf Ebrahimi VkFormatFeatureFlags tiling_features = (image_tiling & VK_IMAGE_TILING_LINEAR) ? format_properties.linearTilingFeatures
4445*b7893ccfSSadaf Ebrahimi : format_properties.optimalTilingFeatures;
4446*b7893ccfSSadaf Ebrahimi
4447*b7893ccfSSadaf Ebrahimi if (tiling_features == 0) {
4448*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4449*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-None-02273",
4450*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->format %s with tiling %s has no supported format features on this "
4451*b7893ccfSSadaf Ebrahimi "physical device.",
4452*b7893ccfSSadaf Ebrahimi string_VkFormat(view_format), string_VkImageTiling(image_tiling));
4453*b7893ccfSSadaf Ebrahimi } else if ((image_usage & VK_IMAGE_USAGE_SAMPLED_BIT) && !(tiling_features & VK_FORMAT_FEATURE_SAMPLED_IMAGE_BIT)) {
4454*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4455*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02274",
4456*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
4457*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_SAMPLED_BIT.",
4458*b7893ccfSSadaf Ebrahimi string_VkFormat(view_format), string_VkImageTiling(image_tiling));
4459*b7893ccfSSadaf Ebrahimi } else if ((image_usage & VK_IMAGE_USAGE_STORAGE_BIT) && !(tiling_features & VK_FORMAT_FEATURE_STORAGE_IMAGE_BIT)) {
4460*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4461*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02275",
4462*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
4463*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_STORAGE_BIT.",
4464*b7893ccfSSadaf Ebrahimi string_VkFormat(view_format), string_VkImageTiling(image_tiling));
4465*b7893ccfSSadaf Ebrahimi } else if ((image_usage & VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT) &&
4466*b7893ccfSSadaf Ebrahimi !(tiling_features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BIT)) {
4467*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4468*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02276",
4469*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
4470*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT.",
4471*b7893ccfSSadaf Ebrahimi string_VkFormat(view_format), string_VkImageTiling(image_tiling));
4472*b7893ccfSSadaf Ebrahimi } else if ((image_usage & VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT) &&
4473*b7893ccfSSadaf Ebrahimi !(tiling_features & VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT)) {
4474*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4475*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-usage-02277",
4476*b7893ccfSSadaf Ebrahimi "vkCreateImageView(): pCreateInfo->format %s with tiling %s does not support usage that includes "
4477*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT.",
4478*b7893ccfSSadaf Ebrahimi string_VkFormat(view_format), string_VkImageTiling(image_tiling));
4479*b7893ccfSSadaf Ebrahimi }
4480*b7893ccfSSadaf Ebrahimi
4481*b7893ccfSSadaf Ebrahimi if (image_usage & VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV) {
4482*b7893ccfSSadaf Ebrahimi if (view_type != VK_IMAGE_VIEW_TYPE_2D && view_type != VK_IMAGE_VIEW_TYPE_2D_ARRAY) {
4483*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4484*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-02086",
4485*b7893ccfSSadaf Ebrahimi "vkCreateImageView() If image was created with usage containing "
4486*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, viewType must be "
4487*b7893ccfSSadaf Ebrahimi "VK_IMAGE_VIEW_TYPE_2D or VK_IMAGE_VIEW_TYPE_2D_ARRAY.");
4488*b7893ccfSSadaf Ebrahimi }
4489*b7893ccfSSadaf Ebrahimi if (view_format != VK_FORMAT_R8_UINT) {
4490*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4491*b7893ccfSSadaf Ebrahimi HandleToUint64(pCreateInfo->image), "VUID-VkImageViewCreateInfo-image-02087",
4492*b7893ccfSSadaf Ebrahimi "vkCreateImageView() If image was created with usage containing "
4493*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_SHADING_RATE_IMAGE_BIT_NV, format must be VK_FORMAT_R8_UINT.");
4494*b7893ccfSSadaf Ebrahimi }
4495*b7893ccfSSadaf Ebrahimi }
4496*b7893ccfSSadaf Ebrahimi }
4497*b7893ccfSSadaf Ebrahimi return skip;
4498*b7893ccfSSadaf Ebrahimi }
4499*b7893ccfSSadaf Ebrahimi
PostCallRecordCreateImageView(VkDevice device,const VkImageViewCreateInfo * pCreateInfo,const VkAllocationCallbacks * pAllocator,VkImageView * pView,VkResult result)4500*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PostCallRecordCreateImageView(VkDevice device, const VkImageViewCreateInfo *pCreateInfo,
4501*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator, VkImageView *pView,
4502*b7893ccfSSadaf Ebrahimi VkResult result) {
4503*b7893ccfSSadaf Ebrahimi if (result != VK_SUCCESS) return;
4504*b7893ccfSSadaf Ebrahimi auto image_state = GetImageState(pCreateInfo->image);
4505*b7893ccfSSadaf Ebrahimi imageViewMap[*pView] = std::unique_ptr<IMAGE_VIEW_STATE>(new IMAGE_VIEW_STATE(image_state, *pView, pCreateInfo));
4506*b7893ccfSSadaf Ebrahimi }
4507*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferCopy * pRegions)4508*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
4509*b7893ccfSSadaf Ebrahimi uint32_t regionCount, const VkBufferCopy *pRegions) {
4510*b7893ccfSSadaf Ebrahimi const auto cb_node = GetCBState(commandBuffer);
4511*b7893ccfSSadaf Ebrahimi const auto src_buffer_state = GetBufferState(srcBuffer);
4512*b7893ccfSSadaf Ebrahimi const auto dst_buffer_state = GetBufferState(dstBuffer);
4513*b7893ccfSSadaf Ebrahimi
4514*b7893ccfSSadaf Ebrahimi bool skip = false;
4515*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToBuffer(src_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-srcBuffer-00119");
4516*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToBuffer(dst_buffer_state, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-dstBuffer-00121");
4517*b7893ccfSSadaf Ebrahimi // Validate that SRC & DST buffers have correct usage flags set
4518*b7893ccfSSadaf Ebrahimi skip |=
4519*b7893ccfSSadaf Ebrahimi ValidateBufferUsageFlags(src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true, "VUID-vkCmdCopyBuffer-srcBuffer-00118",
4520*b7893ccfSSadaf Ebrahimi "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
4521*b7893ccfSSadaf Ebrahimi skip |=
4522*b7893ccfSSadaf Ebrahimi ValidateBufferUsageFlags(dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdCopyBuffer-dstBuffer-00120",
4523*b7893ccfSSadaf Ebrahimi "vkCmdCopyBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
4524*b7893ccfSSadaf Ebrahimi skip |=
4525*b7893ccfSSadaf Ebrahimi ValidateCmdQueueFlags(cb_node, "vkCmdCopyBuffer()", VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
4526*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBuffer-commandBuffer-cmdpool");
4527*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_COPYBUFFER, "vkCmdCopyBuffer()");
4528*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdCopyBuffer()", "VUID-vkCmdCopyBuffer-renderpass");
4529*b7893ccfSSadaf Ebrahimi return skip;
4530*b7893ccfSSadaf Ebrahimi }
4531*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferCopy * pRegions)4532*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer,
4533*b7893ccfSSadaf Ebrahimi uint32_t regionCount, const VkBufferCopy *pRegions) {
4534*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
4535*b7893ccfSSadaf Ebrahimi auto src_buffer_state = GetBufferState(srcBuffer);
4536*b7893ccfSSadaf Ebrahimi auto dst_buffer_state = GetBufferState(dstBuffer);
4537*b7893ccfSSadaf Ebrahimi
4538*b7893ccfSSadaf Ebrahimi // Update bindings between buffers and cmd buffer
4539*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingBuffer(cb_node, src_buffer_state);
4540*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingBuffer(cb_node, dst_buffer_state);
4541*b7893ccfSSadaf Ebrahimi }
4542*b7893ccfSSadaf Ebrahimi
ValidateIdleBuffer(VkBuffer buffer)4543*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateIdleBuffer(VkBuffer buffer) {
4544*b7893ccfSSadaf Ebrahimi bool skip = false;
4545*b7893ccfSSadaf Ebrahimi auto buffer_state = GetBufferState(buffer);
4546*b7893ccfSSadaf Ebrahimi if (!buffer_state) {
4547*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT, HandleToUint64(buffer),
4548*b7893ccfSSadaf Ebrahimi kVUID_Core_DrawState_DoubleDestroy, "Cannot free %s that has not been allocated.",
4549*b7893ccfSSadaf Ebrahimi report_data->FormatHandle(buffer).c_str());
4550*b7893ccfSSadaf Ebrahimi } else {
4551*b7893ccfSSadaf Ebrahimi if (buffer_state->in_use.load()) {
4552*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_BUFFER_EXT,
4553*b7893ccfSSadaf Ebrahimi HandleToUint64(buffer), "VUID-vkDestroyBuffer-buffer-00922",
4554*b7893ccfSSadaf Ebrahimi "Cannot free %s that is in use by a command buffer.", report_data->FormatHandle(buffer).c_str());
4555*b7893ccfSSadaf Ebrahimi }
4556*b7893ccfSSadaf Ebrahimi }
4557*b7893ccfSSadaf Ebrahimi return skip;
4558*b7893ccfSSadaf Ebrahimi }
4559*b7893ccfSSadaf Ebrahimi
PreCallValidateDestroyImageView(VkDevice device,VkImageView imageView,const VkAllocationCallbacks * pAllocator)4560*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateDestroyImageView(VkDevice device, VkImageView imageView, const VkAllocationCallbacks *pAllocator) {
4561*b7893ccfSSadaf Ebrahimi IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
4562*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(imageView, kVulkanObjectTypeImageView);
4563*b7893ccfSSadaf Ebrahimi
4564*b7893ccfSSadaf Ebrahimi bool skip = false;
4565*b7893ccfSSadaf Ebrahimi if (image_view_state) {
4566*b7893ccfSSadaf Ebrahimi skip |=
4567*b7893ccfSSadaf Ebrahimi ValidateObjectNotInUse(image_view_state, obj_struct, "vkDestroyImageView", "VUID-vkDestroyImageView-imageView-01026");
4568*b7893ccfSSadaf Ebrahimi }
4569*b7893ccfSSadaf Ebrahimi return skip;
4570*b7893ccfSSadaf Ebrahimi }
4571*b7893ccfSSadaf Ebrahimi
PreCallRecordDestroyImageView(VkDevice device,VkImageView imageView,const VkAllocationCallbacks * pAllocator)4572*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordDestroyImageView(VkDevice device, VkImageView imageView,
4573*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator) {
4574*b7893ccfSSadaf Ebrahimi IMAGE_VIEW_STATE *image_view_state = GetImageViewState(imageView);
4575*b7893ccfSSadaf Ebrahimi if (!image_view_state) return;
4576*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(imageView, kVulkanObjectTypeImageView);
4577*b7893ccfSSadaf Ebrahimi
4578*b7893ccfSSadaf Ebrahimi // Any bound cmd buffers are now invalid
4579*b7893ccfSSadaf Ebrahimi InvalidateCommandBuffers(image_view_state->cb_bindings, obj_struct);
4580*b7893ccfSSadaf Ebrahimi imageViewMap.erase(imageView);
4581*b7893ccfSSadaf Ebrahimi }
4582*b7893ccfSSadaf Ebrahimi
PreCallValidateDestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator)4583*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
4584*b7893ccfSSadaf Ebrahimi auto buffer_state = GetBufferState(buffer);
4585*b7893ccfSSadaf Ebrahimi
4586*b7893ccfSSadaf Ebrahimi bool skip = false;
4587*b7893ccfSSadaf Ebrahimi if (buffer_state) {
4588*b7893ccfSSadaf Ebrahimi skip |= ValidateIdleBuffer(buffer);
4589*b7893ccfSSadaf Ebrahimi }
4590*b7893ccfSSadaf Ebrahimi return skip;
4591*b7893ccfSSadaf Ebrahimi }
4592*b7893ccfSSadaf Ebrahimi
PreCallRecordDestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator)4593*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
4594*b7893ccfSSadaf Ebrahimi if (!buffer) return;
4595*b7893ccfSSadaf Ebrahimi auto buffer_state = GetBufferState(buffer);
4596*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(buffer, kVulkanObjectTypeBuffer);
4597*b7893ccfSSadaf Ebrahimi
4598*b7893ccfSSadaf Ebrahimi InvalidateCommandBuffers(buffer_state->cb_bindings, obj_struct);
4599*b7893ccfSSadaf Ebrahimi for (auto mem_binding : buffer_state->GetBoundMemory()) {
4600*b7893ccfSSadaf Ebrahimi auto mem_info = GetDevMemState(mem_binding);
4601*b7893ccfSSadaf Ebrahimi if (mem_info) {
4602*b7893ccfSSadaf Ebrahimi RemoveBufferMemoryRange(HandleToUint64(buffer), mem_info);
4603*b7893ccfSSadaf Ebrahimi }
4604*b7893ccfSSadaf Ebrahimi }
4605*b7893ccfSSadaf Ebrahimi ClearMemoryObjectBindings(obj_struct);
4606*b7893ccfSSadaf Ebrahimi bufferMap.erase(buffer_state->buffer);
4607*b7893ccfSSadaf Ebrahimi }
4608*b7893ccfSSadaf Ebrahimi
PreCallRecordDestroyBuffer(VkDevice device,VkBuffer buffer,const VkAllocationCallbacks * pAllocator)4609*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordDestroyBuffer(VkDevice device, VkBuffer buffer, const VkAllocationCallbacks *pAllocator) {
4610*b7893ccfSSadaf Ebrahimi if (!buffer) return;
4611*b7893ccfSSadaf Ebrahimi
4612*b7893ccfSSadaf Ebrahimi // Clean up validation specific data
4613*b7893ccfSSadaf Ebrahimi EraseQFOReleaseBarriers<VkBufferMemoryBarrier>(buffer);
4614*b7893ccfSSadaf Ebrahimi
4615*b7893ccfSSadaf Ebrahimi // Clean up generic buffer state
4616*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordDestroyBuffer(device, buffer, pAllocator);
4617*b7893ccfSSadaf Ebrahimi }
PreCallValidateDestroyBufferView(VkDevice device,VkBufferView bufferView,const VkAllocationCallbacks * pAllocator)4618*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateDestroyBufferView(VkDevice device, VkBufferView bufferView,
4619*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator) {
4620*b7893ccfSSadaf Ebrahimi auto buffer_view_state = GetBufferViewState(bufferView);
4621*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(bufferView, kVulkanObjectTypeBufferView);
4622*b7893ccfSSadaf Ebrahimi bool skip = false;
4623*b7893ccfSSadaf Ebrahimi if (buffer_view_state) {
4624*b7893ccfSSadaf Ebrahimi skip |= ValidateObjectNotInUse(buffer_view_state, obj_struct, "vkDestroyBufferView",
4625*b7893ccfSSadaf Ebrahimi "VUID-vkDestroyBufferView-bufferView-00936");
4626*b7893ccfSSadaf Ebrahimi }
4627*b7893ccfSSadaf Ebrahimi return skip;
4628*b7893ccfSSadaf Ebrahimi }
4629*b7893ccfSSadaf Ebrahimi
PreCallRecordDestroyBufferView(VkDevice device,VkBufferView bufferView,const VkAllocationCallbacks * pAllocator)4630*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordDestroyBufferView(VkDevice device, VkBufferView bufferView,
4631*b7893ccfSSadaf Ebrahimi const VkAllocationCallbacks *pAllocator) {
4632*b7893ccfSSadaf Ebrahimi if (!bufferView) return;
4633*b7893ccfSSadaf Ebrahimi auto buffer_view_state = GetBufferViewState(bufferView);
4634*b7893ccfSSadaf Ebrahimi const VulkanTypedHandle obj_struct(bufferView, kVulkanObjectTypeBufferView);
4635*b7893ccfSSadaf Ebrahimi
4636*b7893ccfSSadaf Ebrahimi // Any bound cmd buffers are now invalid
4637*b7893ccfSSadaf Ebrahimi InvalidateCommandBuffers(buffer_view_state->cb_bindings, obj_struct);
4638*b7893ccfSSadaf Ebrahimi bufferViewMap.erase(bufferView);
4639*b7893ccfSSadaf Ebrahimi }
4640*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer,VkBuffer dstBuffer,VkDeviceSize dstOffset,VkDeviceSize size,uint32_t data)4641*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
4642*b7893ccfSSadaf Ebrahimi VkDeviceSize size, uint32_t data) {
4643*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
4644*b7893ccfSSadaf Ebrahimi auto buffer_state = GetBufferState(dstBuffer);
4645*b7893ccfSSadaf Ebrahimi bool skip = false;
4646*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToBuffer(buffer_state, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-dstBuffer-00031");
4647*b7893ccfSSadaf Ebrahimi skip |=
4648*b7893ccfSSadaf Ebrahimi ValidateCmdQueueFlags(cb_node, "vkCmdFillBuffer()", VK_QUEUE_TRANSFER_BIT | VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT,
4649*b7893ccfSSadaf Ebrahimi "VUID-vkCmdFillBuffer-commandBuffer-cmdpool");
4650*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_FILLBUFFER, "vkCmdFillBuffer()");
4651*b7893ccfSSadaf Ebrahimi // Validate that DST buffer has correct usage flags set
4652*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferUsageFlags(buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true, "VUID-vkCmdFillBuffer-dstBuffer-00029",
4653*b7893ccfSSadaf Ebrahimi "vkCmdFillBuffer()", "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
4654*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdFillBuffer()", "VUID-vkCmdFillBuffer-renderpass");
4655*b7893ccfSSadaf Ebrahimi return skip;
4656*b7893ccfSSadaf Ebrahimi }
4657*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdFillBuffer(VkCommandBuffer commandBuffer,VkBuffer dstBuffer,VkDeviceSize dstOffset,VkDeviceSize size,uint32_t data)4658*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset,
4659*b7893ccfSSadaf Ebrahimi VkDeviceSize size, uint32_t data) {
4660*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
4661*b7893ccfSSadaf Ebrahimi auto buffer_state = GetBufferState(dstBuffer);
4662*b7893ccfSSadaf Ebrahimi // Update bindings between buffer and cmd buffer
4663*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingBuffer(cb_node, buffer_state);
4664*b7893ccfSSadaf Ebrahimi }
4665*b7893ccfSSadaf Ebrahimi
ValidateBufferImageCopyData(uint32_t regionCount,const VkBufferImageCopy * pRegions,IMAGE_STATE * image_state,const char * function)4666*b7893ccfSSadaf Ebrahimi bool CoreChecks::ValidateBufferImageCopyData(uint32_t regionCount, const VkBufferImageCopy *pRegions, IMAGE_STATE *image_state,
4667*b7893ccfSSadaf Ebrahimi const char *function) {
4668*b7893ccfSSadaf Ebrahimi bool skip = false;
4669*b7893ccfSSadaf Ebrahimi
4670*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
4671*b7893ccfSSadaf Ebrahimi if (image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) {
4672*b7893ccfSSadaf Ebrahimi if ((pRegions[i].imageOffset.y != 0) || (pRegions[i].imageExtent.height != 1)) {
4673*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4674*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-srcImage-00199",
4675*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] imageOffset.y is %d and imageExtent.height is %d. For 1D images these must be 0 "
4676*b7893ccfSSadaf Ebrahimi "and 1, respectively.",
4677*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageOffset.y, pRegions[i].imageExtent.height);
4678*b7893ccfSSadaf Ebrahimi }
4679*b7893ccfSSadaf Ebrahimi }
4680*b7893ccfSSadaf Ebrahimi
4681*b7893ccfSSadaf Ebrahimi if ((image_state->createInfo.imageType == VK_IMAGE_TYPE_1D) || (image_state->createInfo.imageType == VK_IMAGE_TYPE_2D)) {
4682*b7893ccfSSadaf Ebrahimi if ((pRegions[i].imageOffset.z != 0) || (pRegions[i].imageExtent.depth != 1)) {
4683*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4684*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-srcImage-00201",
4685*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] imageOffset.z is %d and imageExtent.depth is %d. For 1D and 2D images these "
4686*b7893ccfSSadaf Ebrahimi "must be 0 and 1, respectively.",
4687*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageOffset.z, pRegions[i].imageExtent.depth);
4688*b7893ccfSSadaf Ebrahimi }
4689*b7893ccfSSadaf Ebrahimi }
4690*b7893ccfSSadaf Ebrahimi
4691*b7893ccfSSadaf Ebrahimi if (image_state->createInfo.imageType == VK_IMAGE_TYPE_3D) {
4692*b7893ccfSSadaf Ebrahimi if ((0 != pRegions[i].imageSubresource.baseArrayLayer) || (1 != pRegions[i].imageSubresource.layerCount)) {
4693*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4694*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-baseArrayLayer-00213",
4695*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] imageSubresource.baseArrayLayer is %d and imageSubresource.layerCount is %d. "
4696*b7893ccfSSadaf Ebrahimi "For 3D images these must be 0 and 1, respectively.",
4697*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageSubresource.baseArrayLayer, pRegions[i].imageSubresource.layerCount);
4698*b7893ccfSSadaf Ebrahimi }
4699*b7893ccfSSadaf Ebrahimi }
4700*b7893ccfSSadaf Ebrahimi
4701*b7893ccfSSadaf Ebrahimi // If the the calling command's VkImage parameter's format is not a depth/stencil format,
4702*b7893ccfSSadaf Ebrahimi // then bufferOffset must be a multiple of the calling command's VkImage parameter's element size
4703*b7893ccfSSadaf Ebrahimi uint32_t element_size = FormatElementSize(image_state->createInfo.format, pRegions[i].imageSubresource.aspectMask);
4704*b7893ccfSSadaf Ebrahimi
4705*b7893ccfSSadaf Ebrahimi if (!FormatIsDepthAndStencil(image_state->createInfo.format) && SafeModulo(pRegions[i].bufferOffset, element_size) != 0) {
4706*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4707*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00193",
4708*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64
4709*b7893ccfSSadaf Ebrahimi " must be a multiple of this format's texel size (%" PRIu32 ").",
4710*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].bufferOffset, element_size);
4711*b7893ccfSSadaf Ebrahimi }
4712*b7893ccfSSadaf Ebrahimi
4713*b7893ccfSSadaf Ebrahimi // BufferOffset must be a multiple of 4
4714*b7893ccfSSadaf Ebrahimi if (SafeModulo(pRegions[i].bufferOffset, 4) != 0) {
4715*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4716*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00194",
4717*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferOffset 0x%" PRIxLEAST64 " must be a multiple of 4.", function, i,
4718*b7893ccfSSadaf Ebrahimi pRegions[i].bufferOffset);
4719*b7893ccfSSadaf Ebrahimi }
4720*b7893ccfSSadaf Ebrahimi
4721*b7893ccfSSadaf Ebrahimi // BufferRowLength must be 0, or greater than or equal to the width member of imageExtent
4722*b7893ccfSSadaf Ebrahimi if ((pRegions[i].bufferRowLength != 0) && (pRegions[i].bufferRowLength < pRegions[i].imageExtent.width)) {
4723*b7893ccfSSadaf Ebrahimi skip |=
4724*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4725*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferRowLength-00195",
4726*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferRowLength (%d) must be zero or greater-than-or-equal-to imageExtent.width (%d).",
4727*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].bufferRowLength, pRegions[i].imageExtent.width);
4728*b7893ccfSSadaf Ebrahimi }
4729*b7893ccfSSadaf Ebrahimi
4730*b7893ccfSSadaf Ebrahimi // BufferImageHeight must be 0, or greater than or equal to the height member of imageExtent
4731*b7893ccfSSadaf Ebrahimi if ((pRegions[i].bufferImageHeight != 0) && (pRegions[i].bufferImageHeight < pRegions[i].imageExtent.height)) {
4732*b7893ccfSSadaf Ebrahimi skip |= log_msg(
4733*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4734*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferImageHeight-00196",
4735*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferImageHeight (%d) must be zero or greater-than-or-equal-to imageExtent.height (%d).",
4736*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].bufferImageHeight, pRegions[i].imageExtent.height);
4737*b7893ccfSSadaf Ebrahimi }
4738*b7893ccfSSadaf Ebrahimi
4739*b7893ccfSSadaf Ebrahimi // Calculate adjusted image extent, accounting for multiplane image factors
4740*b7893ccfSSadaf Ebrahimi VkExtent3D adusted_image_extent = GetImageSubresourceExtent(image_state, &pRegions[i].imageSubresource);
4741*b7893ccfSSadaf Ebrahimi // imageOffset.x and (imageExtent.width + imageOffset.x) must both be >= 0 and <= image subresource width
4742*b7893ccfSSadaf Ebrahimi if ((pRegions[i].imageOffset.x < 0) || (pRegions[i].imageOffset.x > static_cast<int32_t>(adusted_image_extent.width)) ||
4743*b7893ccfSSadaf Ebrahimi ((pRegions[i].imageOffset.x + pRegions[i].imageExtent.width) > static_cast<int32_t>(adusted_image_extent.width))) {
4744*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4745*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageOffset-00197",
4746*b7893ccfSSadaf Ebrahimi "%s(): Both pRegion[%d] imageoffset.x (%d) and (imageExtent.width + imageOffset.x) (%d) must be >= "
4747*b7893ccfSSadaf Ebrahimi "zero or <= image subresource width (%d).",
4748*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageOffset.x, (pRegions[i].imageOffset.x + pRegions[i].imageExtent.width),
4749*b7893ccfSSadaf Ebrahimi adusted_image_extent.width);
4750*b7893ccfSSadaf Ebrahimi }
4751*b7893ccfSSadaf Ebrahimi
4752*b7893ccfSSadaf Ebrahimi // imageOffset.y and (imageExtent.height + imageOffset.y) must both be >= 0 and <= image subresource height
4753*b7893ccfSSadaf Ebrahimi if ((pRegions[i].imageOffset.y < 0) || (pRegions[i].imageOffset.y > static_cast<int32_t>(adusted_image_extent.height)) ||
4754*b7893ccfSSadaf Ebrahimi ((pRegions[i].imageOffset.y + pRegions[i].imageExtent.height) > static_cast<int32_t>(adusted_image_extent.height))) {
4755*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4756*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageOffset-00198",
4757*b7893ccfSSadaf Ebrahimi "%s(): Both pRegion[%d] imageoffset.y (%d) and (imageExtent.height + imageOffset.y) (%d) must be >= "
4758*b7893ccfSSadaf Ebrahimi "zero or <= image subresource height (%d).",
4759*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageOffset.y, (pRegions[i].imageOffset.y + pRegions[i].imageExtent.height),
4760*b7893ccfSSadaf Ebrahimi adusted_image_extent.height);
4761*b7893ccfSSadaf Ebrahimi }
4762*b7893ccfSSadaf Ebrahimi
4763*b7893ccfSSadaf Ebrahimi // imageOffset.z and (imageExtent.depth + imageOffset.z) must both be >= 0 and <= image subresource depth
4764*b7893ccfSSadaf Ebrahimi if ((pRegions[i].imageOffset.z < 0) || (pRegions[i].imageOffset.z > static_cast<int32_t>(adusted_image_extent.depth)) ||
4765*b7893ccfSSadaf Ebrahimi ((pRegions[i].imageOffset.z + pRegions[i].imageExtent.depth) > static_cast<int32_t>(adusted_image_extent.depth))) {
4766*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4767*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageOffset-00200",
4768*b7893ccfSSadaf Ebrahimi "%s(): Both pRegion[%d] imageoffset.z (%d) and (imageExtent.depth + imageOffset.z) (%d) must be >= "
4769*b7893ccfSSadaf Ebrahimi "zero or <= image subresource depth (%d).",
4770*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageOffset.z, (pRegions[i].imageOffset.z + pRegions[i].imageExtent.depth),
4771*b7893ccfSSadaf Ebrahimi adusted_image_extent.depth);
4772*b7893ccfSSadaf Ebrahimi }
4773*b7893ccfSSadaf Ebrahimi
4774*b7893ccfSSadaf Ebrahimi // subresource aspectMask must have exactly 1 bit set
4775*b7893ccfSSadaf Ebrahimi const int num_bits = sizeof(VkFlags) * CHAR_BIT;
4776*b7893ccfSSadaf Ebrahimi std::bitset<num_bits> aspect_mask_bits(pRegions[i].imageSubresource.aspectMask);
4777*b7893ccfSSadaf Ebrahimi if (aspect_mask_bits.count() != 1) {
4778*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4779*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-aspectMask-00212",
4780*b7893ccfSSadaf Ebrahimi "%s: aspectMasks for imageSubresource in each region must have only a single bit set.", function);
4781*b7893ccfSSadaf Ebrahimi }
4782*b7893ccfSSadaf Ebrahimi
4783*b7893ccfSSadaf Ebrahimi // image subresource aspect bit must match format
4784*b7893ccfSSadaf Ebrahimi if (!VerifyAspectsPresent(pRegions[i].imageSubresource.aspectMask, image_state->createInfo.format)) {
4785*b7893ccfSSadaf Ebrahimi skip |= log_msg(
4786*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4787*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-aspectMask-00211",
4788*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] subresource aspectMask 0x%x specifies aspects that are not present in image format 0x%x.",
4789*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageSubresource.aspectMask, image_state->createInfo.format);
4790*b7893ccfSSadaf Ebrahimi }
4791*b7893ccfSSadaf Ebrahimi
4792*b7893ccfSSadaf Ebrahimi // Checks that apply only to compressed images
4793*b7893ccfSSadaf Ebrahimi if (FormatIsCompressed(image_state->createInfo.format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
4794*b7893ccfSSadaf Ebrahimi auto block_size = FormatTexelBlockExtent(image_state->createInfo.format);
4795*b7893ccfSSadaf Ebrahimi
4796*b7893ccfSSadaf Ebrahimi // BufferRowLength must be a multiple of block width
4797*b7893ccfSSadaf Ebrahimi if (SafeModulo(pRegions[i].bufferRowLength, block_size.width) != 0) {
4798*b7893ccfSSadaf Ebrahimi skip |= log_msg(
4799*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4800*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferRowLength-00203",
4801*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferRowLength (%d) must be a multiple of the compressed image's texel width (%d)..",
4802*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].bufferRowLength, block_size.width);
4803*b7893ccfSSadaf Ebrahimi }
4804*b7893ccfSSadaf Ebrahimi
4805*b7893ccfSSadaf Ebrahimi // BufferRowHeight must be a multiple of block height
4806*b7893ccfSSadaf Ebrahimi if (SafeModulo(pRegions[i].bufferImageHeight, block_size.height) != 0) {
4807*b7893ccfSSadaf Ebrahimi skip |= log_msg(
4808*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4809*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferImageHeight-00204",
4810*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferImageHeight (%d) must be a multiple of the compressed image's texel height (%d)..",
4811*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].bufferImageHeight, block_size.height);
4812*b7893ccfSSadaf Ebrahimi }
4813*b7893ccfSSadaf Ebrahimi
4814*b7893ccfSSadaf Ebrahimi // image offsets must be multiples of block dimensions
4815*b7893ccfSSadaf Ebrahimi if ((SafeModulo(pRegions[i].imageOffset.x, block_size.width) != 0) ||
4816*b7893ccfSSadaf Ebrahimi (SafeModulo(pRegions[i].imageOffset.y, block_size.height) != 0) ||
4817*b7893ccfSSadaf Ebrahimi (SafeModulo(pRegions[i].imageOffset.z, block_size.depth) != 0)) {
4818*b7893ccfSSadaf Ebrahimi skip |=
4819*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4820*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageOffset-00205",
4821*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] imageOffset(x,y) (%d, %d) must be multiples of the compressed image's texel "
4822*b7893ccfSSadaf Ebrahimi "width & height (%d, %d)..",
4823*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageOffset.x, pRegions[i].imageOffset.y, block_size.width, block_size.height);
4824*b7893ccfSSadaf Ebrahimi }
4825*b7893ccfSSadaf Ebrahimi
4826*b7893ccfSSadaf Ebrahimi // bufferOffset must be a multiple of block size (linear bytes)
4827*b7893ccfSSadaf Ebrahimi uint32_t block_size_in_bytes = FormatElementSize(image_state->createInfo.format);
4828*b7893ccfSSadaf Ebrahimi if (SafeModulo(pRegions[i].bufferOffset, block_size_in_bytes) != 0) {
4829*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4830*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-bufferOffset-00206",
4831*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] bufferOffset (0x%" PRIxLEAST64
4832*b7893ccfSSadaf Ebrahimi ") must be a multiple of the compressed image's texel block size (%" PRIu32 ")..",
4833*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].bufferOffset, block_size_in_bytes);
4834*b7893ccfSSadaf Ebrahimi }
4835*b7893ccfSSadaf Ebrahimi
4836*b7893ccfSSadaf Ebrahimi // imageExtent width must be a multiple of block width, or extent+offset width must equal subresource width
4837*b7893ccfSSadaf Ebrahimi VkExtent3D mip_extent = GetImageSubresourceExtent(image_state, &(pRegions[i].imageSubresource));
4838*b7893ccfSSadaf Ebrahimi if ((SafeModulo(pRegions[i].imageExtent.width, block_size.width) != 0) &&
4839*b7893ccfSSadaf Ebrahimi (pRegions[i].imageExtent.width + pRegions[i].imageOffset.x != mip_extent.width)) {
4840*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4841*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageExtent-00207",
4842*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block width "
4843*b7893ccfSSadaf Ebrahimi "(%d), or when added to offset.x (%d) must equal the image subresource width (%d)..",
4844*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageExtent.width, block_size.width, pRegions[i].imageOffset.x,
4845*b7893ccfSSadaf Ebrahimi mip_extent.width);
4846*b7893ccfSSadaf Ebrahimi }
4847*b7893ccfSSadaf Ebrahimi
4848*b7893ccfSSadaf Ebrahimi // imageExtent height must be a multiple of block height, or extent+offset height must equal subresource height
4849*b7893ccfSSadaf Ebrahimi if ((SafeModulo(pRegions[i].imageExtent.height, block_size.height) != 0) &&
4850*b7893ccfSSadaf Ebrahimi (pRegions[i].imageExtent.height + pRegions[i].imageOffset.y != mip_extent.height)) {
4851*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4852*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageExtent-00208",
4853*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] extent height (%d) must be a multiple of the compressed texture block height "
4854*b7893ccfSSadaf Ebrahimi "(%d), or when added to offset.y (%d) must equal the image subresource height (%d)..",
4855*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageExtent.height, block_size.height, pRegions[i].imageOffset.y,
4856*b7893ccfSSadaf Ebrahimi mip_extent.height);
4857*b7893ccfSSadaf Ebrahimi }
4858*b7893ccfSSadaf Ebrahimi
4859*b7893ccfSSadaf Ebrahimi // imageExtent depth must be a multiple of block depth, or extent+offset depth must equal subresource depth
4860*b7893ccfSSadaf Ebrahimi if ((SafeModulo(pRegions[i].imageExtent.depth, block_size.depth) != 0) &&
4861*b7893ccfSSadaf Ebrahimi (pRegions[i].imageExtent.depth + pRegions[i].imageOffset.z != mip_extent.depth)) {
4862*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
4863*b7893ccfSSadaf Ebrahimi HandleToUint64(image_state->image), "VUID-VkBufferImageCopy-imageExtent-00209",
4864*b7893ccfSSadaf Ebrahimi "%s(): pRegion[%d] extent width (%d) must be a multiple of the compressed texture block depth "
4865*b7893ccfSSadaf Ebrahimi "(%d), or when added to offset.z (%d) must equal the image subresource depth (%d)..",
4866*b7893ccfSSadaf Ebrahimi function, i, pRegions[i].imageExtent.depth, block_size.depth, pRegions[i].imageOffset.z,
4867*b7893ccfSSadaf Ebrahimi mip_extent.depth);
4868*b7893ccfSSadaf Ebrahimi }
4869*b7893ccfSSadaf Ebrahimi }
4870*b7893ccfSSadaf Ebrahimi }
4871*b7893ccfSSadaf Ebrahimi
4872*b7893ccfSSadaf Ebrahimi return skip;
4873*b7893ccfSSadaf Ebrahimi }
4874*b7893ccfSSadaf Ebrahimi
ValidateImageBounds(const debug_report_data * report_data,const IMAGE_STATE * image_state,const uint32_t regionCount,const VkBufferImageCopy * pRegions,const char * func_name,const char * msg_code)4875*b7893ccfSSadaf Ebrahimi static bool ValidateImageBounds(const debug_report_data *report_data, const IMAGE_STATE *image_state, const uint32_t regionCount,
4876*b7893ccfSSadaf Ebrahimi const VkBufferImageCopy *pRegions, const char *func_name, const char *msg_code) {
4877*b7893ccfSSadaf Ebrahimi bool skip = false;
4878*b7893ccfSSadaf Ebrahimi const VkImageCreateInfo *image_info = &(image_state->createInfo);
4879*b7893ccfSSadaf Ebrahimi
4880*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
4881*b7893ccfSSadaf Ebrahimi VkExtent3D extent = pRegions[i].imageExtent;
4882*b7893ccfSSadaf Ebrahimi VkOffset3D offset = pRegions[i].imageOffset;
4883*b7893ccfSSadaf Ebrahimi
4884*b7893ccfSSadaf Ebrahimi if (IsExtentSizeZero(&extent)) // Warn on zero area subresource
4885*b7893ccfSSadaf Ebrahimi {
4886*b7893ccfSSadaf Ebrahimi skip |=
4887*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_WARNING_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)0,
4888*b7893ccfSSadaf Ebrahimi kVUID_Core_Image_ZeroAreaSubregion, "%s: pRegion[%d] imageExtent of {%1d, %1d, %1d} has zero area",
4889*b7893ccfSSadaf Ebrahimi func_name, i, extent.width, extent.height, extent.depth);
4890*b7893ccfSSadaf Ebrahimi }
4891*b7893ccfSSadaf Ebrahimi
4892*b7893ccfSSadaf Ebrahimi VkExtent3D image_extent = GetImageSubresourceExtent(image_state, &(pRegions[i].imageSubresource));
4893*b7893ccfSSadaf Ebrahimi
4894*b7893ccfSSadaf Ebrahimi // If we're using a compressed format, valid extent is rounded up to multiple of block size (per 18.1)
4895*b7893ccfSSadaf Ebrahimi if (FormatIsCompressed(image_info->format)) {
4896*b7893ccfSSadaf Ebrahimi auto block_extent = FormatTexelBlockExtent(image_info->format);
4897*b7893ccfSSadaf Ebrahimi if (image_extent.width % block_extent.width) {
4898*b7893ccfSSadaf Ebrahimi image_extent.width += (block_extent.width - (image_extent.width % block_extent.width));
4899*b7893ccfSSadaf Ebrahimi }
4900*b7893ccfSSadaf Ebrahimi if (image_extent.height % block_extent.height) {
4901*b7893ccfSSadaf Ebrahimi image_extent.height += (block_extent.height - (image_extent.height % block_extent.height));
4902*b7893ccfSSadaf Ebrahimi }
4903*b7893ccfSSadaf Ebrahimi if (image_extent.depth % block_extent.depth) {
4904*b7893ccfSSadaf Ebrahimi image_extent.depth += (block_extent.depth - (image_extent.depth % block_extent.depth));
4905*b7893ccfSSadaf Ebrahimi }
4906*b7893ccfSSadaf Ebrahimi }
4907*b7893ccfSSadaf Ebrahimi
4908*b7893ccfSSadaf Ebrahimi if (0 != ExceedsBounds(&offset, &extent, &image_extent)) {
4909*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)0,
4910*b7893ccfSSadaf Ebrahimi msg_code, "%s: pRegion[%d] exceeds image bounds..", func_name, i);
4911*b7893ccfSSadaf Ebrahimi }
4912*b7893ccfSSadaf Ebrahimi }
4913*b7893ccfSSadaf Ebrahimi
4914*b7893ccfSSadaf Ebrahimi return skip;
4915*b7893ccfSSadaf Ebrahimi }
4916*b7893ccfSSadaf Ebrahimi
ValidateBufferBounds(const debug_report_data * report_data,IMAGE_STATE * image_state,BUFFER_STATE * buff_state,uint32_t regionCount,const VkBufferImageCopy * pRegions,const char * func_name,const char * msg_code)4917*b7893ccfSSadaf Ebrahimi static inline bool ValidateBufferBounds(const debug_report_data *report_data, IMAGE_STATE *image_state, BUFFER_STATE *buff_state,
4918*b7893ccfSSadaf Ebrahimi uint32_t regionCount, const VkBufferImageCopy *pRegions, const char *func_name,
4919*b7893ccfSSadaf Ebrahimi const char *msg_code) {
4920*b7893ccfSSadaf Ebrahimi bool skip = false;
4921*b7893ccfSSadaf Ebrahimi
4922*b7893ccfSSadaf Ebrahimi VkDeviceSize buffer_size = buff_state->createInfo.size;
4923*b7893ccfSSadaf Ebrahimi
4924*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; i++) {
4925*b7893ccfSSadaf Ebrahimi VkExtent3D copy_extent = pRegions[i].imageExtent;
4926*b7893ccfSSadaf Ebrahimi
4927*b7893ccfSSadaf Ebrahimi VkDeviceSize buffer_width = (0 == pRegions[i].bufferRowLength ? copy_extent.width : pRegions[i].bufferRowLength);
4928*b7893ccfSSadaf Ebrahimi VkDeviceSize buffer_height = (0 == pRegions[i].bufferImageHeight ? copy_extent.height : pRegions[i].bufferImageHeight);
4929*b7893ccfSSadaf Ebrahimi VkDeviceSize unit_size = FormatElementSize(image_state->createInfo.format,
4930*b7893ccfSSadaf Ebrahimi pRegions[i].imageSubresource.aspectMask); // size (bytes) of texel or block
4931*b7893ccfSSadaf Ebrahimi
4932*b7893ccfSSadaf Ebrahimi if (FormatIsCompressed(image_state->createInfo.format) || FormatIsSinglePlane_422(image_state->createInfo.format)) {
4933*b7893ccfSSadaf Ebrahimi // Switch to texel block units, rounding up for any partially-used blocks
4934*b7893ccfSSadaf Ebrahimi auto block_dim = FormatTexelBlockExtent(image_state->createInfo.format);
4935*b7893ccfSSadaf Ebrahimi buffer_width = (buffer_width + block_dim.width - 1) / block_dim.width;
4936*b7893ccfSSadaf Ebrahimi buffer_height = (buffer_height + block_dim.height - 1) / block_dim.height;
4937*b7893ccfSSadaf Ebrahimi
4938*b7893ccfSSadaf Ebrahimi copy_extent.width = (copy_extent.width + block_dim.width - 1) / block_dim.width;
4939*b7893ccfSSadaf Ebrahimi copy_extent.height = (copy_extent.height + block_dim.height - 1) / block_dim.height;
4940*b7893ccfSSadaf Ebrahimi copy_extent.depth = (copy_extent.depth + block_dim.depth - 1) / block_dim.depth;
4941*b7893ccfSSadaf Ebrahimi }
4942*b7893ccfSSadaf Ebrahimi
4943*b7893ccfSSadaf Ebrahimi // Either depth or layerCount may be greater than 1 (not both). This is the number of 'slices' to copy
4944*b7893ccfSSadaf Ebrahimi uint32_t z_copies = std::max(copy_extent.depth, pRegions[i].imageSubresource.layerCount);
4945*b7893ccfSSadaf Ebrahimi if (IsExtentSizeZero(©_extent) || (0 == z_copies)) {
4946*b7893ccfSSadaf Ebrahimi // TODO: Issue warning here? Already warned in ValidateImageBounds()...
4947*b7893ccfSSadaf Ebrahimi } else {
4948*b7893ccfSSadaf Ebrahimi // Calculate buffer offset of final copied byte, + 1.
4949*b7893ccfSSadaf Ebrahimi VkDeviceSize max_buffer_offset = (z_copies - 1) * buffer_height * buffer_width; // offset to slice
4950*b7893ccfSSadaf Ebrahimi max_buffer_offset += ((copy_extent.height - 1) * buffer_width) + copy_extent.width; // add row,col
4951*b7893ccfSSadaf Ebrahimi max_buffer_offset *= unit_size; // convert to bytes
4952*b7893ccfSSadaf Ebrahimi max_buffer_offset += pRegions[i].bufferOffset; // add initial offset (bytes)
4953*b7893ccfSSadaf Ebrahimi
4954*b7893ccfSSadaf Ebrahimi if (buffer_size < max_buffer_offset) {
4955*b7893ccfSSadaf Ebrahimi skip |=
4956*b7893ccfSSadaf Ebrahimi log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT, (uint64_t)0,
4957*b7893ccfSSadaf Ebrahimi msg_code, "%s: pRegion[%d] exceeds buffer size of %" PRIu64 " bytes..", func_name, i, buffer_size);
4958*b7893ccfSSadaf Ebrahimi }
4959*b7893ccfSSadaf Ebrahimi }
4960*b7893ccfSSadaf Ebrahimi }
4961*b7893ccfSSadaf Ebrahimi
4962*b7893ccfSSadaf Ebrahimi return skip;
4963*b7893ccfSSadaf Ebrahimi }
4964*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferImageCopy * pRegions)4965*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
4966*b7893ccfSSadaf Ebrahimi VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
4967*b7893ccfSSadaf Ebrahimi const auto cb_node = GetCBState(commandBuffer);
4968*b7893ccfSSadaf Ebrahimi const auto src_image_state = GetImageState(srcImage);
4969*b7893ccfSSadaf Ebrahimi const auto dst_buffer_state = GetBufferState(dstBuffer);
4970*b7893ccfSSadaf Ebrahimi
4971*b7893ccfSSadaf Ebrahimi bool skip = ValidateBufferImageCopyData(regionCount, pRegions, src_image_state, "vkCmdCopyImageToBuffer");
4972*b7893ccfSSadaf Ebrahimi
4973*b7893ccfSSadaf Ebrahimi // Validate command buffer state
4974*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_COPYIMAGETOBUFFER, "vkCmdCopyImageToBuffer()");
4975*b7893ccfSSadaf Ebrahimi
4976*b7893ccfSSadaf Ebrahimi // Command pool must support graphics, compute, or transfer operations
4977*b7893ccfSSadaf Ebrahimi const auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool);
4978*b7893ccfSSadaf Ebrahimi
4979*b7893ccfSSadaf Ebrahimi VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
4980*b7893ccfSSadaf Ebrahimi
4981*b7893ccfSSadaf Ebrahimi if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
4982*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
4983*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->createInfo.commandPool), "VUID-vkCmdCopyImageToBuffer-commandBuffer-cmdpool",
4984*b7893ccfSSadaf Ebrahimi "Cannot call vkCmdCopyImageToBuffer() on a command buffer allocated from a pool without graphics, compute, "
4985*b7893ccfSSadaf Ebrahimi "or transfer capabilities..");
4986*b7893ccfSSadaf Ebrahimi }
4987*b7893ccfSSadaf Ebrahimi skip |= ValidateImageBounds(report_data, src_image_state, regionCount, pRegions, "vkCmdCopyImageToBuffer()",
4988*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-pRegions-00182");
4989*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferBounds(report_data, src_image_state, dst_buffer_state, regionCount, pRegions, "vkCmdCopyImageToBuffer()",
4990*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-pRegions-00183");
4991*b7893ccfSSadaf Ebrahimi
4992*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSampleCount(src_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdCopyImageToBuffer(): srcImage",
4993*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-srcImage-00188");
4994*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(src_image_state, "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-srcImage-00187");
4995*b7893ccfSSadaf Ebrahimi skip |=
4996*b7893ccfSSadaf Ebrahimi ValidateMemoryIsBoundToBuffer(dst_buffer_state, "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-dstBuffer-00192");
4997*b7893ccfSSadaf Ebrahimi
4998*b7893ccfSSadaf Ebrahimi // Validate that SRC image & DST buffer have correct usage flags set
4999*b7893ccfSSadaf Ebrahimi skip |= ValidateImageUsageFlags(src_image_state, VK_IMAGE_USAGE_TRANSFER_SRC_BIT, true,
5000*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-srcImage-00186", "vkCmdCopyImageToBuffer()",
5001*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_TRANSFER_SRC_BIT");
5002*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferUsageFlags(dst_buffer_state, VK_BUFFER_USAGE_TRANSFER_DST_BIT, true,
5003*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-dstBuffer-00191", "vkCmdCopyImageToBuffer()",
5004*b7893ccfSSadaf Ebrahimi "VK_BUFFER_USAGE_TRANSFER_DST_BIT");
5005*b7893ccfSSadaf Ebrahimi if (api_version >= VK_API_VERSION_1_1 || device_extensions.vk_khr_maintenance1) {
5006*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(src_image_state, VK_FORMAT_FEATURE_TRANSFER_SRC_BIT, "vkCmdCopyImageToBuffer()",
5007*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-srcImage-01998",
5008*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-srcImage-01998");
5009*b7893ccfSSadaf Ebrahimi }
5010*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-renderpass");
5011*b7893ccfSSadaf Ebrahimi bool hit_error = false;
5012*b7893ccfSSadaf Ebrahimi const char *src_invalid_layout_vuid = (src_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
5013*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdCopyImageToBuffer-srcImageLayout-01397"
5014*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00190";
5015*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
5016*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSubresourceLayers(cb_node, &pRegions[i].imageSubresource, "vkCmdCopyImageToBuffer()",
5017*b7893ccfSSadaf Ebrahimi "imageSubresource", i);
5018*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, src_image_state, pRegions[i].imageSubresource, srcImageLayout,
5019*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, "vkCmdCopyImageToBuffer()", src_invalid_layout_vuid,
5020*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyImageToBuffer-srcImageLayout-00189", &hit_error);
5021*b7893ccfSSadaf Ebrahimi skip |= ValidateCopyBufferImageTransferGranularityRequirements(
5022*b7893ccfSSadaf Ebrahimi cb_node, src_image_state, &pRegions[i], i, "vkCmdCopyImageToBuffer()", "VUID-vkCmdCopyImageToBuffer-imageOffset-01794");
5023*b7893ccfSSadaf Ebrahimi skip |=
5024*b7893ccfSSadaf Ebrahimi ValidateImageMipLevel(cb_node, src_image_state, pRegions[i].imageSubresource.mipLevel, i, "vkCmdCopyImageToBuffer()",
5025*b7893ccfSSadaf Ebrahimi "imageSubresource", "VUID-vkCmdCopyImageToBuffer-imageSubresource-01703");
5026*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, src_image_state, pRegions[i].imageSubresource.baseArrayLayer,
5027*b7893ccfSSadaf Ebrahimi pRegions[i].imageSubresource.layerCount, i, "vkCmdCopyImageToBuffer()",
5028*b7893ccfSSadaf Ebrahimi "imageSubresource", "VUID-vkCmdCopyImageToBuffer-imageSubresource-01704");
5029*b7893ccfSSadaf Ebrahimi }
5030*b7893ccfSSadaf Ebrahimi return skip;
5031*b7893ccfSSadaf Ebrahimi }
5032*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferImageCopy * pRegions)5033*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage,
5034*b7893ccfSSadaf Ebrahimi VkImageLayout srcImageLayout, VkBuffer dstBuffer,
5035*b7893ccfSSadaf Ebrahimi uint32_t regionCount, const VkBufferImageCopy *pRegions) {
5036*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
5037*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
5038*b7893ccfSSadaf Ebrahimi auto dst_buffer_state = GetBufferState(dstBuffer);
5039*b7893ccfSSadaf Ebrahimi
5040*b7893ccfSSadaf Ebrahimi // Update bindings between buffer/image and cmd buffer
5041*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, src_image_state);
5042*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingBuffer(cb_node, dst_buffer_state);
5043*b7893ccfSSadaf Ebrahimi }
PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer,VkImage srcImage,VkImageLayout srcImageLayout,VkBuffer dstBuffer,uint32_t regionCount,const VkBufferImageCopy * pRegions)5044*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdCopyImageToBuffer(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout srcImageLayout,
5045*b7893ccfSSadaf Ebrahimi VkBuffer dstBuffer, uint32_t regionCount, const VkBufferImageCopy *pRegions) {
5046*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordCmdCopyImageToBuffer(commandBuffer, srcImage, srcImageLayout, dstBuffer, regionCount, pRegions);
5047*b7893ccfSSadaf Ebrahimi
5048*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
5049*b7893ccfSSadaf Ebrahimi auto src_image_state = GetImageState(srcImage);
5050*b7893ccfSSadaf Ebrahimi // Make sure that all image slices record referenced layout
5051*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
5052*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *src_image_state, pRegions[i].imageSubresource, srcImageLayout);
5053*b7893ccfSSadaf Ebrahimi }
5054*b7893ccfSSadaf Ebrahimi }
5055*b7893ccfSSadaf Ebrahimi
PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkBufferImageCopy * pRegions)5056*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
5057*b7893ccfSSadaf Ebrahimi VkImageLayout dstImageLayout, uint32_t regionCount,
5058*b7893ccfSSadaf Ebrahimi const VkBufferImageCopy *pRegions) {
5059*b7893ccfSSadaf Ebrahimi const auto cb_node = GetCBState(commandBuffer);
5060*b7893ccfSSadaf Ebrahimi const auto src_buffer_state = GetBufferState(srcBuffer);
5061*b7893ccfSSadaf Ebrahimi const auto dst_image_state = GetImageState(dstImage);
5062*b7893ccfSSadaf Ebrahimi
5063*b7893ccfSSadaf Ebrahimi bool skip = ValidateBufferImageCopyData(regionCount, pRegions, dst_image_state, "vkCmdCopyBufferToImage");
5064*b7893ccfSSadaf Ebrahimi
5065*b7893ccfSSadaf Ebrahimi // Validate command buffer state
5066*b7893ccfSSadaf Ebrahimi skip |= ValidateCmd(cb_node, CMD_COPYBUFFERTOIMAGE, "vkCmdCopyBufferToImage()");
5067*b7893ccfSSadaf Ebrahimi
5068*b7893ccfSSadaf Ebrahimi // Command pool must support graphics, compute, or transfer operations
5069*b7893ccfSSadaf Ebrahimi const auto pPool = GetCommandPoolState(cb_node->createInfo.commandPool);
5070*b7893ccfSSadaf Ebrahimi VkQueueFlags queue_flags = GetPhysicalDeviceState()->queue_family_properties[pPool->queueFamilyIndex].queueFlags;
5071*b7893ccfSSadaf Ebrahimi if (0 == (queue_flags & (VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_COMPUTE_BIT | VK_QUEUE_TRANSFER_BIT))) {
5072*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_COMMAND_BUFFER_EXT,
5073*b7893ccfSSadaf Ebrahimi HandleToUint64(cb_node->createInfo.commandPool), "VUID-vkCmdCopyBufferToImage-commandBuffer-cmdpool",
5074*b7893ccfSSadaf Ebrahimi "Cannot call vkCmdCopyBufferToImage() on a command buffer allocated from a pool without graphics, compute, "
5075*b7893ccfSSadaf Ebrahimi "or transfer capabilities..");
5076*b7893ccfSSadaf Ebrahimi }
5077*b7893ccfSSadaf Ebrahimi skip |= ValidateImageBounds(report_data, dst_image_state, regionCount, pRegions, "vkCmdCopyBufferToImage()",
5078*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-pRegions-00172");
5079*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferBounds(report_data, dst_image_state, src_buffer_state, regionCount, pRegions, "vkCmdCopyBufferToImage()",
5080*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-pRegions-00171");
5081*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSampleCount(dst_image_state, VK_SAMPLE_COUNT_1_BIT, "vkCmdCopyBufferToImage(): dstImage",
5082*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-dstImage-00179");
5083*b7893ccfSSadaf Ebrahimi skip |=
5084*b7893ccfSSadaf Ebrahimi ValidateMemoryIsBoundToBuffer(src_buffer_state, "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-srcBuffer-00176");
5085*b7893ccfSSadaf Ebrahimi skip |= ValidateMemoryIsBoundToImage(dst_image_state, "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-dstImage-00178");
5086*b7893ccfSSadaf Ebrahimi skip |= ValidateBufferUsageFlags(src_buffer_state, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, true,
5087*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-srcBuffer-00174", "vkCmdCopyBufferToImage()",
5088*b7893ccfSSadaf Ebrahimi "VK_BUFFER_USAGE_TRANSFER_SRC_BIT");
5089*b7893ccfSSadaf Ebrahimi skip |= ValidateImageUsageFlags(dst_image_state, VK_IMAGE_USAGE_TRANSFER_DST_BIT, true,
5090*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-dstImage-00177", "vkCmdCopyBufferToImage()",
5091*b7893ccfSSadaf Ebrahimi "VK_IMAGE_USAGE_TRANSFER_DST_BIT");
5092*b7893ccfSSadaf Ebrahimi if (api_version >= VK_API_VERSION_1_1 || device_extensions.vk_khr_maintenance1) {
5093*b7893ccfSSadaf Ebrahimi skip |= ValidateImageFormatFeatureFlags(dst_image_state, VK_FORMAT_FEATURE_TRANSFER_DST_BIT, "vkCmdCopyBufferToImage()",
5094*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-dstImage-01997",
5095*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-dstImage-01997");
5096*b7893ccfSSadaf Ebrahimi }
5097*b7893ccfSSadaf Ebrahimi skip |= InsideRenderPass(cb_node, "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-renderpass");
5098*b7893ccfSSadaf Ebrahimi bool hit_error = false;
5099*b7893ccfSSadaf Ebrahimi const char *dst_invalid_layout_vuid = (dst_image_state->shared_presentable && device_extensions.vk_khr_shared_presentable_image)
5100*b7893ccfSSadaf Ebrahimi ? "VUID-vkCmdCopyBufferToImage-dstImageLayout-01396"
5101*b7893ccfSSadaf Ebrahimi : "VUID-vkCmdCopyBufferToImage-dstImageLayout-00181";
5102*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
5103*b7893ccfSSadaf Ebrahimi skip |= ValidateImageSubresourceLayers(cb_node, &pRegions[i].imageSubresource, "vkCmdCopyBufferToImage()",
5104*b7893ccfSSadaf Ebrahimi "imageSubresource", i);
5105*b7893ccfSSadaf Ebrahimi skip |= VerifyImageLayout(cb_node, dst_image_state, pRegions[i].imageSubresource, dstImageLayout,
5106*b7893ccfSSadaf Ebrahimi VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, "vkCmdCopyBufferToImage()", dst_invalid_layout_vuid,
5107*b7893ccfSSadaf Ebrahimi "VUID-vkCmdCopyBufferToImage-dstImageLayout-00180", &hit_error);
5108*b7893ccfSSadaf Ebrahimi skip |= ValidateCopyBufferImageTransferGranularityRequirements(
5109*b7893ccfSSadaf Ebrahimi cb_node, dst_image_state, &pRegions[i], i, "vkCmdCopyBufferToImage()", "VUID-vkCmdCopyBufferToImage-imageOffset-01793");
5110*b7893ccfSSadaf Ebrahimi skip |=
5111*b7893ccfSSadaf Ebrahimi ValidateImageMipLevel(cb_node, dst_image_state, pRegions[i].imageSubresource.mipLevel, i, "vkCmdCopyBufferToImage()",
5112*b7893ccfSSadaf Ebrahimi "imageSubresource", "VUID-vkCmdCopyBufferToImage-imageSubresource-01701");
5113*b7893ccfSSadaf Ebrahimi skip |= ValidateImageArrayLayerRange(cb_node, dst_image_state, pRegions[i].imageSubresource.baseArrayLayer,
5114*b7893ccfSSadaf Ebrahimi pRegions[i].imageSubresource.layerCount, i, "vkCmdCopyBufferToImage()",
5115*b7893ccfSSadaf Ebrahimi "imageSubresource", "VUID-vkCmdCopyBufferToImage-imageSubresource-01702");
5116*b7893ccfSSadaf Ebrahimi }
5117*b7893ccfSSadaf Ebrahimi return skip;
5118*b7893ccfSSadaf Ebrahimi }
5119*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkBufferImageCopy * pRegions)5120*b7893ccfSSadaf Ebrahimi void ValidationStateTracker::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
5121*b7893ccfSSadaf Ebrahimi VkImageLayout dstImageLayout, uint32_t regionCount,
5122*b7893ccfSSadaf Ebrahimi const VkBufferImageCopy *pRegions) {
5123*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
5124*b7893ccfSSadaf Ebrahimi auto src_buffer_state = GetBufferState(srcBuffer);
5125*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
5126*b7893ccfSSadaf Ebrahimi
5127*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingBuffer(cb_node, src_buffer_state);
5128*b7893ccfSSadaf Ebrahimi AddCommandBufferBindingImage(cb_node, dst_image_state);
5129*b7893ccfSSadaf Ebrahimi }
5130*b7893ccfSSadaf Ebrahimi
PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer,VkBuffer srcBuffer,VkImage dstImage,VkImageLayout dstImageLayout,uint32_t regionCount,const VkBufferImageCopy * pRegions)5131*b7893ccfSSadaf Ebrahimi void CoreChecks::PreCallRecordCmdCopyBufferToImage(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkImage dstImage,
5132*b7893ccfSSadaf Ebrahimi VkImageLayout dstImageLayout, uint32_t regionCount,
5133*b7893ccfSSadaf Ebrahimi const VkBufferImageCopy *pRegions) {
5134*b7893ccfSSadaf Ebrahimi StateTracker::PreCallRecordCmdCopyBufferToImage(commandBuffer, srcBuffer, dstImage, dstImageLayout, regionCount, pRegions);
5135*b7893ccfSSadaf Ebrahimi
5136*b7893ccfSSadaf Ebrahimi auto cb_node = GetCBState(commandBuffer);
5137*b7893ccfSSadaf Ebrahimi auto dst_image_state = GetImageState(dstImage);
5138*b7893ccfSSadaf Ebrahimi // Make sure that all image slices are record referenced layout
5139*b7893ccfSSadaf Ebrahimi for (uint32_t i = 0; i < regionCount; ++i) {
5140*b7893ccfSSadaf Ebrahimi SetImageInitialLayout(cb_node, *dst_image_state, pRegions[i].imageSubresource, dstImageLayout);
5141*b7893ccfSSadaf Ebrahimi }
5142*b7893ccfSSadaf Ebrahimi }
5143*b7893ccfSSadaf Ebrahimi
PreCallValidateGetImageSubresourceLayout(VkDevice device,VkImage image,const VkImageSubresource * pSubresource,VkSubresourceLayout * pLayout)5144*b7893ccfSSadaf Ebrahimi bool CoreChecks::PreCallValidateGetImageSubresourceLayout(VkDevice device, VkImage image, const VkImageSubresource *pSubresource,
5145*b7893ccfSSadaf Ebrahimi VkSubresourceLayout *pLayout) {
5146*b7893ccfSSadaf Ebrahimi bool skip = false;
5147*b7893ccfSSadaf Ebrahimi const VkImageAspectFlags sub_aspect = pSubresource->aspectMask;
5148*b7893ccfSSadaf Ebrahimi
5149*b7893ccfSSadaf Ebrahimi // The aspectMask member of pSubresource must only have a single bit set
5150*b7893ccfSSadaf Ebrahimi const int num_bits = sizeof(sub_aspect) * CHAR_BIT;
5151*b7893ccfSSadaf Ebrahimi std::bitset<num_bits> aspect_mask_bits(sub_aspect);
5152*b7893ccfSSadaf Ebrahimi if (aspect_mask_bits.count() != 1) {
5153*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
5154*b7893ccfSSadaf Ebrahimi "VUID-vkGetImageSubresourceLayout-aspectMask-00997",
5155*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): VkImageSubresource.aspectMask must have exactly 1 bit set.");
5156*b7893ccfSSadaf Ebrahimi }
5157*b7893ccfSSadaf Ebrahimi
5158*b7893ccfSSadaf Ebrahimi const IMAGE_STATE *image_entry = GetImageState(image);
5159*b7893ccfSSadaf Ebrahimi if (!image_entry) {
5160*b7893ccfSSadaf Ebrahimi return skip;
5161*b7893ccfSSadaf Ebrahimi }
5162*b7893ccfSSadaf Ebrahimi
5163*b7893ccfSSadaf Ebrahimi // image must have been created with tiling equal to VK_IMAGE_TILING_LINEAR
5164*b7893ccfSSadaf Ebrahimi if (image_entry->createInfo.tiling != VK_IMAGE_TILING_LINEAR) {
5165*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
5166*b7893ccfSSadaf Ebrahimi "VUID-vkGetImageSubresourceLayout-image-00996",
5167*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): Image must have tiling of VK_IMAGE_TILING_LINEAR.");
5168*b7893ccfSSadaf Ebrahimi }
5169*b7893ccfSSadaf Ebrahimi
5170*b7893ccfSSadaf Ebrahimi // mipLevel must be less than the mipLevels specified in VkImageCreateInfo when the image was created
5171*b7893ccfSSadaf Ebrahimi if (pSubresource->mipLevel >= image_entry->createInfo.mipLevels) {
5172*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
5173*b7893ccfSSadaf Ebrahimi "VUID-vkGetImageSubresourceLayout-mipLevel-01716",
5174*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): pSubresource.mipLevel (%d) must be less than %d.", pSubresource->mipLevel,
5175*b7893ccfSSadaf Ebrahimi image_entry->createInfo.mipLevels);
5176*b7893ccfSSadaf Ebrahimi }
5177*b7893ccfSSadaf Ebrahimi
5178*b7893ccfSSadaf Ebrahimi // arrayLayer must be less than the arrayLayers specified in VkImageCreateInfo when the image was created
5179*b7893ccfSSadaf Ebrahimi if (pSubresource->arrayLayer >= image_entry->createInfo.arrayLayers) {
5180*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
5181*b7893ccfSSadaf Ebrahimi "VUID-vkGetImageSubresourceLayout-arrayLayer-01717",
5182*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): pSubresource.arrayLayer (%d) must be less than %d.",
5183*b7893ccfSSadaf Ebrahimi pSubresource->arrayLayer, image_entry->createInfo.arrayLayers);
5184*b7893ccfSSadaf Ebrahimi }
5185*b7893ccfSSadaf Ebrahimi
5186*b7893ccfSSadaf Ebrahimi // subresource's aspect must be compatible with image's format.
5187*b7893ccfSSadaf Ebrahimi const VkFormat img_format = image_entry->createInfo.format;
5188*b7893ccfSSadaf Ebrahimi if (FormatIsMultiplane(img_format)) {
5189*b7893ccfSSadaf Ebrahimi VkImageAspectFlags allowed_flags = (VK_IMAGE_ASPECT_PLANE_0_BIT_KHR | VK_IMAGE_ASPECT_PLANE_1_BIT_KHR);
5190*b7893ccfSSadaf Ebrahimi const char *vuid = "VUID-vkGetImageSubresourceLayout-format-01581"; // 2-plane version
5191*b7893ccfSSadaf Ebrahimi if (FormatPlaneCount(img_format) > 2u) {
5192*b7893ccfSSadaf Ebrahimi allowed_flags |= VK_IMAGE_ASPECT_PLANE_2_BIT_KHR;
5193*b7893ccfSSadaf Ebrahimi vuid = "VUID-vkGetImageSubresourceLayout-format-01582"; // 3-plane version
5194*b7893ccfSSadaf Ebrahimi }
5195*b7893ccfSSadaf Ebrahimi if (sub_aspect != (sub_aspect & allowed_flags)) {
5196*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
5197*b7893ccfSSadaf Ebrahimi HandleToUint64(image), vuid,
5198*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): For multi-planar images, VkImageSubresource.aspectMask (0x%" PRIx32
5199*b7893ccfSSadaf Ebrahimi ") must be a single-plane specifier flag.",
5200*b7893ccfSSadaf Ebrahimi sub_aspect);
5201*b7893ccfSSadaf Ebrahimi }
5202*b7893ccfSSadaf Ebrahimi } else if (FormatIsColor(img_format)) {
5203*b7893ccfSSadaf Ebrahimi if (sub_aspect != VK_IMAGE_ASPECT_COLOR_BIT) {
5204*b7893ccfSSadaf Ebrahimi skip |= log_msg(
5205*b7893ccfSSadaf Ebrahimi report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT, HandleToUint64(image),
5206*b7893ccfSSadaf Ebrahimi "VUID-VkImageSubresource-aspectMask-parameter",
5207*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): For color formats, VkImageSubresource.aspectMask must be VK_IMAGE_ASPECT_COLOR.");
5208*b7893ccfSSadaf Ebrahimi }
5209*b7893ccfSSadaf Ebrahimi } else if (FormatIsDepthOrStencil(img_format)) {
5210*b7893ccfSSadaf Ebrahimi if ((sub_aspect != VK_IMAGE_ASPECT_DEPTH_BIT) && (sub_aspect != VK_IMAGE_ASPECT_STENCIL_BIT)) {
5211*b7893ccfSSadaf Ebrahimi skip |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, VK_DEBUG_REPORT_OBJECT_TYPE_IMAGE_EXT,
5212*b7893ccfSSadaf Ebrahimi HandleToUint64(image), "VUID-VkImageSubresource-aspectMask-parameter",
5213*b7893ccfSSadaf Ebrahimi "vkGetImageSubresourceLayout(): For depth/stencil formats, VkImageSubresource.aspectMask must be "
5214*b7893ccfSSadaf Ebrahimi "either VK_IMAGE_ASPECT_DEPTH_BIT or VK_IMAGE_ASPECT_STENCIL_BIT.");
5215*b7893ccfSSadaf Ebrahimi }
5216*b7893ccfSSadaf Ebrahimi }
5217*b7893ccfSSadaf Ebrahimi
5218*b7893ccfSSadaf Ebrahimi if (device_extensions.vk_android_external_memory_android_hardware_buffer) {
5219*b7893ccfSSadaf Ebrahimi skip |= ValidateGetImageSubresourceLayoutANDROID(image);
5220*b7893ccfSSadaf Ebrahimi }
5221*b7893ccfSSadaf Ebrahimi
5222*b7893ccfSSadaf Ebrahimi return skip;
5223*b7893ccfSSadaf Ebrahimi }
5224