blob: a0c8813c033f87542d4c82cdba3e038d94603a4e [file] [log] [blame]
/* Copyright (c) 2015-2024 The Khronos Group Inc.
* Copyright (c) 2015-2024 Valve Corporation
* Copyright (c) 2015-2024 LunarG, Inc.
* Copyright (C) 2015-2024 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "stateless/stateless_validation.h"
bool StatelessValidation::manual_PreCallValidateCmdSetViewportWithCount(VkCommandBuffer commandBuffer, uint32_t viewportCount,
const VkViewport *pViewports,
const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.multiViewport) {
if (viewportCount != 1) {
skip |= LogError("VUID-vkCmdSetViewportWithCount-viewportCount-03395", commandBuffer,
error_obj.location.dot(Field::viewportCount),
"(%" PRIu32 ") is not 1, but the multiViewport feature is not enabled.", viewportCount);
}
} else { // multiViewport enabled
if (viewportCount < 1 || viewportCount > device_limits.maxViewports) {
skip |= LogError("VUID-vkCmdSetViewportWithCount-viewportCount-03394", commandBuffer,
error_obj.location.dot(Field::viewportCount),
"(%" PRIu32
") must "
"not be greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
viewportCount, device_limits.maxViewports);
}
}
if (pViewports) {
for (uint32_t viewport_i = 0; viewport_i < viewportCount; ++viewport_i) {
const auto &viewport = pViewports[viewport_i]; // will crash on invalid ptr
skip |= ValidateViewport(viewport, commandBuffer, error_obj.location.dot(Field::pViewports, viewport_i));
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetScissorWithCount(VkCommandBuffer commandBuffer, uint32_t scissorCount,
const VkRect2D *pScissors,
const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.multiViewport) {
if (scissorCount != 1) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-scissorCount-03398", commandBuffer,
error_obj.location.dot(Field::scissorCount),
"(%" PRIu32
") must "
"be 1 when the multiViewport feature is disabled.",
scissorCount);
}
} else { // multiViewport enabled
if (scissorCount == 0) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-scissorCount-03397", commandBuffer,
error_obj.location.dot(Field::scissorCount),
"(%" PRIu32
") must "
"be great than zero.",
scissorCount);
} else if (scissorCount > device_limits.maxViewports) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-scissorCount-03397", commandBuffer,
error_obj.location.dot(Field::scissorCount),
"(%" PRIu32
") must "
"not be greater than maxViewports (%" PRIu32 ").",
scissorCount, device_limits.maxViewports);
}
}
if (pScissors) {
for (uint32_t scissor_i = 0; scissor_i < scissorCount; ++scissor_i) {
const Location scissor_loc = error_obj.location.dot(Field::pScissors, scissor_i);
const auto &scissor = pScissors[scissor_i]; // will crash on invalid ptr
if (scissor.offset.x < 0) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-x-03399", commandBuffer,
scissor_loc.dot(Field::offset).dot(Field::x), "(%" PRId32 ") is negative.", scissor.offset.x);
}
if (scissor.offset.y < 0) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-x-03399", commandBuffer,
scissor_loc.dot(Field::offset).dot(Field::y), "(%" PRId32 ") is negative.", scissor.offset.y);
}
const int64_t x_sum = static_cast<int64_t>(scissor.offset.x) + static_cast<int64_t>(scissor.extent.width);
if (x_sum > vvl::kI32Max) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-offset-03400", commandBuffer, scissor_loc,
"offset.x (%" PRId32 ") + extent.width (%" PRIu32 ") is %" PRIi64 " which will overflow int32_t.",
scissor.offset.x, scissor.extent.width, x_sum);
}
const int64_t y_sum = static_cast<int64_t>(scissor.offset.y) + static_cast<int64_t>(scissor.extent.height);
if (y_sum > vvl::kI32Max) {
skip |= LogError("VUID-vkCmdSetScissorWithCount-offset-03401", commandBuffer, scissor_loc,
"offset.y (%" PRId32 ") + extent.height (%" PRIu32 ") is %" PRIi64 " which will overflow int32_t.",
scissor.offset.y, scissor.extent.height, y_sum);
}
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetVertexInputEXT(
VkCommandBuffer commandBuffer, uint32_t vertexBindingDescriptionCount,
const VkVertexInputBindingDescription2EXT *pVertexBindingDescriptions, uint32_t vertexAttributeDescriptionCount,
const VkVertexInputAttributeDescription2EXT *pVertexAttributeDescriptions, const ErrorObject &error_obj) const {
bool skip = false;
const auto *vertex_attribute_divisor_features =
vku::FindStructInPNextChain<VkPhysicalDeviceVertexAttributeDivisorFeaturesEXT>(device_createinfo_pnext);
if (vertexBindingDescriptionCount > device_limits.maxVertexInputBindings) {
skip |= LogError("VUID-vkCmdSetVertexInputEXT-vertexBindingDescriptionCount-04791", commandBuffer,
error_obj.location.dot(Field::vertexBindingDescriptionCount),
"(%" PRIu32 ") is greater than the maxVertexInputBindings limit (%" PRIu32 ").",
vertexBindingDescriptionCount, device_limits.maxVertexInputBindings);
}
if (vertexAttributeDescriptionCount > device_limits.maxVertexInputAttributes) {
skip |= LogError("VUID-vkCmdSetVertexInputEXT-vertexAttributeDescriptionCount-04792", commandBuffer,
error_obj.location.dot(Field::vertexAttributeDescriptionCount),
"(%" PRIu32 ") is greater than the maxVertexInputAttributes limit (%" PRIu32 ").",
vertexAttributeDescriptionCount, device_limits.maxVertexInputAttributes);
}
for (uint32_t attribute = 0; attribute < vertexAttributeDescriptionCount; ++attribute) {
bool binding_found = false;
for (uint32_t binding = 0; binding < vertexBindingDescriptionCount; ++binding) {
if (pVertexAttributeDescriptions[attribute].binding == pVertexBindingDescriptions[binding].binding) {
binding_found = true;
break;
}
}
if (!binding_found) {
skip |= LogError("VUID-vkCmdSetVertexInputEXT-binding-04793", commandBuffer,
error_obj.location.dot(Field::pVertexAttributeDescriptions, attribute),
"references an unspecified binding.");
}
}
// check for distinct values
{
vvl::unordered_set<uint32_t> vertex_bindings(vertexBindingDescriptionCount);
for (uint32_t i = 0; i < vertexBindingDescriptionCount; ++i) {
const uint32_t binding = pVertexBindingDescriptions[i].binding;
auto const &binding_it = vertex_bindings.find(binding);
if (binding_it != vertex_bindings.cend()) {
skip |= LogError("VUID-vkCmdSetVertexInputEXT-pVertexBindingDescriptions-04794", commandBuffer,
error_obj.location.dot(Field::pVertexBindingDescriptions, binding),
"is already in pVertexBindingDescriptions[%" PRIu32 "].", *binding_it);
break;
}
vertex_bindings.insert(binding);
}
vvl::unordered_set<uint32_t> vertex_locations(vertexAttributeDescriptionCount);
for (uint32_t i = 0; i < vertexAttributeDescriptionCount; ++i) {
const uint32_t location = pVertexAttributeDescriptions[i].location;
auto const &location_it = vertex_locations.find(location);
if (location_it != vertex_locations.cend()) {
skip |= LogError("VUID-vkCmdSetVertexInputEXT-pVertexAttributeDescriptions-04795", commandBuffer,
error_obj.location.dot(Field::pVertexAttributeDescriptions, location),
"is already in pVertexAttributeDescriptions[%" PRIu32 "].", *location_it);
break;
}
vertex_locations.insert(location);
}
}
for (uint32_t binding = 0; binding < vertexBindingDescriptionCount; ++binding) {
const Location binding_loc = error_obj.location.dot(Field::pVertexBindingDescriptions, binding);
if (pVertexBindingDescriptions[binding].binding > device_limits.maxVertexInputBindings) {
skip |= LogError("VUID-VkVertexInputBindingDescription2EXT-binding-04796", commandBuffer,
binding_loc.dot(Field::binding), "(%" PRIu32 ") is greater than maxVertexInputBindings (%" PRIu32 ").",
pVertexBindingDescriptions[binding].binding, device_limits.maxVertexInputBindings);
}
if (pVertexBindingDescriptions[binding].stride > device_limits.maxVertexInputBindingStride) {
skip |= LogError("VUID-VkVertexInputBindingDescription2EXT-stride-04797", commandBuffer, binding_loc.dot(Field::stride),
"(%" PRIu32 ") is greater than maxVertexInputBindingStride (%" PRIu32 ").",
pVertexBindingDescriptions[binding].stride, device_limits.maxVertexInputBindingStride);
}
if (pVertexBindingDescriptions[binding].divisor == 0 &&
(!vertex_attribute_divisor_features || !vertex_attribute_divisor_features->vertexAttributeInstanceRateZeroDivisor)) {
skip |=
LogError("VUID-VkVertexInputBindingDescription2EXT-divisor-04798", commandBuffer, binding_loc.dot(Field::divisor),
"is zero but "
"vertexAttributeInstanceRateZeroDivisor feature was not enabled");
}
if (pVertexBindingDescriptions[binding].divisor > 1) {
if (!vertex_attribute_divisor_features || !vertex_attribute_divisor_features->vertexAttributeInstanceRateDivisor) {
skip |= LogError("VUID-VkVertexInputBindingDescription2EXT-divisor-04799", commandBuffer,
binding_loc.dot(Field::divisor),
"is %" PRIu32
" (greater than 1) but "
"vertexAttributeInstanceRateDivisor feature was not enabled",
pVertexBindingDescriptions[binding].divisor);
} else {
if (pVertexBindingDescriptions[binding].divisor >
phys_dev_ext_props.vertex_attribute_divisor_props.maxVertexAttribDivisor) {
skip |= LogError("VUID-VkVertexInputBindingDescription2EXT-divisor-06226", commandBuffer,
binding_loc.dot(Field::divisor),
"(%" PRIu32 ") is greater than maxVertexAttribDivisor (%" PRIu32 ")",
pVertexBindingDescriptions[binding].divisor,
phys_dev_ext_props.vertex_attribute_divisor_props.maxVertexAttribDivisor);
}
if (pVertexBindingDescriptions[binding].inputRate != VK_VERTEX_INPUT_RATE_INSTANCE) {
skip |= LogError("VUID-VkVertexInputBindingDescription2EXT-divisor-06227", commandBuffer,
binding_loc.dot(Field::divisor), "is %" PRIu32 " (greater than 1) but inputRate is %s.",
pVertexBindingDescriptions[binding].divisor,
string_VkVertexInputRate(pVertexBindingDescriptions[binding].inputRate));
}
}
}
}
for (uint32_t attribute = 0; attribute < vertexAttributeDescriptionCount; ++attribute) {
const Location attribute_loc = error_obj.location.dot(Field::pVertexAttributeDescriptions, attribute);
if (pVertexAttributeDescriptions[attribute].location > device_limits.maxVertexInputAttributes) {
skip |= LogError("VUID-VkVertexInputAttributeDescription2EXT-location-06228", commandBuffer,
attribute_loc.dot(Field::location),
"(%" PRIu32 ") is greater than maxVertexInputAttributes (%" PRIu32 ").",
pVertexAttributeDescriptions[attribute].location, device_limits.maxVertexInputAttributes);
}
if (pVertexAttributeDescriptions[attribute].binding > device_limits.maxVertexInputBindings) {
skip |=
LogError("VUID-VkVertexInputAttributeDescription2EXT-binding-06229", commandBuffer,
attribute_loc.dot(Field::binding), "(%" PRIu32 ") is greater than maxVertexInputBindings (%" PRIu32 ").",
pVertexAttributeDescriptions[attribute].binding, device_limits.maxVertexInputBindings);
}
if (pVertexAttributeDescriptions[attribute].offset > device_limits.maxVertexInputAttributeOffset) {
skip |=
LogError("VUID-VkVertexInputAttributeDescription2EXT-offset-06230", commandBuffer, attribute_loc.dot(Field::offset),
"(%" PRIu32 ") is greater than maxVertexInputAttributeOffset (%" PRIu32 ").",
pVertexAttributeDescriptions[attribute].offset, device_limits.maxVertexInputAttributeOffset);
}
VkFormatProperties properties;
DispatchGetPhysicalDeviceFormatProperties(physical_device, pVertexAttributeDescriptions[attribute].format, &properties);
if ((properties.bufferFeatures & VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT) == 0) {
skip |=
LogError("VUID-VkVertexInputAttributeDescription2EXT-format-04805", commandBuffer, attribute_loc.dot(Field::format),
"(%s) is not a "
"VK_FORMAT_FEATURE_VERTEX_BUFFER_BIT supported format. (supported bufferFeatures: %s)",
string_VkFormat(pVertexAttributeDescriptions[attribute].format),
string_VkFormatFeatureFlags2(properties.bufferFeatures).c_str());
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetDiscardRectangleEXT(VkCommandBuffer commandBuffer,
uint32_t firstDiscardRectangle,
uint32_t discardRectangleCount,
const VkRect2D *pDiscardRectangles,
const ErrorObject &error_obj) const {
bool skip = false;
if (!pDiscardRectangles) {
return skip;
}
for (uint32_t i = 0; i < discardRectangleCount; ++i) {
const Location loc = error_obj.location.dot(Field::pDiscardRectangles, i);
const int64_t x_sum =
static_cast<int64_t>(pDiscardRectangles[i].offset.x) + static_cast<int64_t>(pDiscardRectangles[i].extent.width);
if (x_sum > std::numeric_limits<int32_t>::max()) {
skip |= LogError("VUID-vkCmdSetDiscardRectangleEXT-offset-00588", commandBuffer, loc,
"offset.x (%" PRId32 ") + extent.width (%" PRIu32 ") is %" PRIi64 ") which will overflow int32_t.",
pDiscardRectangles[i].offset.x, pDiscardRectangles[i].extent.width, x_sum);
}
const int64_t y_sum =
static_cast<int64_t>(pDiscardRectangles[i].offset.y) + static_cast<int64_t>(pDiscardRectangles[i].extent.height);
if (y_sum > std::numeric_limits<int32_t>::max()) {
skip |= LogError("VUID-vkCmdSetDiscardRectangleEXT-offset-00589", commandBuffer, loc,
"offset.y (%" PRId32 ") + extent.height (%" PRIu32 ") is %" PRIi64 ") which will overflow int32_t.",
pDiscardRectangles[i].offset.y, pDiscardRectangles[i].extent.height, y_sum);
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetDiscardRectangleEnableEXT(VkCommandBuffer commandBuffer,
VkBool32 discardRectangleEnable,
const ErrorObject &error_obj) const {
bool skip = false;
if (discard_rectangles_extension_version < 2) {
skip |= LogError("VUID-vkCmdSetDiscardRectangleEnableEXT-specVersion-07851", commandBuffer, error_obj.location,
"Requires support for version 2 of VK_EXT_discard_rectangles.");
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetDiscardRectangleModeEXT(VkCommandBuffer commandBuffer,
VkDiscardRectangleModeEXT discardRectangleMode,
const ErrorObject &error_obj) const {
bool skip = false;
if (discard_rectangles_extension_version < 2) {
skip |= LogError("VUID-vkCmdSetDiscardRectangleModeEXT-specVersion-07852", commandBuffer, error_obj.location,
"Requires support for version 2 of VK_EXT_discard_rectangles.");
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetExclusiveScissorEnableNV(VkCommandBuffer commandBuffer,
uint32_t firstExclusiveScissor,
uint32_t exclusiveScissorCount,
const VkBool32 *pExclusiveScissorEnables,
const ErrorObject &error_obj) const {
bool skip = false;
if (scissor_exclusive_extension_version < 2) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorEnableNV-exclusiveScissor-07853", commandBuffer, error_obj.location,
"Requires support for version 2 of VK_NV_scissor_exclusive.");
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetExclusiveScissorNV(VkCommandBuffer commandBuffer,
uint32_t firstExclusiveScissor,
uint32_t exclusiveScissorCount,
const VkRect2D *pExclusiveScissors,
const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.multiViewport) {
if (firstExclusiveScissor != 0) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02035", commandBuffer,
error_obj.location.dot(Field::firstExclusiveScissor),
"is %" PRIu32 " but the multiViewport feature is not enabled.", firstExclusiveScissor);
}
if (exclusiveScissorCount > 1) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-exclusiveScissorCount-02036", commandBuffer,
error_obj.location.dot(Field::exclusiveScissorCount),
"is %" PRIu32 " but the multiViewport feature is not enabled.", exclusiveScissorCount);
}
} else { // multiViewport enabled
const uint64_t sum = static_cast<uint64_t>(firstExclusiveScissor) + static_cast<uint64_t>(exclusiveScissorCount);
if (sum > device_limits.maxViewports) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-firstExclusiveScissor-02034", commandBuffer, error_obj.location,
"firstExclusiveScissor + exclusiveScissorCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
firstExclusiveScissor, exclusiveScissorCount, sum, device_limits.maxViewports);
}
}
if (pExclusiveScissors) {
for (uint32_t scissor_i = 0; scissor_i < exclusiveScissorCount; ++scissor_i) {
const Location scissor_loc = error_obj.location.dot(Field::pExclusiveScissors, scissor_i);
const auto &scissor = pExclusiveScissors[scissor_i]; // will crash on invalid ptr
if (scissor.offset.x < 0) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-x-02037", commandBuffer,
scissor_loc.dot(Field::offset).dot(Field::x), "(%" PRId32 ") is negative.", scissor.offset.x);
}
if (scissor.offset.y < 0) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-x-02037", commandBuffer,
scissor_loc.dot(Field::offset).dot(Field::y), "(%" PRId32 ") is negative.", scissor.offset.y);
}
const int64_t x_sum = static_cast<int64_t>(scissor.offset.x) + static_cast<int64_t>(scissor.extent.width);
if (x_sum > vvl::kI32Max) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-offset-02038", commandBuffer, scissor_loc,
"offset.x (%" PRId32 ") + extent.width (%" PRIu32 ") is %" PRIi64 " which will overflow int32_t.",
scissor.offset.x, scissor.extent.width, x_sum);
}
const int64_t y_sum = static_cast<int64_t>(scissor.offset.y) + static_cast<int64_t>(scissor.extent.height);
if (y_sum > vvl::kI32Max) {
skip |= LogError("VUID-vkCmdSetExclusiveScissorNV-offset-02039", commandBuffer, scissor_loc,
"offset.y (%" PRId32 ") + extent.height (%" PRIu32 ") is %" PRIi64 " which will overflow int32_t.",
scissor.offset.y, scissor.extent.height, y_sum);
}
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetViewportWScalingNV(VkCommandBuffer commandBuffer, uint32_t firstViewport,
uint32_t viewportCount,
const VkViewportWScalingNV *pViewportWScalings,
const ErrorObject &error_obj) const {
bool skip = false;
const uint64_t sum = static_cast<uint64_t>(firstViewport) + static_cast<uint64_t>(viewportCount);
if ((sum < 1) || (sum > device_limits.maxViewports)) {
skip |= LogError("VUID-vkCmdSetViewportWScalingNV-firstViewport-01324", commandBuffer, error_obj.location,
"firstViewport + viewportCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
") must be between 1 and VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 "), inculsive.",
firstViewport, viewportCount, sum, device_limits.maxViewports);
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetViewportShadingRatePaletteNV(
VkCommandBuffer commandBuffer, uint32_t firstViewport, uint32_t viewportCount,
const VkShadingRatePaletteNV *pShadingRatePalettes, const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.multiViewport) {
if (firstViewport != 0) {
skip |= LogError("VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02068", commandBuffer,
error_obj.location.dot(Field::firstViewport),
"is %" PRIu32 " but the multiViewport feature was not enabled.", firstViewport);
}
if (viewportCount > 1) {
skip |= LogError("VUID-vkCmdSetViewportShadingRatePaletteNV-viewportCount-02069", commandBuffer,
error_obj.location.dot(Field::viewportCount),
"is %" PRIu32 " but the multiViewport feature was not enabled.", viewportCount);
}
}
const uint64_t sum = static_cast<uint64_t>(firstViewport) + static_cast<uint64_t>(viewportCount);
if (sum > device_limits.maxViewports) {
skip |= LogError("VUID-vkCmdSetViewportShadingRatePaletteNV-firstViewport-02067", commandBuffer, error_obj.location,
"firstViewport + viewportCount (=%" PRIu32 " + %" PRIu32 " = %" PRIu64
") is greater than VkPhysicalDeviceLimits::maxViewports (=%" PRIu32 ").",
firstViewport, viewportCount, sum, device_limits.maxViewports);
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetCoarseSampleOrderNV(VkCommandBuffer commandBuffer,
VkCoarseSampleOrderTypeNV sampleOrderType,
uint32_t customSampleOrderCount,
const VkCoarseSampleOrderCustomNV *pCustomSampleOrders,
const ErrorObject &error_obj) const {
bool skip = false;
if (sampleOrderType != VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV && customSampleOrderCount != 0) {
skip |= LogError("VUID-vkCmdSetCoarseSampleOrderNV-sampleOrderType-02081", commandBuffer, error_obj.location,
"If sampleOrderType is not VK_COARSE_SAMPLE_ORDER_TYPE_CUSTOM_NV, "
"customSampleOrderCount must be 0.");
}
for (uint32_t order_i = 0; order_i < customSampleOrderCount; ++order_i) {
skip |= ValidateCoarseSampleOrderCustomNV(&pCustomSampleOrders[order_i],
error_obj.location.dot(Field::pCustomSampleOrders, order_i));
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetViewport(VkCommandBuffer commandBuffer, uint32_t firstViewport,
uint32_t viewportCount, const VkViewport *pViewports,
const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.multiViewport) {
if (firstViewport != 0) {
skip |=
LogError("VUID-vkCmdSetViewport-firstViewport-01224", commandBuffer, error_obj.location.dot(Field::firstViewport),
"is %" PRIu32 " but the multiViewport feature was not enabled.", firstViewport);
}
if (viewportCount > 1) {
skip |=
LogError("VUID-vkCmdSetViewport-viewportCount-01225", commandBuffer, error_obj.location.dot(Field::viewportCount),
"is %" PRIu32 " but the multiViewport feature was not enabled.", viewportCount);
}
} else { // multiViewport enabled
const uint64_t sum = static_cast<uint64_t>(firstViewport) + static_cast<uint64_t>(viewportCount);
if (sum > device_limits.maxViewports) {
skip |= LogError("VUID-vkCmdSetViewport-firstViewport-01223", commandBuffer, error_obj.location,
"firstViewport (%" PRIu32 ") + viewportCount (%" PRIu32 ") is %" PRIu64
" which is greater than maxViewports (%" PRIu32 ").",
firstViewport, viewportCount, sum, device_limits.maxViewports);
}
}
if (pViewports) {
for (uint32_t viewport_i = 0; viewport_i < viewportCount; ++viewport_i) {
const auto &viewport = pViewports[viewport_i]; // will crash on invalid ptr
skip |= ValidateViewport(viewport, commandBuffer, error_obj.location.dot(Field::pViewports, viewport_i));
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetScissor(VkCommandBuffer commandBuffer, uint32_t firstScissor,
uint32_t scissorCount, const VkRect2D *pScissors,
const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.multiViewport) {
if (firstScissor != 0) {
skip |= LogError("VUID-vkCmdSetScissor-firstScissor-00593", commandBuffer, error_obj.location.dot(Field::firstScissor),
"is %" PRIu32 " but the multiViewport feature was not enabled.", firstScissor);
}
if (scissorCount > 1) {
skip |= LogError("VUID-vkCmdSetScissor-scissorCount-00594", commandBuffer, error_obj.location.dot(Field::scissorCount),
"is %" PRIu32 " but the multiViewport feature was not enabled.", scissorCount);
}
} else { // multiViewport enabled
const uint64_t sum = static_cast<uint64_t>(firstScissor) + static_cast<uint64_t>(scissorCount);
if (sum > device_limits.maxViewports) {
skip |= LogError("VUID-vkCmdSetScissor-firstScissor-00592", commandBuffer, error_obj.location,
"firstScissor (%" PRIu32 ") + scissorCount (%" PRIu32 ") is %" PRIu64
" which is greater than maxViewports (%" PRIu32 ").",
firstScissor, scissorCount, sum, device_limits.maxViewports);
}
}
if (pScissors) {
for (uint32_t scissor_i = 0; scissor_i < scissorCount; ++scissor_i) {
const Location scissor_loc = error_obj.location.dot(Field::pScissors, scissor_i);
const auto &scissor = pScissors[scissor_i]; // will crash on invalid ptr
if (scissor.offset.x < 0) {
skip |= LogError("VUID-vkCmdSetScissor-x-00595", commandBuffer, scissor_loc.dot(Field::offset).dot(Field::x),
"(%" PRId32 ") is negative.", scissor.offset.x);
}
if (scissor.offset.y < 0) {
skip |= LogError("VUID-vkCmdSetScissor-x-00595", commandBuffer, scissor_loc.dot(Field::offset).dot(Field::y),
"(%" PRId32 ") is negative.", scissor.offset.y);
}
const int64_t x_sum = static_cast<int64_t>(scissor.offset.x) + static_cast<int64_t>(scissor.extent.width);
if (x_sum > vvl::kI32Max) {
skip |= LogError("VUID-vkCmdSetScissor-offset-00596", commandBuffer, scissor_loc,
"offset.x (%" PRId32 ") + extent.width (%" PRIu32 ") is %" PRIi64 " which will overflow int32_t.",
scissor.offset.x, scissor.extent.width, x_sum);
}
const int64_t y_sum = static_cast<int64_t>(scissor.offset.y) + static_cast<int64_t>(scissor.extent.height);
if (y_sum > vvl::kI32Max) {
skip |= LogError("VUID-vkCmdSetScissor-offset-00597", commandBuffer, scissor_loc,
"offset.y (%" PRId32 ") + extent.height (%" PRIu32 ") is %" PRIi64 " which will overflow int32_t.",
scissor.offset.y, scissor.extent.height, y_sum);
}
}
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetLineWidth(VkCommandBuffer commandBuffer, float lineWidth,
const ErrorObject &error_obj) const {
bool skip = false;
if (!physical_device_features.wideLines && (lineWidth != 1.0f)) {
skip |= LogError("VUID-vkCmdSetLineWidth-lineWidth-00788", commandBuffer, error_obj.location.dot(Field::lineWidth),
"is %f (not 1.0), but wideLines was not enabled.", lineWidth);
}
return skip;
}
bool StatelessValidation::manual_PreCallValidateCmdSetLineStippleKHR(VkCommandBuffer commandBuffer, uint32_t lineStippleFactor,
uint16_t lineStipplePattern,
const ErrorObject &error_obj) const {
bool skip = false;
if (lineStippleFactor < 1 || lineStippleFactor > 256) {
skip |= LogError("VUID-vkCmdSetLineStippleEXT-lineStippleFactor-02776", commandBuffer,
error_obj.location.dot(Field::lineStippleFactor), "%" PRIu32 " is not in [1,256].", lineStippleFactor);
}
return skip;
}