diff options
| author | Dustin Graves <dustin@lunarg.com> | 2016-04-18 18:33:21 -0600 |
|---|---|---|
| committer | Dustin Graves <dustin@lunarg.com> | 2016-04-20 10:06:41 -0600 |
| commit | 43901a048d87f5b5dde23298df412c0775c63bfe (patch) | |
| tree | 59ce2bdee5c4407294891f57f0daeb820f8a5151 | |
| parent | f19bf1cab588dbfc51e9c2c8586598aeff43b93b (diff) | |
| download | usermoji-43901a048d87f5b5dde23298df412c0775c63bfe.tar.xz | |
layers: Add handle NULL checks to codegen
Add support for validating that required handle parameters are not
specified as VK_NULL_HANDLE to the parameter validation layer's code
generator.
- Add new parameter validation utility functions to validate required
handles and arrays of handles.
- Add new parameter validation layer entrypoints for functions that
previously had no parameters to validate.
- Add handle validation logic to the parameter validation code generator.
Change-Id: I7a5680954245db4c1b12587f78e30e17c3903d6c
| -rw-r--r-- | generator.py | 59 | ||||
| -rw-r--r-- | layers/parameter_validation.cpp | 240 | ||||
| -rw-r--r-- | layers/parameter_validation_utils.h | 83 |
3 files changed, 329 insertions, 53 deletions
diff --git a/generator.py b/generator.py index 8040346f..0bf6e95d 100644 --- a/generator.py +++ b/generator.py @@ -2845,6 +2845,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): self.structNames = [] # List of Vulkan struct typenames self.stypes = [] # Values from the VkStructureType enumeration self.structTypes = dict() # Map of Vulkan struct typename to required VkStructureType + self.handleTypes = set() # Set of handle type names self.commands = [] # List of CommandData records for all Vulkan commands self.structMembers = [] # List of StructMemberData records for all Vulkan structs self.validatedStructs = dict() # Map of structs type names to generated validation code for that struct type @@ -2852,7 +2853,8 @@ class ParamCheckerOutputGenerator(OutputGenerator): # Named tuples to store struct and command data self.StructType = namedtuple('StructType', ['name', 'value']) self.CommandParam = namedtuple('CommandParam', ['type', 'name', 'ispointer', 'isstaticarray', 'isbool', 'israngedenum', - 'isconst', 'isoptional', 'iscount', 'len', 'extstructs', 'condition', 'cdecl']) + 'isconst', 'isoptional', 'iscount', 'noautovalidity', 'len', 'extstructs', + 'condition', 'cdecl']) self.CommandData = namedtuple('CommandData', ['name', 'params', 'cdecl']) self.StructMemberData = namedtuple('StructMemberData', ['name', 'members']) # @@ -2915,6 +2917,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): self.structNames = [] self.stypes = [] self.structTypes = dict() + self.handleTypes = set() self.commands = [] self.structMembers = [] self.validatedStructs = dict() @@ -2960,6 +2963,8 @@ class ParamCheckerOutputGenerator(OutputGenerator): if (category == 'struct' or category == 'union'): self.structNames.append(name) self.genStruct(typeinfo, name) + elif (category == 'handle'): + self.handleTypes.add(name) # # Struct parameter check generation. # This is a special case of the <type> tag where the contents are @@ -3034,6 +3039,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): isconst=True if 'const' in cdecl else False, isoptional=isoptional, iscount=iscount, + noautovalidity=True if member.attrib.get('noautovalidity') is not None else False, len=self.getLen(member), extstructs=member.attrib.get('validextensionstructs') if name == 'pNext' else None, condition=conditions[name] if conditions and name in conditions else None, @@ -3094,6 +3100,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): isconst=True if 'const' in cdecl else False, isoptional=self.paramIsOptional(param), iscount=iscount, + noautovalidity=True if param.attrib.get('noautovalidity') is not None else False, len=self.getLen(param), extstructs=None, condition=None, @@ -3142,6 +3149,20 @@ class ParamCheckerOutputGenerator(OutputGenerator): isoptional = opts return isoptional # + # Check if the handle passed in is optional + # Uses the same logic as ValidityOutputGenerator.isHandleOptional + def isHandleOptional(self, param, lenParam): + # Simple, if it's optional, return true + if param.isoptional: + return True + # If no validity is being generated, it usually means that validity is complex and not absolute, so let's say yes. + if param.noautovalidity: + return True + # If the parameter is an array and we haven't already returned, find out if any of the len parameters are optional + if lenParam and lenParam.isoptional: + return True + return False + # # Retrieve the value of the len tag def getLen(self, param): result = None @@ -3201,7 +3222,8 @@ class ParamCheckerOutputGenerator(OutputGenerator): if '->' in name: # The count is obtained by dereferencing a member of a struct parameter lenParam = self.CommandParam(name=name, iscount=True, ispointer=False, isbool=False, israngedenum=False, isconst=False, - isstaticarray=None, isoptional=False, type=None, len=None, extstructs=None, condition=None, cdecl=None) + isstaticarray=None, isoptional=False, type=None, noautovalidity=False, len=None, extstructs=None, + condition=None, cdecl=None) elif 'latexmath' in name: lenName, decoratedName = self.parseLateXMath(name) lenParam = self.getParamByName(params, lenName) @@ -3211,7 +3233,7 @@ class ParamCheckerOutputGenerator(OutputGenerator): #lenParam = self.CommandParam(name=decoratedName, iscount=param.iscount, ispointer=param.ispointer, # isoptional=param.isoptional, type=param.type, len=param.len, # isstaticarray=param.isstaticarray, extstructs=param.extstructs, - # condition=None, cdecl=param.cdecl) + # noautovalidity=True, condition=None, cdecl=param.cdecl) else: lenParam = self.getParamByName(params, name) return lenParam @@ -3289,6 +3311,22 @@ class ParamCheckerOutputGenerator(OutputGenerator): funcPrintName, valuePrintName, prefix, valueRequired, vn=value.name, sv=stype.value)) return checkExpr # + # Generate the sType check string + def makeHandleCheck(self, prefix, value, lenValue, valueRequired, lenValueRequired, funcPrintName, lenPrintName, valuePrintName): + checkExpr = [] + if lenValue: + # This is assumed to be an output array with a pointer to a count value + if lenValue.ispointer: + raise('Unsupported parameter validation case: Output handle array elements are not NULL checked') + # This is an array with an integer count value + else: + checkExpr.append('skipCall |= validate_handle_array(report_data, "{}", "{ldn}", "{dn}", {pf}{ln}, {pf}{vn}, {}, {});\n'.format( + funcPrintName, lenValueRequired, valueRequired, ln=lenValue.name, ldn=lenPrintName, dn=valuePrintName, vn=value.name, pf=prefix)) + # This is assumed to be an output handle pointer + else: + raise('Unsupported parameter validation case: Output handles are not NULL checked') + return checkExpr + # # Generate pNext check string def makeStructNextCheck(self, prefix, value, funcPrintName, valuePrintName): checkExpr = [] @@ -3431,6 +3469,9 @@ class ParamCheckerOutputGenerator(OutputGenerator): # If this is a pointer to a struct with an sType field, verify the type if value.type in self.structTypes: usedLines += self.makeStructTypeCheck(valuePrefix, value, lenParam, req, cvReq, cpReq, funcName, lenDisplayName, valueDisplayName) + # If this is an input handle array that is not allowed to contain NULL handles, verify that none of the handles are VK_NULL_HANDLE + elif value.type in self.handleTypes and value.isconst and not self.isHandleOptional(value, lenParam): + usedLines += self.makeHandleCheck(valuePrefix, value, lenParam, req, cvReq, funcName, lenDisplayName, valueDisplayName) elif value.name == 'pNext': # We need to ignore VkDeviceCreateInfo and VkInstanceCreateInfo, as the loader manipulates them in a way that is not documented in vk.xml if not structTypeName in ['VkDeviceCreateInfo', 'VkInstanceCreateInfo']: @@ -3451,6 +3492,9 @@ class ParamCheckerOutputGenerator(OutputGenerator): memberNamePrefix = '{}{}.'.format(valuePrefix, value.name) memberDisplayNamePrefix = '{}.'.format(valueDisplayName) usedLines.append(self.expandStructCode(self.validatedStructs[value.type], funcName, memberNamePrefix, memberDisplayNamePrefix, '', [])) + elif value.type in self.handleTypes: + if not self.isHandleOptional(value, None): + usedLines.append('skipCall |= validate_required_handle(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name)) elif value.isbool: usedLines.append('skipCall |= validate_bool32(report_data, "{}", "{}", {}{});\n'.format(funcName, valueDisplayName, valuePrefix, value.name)) elif value.israngedenum: @@ -3483,7 +3527,9 @@ class ParamCheckerOutputGenerator(OutputGenerator): def processCmdData(self): indent = self.incIndent(None) for command in self.commands: - lines, unused = self.genFuncBody(command.name, command.params, '', '', None) + # Skip first parameter if it is a dispatch handle (everything except vkCreateInstance) + startIndex = 0 if command.name == 'vkCreateInstance' else 1 + lines, unused = self.genFuncBody(command.name, command.params[startIndex:], '', '', None) if lines: cmdDef = self.getCmdDef(command) + '\n' cmdDef += '{\n' @@ -3491,10 +3537,9 @@ class ParamCheckerOutputGenerator(OutputGenerator): # processed by parameter_validation (except for vkCreateInstance, which does not have a # handle as its first parameter) if unused: - startIndex = 0 if command.name == 'vkCreateInstance' else 1 - for name in unused[startIndex:]: + for name in unused: cmdDef += indent + 'UNUSED_PARAMETER({});\n'.format(name) - if len(unused) > startIndex: + if len(unused) > 0: cmdDef += '\n' cmdDef += indent + 'bool skipCall = false;\n' for line in lines: diff --git a/layers/parameter_validation.cpp b/layers/parameter_validation.cpp index c8d2f42f..9a995d98 100644 --- a/layers/parameter_validation.cpp +++ b/layers/parameter_validation.cpp @@ -1485,12 +1485,6 @@ void validateDeviceCreateInfo(VkPhysicalDevice physicalDevice, const VkDeviceCre set.insert(pCreateInfo->pQueueCreateInfos[i].queueFamilyIndex); } - if (pCreateInfo->pQueueCreateInfos[i].queueCount == 0) { - log_msg(mdd(physicalDevice), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, - "PARAMCHECK", "VkDeviceCreateInfo parameter, uint32_t pQueueCreateInfos[%d]->queueCount, cannot be zero.", - i); - } - if (pCreateInfo->pQueueCreateInfos[i].pQueuePriorities != nullptr) { for (uint32_t j = 0; j < pCreateInfo->pQueueCreateInfos[i].queueCount; ++j) { if ((pCreateInfo->pQueueCreateInfos[i].pQueuePriorities[j] < 0.f) || @@ -1748,6 +1742,18 @@ vkMapMemory(VkDevice device, VkDeviceMemory memory, VkDeviceSize offset, VkDevic return result; } +VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkUnmapMemory(VkDevice device, VkDeviceMemory memory) { + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkUnmapMemory(my_data->report_data, memory); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, device)->UnmapMemory(device, memory); + } +} + VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkFlushMappedMemoryRanges(VkDevice device, uint32_t memoryRangeCount, const VkMappedMemoryRange *pMemoryRanges) { VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; @@ -1798,26 +1804,38 @@ vkGetDeviceMemoryCommitment(VkDevice device, VkDeviceMemory memory, VkDeviceSize } } -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory mem, VkDeviceSize memoryOffset) { +VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkBindBufferMemory(VkDevice device, VkBuffer buffer, VkDeviceMemory memory, + VkDeviceSize memoryOffset) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->BindBufferMemory(device, buffer, mem, memoryOffset); + skipCall |= parameter_validation_vkBindBufferMemory(my_data->report_data, buffer, memory, memoryOffset); - validate_result(my_data->report_data, "vkBindBufferMemory", result); + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->BindBufferMemory(device, buffer, memory, memoryOffset); + + validate_result(my_data->report_data, "vkBindBufferMemory", result); + } return result; } -VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL -vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory mem, VkDeviceSize memoryOffset) { +VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkBindImageMemory(VkDevice device, VkImage image, VkDeviceMemory memory, + VkDeviceSize memoryOffset) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->BindImageMemory(device, image, mem, memoryOffset); + skipCall |= parameter_validation_vkBindImageMemory(my_data->report_data, image, memory, memoryOffset); - validate_result(my_data->report_data, "vkBindImageMemory", result); + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->BindImageMemory(device, image, memory, memoryOffset); + + validate_result(my_data->report_data, "vkBindImageMemory", result); + } return result; } @@ -1985,12 +2003,18 @@ VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetFences(VkDevice device, ui } VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetFenceStatus(VkDevice device, VkFence fence) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->GetFenceStatus(device, fence); + skipCall |= parameter_validation_vkGetFenceStatus(my_data->report_data, fence); - validate_result(my_data->report_data, "vkGetFenceStatus", result); + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->GetFenceStatus(device, fence); + + validate_result(my_data->report_data, "vkGetFenceStatus", result); + } return result; } @@ -2075,34 +2099,52 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkDestroyEvent(VkDevice device, VkEve } VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkGetEventStatus(VkDevice device, VkEvent event) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->GetEventStatus(device, event); + skipCall |= parameter_validation_vkGetEventStatus(my_data->report_data, event); + + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->GetEventStatus(device, event); - validate_result(my_data->report_data, "vkGetEventStatus", result); + validate_result(my_data->report_data, "vkGetEventStatus", result); + } return result; } VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkSetEvent(VkDevice device, VkEvent event) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->SetEvent(device, event); + skipCall |= parameter_validation_vkSetEvent(my_data->report_data, event); - validate_result(my_data->report_data, "vkSetEvent", result); + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->SetEvent(device, event); + + validate_result(my_data->report_data, "vkSetEvent", result); + } return result; } VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetEvent(VkDevice device, VkEvent event) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->ResetEvent(device, event); + skipCall |= parameter_validation_vkResetEvent(my_data->report_data, event); - validate_result(my_data->report_data, "vkSetEvent", result); + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->ResetEvent(device, event); + + validate_result(my_data->report_data, "vkResetEvent", result); + } return result; } @@ -2474,10 +2516,6 @@ bool PreCreateGraphicsPipelines(VkDevice device, const VkGraphicsPipelineCreateI return false; } } - if (pCreateInfos->renderPass == VK_NULL_HANDLE) { - log_msg(mdd(device), VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, "PARAMCHECK", - "vkCreateGraphicsPipelines parameter, VkRenderPass pCreateInfos->renderPass, is null pointer"); - } int i = 0; for (size_t j = 0; j < pCreateInfos[i].stageCount; j++) { @@ -2696,12 +2734,18 @@ vkDestroyDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, const VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetDescriptorPool(VkDevice device, VkDescriptorPool descriptorPool, VkDescriptorPoolResetFlags flags) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->ResetDescriptorPool(device, descriptorPool, flags); + skipCall |= parameter_validation_vkResetDescriptorPool(my_data->report_data, descriptorPool, flags); + + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->ResetDescriptorPool(device, descriptorPool, flags); - validate_result(my_data->report_data, "vkResetDescriptorPool", result); + validate_result(my_data->report_data, "vkResetDescriptorPool", result); + } return result; } @@ -2873,12 +2917,18 @@ vkDestroyCommandPool(VkDevice device, VkCommandPool commandPool, const VkAllocat VK_LAYER_EXPORT VKAPI_ATTR VkResult VKAPI_CALL vkResetCommandPool(VkDevice device, VkCommandPool commandPool, VkCommandPoolResetFlags flags) { + VkResult result = VK_ERROR_VALIDATION_FAILED_EXT; + bool skipCall = false; layer_data *my_data = get_my_data_ptr(get_dispatch_key(device), layer_data_map); assert(my_data != NULL); - VkResult result = get_dispatch_table(pc_device_table_map, device)->ResetCommandPool(device, commandPool, flags); + skipCall |= parameter_validation_vkResetCommandPool(my_data->report_data, commandPool, flags); - validate_result(my_data->report_data, "vkResetCommandPool", result); + if (!skipCall) { + result = get_dispatch_table(pc_device_table_map, device)->ResetCommandPool(device, commandPool, flags); + + validate_result(my_data->report_data, "vkResetCommandPool", result); + } return result; } @@ -3123,12 +3173,29 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexed(VkCommandBuffer comm VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdDrawIndirect(my_data->report_data, buffer, offset, count, stride); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDrawIndirect(commandBuffer, buffer, offset, count, stride); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDrawIndexedIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset, uint32_t count, uint32_t stride) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdDrawIndexedIndirect(my_data->report_data, buffer, offset, count, stride); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer) + ->CmdDrawIndexedIndirect(commandBuffer, buffer, offset, count, stride); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer commandBuffer, uint32_t x, uint32_t y, uint32_t z) { @@ -3137,7 +3204,15 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatch(VkCommandBuffer command VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdDispatchIndirect(VkCommandBuffer commandBuffer, VkBuffer buffer, VkDeviceSize offset) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDispatchIndirect(commandBuffer, buffer, offset); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdDispatchIndirect(my_data->report_data, buffer, offset); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdDispatchIndirect(commandBuffer, buffer, offset); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyBuffer(VkCommandBuffer commandBuffer, VkBuffer srcBuffer, VkBuffer dstBuffer, @@ -3308,7 +3383,15 @@ VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdUpdateBuffer(VkCommandBuffer com VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdFillBuffer(VkCommandBuffer commandBuffer, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize size, uint32_t data) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdFillBuffer(my_data->report_data, dstBuffer, dstOffset, size, data); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdFillBuffer(commandBuffer, dstBuffer, dstOffset, size, data); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdClearColorImage(VkCommandBuffer commandBuffer, VkImage image, @@ -3399,12 +3482,28 @@ vkCmdResolveImage(VkCommandBuffer commandBuffer, VkImage srcImage, VkImageLayout VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdSetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetEvent(commandBuffer, event, stageMask); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdSetEvent(my_data->report_data, event, stageMask); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdSetEvent(commandBuffer, event, stageMask); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdResetEvent(VkCommandBuffer commandBuffer, VkEvent event, VkPipelineStageFlags stageMask) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdResetEvent(commandBuffer, event, stageMask); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdResetEvent(my_data->report_data, event, stageMask); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdResetEvent(commandBuffer, event, stageMask); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL @@ -3449,16 +3548,40 @@ vkCmdPipelineBarrier(VkCommandBuffer commandBuffer, VkPipelineStageFlags srcStag VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdBeginQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot, VkQueryControlFlags flags) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdBeginQuery(commandBuffer, queryPool, slot, flags); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdBeginQuery(my_data->report_data, queryPool, slot, flags); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdBeginQuery(commandBuffer, queryPool, slot, flags); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdEndQuery(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t slot) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdEndQuery(commandBuffer, queryPool, slot); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdEndQuery(my_data->report_data, queryPool, slot); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdEndQuery(commandBuffer, queryPool, slot); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdResetQueryPool(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdResetQueryPool(my_data->report_data, queryPool, firstQuery, queryCount); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdResetQueryPool(commandBuffer, queryPool, firstQuery, queryCount); + } } bool PostCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, @@ -3469,18 +3592,35 @@ bool PostCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBit return true; } -VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL -vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, VkQueryPool queryPool, uint32_t slot) { - get_dispatch_table(pc_device_table_map, commandBuffer)->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot); +VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdWriteTimestamp(VkCommandBuffer commandBuffer, VkPipelineStageFlagBits pipelineStage, + VkQueryPool queryPool, uint32_t query) { + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdWriteTimestamp(my_data->report_data, pipelineStage, queryPool, query); - PostCmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, slot); + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer)->CmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query); + + PostCmdWriteTimestamp(commandBuffer, pipelineStage, queryPool, query); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdCopyQueryPoolResults(VkCommandBuffer commandBuffer, VkQueryPool queryPool, uint32_t firstQuery, uint32_t queryCount, VkBuffer dstBuffer, VkDeviceSize dstOffset, VkDeviceSize stride, VkQueryResultFlags flags) { - get_dispatch_table(pc_device_table_map, commandBuffer) - ->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags); + bool skipCall = false; + layer_data *my_data = get_my_data_ptr(get_dispatch_key(commandBuffer), layer_data_map); + assert(my_data != NULL); + + skipCall |= parameter_validation_vkCmdCopyQueryPoolResults(my_data->report_data, queryPool, firstQuery, queryCount, dstBuffer, + dstOffset, stride, flags); + + if (!skipCall) { + get_dispatch_table(pc_device_table_map, commandBuffer) + ->CmdCopyQueryPoolResults(commandBuffer, queryPool, firstQuery, queryCount, dstBuffer, dstOffset, stride, flags); + } } VK_LAYER_EXPORT VKAPI_ATTR void VKAPI_CALL vkCmdPushConstants(VkCommandBuffer commandBuffer, VkPipelineLayout layout, @@ -3566,10 +3706,18 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkD return (PFN_vkVoidFunction)vkFreeMemory; if (!strcmp(funcName, "vkMapMemory")) return (PFN_vkVoidFunction)vkMapMemory; + if (!strcmp(funcName, "vkUnmapMemory")) + return (PFN_vkVoidFunction)vkUnmapMemory; if (!strcmp(funcName, "vkFlushMappedMemoryRanges")) return (PFN_vkVoidFunction)vkFlushMappedMemoryRanges; if (!strcmp(funcName, "vkInvalidateMappedMemoryRanges")) return (PFN_vkVoidFunction)vkInvalidateMappedMemoryRanges; + if (!strcmp(funcName, "vkGetDeviceMemoryCommitment")) + return (PFN_vkVoidFunction)vkGetDeviceMemoryCommitment; + if (!strcmp(funcName, "vkBindBufferMemory")) + return (PFN_vkVoidFunction)vkBindBufferMemory; + if (!strcmp(funcName, "vkBindImageMemory")) + return (PFN_vkVoidFunction)vkBindImageMemory; if (!strcmp(funcName, "vkCreateFence")) return (PFN_vkVoidFunction)vkCreateFence; if (!strcmp(funcName, "vkDestroyFence")) @@ -3754,6 +3902,8 @@ VK_LAYER_EXPORT VKAPI_ATTR PFN_vkVoidFunction VKAPI_CALL vkGetDeviceProcAddr(VkD return (PFN_vkVoidFunction)vkCreateCommandPool; if (!strcmp(funcName, "vkDestroyCommandPool")) return (PFN_vkVoidFunction)vkDestroyCommandPool; + if (!strcmp(funcName, "vkResetCommandPool")) + return (PFN_vkVoidFunction)vkResetCommandPool; if (!strcmp(funcName, "vkCmdBeginRenderPass")) return (PFN_vkVoidFunction)vkCmdBeginRenderPass; if (!strcmp(funcName, "vkCmdNextSubpass")) diff --git a/layers/parameter_validation_utils.h b/layers/parameter_validation_utils.h index 70e5fccc..83315f6d 100644 --- a/layers/parameter_validation_utils.h +++ b/layers/parameter_validation_utils.h @@ -161,7 +161,11 @@ bool validate_array(debug_report_data *report_data, const char *apiName, const c } /** - * Validate an Vulkan structure type. + * Validate a pointer to a Vulkan structure. + * + * Verify that a required pointer to a structure is not NULL. If the pointer is + * not NULL, verify that each structure's sType field is set to the correct + * VkStructureType value. * * @param report_data debug_report_data object for routing validation messages. * @param apiName Name of API call being validated. @@ -283,6 +287,83 @@ bool validate_struct_type_array(debug_report_data *report_data, const char *apiN } /** +* Validate a Vulkan handle. +* +* Verify that the specified handle is not VK_NULL_HANDLE. +* +* @param report_data debug_report_data object for routing validation messages. +* @param api_name Name of API call being validated. +* @param parameter_name Name of struct parameter being validated. +* @param value Handle to validate. +* @return Boolean value indicating that the call should be skipped. +*/ +template <typename T> +bool validate_required_handle(debug_report_data *report_data, const char *api_name, const char *parameter_name, T value) { + bool skip_call = false; + + if (value == VK_NULL_HANDLE) { + skip_call |= + log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: required parameter %s specified as VK_NULL_HANDLE", api_name, parameter_name); + } + + return skip_call; +} + +/** +* Validate an array of Vulkan handles. +* +* Verify that required count and array parameters are not NULL. If count +* is not NULL and its value is not optional, verify that it is not 0. +* If the array contains 1 or more handles, verify that no handle is set to +* VK_NULL_HANDLE. +* +* @note This function is only intended to validate arrays of handles when none +* of the handles are allowed to be VK_NULL_HANDLE. For arrays of handles +* that are allowed to contain VK_NULL_HANDLE, use validate_array() instead. +* +* @param report_data debug_report_data object for routing validation messages. +* @param api_name Name of API call being validated. +* @param count_name Name of count parameter. +* @param array_name Name of array parameter. +* @param count Number of elements in the array. +* @param array Array to validate. +* @param count_required The 'count' parameter may not be 0 when true. +* @param array_required The 'array' parameter may not be NULL when true. +* @return Boolean value indicating that the call should be skipped. +*/ +template <typename T> +bool validate_handle_array(debug_report_data *report_data, const char *api_name, const char *count_name, const char *array_name, + uint32_t count, const T *array, bool count_required, bool array_required) { + bool skip_call = false; + + if ((count == 0) || (array == NULL)) { + // Count parameters not tagged as optional cannot be 0 + if ((count == 0) && count_required) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: parameter %s must be greater than 0", api_name, count_name); + } + + // Array parameters not tagged as optional cannot be NULL, unless the count is 0 + if ((array == NULL) && array_required && (count != 0)) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: required parameter %s specified as NULL", api_name, array_name); + } + } else { + // Verify that no handles in the array are VK_NULL_HANDLE + for (uint32_t i = 0; i < count; ++i) { + if (array[i] == VK_NULL_HANDLE) { + skip_call |= log_msg(report_data, VK_DEBUG_REPORT_ERROR_BIT_EXT, (VkDebugReportObjectTypeEXT)0, 0, __LINE__, 1, + ParameterValidationName, "%s: required parameter %s[%d] specified as VK_NULL_HANDLE", api_name, + array_name, i); + } + } + } + + return skip_call; +} + +/** * Validate string array count and content. * * Verify that required count and array parameters are not 0 or NULL. If the |
