Home | History | Annotate | Download | only in layers
      1 /* Copyright (c) 2015-2016 The Khronos Group Inc.
      2  * Copyright (c) 2015-2016 Valve Corporation
      3  * Copyright (c) 2015-2016 LunarG, Inc.
      4  * Copyright (C) 2015-2016 Google Inc.
      5  *
      6  * Permission is hereby granted, free of charge, to any person obtaining a copy
      7  * of this software and/or associated documentation files (the "Materials"), to
      8  * deal in the Materials without restriction, including without limitation the
      9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
     10  * sell copies of the Materials, and to permit persons to whom the Materials
     11  * are furnished to do so, subject to the following conditions:
     12  *
     13  * The above copyright notice(s) and this permission notice shall be included
     14  * in all copies or substantial portions of the Materials.
     15  *
     16  * The Materials are Confidential Information as defined by the Khronos
     17  * Membership Agreement until designated non-confidential by Khronos, at which
     18  * point this condition clause shall be removed.
     19  *
     20  * THE MATERIALS ARE PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     21  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     22  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23  *
     24  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
     25  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
     26  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE MATERIALS OR THE
     27  * USE OR OTHER DEALINGS IN THE MATERIALS
     28  *
     29  * Author: Dustin Graves <dustin (at) lunarg.com>
     30  */
     31 
     32 #ifndef PARAMETER_VALIDATION_UTILS_H
     33 #define PARAMETER_VALIDATION_UTILS_H
     34 
     35 #include <algorithm>
     36 #include <string>
     37 
     38 #include "vulkan/vulkan.h"
     39 #include "vk_enum_string_helper.h"
     40 #include "vk_layer_logging.h"
     41 
     42 namespace {
     43 struct GenericHeader {
     44     VkStructureType sType;
     45     const void *pNext;
     46 };
     47 }
     48 
     49 // String returned by string_VkStructureType for an unrecognized type
     50 const std::string UnsupportedStructureTypeString = "Unhandled VkStructureType";
     51 
     52 /**
     53  * Validate a required pointer.
     54  *
     55  * Verify that a required pointer is not NULL.
     56  *
     57  * @param report_data debug_report_data object for routing validation messages.
     58  * @param apiName Name of API call being validated.
     59  * @param parameterName Name of parameter being validated.
     60  * @param value Pointer to validate.
     61  * @return Boolean value indicating that the call should be skipped.
     62  */
     63 static VkBool32 validate_required_pointer(debug_report_data *report_data, const char *apiName, const char *parameterName,
     64                                           const void *value) {
     65     VkBool32 skipCall = VK_FALSE;
     66 
     67     if (value == NULL) {
     68         skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK",
     69                             "%s: required parameter %s specified as NULL", apiName, parameterName);
     70     }
     71 
     72     return skipCall;
     73 }
     74 
     75 /**
     76  * Validate pointer to array count and pointer to array.
     77  *
     78  * Verify that required count and array parameters are not NULL.  If count
     79  * is not NULL and its value is not optional, verify that it is not 0.  If the
     80  * array parameter is NULL, and it is not optional, verify that count is 0.
     81  * The array parameter will typically be optional for this case (where count is
     82  * a pointer), allowing the caller to retrieve the available count.
     83  *
     84  * @param report_data debug_report_data object for routing validation messages.
     85  * @param apiName Name of API call being validated.
     86  * @param countName Name of count parameter.
     87  * @param arrayName Name of array parameter.
     88  * @param count Pointer to the number of elements in the array.
     89  * @param array Array to validate.
     90  * @param countPtrRequired The 'count' parameter may not be NULL when true.
     91  * @param countValueRequired The '*count' value may not be 0 when true.
     92  * @param arrayRequired The 'array' parameter may not be NULL when true.
     93  * @return Boolean value indicating that the call should be skipped.
     94  */
     95 template <typename T>
     96 VkBool32 validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName,
     97                         const T *count, const void *array, VkBool32 countPtrRequired, VkBool32 countValueRequired,
     98                         VkBool32 arrayRequired) {
     99     VkBool32 skipCall = VK_FALSE;
    100 
    101     if (count == NULL) {
    102         if (countPtrRequired == VK_TRUE) {
    103             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    104                                 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, countName);
    105         }
    106     } else {
    107         skipCall |= validate_array(report_data, apiName, countName, arrayName, (*count), array, countValueRequired, arrayRequired);
    108     }
    109 
    110     return skipCall;
    111 }
    112 
    113 /**
    114  * Validate array count and pointer to array.
    115  *
    116  * Verify that required count and array parameters are not 0 or NULL.  If the
    117  * count parameter is not optional, verify that it is not 0.  If the array
    118  * parameter is NULL, and it is not optional, verify that count is 0.
    119  *
    120  * @param report_data debug_report_data object for routing validation messages.
    121  * @param apiName Name of API call being validated.
    122  * @param countName Name of count parameter.
    123  * @param arrayName Name of array parameter.
    124  * @param count Number of elements in the array.
    125  * @param array Array to validate.
    126  * @param countRequired The 'count' parameter may not be 0 when true.
    127  * @param arrayRequired The 'array' parameter may not be NULL when true.
    128  * @return Boolean value indicating that the call should be skipped.
    129  */
    130 template <typename T>
    131 VkBool32 validate_array(debug_report_data *report_data, const char *apiName, const char *countName, const char *arrayName, T count,
    132                         const void *array, VkBool32 countRequired, VkBool32 arrayRequired) {
    133     VkBool32 skipCall = VK_FALSE;
    134 
    135     // Count parameters not tagged as optional cannot be 0
    136     if ((count == 0) && (countRequired == VK_TRUE)) {
    137         skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK",
    138                             "%s: value of %s must be greater than 0", apiName, countName);
    139     }
    140 
    141     // Array parameters not tagged as optional cannot be NULL,
    142     // unless the count is 0
    143     if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) {
    144         skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK",
    145                             "%s: required parameter %s specified as NULL", apiName, arrayName);
    146     }
    147 
    148     return skipCall;
    149 }
    150 
    151 /**
    152  * Validate an Vulkan structure type.
    153  *
    154  * @param report_data debug_report_data object for routing validation messages.
    155  * @param apiName Name of API call being validated.
    156  * @param parameterName Name of struct parameter being validated.
    157  * @param sTypeName Name of expected VkStructureType value.
    158  * @param value Pointer to the struct to validate.
    159  * @param sType VkStructureType for structure validation.
    160  * @param required The parameter may not be NULL when true.
    161  * @return Boolean value indicating that the call should be skipped.
    162  */
    163 template <typename T>
    164 VkBool32 validate_struct_type(debug_report_data *report_data, const char *apiName, const char *parameterName, const char *sTypeName,
    165                               const T *value, VkStructureType sType, VkBool32 required) {
    166     VkBool32 skipCall = VK_FALSE;
    167 
    168     if (value == NULL) {
    169         if (required == VK_TRUE) {
    170             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    171                                 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, parameterName);
    172         }
    173     } else if (value->sType != sType) {
    174         skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK",
    175                             "%s: parameter %s->sType must be %s", apiName, parameterName, sTypeName);
    176     }
    177 
    178     return skipCall;
    179 }
    180 
    181 /**
    182  * Validate an array of Vulkan structures.
    183  *
    184  * Verify that required count and array parameters are not NULL.  If count
    185  * is not NULL and its value is not optional, verify that it is not 0.
    186  * If the array contains 1 or more structures, verify that each structure's
    187  * sType field is set to the correct VkStructureType value.
    188  *
    189  * @param report_data debug_report_data object for routing validation messages.
    190  * @param apiName Name of API call being validated.
    191  * @param countName Name of count parameter.
    192  * @param arrayName Name of array parameter.
    193  * @param sTypeName Name of expected VkStructureType value.
    194  * @param count Pointer to the number of elements in the array.
    195  * @param array Array to validate.
    196  * @param sType VkStructureType for structure validation.
    197  * @param countPtrRequired The 'count' parameter may not be NULL when true.
    198  * @param countValueRequired The '*count' value may not be 0 when true.
    199  * @param arrayRequired The 'array' parameter may not be NULL when true.
    200  * @return Boolean value indicating that the call should be skipped.
    201  */
    202 template <typename T>
    203 VkBool32 validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName,
    204                                     const char *arrayName, const char *sTypeName, const uint32_t *count, const T *array,
    205                                     VkStructureType sType, VkBool32 countPtrRequired, VkBool32 countValueRequired,
    206                                     VkBool32 arrayRequired) {
    207     VkBool32 skipCall = VK_FALSE;
    208 
    209     if (count == NULL) {
    210         if (countPtrRequired == VK_TRUE) {
    211             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    212                                 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, countName);
    213         }
    214     } else {
    215         skipCall |= validate_struct_type_array(report_data, apiName, countName, arrayName, sTypeName, (*count), array, sType,
    216                                                countValueRequired, arrayRequired);
    217     }
    218 
    219     return skipCall;
    220 }
    221 
    222 /**
    223  * Validate an array of Vulkan structures
    224  *
    225  * Verify that required count and array parameters are not 0 or NULL.  If
    226  * the array contains 1 or more structures, verify that each structure's
    227  * sType field is set to the correct VkStructureType value.
    228  *
    229  * @param report_data debug_report_data object for routing validation messages.
    230  * @param apiName Name of API call being validated.
    231  * @param countName Name of count parameter.
    232  * @param arrayName Name of array parameter.
    233  * @param sTypeName Name of expected VkStructureType value.
    234  * @param count Number of elements in the array.
    235  * @param array Array to validate.
    236  * @param sType VkStructureType for structure validation.
    237  * @param countRequired The 'count' parameter may not be 0 when true.
    238  * @param arrayRequired The 'array' parameter may not be NULL when true.
    239  * @return Boolean value indicating that the call should be skipped.
    240  */
    241 template <typename T>
    242 VkBool32 validate_struct_type_array(debug_report_data *report_data, const char *apiName, const char *countName,
    243                                     const char *arrayName, const char *sTypeName, uint32_t count, const T *array,
    244                                     VkStructureType sType, VkBool32 countRequired, VkBool32 arrayRequired) {
    245     VkBool32 skipCall = VK_FALSE;
    246 
    247     if ((count == 0) || (array == NULL)) {
    248         // Count parameters not tagged as optional cannot be 0
    249         if ((count == 0) && (countRequired == VK_TRUE)) {
    250             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    251                                 "PARAMCHECK", "%s: parameter %s must be greater than 0", apiName, countName);
    252         }
    253 
    254         // Array parameters not tagged as optional cannot be NULL,
    255         // unless the count is 0
    256         if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) {
    257             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    258                                 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, arrayName);
    259         }
    260     } else {
    261         // Verify that all structs in the array have the correct type
    262         for (uint32_t i = 0; i < count; ++i) {
    263             if (array[i].sType != sType) {
    264                 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    265                                     "PARAMCHECK", "%s: parameter %s[%d].sType must be %s", apiName, arrayName, i, sTypeName);
    266             }
    267         }
    268     }
    269 
    270     return skipCall;
    271 }
    272 
    273 /**
    274  * Validate string array count and content.
    275  *
    276  * Verify that required count and array parameters are not 0 or NULL.  If the
    277  * count parameter is not optional, verify that it is not 0.  If the array
    278  * parameter is NULL, and it is not optional, verify that count is 0.  If the
    279  * array parameter is not NULL, verify that none of the strings are NULL.
    280  *
    281  * @param report_data debug_report_data object for routing validation messages.
    282  * @param apiName Name of API call being validated.
    283  * @param countName Name of count parameter.
    284  * @param arrayName Name of array parameter.
    285  * @param count Number of strings in the array.
    286  * @param array Array of strings to validate.
    287  * @param countRequired The 'count' parameter may not be 0 when true.
    288  * @param arrayRequired The 'array' parameter may not be NULL when true.
    289  * @return Boolean value indicating that the call should be skipped.
    290  */
    291 static VkBool32 validate_string_array(debug_report_data *report_data, const char *apiName, const char *countName,
    292                                       const char *arrayName, uint32_t count, const char *const *array, VkBool32 countRequired,
    293                                       VkBool32 arrayRequired) {
    294     VkBool32 skipCall = VK_FALSE;
    295 
    296     if ((count == 0) || (array == NULL)) {
    297         // Count parameters not tagged as optional cannot be 0
    298         if ((count == 0) && (countRequired == VK_TRUE)) {
    299             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    300                                 "PARAMCHECK", "%s: parameter %s must be greater than 0", apiName, countName);
    301         }
    302 
    303         // Array parameters not tagged as optional cannot be NULL,
    304         // unless the count is 0
    305         if ((array == NULL) && (arrayRequired == VK_TRUE) && (count != 0)) {
    306             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    307                                 "PARAMCHECK", "%s: required parameter %s specified as NULL", apiName, arrayName);
    308         }
    309     } else {
    310         // Verify that strings in the array not NULL
    311         for (uint32_t i = 0; i < count; ++i) {
    312             if (array[i] == NULL) {
    313                 skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    314                                     "PARAMCHECK", "%s: required parameter %s[%d] specified as NULL", apiName, arrayName, i);
    315             }
    316         }
    317     }
    318 
    319     return skipCall;
    320 }
    321 
    322 /**
    323  * Validate a structure's pNext member.
    324  *
    325  * Verify that the specified pNext value points to the head of a list of
    326  * allowed extension structures.  If no extension structures are allowed,
    327  * verify that pNext is null.
    328  *
    329  * @param report_data debug_report_data object for routing validation messages.
    330  * @param apiName Name of API call being validated.
    331  * @param parameterName Name of parameter being validated.
    332  * @param allowedStructNames Names of allowed structs.
    333  * @param next Pointer to validate.
    334  * @param allowedTypeCount total number of allowed structure types.
    335  * @param allowedTypes array of strcuture types allowed for pNext.
    336  * @return Boolean value indicating that the call should be skipped.
    337  */
    338 static VkBool32 validate_struct_pnext(debug_report_data *report_data, const char *apiName, const char *parameterName,
    339                                       const char *allowedStructNames, const void *next, size_t allowedTypeCount,
    340                                       const VkStructureType *allowedTypes) {
    341     VkBool32 skipCall = VK_FALSE;
    342 
    343     if (next != NULL) {
    344         if (allowedTypeCount == 0) {
    345             skipCall |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1,
    346                                 "PARAMCHECK", "%s: value of %s must be NULL", apiName, parameterName);
    347         } else {
    348             const VkStructureType *start = allowedTypes;
    349             const VkStructureType *end = allowedTypes + allowedTypeCount;
    350             const GenericHeader *current = reinterpret_cast<const GenericHeader *>(next);
    351 
    352             while (current != NULL) {
    353                 if (std::find(start, end, current->sType) == end) {
    354                     std::string typeName = string_VkStructureType(current->sType);
    355 
    356                     if (typeName == UnsupportedStructureTypeString) {
    357                         skipCall |= log_msg(
    358                             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK",
    359                             "%s: %s chain includes a structure with unexpected VkStructureType (%d); Allowed structures are [%s]",
    360                             apiName, parameterName, current->sType, allowedStructNames);
    361                     } else {
    362                         skipCall |= log_msg(
    363                             report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK",
    364                             "%s: %s chain includes a structure with unexpected VkStructureType %s; Allowed structures are [%s]",
    365                             apiName, parameterName, typeName.c_str(), allowedStructNames);
    366                     }
    367                 }
    368 
    369                 current = reinterpret_cast<const GenericHeader *>(current->pNext);
    370             }
    371         }
    372     }
    373 
    374     return skipCall;
    375 }
    376 
    377 #endif // PARAMETER_VALIDATION_UTILS_H
    378